Currently, tests panic if compiled with tinygo v0.33 when decoding data with 24+ nested levels. This commit reduces default MaxNestedLevels to 16 (was 32). To allow testing, etc. the user configurable limits are unchanged (allows up to 65535).
10079 lines
314 KiB
Go
10079 lines
314 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"
|
|
"encoding/binary"
|
|
"encoding/hex"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"math"
|
|
"math/big"
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
var (
|
|
typeBool = reflect.TypeOf(true)
|
|
typeUint8 = reflect.TypeOf(uint8(0))
|
|
typeUint16 = reflect.TypeOf(uint16(0))
|
|
typeUint32 = reflect.TypeOf(uint32(0))
|
|
typeUint64 = reflect.TypeOf(uint64(0))
|
|
typeInt8 = reflect.TypeOf(int8(0))
|
|
typeInt16 = reflect.TypeOf(int16(0))
|
|
typeInt32 = reflect.TypeOf(int32(0))
|
|
typeInt64 = reflect.TypeOf(int64(0))
|
|
typeFloat32 = reflect.TypeOf(float32(0))
|
|
typeFloat64 = reflect.TypeOf(float64(0))
|
|
typeByteArray = reflect.TypeOf([5]byte{})
|
|
typeIntSlice = reflect.TypeOf([]int{})
|
|
typeStringSlice = reflect.TypeOf([]string{})
|
|
typeMapIntfIntf = reflect.TypeOf(map[interface{}]interface{}{})
|
|
typeMapStringInt = reflect.TypeOf(map[string]int{})
|
|
typeMapStringString = reflect.TypeOf(map[string]string{})
|
|
typeMapStringIntf = reflect.TypeOf(map[string]interface{}{})
|
|
)
|
|
|
|
type unmarshalTest struct {
|
|
data []byte
|
|
wantInterfaceValue interface{}
|
|
wantValues []interface{}
|
|
wrongTypes []reflect.Type
|
|
}
|
|
|
|
var unmarshalTests = []unmarshalTest{
|
|
// CBOR test data are from https://tools.ietf.org/html/rfc7049#appendix-A.
|
|
|
|
// unsigned integer
|
|
{
|
|
data: hexDecode("00"),
|
|
wantInterfaceValue: uint64(0),
|
|
wantValues: []interface{}{
|
|
uint8(0),
|
|
uint16(0),
|
|
uint32(0),
|
|
uint64(0),
|
|
uint(0),
|
|
int8(0),
|
|
int16(0),
|
|
int32(0),
|
|
int64(0),
|
|
int(0),
|
|
float32(0),
|
|
float64(0),
|
|
bigIntOrPanic("0"),
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeString,
|
|
typeBool,
|
|
typeByteArray,
|
|
typeIntSlice,
|
|
typeMapStringInt,
|
|
typeTag,
|
|
typeRawTag,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
},
|
|
{
|
|
data: hexDecode("01"),
|
|
wantInterfaceValue: uint64(1),
|
|
wantValues: []interface{}{
|
|
uint8(1),
|
|
uint16(1),
|
|
uint32(1),
|
|
uint64(1),
|
|
uint(1),
|
|
int8(1),
|
|
int16(1),
|
|
int32(1),
|
|
int64(1),
|
|
int(1),
|
|
float32(1),
|
|
float64(1),
|
|
bigIntOrPanic("1"),
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeString,
|
|
typeBool,
|
|
typeByteArray,
|
|
typeIntSlice,
|
|
typeMapStringInt,
|
|
typeTag,
|
|
typeRawTag,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
},
|
|
{
|
|
data: hexDecode("0a"),
|
|
wantInterfaceValue: uint64(10),
|
|
wantValues: []interface{}{
|
|
uint8(10),
|
|
uint16(10),
|
|
uint32(10),
|
|
uint64(10),
|
|
uint(10),
|
|
int8(10),
|
|
int16(10),
|
|
int32(10),
|
|
int64(10),
|
|
int(10),
|
|
float32(10),
|
|
float64(10),
|
|
bigIntOrPanic("10"),
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeString,
|
|
typeBool,
|
|
typeByteArray,
|
|
typeIntSlice,
|
|
typeMapStringInt,
|
|
typeTag,
|
|
typeRawTag,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
},
|
|
{
|
|
data: hexDecode("17"),
|
|
wantInterfaceValue: uint64(23),
|
|
wantValues: []interface{}{
|
|
uint8(23),
|
|
uint16(23),
|
|
uint32(23),
|
|
uint64(23),
|
|
uint(23),
|
|
int8(23),
|
|
int16(23),
|
|
int32(23),
|
|
int64(23),
|
|
int(23),
|
|
float32(23),
|
|
float64(23),
|
|
bigIntOrPanic("23"),
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeString,
|
|
typeBool,
|
|
typeByteArray,
|
|
typeIntSlice,
|
|
typeMapStringInt,
|
|
typeTag,
|
|
typeRawTag,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
},
|
|
{
|
|
data: hexDecode("1818"),
|
|
wantInterfaceValue: uint64(24),
|
|
wantValues: []interface{}{
|
|
uint8(24),
|
|
uint16(24),
|
|
uint32(24),
|
|
uint64(24),
|
|
uint(24),
|
|
int8(24),
|
|
int16(24),
|
|
int32(24),
|
|
int64(24),
|
|
int(24),
|
|
float32(24),
|
|
float64(24),
|
|
bigIntOrPanic("24"),
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeString,
|
|
typeBool,
|
|
typeByteArray,
|
|
typeIntSlice,
|
|
typeMapStringInt,
|
|
typeTag,
|
|
typeRawTag,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
},
|
|
{
|
|
data: hexDecode("1819"),
|
|
wantInterfaceValue: uint64(25),
|
|
wantValues: []interface{}{
|
|
uint8(25),
|
|
uint16(25),
|
|
uint32(25),
|
|
uint64(25),
|
|
uint(25),
|
|
int8(25),
|
|
int16(25),
|
|
int32(25),
|
|
int64(25),
|
|
int(25),
|
|
float32(25),
|
|
float64(25),
|
|
bigIntOrPanic("25"),
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeString,
|
|
typeBool,
|
|
typeByteArray,
|
|
typeIntSlice,
|
|
typeMapStringInt,
|
|
typeTag,
|
|
typeRawTag,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
},
|
|
{
|
|
data: hexDecode("1864"),
|
|
wantInterfaceValue: uint64(100),
|
|
wantValues: []interface{}{
|
|
uint8(100),
|
|
uint16(100),
|
|
uint32(100),
|
|
uint64(100),
|
|
uint(100),
|
|
int8(100),
|
|
int16(100),
|
|
int32(100),
|
|
int64(100),
|
|
int(100),
|
|
float32(100),
|
|
float64(100),
|
|
bigIntOrPanic("100"),
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeString,
|
|
typeBool,
|
|
typeByteArray,
|
|
typeIntSlice,
|
|
typeMapStringInt,
|
|
typeTag,
|
|
typeRawTag,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
},
|
|
{
|
|
data: hexDecode("1903e8"),
|
|
wantInterfaceValue: uint64(1000),
|
|
wantValues: []interface{}{
|
|
uint16(1000),
|
|
uint32(1000),
|
|
uint64(1000),
|
|
uint(1000),
|
|
int16(1000),
|
|
int32(1000),
|
|
int64(1000),
|
|
int(1000),
|
|
float32(1000),
|
|
float64(1000),
|
|
bigIntOrPanic("1000"),
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeInt8,
|
|
typeString,
|
|
typeBool,
|
|
typeByteArray,
|
|
typeIntSlice,
|
|
typeMapStringInt,
|
|
typeTag,
|
|
typeRawTag,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
},
|
|
{
|
|
data: hexDecode("1a000f4240"),
|
|
wantInterfaceValue: uint64(1000000),
|
|
wantValues: []interface{}{
|
|
uint32(1000000),
|
|
uint64(1000000),
|
|
uint(1000000),
|
|
int32(1000000),
|
|
int64(1000000),
|
|
int(1000000),
|
|
float32(1000000),
|
|
float64(1000000),
|
|
bigIntOrPanic("1000000"),
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeInt8,
|
|
typeInt16,
|
|
typeString,
|
|
typeBool,
|
|
typeByteArray,
|
|
typeIntSlice,
|
|
typeMapStringInt,
|
|
typeTag,
|
|
typeRawTag,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
},
|
|
{
|
|
data: hexDecode("1b000000e8d4a51000"),
|
|
wantInterfaceValue: uint64(1000000000000),
|
|
wantValues: []interface{}{
|
|
uint64(1000000000000),
|
|
uint(1000000000000),
|
|
int64(1000000000000),
|
|
int(1000000000000),
|
|
float32(1000000000000),
|
|
float64(1000000000000),
|
|
bigIntOrPanic("1000000000000"),
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeUint32,
|
|
typeInt8,
|
|
typeInt16,
|
|
typeInt32,
|
|
typeString,
|
|
typeBool,
|
|
typeByteArray,
|
|
typeIntSlice,
|
|
typeMapStringInt,
|
|
typeTag,
|
|
typeRawTag,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
},
|
|
{
|
|
data: hexDecode("1bffffffffffffffff"),
|
|
wantInterfaceValue: uint64(18446744073709551615),
|
|
wantValues: []interface{}{
|
|
uint64(18446744073709551615),
|
|
uint(18446744073709551615),
|
|
float32(18446744073709551615),
|
|
float64(18446744073709551615),
|
|
bigIntOrPanic("18446744073709551615"),
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeUint32,
|
|
typeInt8,
|
|
typeInt16,
|
|
typeInt32,
|
|
typeString,
|
|
typeBool,
|
|
typeByteArray,
|
|
typeIntSlice,
|
|
typeMapStringInt,
|
|
typeTag,
|
|
typeRawTag,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
},
|
|
|
|
// negative integer
|
|
{
|
|
data: hexDecode("20"),
|
|
wantInterfaceValue: int64(-1),
|
|
wantValues: []interface{}{
|
|
int8(-1),
|
|
int16(-1),
|
|
int32(-1),
|
|
int64(-1),
|
|
int(-1),
|
|
float32(-1),
|
|
float64(-1),
|
|
bigIntOrPanic("-1"),
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeUint32,
|
|
typeUint64,
|
|
typeString,
|
|
typeBool,
|
|
typeByteArray,
|
|
typeIntSlice,
|
|
typeMapStringInt,
|
|
typeTag,
|
|
typeRawTag,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
},
|
|
{
|
|
data: hexDecode("29"),
|
|
wantInterfaceValue: int64(-10),
|
|
wantValues: []interface{}{
|
|
int8(-10),
|
|
int16(-10),
|
|
int32(-10),
|
|
int64(-10),
|
|
int(-10),
|
|
float32(-10),
|
|
float64(-10),
|
|
bigIntOrPanic("-10"),
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeUint32,
|
|
typeUint64,
|
|
typeString,
|
|
typeBool,
|
|
typeByteArray,
|
|
typeIntSlice,
|
|
typeMapStringInt,
|
|
typeTag,
|
|
typeRawTag,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
},
|
|
{
|
|
data: hexDecode("3863"),
|
|
wantInterfaceValue: int64(-100),
|
|
wantValues: []interface{}{
|
|
int8(-100),
|
|
int16(-100),
|
|
int32(-100),
|
|
int64(-100),
|
|
int(-100),
|
|
float32(-100),
|
|
float64(-100),
|
|
bigIntOrPanic("-100"),
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeUint32,
|
|
typeUint64,
|
|
typeString,
|
|
typeBool,
|
|
typeByteArray,
|
|
typeIntSlice,
|
|
typeMapStringInt,
|
|
typeTag,
|
|
typeRawTag,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
},
|
|
{
|
|
data: hexDecode("3903e7"),
|
|
wantInterfaceValue: int64(-1000),
|
|
wantValues: []interface{}{
|
|
int16(-1000),
|
|
int32(-1000),
|
|
int64(-1000),
|
|
int(-1000),
|
|
float32(-1000),
|
|
float64(-1000),
|
|
bigIntOrPanic("-1000"),
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeUint32,
|
|
typeUint64,
|
|
typeInt8,
|
|
typeString,
|
|
typeBool,
|
|
typeByteArray,
|
|
typeIntSlice,
|
|
typeMapStringInt,
|
|
typeTag,
|
|
typeRawTag,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
},
|
|
{
|
|
data: hexDecode("3bffffffffffffffff"),
|
|
wantInterfaceValue: bigIntOrPanic("-18446744073709551616"),
|
|
wantValues: []interface{}{
|
|
bigIntOrPanic("-18446744073709551616"),
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeUint32,
|
|
typeUint64,
|
|
typeInt8,
|
|
typeInt16,
|
|
typeInt32,
|
|
typeInt64,
|
|
typeString,
|
|
typeBool,
|
|
typeByteArray,
|
|
typeIntSlice,
|
|
typeMapStringInt,
|
|
typeTag,
|
|
typeRawTag,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
}, // CBOR value -18446744073709551616 overflows Go's int64, see TestNegIntOverflow
|
|
|
|
// byte string
|
|
{
|
|
data: hexDecode("40"),
|
|
wantInterfaceValue: []byte{},
|
|
wantValues: []interface{}{
|
|
[]byte{},
|
|
[0]byte{},
|
|
[1]byte{0},
|
|
[5]byte{0, 0, 0, 0, 0},
|
|
ByteString(""),
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeUint32,
|
|
typeUint64,
|
|
typeInt8,
|
|
typeInt16,
|
|
typeInt32,
|
|
typeInt64,
|
|
typeFloat32,
|
|
typeFloat64,
|
|
typeBool,
|
|
typeIntSlice,
|
|
typeMapStringInt,
|
|
typeTag,
|
|
typeRawTag,
|
|
typeBigInt,
|
|
typeSimpleValue,
|
|
},
|
|
},
|
|
{
|
|
data: hexDecode("4401020304"),
|
|
wantInterfaceValue: []byte{1, 2, 3, 4},
|
|
wantValues: []interface{}{
|
|
[]byte{1, 2, 3, 4},
|
|
[0]byte{},
|
|
[1]byte{1},
|
|
[5]byte{1, 2, 3, 4, 0},
|
|
ByteString("\x01\x02\x03\x04"),
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeUint32,
|
|
typeUint64,
|
|
typeInt8,
|
|
typeInt16,
|
|
typeInt32,
|
|
typeInt64,
|
|
typeFloat32,
|
|
typeFloat64,
|
|
typeBool,
|
|
typeIntSlice,
|
|
typeMapStringInt,
|
|
typeTag,
|
|
typeRawTag,
|
|
typeBigInt,
|
|
typeSimpleValue,
|
|
},
|
|
},
|
|
{
|
|
data: hexDecode("5f42010243030405ff"),
|
|
wantInterfaceValue: []byte{1, 2, 3, 4, 5},
|
|
wantValues: []interface{}{
|
|
[]byte{1, 2, 3, 4, 5},
|
|
[0]byte{},
|
|
[1]byte{1},
|
|
[5]byte{1, 2, 3, 4, 5},
|
|
[6]byte{1, 2, 3, 4, 5, 0},
|
|
ByteString("\x01\x02\x03\x04\x05"),
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeUint32,
|
|
typeUint64,
|
|
typeInt8,
|
|
typeInt16,
|
|
typeInt32,
|
|
typeInt64,
|
|
typeFloat32,
|
|
typeFloat64,
|
|
typeBool,
|
|
typeIntSlice,
|
|
typeMapStringInt,
|
|
typeTag,
|
|
typeRawTag,
|
|
typeBigInt,
|
|
typeSimpleValue,
|
|
},
|
|
},
|
|
|
|
// text string
|
|
{
|
|
data: hexDecode("60"),
|
|
wantInterfaceValue: "",
|
|
wantValues: []interface{}{""},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeUint32,
|
|
typeUint64,
|
|
typeInt8,
|
|
typeInt16,
|
|
typeInt32,
|
|
typeInt64,
|
|
typeFloat32,
|
|
typeFloat64,
|
|
typeBool,
|
|
typeByteArray,
|
|
typeIntSlice,
|
|
typeMapStringInt,
|
|
typeTag,
|
|
typeRawTag,
|
|
typeBigInt,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
},
|
|
{
|
|
data: hexDecode("6161"),
|
|
wantInterfaceValue: "a",
|
|
wantValues: []interface{}{"a"},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeUint32,
|
|
typeUint64,
|
|
typeInt8,
|
|
typeInt16,
|
|
typeInt32,
|
|
typeInt64,
|
|
typeFloat32,
|
|
typeFloat64,
|
|
typeBool,
|
|
typeByteArray,
|
|
typeIntSlice,
|
|
typeMapStringInt,
|
|
typeTag,
|
|
typeRawTag,
|
|
typeBigInt,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
},
|
|
{
|
|
data: hexDecode("6449455446"),
|
|
wantInterfaceValue: "IETF",
|
|
wantValues: []interface{}{"IETF"},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeUint32,
|
|
typeUint64,
|
|
typeInt8,
|
|
typeInt16,
|
|
typeInt32,
|
|
typeInt64,
|
|
typeFloat32,
|
|
typeFloat64,
|
|
typeBool,
|
|
typeByteArray,
|
|
typeIntSlice,
|
|
typeMapStringInt,
|
|
typeTag,
|
|
typeRawTag,
|
|
typeBigInt,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
},
|
|
{
|
|
data: hexDecode("62225c"),
|
|
wantInterfaceValue: "\"\\",
|
|
wantValues: []interface{}{"\"\\"},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeUint32,
|
|
typeUint64,
|
|
typeInt8,
|
|
typeInt16,
|
|
typeInt32,
|
|
typeInt64,
|
|
typeFloat32,
|
|
typeFloat64,
|
|
typeBool,
|
|
typeByteArray,
|
|
typeIntSlice,
|
|
typeMapStringInt,
|
|
typeTag,
|
|
typeRawTag,
|
|
typeBigInt,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
},
|
|
{
|
|
data: hexDecode("62c3bc"),
|
|
wantInterfaceValue: "ü",
|
|
wantValues: []interface{}{"ü"},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeUint32,
|
|
typeUint64,
|
|
typeInt8,
|
|
typeInt16,
|
|
typeInt32,
|
|
typeInt64,
|
|
typeFloat32,
|
|
typeFloat64,
|
|
typeBool,
|
|
typeByteArray,
|
|
typeIntSlice,
|
|
typeMapStringInt,
|
|
typeTag,
|
|
typeRawTag,
|
|
typeBigInt,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
},
|
|
{
|
|
data: hexDecode("63e6b0b4"),
|
|
wantInterfaceValue: "水",
|
|
wantValues: []interface{}{"水"},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeUint32,
|
|
typeUint64,
|
|
typeInt8,
|
|
typeInt16,
|
|
typeInt32,
|
|
typeInt64,
|
|
typeFloat32,
|
|
typeFloat64,
|
|
typeBool,
|
|
typeByteArray,
|
|
typeIntSlice,
|
|
typeMapStringInt,
|
|
typeTag,
|
|
typeRawTag,
|
|
typeBigInt,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
},
|
|
{
|
|
data: hexDecode("64f0908591"),
|
|
wantInterfaceValue: "𐅑",
|
|
wantValues: []interface{}{"𐅑"},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeUint32,
|
|
typeUint64,
|
|
typeInt8,
|
|
typeInt16,
|
|
typeInt32,
|
|
typeInt64,
|
|
typeFloat32,
|
|
typeFloat64,
|
|
typeBool,
|
|
typeByteArray,
|
|
typeIntSlice,
|
|
typeMapStringInt,
|
|
typeTag,
|
|
typeRawTag,
|
|
typeBigInt,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
},
|
|
{
|
|
data: hexDecode("7f657374726561646d696e67ff"),
|
|
wantInterfaceValue: "streaming",
|
|
wantValues: []interface{}{"streaming"},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeUint32,
|
|
typeUint64,
|
|
typeInt8,
|
|
typeInt16,
|
|
typeInt32,
|
|
typeInt64,
|
|
typeFloat32,
|
|
typeFloat64,
|
|
typeBool,
|
|
typeByteArray,
|
|
typeIntSlice,
|
|
typeMapStringInt,
|
|
typeTag,
|
|
typeRawTag,
|
|
typeBigInt,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
},
|
|
|
|
// array
|
|
{
|
|
data: hexDecode("80"),
|
|
wantInterfaceValue: []interface{}{},
|
|
wantValues: []interface{}{
|
|
[]interface{}{},
|
|
[]byte{},
|
|
[]string{},
|
|
[]int{},
|
|
[0]int{},
|
|
[1]int{0},
|
|
[5]int{0},
|
|
[]float32{},
|
|
[]float64{},
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeUint32,
|
|
typeUint64,
|
|
typeInt8,
|
|
typeInt16,
|
|
typeInt32,
|
|
typeInt64,
|
|
typeFloat32,
|
|
typeFloat64,
|
|
typeString,
|
|
typeBool,
|
|
typeMapStringInt,
|
|
typeTag,
|
|
typeRawTag,
|
|
typeBigInt,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
},
|
|
{
|
|
data: hexDecode("83010203"),
|
|
wantInterfaceValue: []interface{}{uint64(1), uint64(2), uint64(3)},
|
|
wantValues: []interface{}{
|
|
[]interface{}{uint64(1), uint64(2), uint64(3)},
|
|
[]byte{1, 2, 3},
|
|
[]int{1, 2, 3},
|
|
[]uint{1, 2, 3},
|
|
[0]int{},
|
|
[1]int{1},
|
|
[3]int{1, 2, 3},
|
|
[5]int{1, 2, 3, 0, 0},
|
|
[]float32{1, 2, 3},
|
|
[]float64{1, 2, 3},
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeUint32,
|
|
typeUint64,
|
|
typeInt8,
|
|
typeInt16,
|
|
typeInt32,
|
|
typeInt64,
|
|
typeFloat32,
|
|
typeFloat64,
|
|
typeString,
|
|
typeBool,
|
|
typeStringSlice,
|
|
typeMapStringInt,
|
|
reflect.TypeOf([3]string{}),
|
|
typeTag,
|
|
typeRawTag,
|
|
typeBigInt,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
},
|
|
{
|
|
data: hexDecode("8301820203820405"),
|
|
wantInterfaceValue: []interface{}{uint64(1), []interface{}{uint64(2), uint64(3)}, []interface{}{uint64(4), uint64(5)}},
|
|
wantValues: []interface{}{
|
|
[]interface{}{uint64(1), []interface{}{uint64(2), uint64(3)}, []interface{}{uint64(4), uint64(5)}},
|
|
[...]interface{}{uint64(1), []interface{}{uint64(2), uint64(3)}, []interface{}{uint64(4), uint64(5)}},
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeUint32,
|
|
typeUint64,
|
|
typeInt8,
|
|
typeInt16,
|
|
typeInt32,
|
|
typeInt64,
|
|
typeFloat32,
|
|
typeFloat64,
|
|
typeString,
|
|
typeBool,
|
|
typeStringSlice,
|
|
typeMapStringInt,
|
|
reflect.TypeOf([3]string{}),
|
|
typeTag,
|
|
typeRawTag,
|
|
typeBigInt,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
},
|
|
{
|
|
data: hexDecode("83018202039f0405ff"),
|
|
wantInterfaceValue: []interface{}{uint64(1), []interface{}{uint64(2), uint64(3)}, []interface{}{uint64(4), uint64(5)}},
|
|
wantValues: []interface{}{
|
|
[]interface{}{uint64(1), []interface{}{uint64(2), uint64(3)}, []interface{}{uint64(4), uint64(5)}},
|
|
[...]interface{}{uint64(1), []interface{}{uint64(2), uint64(3)}, []interface{}{uint64(4), uint64(5)}},
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeUint32,
|
|
typeUint64,
|
|
typeInt8,
|
|
typeInt16,
|
|
typeInt32,
|
|
typeInt64,
|
|
typeFloat32,
|
|
typeFloat64,
|
|
typeString,
|
|
typeBool,
|
|
typeStringSlice,
|
|
typeMapStringInt,
|
|
reflect.TypeOf([3]string{}),
|
|
typeTag,
|
|
typeRawTag,
|
|
typeBigInt,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
},
|
|
{
|
|
data: hexDecode("83019f0203ff820405"),
|
|
wantInterfaceValue: []interface{}{uint64(1), []interface{}{uint64(2), uint64(3)}, []interface{}{uint64(4), uint64(5)}},
|
|
wantValues: []interface{}{
|
|
[]interface{}{uint64(1), []interface{}{uint64(2), uint64(3)}, []interface{}{uint64(4), uint64(5)}},
|
|
[...]interface{}{uint64(1), []interface{}{uint64(2), uint64(3)}, []interface{}{uint64(4), uint64(5)}},
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeUint32,
|
|
typeUint64,
|
|
typeInt8,
|
|
typeInt16,
|
|
typeInt32,
|
|
typeInt64,
|
|
typeFloat32,
|
|
typeFloat64,
|
|
typeString,
|
|
typeBool,
|
|
typeStringSlice,
|
|
typeMapStringInt,
|
|
reflect.TypeOf([3]string{}),
|
|
typeTag,
|
|
typeRawTag,
|
|
typeBigInt,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
},
|
|
{
|
|
data: hexDecode("98190102030405060708090a0b0c0d0e0f101112131415161718181819"),
|
|
wantInterfaceValue: []interface{}{uint64(1), uint64(2), uint64(3), uint64(4), uint64(5), uint64(6), uint64(7), uint64(8), uint64(9), uint64(10), uint64(11), uint64(12), uint64(13), uint64(14), uint64(15), uint64(16), uint64(17), uint64(18), uint64(19), uint64(20), uint64(21), uint64(22), uint64(23), uint64(24), uint64(25)},
|
|
wantValues: []interface{}{
|
|
[]interface{}{uint64(1), uint64(2), uint64(3), uint64(4), uint64(5), uint64(6), uint64(7), uint64(8), uint64(9), uint64(10), uint64(11), uint64(12), uint64(13), uint64(14), uint64(15), uint64(16), uint64(17), uint64(18), uint64(19), uint64(20), uint64(21), uint64(22), uint64(23), uint64(24), uint64(25)},
|
|
[]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25},
|
|
[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25},
|
|
[]uint{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25},
|
|
[0]int{},
|
|
[1]int{1},
|
|
[...]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25},
|
|
[30]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0},
|
|
[]float32{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25},
|
|
[]float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25}},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeUint32,
|
|
typeUint64,
|
|
typeInt8,
|
|
typeInt16,
|
|
typeInt32,
|
|
typeInt64,
|
|
typeFloat32,
|
|
typeFloat64,
|
|
typeString,
|
|
typeBool,
|
|
typeStringSlice,
|
|
typeMapStringInt,
|
|
reflect.TypeOf([3]string{}),
|
|
typeTag,
|
|
typeRawTag,
|
|
typeBigInt,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
},
|
|
{
|
|
data: hexDecode("9fff"),
|
|
wantInterfaceValue: []interface{}{},
|
|
wantValues: []interface{}{
|
|
[]interface{}{},
|
|
[]byte{},
|
|
[]string{},
|
|
[]int{},
|
|
[0]int{},
|
|
[1]int{0},
|
|
[5]int{0, 0, 0, 0, 0},
|
|
[]float32{},
|
|
[]float64{},
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeUint32,
|
|
typeUint64,
|
|
typeInt8,
|
|
typeInt16,
|
|
typeInt32,
|
|
typeInt64,
|
|
typeFloat32,
|
|
typeFloat64,
|
|
typeString,
|
|
typeBool,
|
|
typeMapStringInt,
|
|
typeTag,
|
|
typeRawTag,
|
|
typeBigInt,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
},
|
|
{
|
|
data: hexDecode("9f018202039f0405ffff"),
|
|
wantInterfaceValue: []interface{}{uint64(1), []interface{}{uint64(2), uint64(3)}, []interface{}{uint64(4), uint64(5)}},
|
|
wantValues: []interface{}{
|
|
[]interface{}{uint64(1), []interface{}{uint64(2), uint64(3)}, []interface{}{uint64(4), uint64(5)}},
|
|
[...]interface{}{uint64(1), []interface{}{uint64(2), uint64(3)}, []interface{}{uint64(4), uint64(5)}},
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeUint32,
|
|
typeUint64,
|
|
typeInt8,
|
|
typeInt16,
|
|
typeInt32,
|
|
typeInt64,
|
|
typeFloat32,
|
|
typeFloat64,
|
|
typeString,
|
|
typeBool,
|
|
typeStringSlice,
|
|
typeMapStringInt,
|
|
reflect.TypeOf([3]string{}),
|
|
typeTag,
|
|
typeRawTag,
|
|
typeBigInt,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
},
|
|
{
|
|
data: hexDecode("9f01820203820405ff"),
|
|
wantInterfaceValue: []interface{}{uint64(1), []interface{}{uint64(2), uint64(3)}, []interface{}{uint64(4), uint64(5)}},
|
|
wantValues: []interface{}{
|
|
[]interface{}{uint64(1), []interface{}{uint64(2), uint64(3)}, []interface{}{uint64(4), uint64(5)}},
|
|
[...]interface{}{uint64(1), []interface{}{uint64(2), uint64(3)}, []interface{}{uint64(4), uint64(5)}},
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeUint32,
|
|
typeUint64,
|
|
typeInt8,
|
|
typeInt16,
|
|
typeInt32,
|
|
typeInt64,
|
|
typeFloat32,
|
|
typeFloat64,
|
|
typeString,
|
|
typeBool,
|
|
typeStringSlice,
|
|
typeMapStringInt,
|
|
reflect.TypeOf([3]string{}),
|
|
typeTag,
|
|
typeRawTag,
|
|
typeBigInt,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
},
|
|
{
|
|
data: hexDecode("9f0102030405060708090a0b0c0d0e0f101112131415161718181819ff"),
|
|
wantInterfaceValue: []interface{}{uint64(1), uint64(2), uint64(3), uint64(4), uint64(5), uint64(6), uint64(7), uint64(8), uint64(9), uint64(10), uint64(11), uint64(12), uint64(13), uint64(14), uint64(15), uint64(16), uint64(17), uint64(18), uint64(19), uint64(20), uint64(21), uint64(22), uint64(23), uint64(24), uint64(25)},
|
|
wantValues: []interface{}{
|
|
[]interface{}{uint64(1), uint64(2), uint64(3), uint64(4), uint64(5), uint64(6), uint64(7), uint64(8), uint64(9), uint64(10), uint64(11), uint64(12), uint64(13), uint64(14), uint64(15), uint64(16), uint64(17), uint64(18), uint64(19), uint64(20), uint64(21), uint64(22), uint64(23), uint64(24), uint64(25)},
|
|
[]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25},
|
|
[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25},
|
|
[]uint{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25},
|
|
[0]int{},
|
|
[1]int{1},
|
|
[...]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25},
|
|
[30]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0},
|
|
[]float32{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25},
|
|
[]float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25}},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeUint32,
|
|
typeUint64,
|
|
typeInt8,
|
|
typeInt16,
|
|
typeInt32,
|
|
typeInt64,
|
|
typeFloat32,
|
|
typeFloat64,
|
|
typeString,
|
|
typeBool,
|
|
typeStringSlice,
|
|
typeMapStringInt,
|
|
reflect.TypeOf([3]string{}),
|
|
typeTag,
|
|
typeRawTag,
|
|
typeBigInt,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
},
|
|
{
|
|
data: hexDecode("826161a161626163"),
|
|
wantInterfaceValue: []interface{}{"a", map[interface{}]interface{}{"b": "c"}},
|
|
wantValues: []interface{}{
|
|
[]interface{}{"a", map[interface{}]interface{}{"b": "c"}},
|
|
[...]interface{}{"a", map[interface{}]interface{}{"b": "c"}},
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeUint32,
|
|
typeUint64,
|
|
typeInt8,
|
|
typeInt16,
|
|
typeInt32,
|
|
typeInt64,
|
|
typeFloat32,
|
|
typeFloat64,
|
|
typeString,
|
|
typeBool,
|
|
typeByteArray,
|
|
typeStringSlice,
|
|
typeMapStringInt,
|
|
reflect.TypeOf([3]string{}),
|
|
typeTag,
|
|
typeRawTag,
|
|
typeBigInt,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
},
|
|
{
|
|
data: hexDecode("826161bf61626163ff"),
|
|
wantInterfaceValue: []interface{}{"a", map[interface{}]interface{}{"b": "c"}},
|
|
wantValues: []interface{}{
|
|
[]interface{}{"a", map[interface{}]interface{}{"b": "c"}},
|
|
[...]interface{}{"a", map[interface{}]interface{}{"b": "c"}},
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeUint32,
|
|
typeUint64,
|
|
typeInt8,
|
|
typeInt16,
|
|
typeInt32,
|
|
typeInt64,
|
|
typeFloat32,
|
|
typeFloat64,
|
|
typeString,
|
|
typeBool,
|
|
typeByteArray,
|
|
typeStringSlice,
|
|
typeMapStringInt,
|
|
reflect.TypeOf([3]string{}),
|
|
typeTag,
|
|
typeRawTag,
|
|
typeBigInt,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
},
|
|
|
|
// map
|
|
{
|
|
data: hexDecode("a0"),
|
|
wantInterfaceValue: map[interface{}]interface{}{},
|
|
wantValues: []interface{}{
|
|
map[interface{}]interface{}{},
|
|
map[string]bool{},
|
|
map[string]int{},
|
|
map[int]string{},
|
|
map[int]bool{},
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeUint32,
|
|
typeUint64,
|
|
typeInt8,
|
|
typeInt16,
|
|
typeInt32,
|
|
typeInt64,
|
|
typeFloat32,
|
|
typeFloat64,
|
|
typeByteSlice,
|
|
typeByteArray,
|
|
typeString,
|
|
typeBool,
|
|
typeIntSlice,
|
|
typeTag,
|
|
typeRawTag,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
},
|
|
{
|
|
data: hexDecode("a201020304"),
|
|
wantInterfaceValue: map[interface{}]interface{}{uint64(1): uint64(2), uint64(3): uint64(4)},
|
|
wantValues: []interface{}{
|
|
map[interface{}]interface{}{uint64(1): uint64(2), uint64(3): uint64(4)},
|
|
map[uint]int{1: 2, 3: 4}, map[int]uint{1: 2, 3: 4},
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeUint32,
|
|
typeUint64,
|
|
typeInt8,
|
|
typeInt16,
|
|
typeInt32,
|
|
typeInt64,
|
|
typeFloat32,
|
|
typeFloat64,
|
|
typeByteSlice,
|
|
typeByteArray,
|
|
typeString,
|
|
typeBool,
|
|
typeIntSlice,
|
|
typeMapStringInt,
|
|
typeTag,
|
|
typeRawTag,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
},
|
|
{
|
|
data: hexDecode("a26161016162820203"),
|
|
wantInterfaceValue: map[interface{}]interface{}{"a": uint64(1), "b": []interface{}{uint64(2), uint64(3)}},
|
|
wantValues: []interface{}{
|
|
map[interface{}]interface{}{"a": uint64(1), "b": []interface{}{uint64(2), uint64(3)}},
|
|
map[string]interface{}{"a": uint64(1), "b": []interface{}{uint64(2), uint64(3)}},
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeUint32,
|
|
typeUint64,
|
|
typeInt8,
|
|
typeInt16,
|
|
typeInt32,
|
|
typeInt64,
|
|
typeFloat32,
|
|
typeFloat64,
|
|
typeByteSlice,
|
|
typeByteArray,
|
|
typeString,
|
|
typeBool,
|
|
typeIntSlice,
|
|
typeMapStringInt,
|
|
typeTag,
|
|
typeRawTag,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
},
|
|
{
|
|
data: hexDecode("a56161614161626142616361436164614461656145"),
|
|
wantInterfaceValue: map[interface{}]interface{}{"a": "A", "b": "B", "c": "C", "d": "D", "e": "E"},
|
|
wantValues: []interface{}{
|
|
map[interface{}]interface{}{"a": "A", "b": "B", "c": "C", "d": "D", "e": "E"},
|
|
map[string]interface{}{"a": "A", "b": "B", "c": "C", "d": "D", "e": "E"},
|
|
map[string]string{"a": "A", "b": "B", "c": "C", "d": "D", "e": "E"},
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeUint32,
|
|
typeUint64,
|
|
typeInt8,
|
|
typeInt16,
|
|
typeInt32,
|
|
typeInt64,
|
|
typeFloat32,
|
|
typeFloat64,
|
|
typeByteSlice,
|
|
typeByteArray,
|
|
typeString,
|
|
typeBool,
|
|
typeIntSlice,
|
|
typeMapStringInt,
|
|
typeTag,
|
|
typeRawTag,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
},
|
|
{
|
|
data: hexDecode("bf61610161629f0203ffff"),
|
|
wantInterfaceValue: map[interface{}]interface{}{"a": uint64(1), "b": []interface{}{uint64(2), uint64(3)}},
|
|
wantValues: []interface{}{
|
|
map[interface{}]interface{}{"a": uint64(1), "b": []interface{}{uint64(2), uint64(3)}},
|
|
map[string]interface{}{"a": uint64(1), "b": []interface{}{uint64(2), uint64(3)}},
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeUint32,
|
|
typeUint64,
|
|
typeInt8,
|
|
typeInt16,
|
|
typeInt32,
|
|
typeInt64,
|
|
typeFloat32,
|
|
typeFloat64,
|
|
typeByteSlice,
|
|
typeByteArray,
|
|
typeString,
|
|
typeBool,
|
|
typeIntSlice,
|
|
typeMapStringInt,
|
|
typeTag,
|
|
typeRawTag,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
},
|
|
{
|
|
data: hexDecode("bf6346756ef563416d7421ff"),
|
|
wantInterfaceValue: map[interface{}]interface{}{"Fun": true, "Amt": int64(-2)},
|
|
wantValues: []interface{}{
|
|
map[interface{}]interface{}{"Fun": true, "Amt": int64(-2)},
|
|
map[string]interface{}{"Fun": true, "Amt": int64(-2)},
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeUint32,
|
|
typeUint64,
|
|
typeInt8,
|
|
typeInt16,
|
|
typeInt32,
|
|
typeInt64,
|
|
typeFloat32,
|
|
typeFloat64,
|
|
typeByteSlice,
|
|
typeByteArray,
|
|
typeString,
|
|
typeBool,
|
|
typeIntSlice,
|
|
typeMapStringInt,
|
|
typeTag,
|
|
typeRawTag,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
},
|
|
|
|
// tag
|
|
{
|
|
data: hexDecode("c074323031332d30332d32315432303a30343a30305a"),
|
|
wantInterfaceValue: time.Date(2013, 3, 21, 20, 4, 0, 0, time.UTC), // 2013-03-21 20:04:00 +0000 UTC
|
|
wantValues: []interface{}{
|
|
"2013-03-21T20:04:00Z",
|
|
time.Date(2013, 3, 21, 20, 4, 0, 0, time.UTC),
|
|
Tag{0, "2013-03-21T20:04:00Z"},
|
|
RawTag{0, hexDecode("74323031332d30332d32315432303a30343a30305a")},
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeUint32,
|
|
typeUint64,
|
|
typeInt8,
|
|
typeInt16,
|
|
typeInt32,
|
|
typeInt64,
|
|
typeFloat32,
|
|
typeFloat64,
|
|
typeBool,
|
|
typeByteArray,
|
|
typeIntSlice,
|
|
typeMapStringInt,
|
|
typeBigInt,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
}, // 0: standard date/time
|
|
{
|
|
data: hexDecode("c11a514b67b0"),
|
|
wantInterfaceValue: time.Date(2013, 3, 21, 20, 4, 0, 0, time.UTC), // 2013-03-21 20:04:00 +0000 UTC
|
|
wantValues: []interface{}{
|
|
uint32(1363896240),
|
|
uint64(1363896240),
|
|
int32(1363896240),
|
|
int64(1363896240),
|
|
float32(1363896240),
|
|
float64(1363896240),
|
|
time.Date(2013, 3, 21, 20, 4, 0, 0, time.UTC),
|
|
Tag{1, uint64(1363896240)},
|
|
RawTag{1, hexDecode("1a514b67b0")},
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeInt8,
|
|
typeInt16,
|
|
typeByteSlice,
|
|
typeString,
|
|
typeBool,
|
|
typeByteArray,
|
|
typeIntSlice,
|
|
typeMapStringInt,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
}, // 1: epoch-based date/time
|
|
{
|
|
data: hexDecode("c249010000000000000000"),
|
|
wantInterfaceValue: bigIntOrPanic("18446744073709551616"),
|
|
wantValues: []interface{}{
|
|
// Decode to byte slice
|
|
[]byte{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
|
// Decode to array of various lengths
|
|
[0]byte{},
|
|
[1]byte{0x01},
|
|
[3]byte{0x01, 0x00, 0x00},
|
|
[...]byte{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
|
[10]byte{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
|
// Decode to Tag and RawTag
|
|
Tag{2, []byte{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
|
|
RawTag{2, hexDecode("49010000000000000000")},
|
|
// Decode to big.Int
|
|
bigIntOrPanic("18446744073709551616"),
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeUint32,
|
|
typeUint64,
|
|
typeInt8,
|
|
typeInt16,
|
|
typeInt32,
|
|
typeInt64,
|
|
typeFloat32,
|
|
typeFloat64,
|
|
typeBool,
|
|
typeIntSlice,
|
|
typeMapStringInt,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
}, // 2: positive bignum: 18446744073709551616
|
|
{
|
|
data: hexDecode("c349010000000000000000"),
|
|
wantInterfaceValue: bigIntOrPanic("-18446744073709551617"),
|
|
wantValues: []interface{}{
|
|
// Decode to byte slice
|
|
[]byte{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
|
// Decode to array of various lengths
|
|
[0]byte{},
|
|
[1]byte{0x01},
|
|
[3]byte{0x01, 0x00, 0x00},
|
|
[...]byte{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
|
[10]byte{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
|
// Decode to Tag and RawTag
|
|
Tag{3, []byte{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
|
|
RawTag{3, hexDecode("49010000000000000000")},
|
|
// Decode to big.Int
|
|
bigIntOrPanic("-18446744073709551617"),
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeUint32,
|
|
typeUint64,
|
|
typeInt8,
|
|
typeInt16,
|
|
typeInt32,
|
|
typeInt64,
|
|
typeFloat32,
|
|
typeFloat64,
|
|
typeBool,
|
|
typeIntSlice,
|
|
typeMapStringInt,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
}, // 3: negative bignum: -18446744073709551617
|
|
{
|
|
data: hexDecode("c1fb41d452d9ec200000"),
|
|
wantInterfaceValue: time.Date(2013, 3, 21, 20, 4, 0, 500000000, time.UTC), // 2013-03-21 20:04:00.5 +0000 UTC
|
|
wantValues: []interface{}{
|
|
float32(1363896240.5),
|
|
float64(1363896240.5),
|
|
time.Date(2013, 3, 21, 20, 4, 0, 500000000, time.UTC),
|
|
Tag{1, float64(1363896240.5)},
|
|
RawTag{1, hexDecode("fb41d452d9ec200000")},
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeUint32,
|
|
typeUint64,
|
|
typeInt8,
|
|
typeInt16,
|
|
typeInt32,
|
|
typeInt64,
|
|
typeByteSlice,
|
|
typeByteArray,
|
|
typeString,
|
|
typeBool,
|
|
typeIntSlice,
|
|
typeMapStringInt,
|
|
typeBigInt,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
}, // 1: epoch-based date/time
|
|
{
|
|
data: hexDecode("d74401020304"),
|
|
wantInterfaceValue: Tag{23, []byte{0x01, 0x02, 0x03, 0x04}},
|
|
wantValues: []interface{}{
|
|
[]byte{0x01, 0x02, 0x03, 0x04},
|
|
[0]byte{},
|
|
[1]byte{0x01},
|
|
[3]byte{0x01, 0x02, 0x03},
|
|
[...]byte{0x01, 0x02, 0x03, 0x04},
|
|
[5]byte{0x01, 0x02, 0x03, 0x04, 0x00},
|
|
Tag{23, []byte{0x01, 0x02, 0x03, 0x04}},
|
|
RawTag{23, hexDecode("4401020304")},
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeUint32,
|
|
typeUint64,
|
|
typeInt8,
|
|
typeInt16,
|
|
typeInt32,
|
|
typeInt64,
|
|
typeFloat32,
|
|
typeFloat64,
|
|
typeBool,
|
|
typeIntSlice,
|
|
typeMapStringInt,
|
|
typeBigInt,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
}, // 23: expected conversion to base16 encoding
|
|
{
|
|
data: hexDecode("d818456449455446"),
|
|
wantInterfaceValue: Tag{24, []byte{0x64, 0x49, 0x45, 0x54, 0x46}},
|
|
wantValues: []interface{}{
|
|
[]byte{0x64, 0x49, 0x45, 0x54, 0x46},
|
|
[0]byte{},
|
|
[1]byte{0x64},
|
|
[3]byte{0x64, 0x49, 0x45},
|
|
[...]byte{0x64, 0x49, 0x45, 0x54, 0x46},
|
|
[6]byte{0x64, 0x49, 0x45, 0x54, 0x46, 0x00},
|
|
Tag{24, []byte{0x64, 0x49, 0x45, 0x54, 0x46}},
|
|
RawTag{24, hexDecode("456449455446")},
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeUint32,
|
|
typeUint64,
|
|
typeInt8,
|
|
typeInt16,
|
|
typeInt32,
|
|
typeInt64,
|
|
typeFloat32,
|
|
typeFloat64,
|
|
typeBool,
|
|
typeIntSlice,
|
|
typeMapStringInt,
|
|
typeBigInt,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
}, // 24: encoded cborBytes data item
|
|
{
|
|
data: hexDecode("d82076687474703a2f2f7777772e6578616d706c652e636f6d"),
|
|
wantInterfaceValue: Tag{32, "http://www.example.com"},
|
|
wantValues: []interface{}{
|
|
"http://www.example.com",
|
|
Tag{32, "http://www.example.com"},
|
|
RawTag{32, hexDecode("76687474703a2f2f7777772e6578616d706c652e636f6d")},
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeUint32,
|
|
typeUint64,
|
|
typeInt8,
|
|
typeInt16,
|
|
typeInt32,
|
|
typeInt64,
|
|
typeFloat32,
|
|
typeFloat64,
|
|
typeBool,
|
|
typeByteArray,
|
|
typeIntSlice,
|
|
typeMapStringInt,
|
|
typeBigInt,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
}, // 32: URI
|
|
|
|
// primitives
|
|
{
|
|
data: hexDecode("f4"),
|
|
wantInterfaceValue: false,
|
|
wantValues: []interface{}{
|
|
false,
|
|
SimpleValue(20),
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeUint32,
|
|
typeUint64,
|
|
typeInt8,
|
|
typeInt16,
|
|
typeInt32,
|
|
typeInt64,
|
|
typeFloat32,
|
|
typeFloat64,
|
|
typeByteArray,
|
|
typeByteSlice,
|
|
typeString,
|
|
typeIntSlice,
|
|
typeMapStringInt,
|
|
typeTag,
|
|
typeRawTag,
|
|
typeBigInt,
|
|
typeByteString,
|
|
},
|
|
},
|
|
{
|
|
data: hexDecode("f5"),
|
|
wantInterfaceValue: true,
|
|
wantValues: []interface{}{
|
|
true,
|
|
SimpleValue(21),
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeUint32,
|
|
typeUint64,
|
|
typeInt8,
|
|
typeInt16,
|
|
typeInt32,
|
|
typeInt64,
|
|
typeFloat32,
|
|
typeFloat64,
|
|
typeByteArray,
|
|
typeByteSlice,
|
|
typeString,
|
|
typeIntSlice,
|
|
typeMapStringInt,
|
|
typeTag,
|
|
typeRawTag,
|
|
typeBigInt,
|
|
typeByteString,
|
|
},
|
|
},
|
|
{
|
|
data: hexDecode("f6"),
|
|
wantInterfaceValue: nil,
|
|
wantValues: []interface{}{
|
|
SimpleValue(22),
|
|
false,
|
|
uint(0),
|
|
uint8(0),
|
|
uint16(0),
|
|
uint32(0),
|
|
uint64(0),
|
|
int(0),
|
|
int8(0),
|
|
int16(0),
|
|
int32(0),
|
|
int64(0),
|
|
float32(0.0),
|
|
float64(0.0),
|
|
"",
|
|
[]byte(nil),
|
|
[]int(nil),
|
|
[]string(nil),
|
|
map[string]int(nil),
|
|
time.Time{},
|
|
bigIntOrPanic("0"),
|
|
Tag{},
|
|
RawTag{},
|
|
},
|
|
wrongTypes: nil,
|
|
},
|
|
{
|
|
data: hexDecode("f7"),
|
|
wantInterfaceValue: nil,
|
|
wantValues: []interface{}{
|
|
SimpleValue(23),
|
|
false,
|
|
uint(0),
|
|
uint8(0),
|
|
uint16(0),
|
|
uint32(0),
|
|
uint64(0),
|
|
int(0),
|
|
int8(0),
|
|
int16(0),
|
|
int32(0),
|
|
int64(0),
|
|
float32(0.0),
|
|
float64(0.0),
|
|
"",
|
|
[]byte(nil),
|
|
[]int(nil),
|
|
[]string(nil),
|
|
map[string]int(nil),
|
|
time.Time{},
|
|
bigIntOrPanic("0"),
|
|
Tag{},
|
|
RawTag{},
|
|
},
|
|
wrongTypes: nil,
|
|
},
|
|
{
|
|
data: hexDecode("f0"),
|
|
wantInterfaceValue: SimpleValue(16),
|
|
wantValues: []interface{}{
|
|
SimpleValue(16),
|
|
uint8(16),
|
|
uint16(16),
|
|
uint32(16),
|
|
uint64(16),
|
|
uint(16),
|
|
int8(16),
|
|
int16(16),
|
|
int32(16),
|
|
int64(16),
|
|
int(16),
|
|
float32(16),
|
|
float64(16),
|
|
bigIntOrPanic("16"),
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeByteSlice,
|
|
typeString,
|
|
typeBool,
|
|
typeByteArray,
|
|
typeIntSlice,
|
|
typeMapStringInt,
|
|
typeTag,
|
|
typeRawTag,
|
|
typeByteString,
|
|
},
|
|
},
|
|
// This example is not well-formed because Simple value (with 5-bit value 24) must be >= 32.
|
|
// See RFC 7049 section 2.3 for details, instead of the incorrect example in RFC 7049 Appendex A.
|
|
// I reported an errata to RFC 7049 and Carsten Bormann confirmed at https://github.com/fxamacker/cbor/issues/46
|
|
// {
|
|
// data: hexDecode("f818"),
|
|
// wantInterfaceValue: uint64(24),
|
|
// wantValues: []interface{}{uint8(24), uint16(24), uint32(24), uint64(24), uint(24), int8(24), int16(24), int32(24), int64(24), int(24), float32(24), float64(24)},
|
|
// wrongTypes: []reflect.Type{typeByteSlice, typeString, typeBool, typeIntSlice, typeMapStringInt},
|
|
// },
|
|
{
|
|
data: hexDecode("f820"),
|
|
wantInterfaceValue: SimpleValue(32),
|
|
wantValues: []interface{}{
|
|
SimpleValue(32),
|
|
uint8(32),
|
|
uint16(32),
|
|
uint32(32),
|
|
uint64(32),
|
|
uint(32),
|
|
int8(32),
|
|
int16(32),
|
|
int32(32),
|
|
int64(32),
|
|
int(32),
|
|
float32(32),
|
|
float64(32),
|
|
bigIntOrPanic("32"),
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeByteSlice,
|
|
typeString,
|
|
typeBool,
|
|
typeByteArray,
|
|
typeIntSlice,
|
|
typeMapStringInt,
|
|
typeTag,
|
|
typeRawTag,
|
|
typeByteString,
|
|
},
|
|
},
|
|
{
|
|
data: hexDecode("f8ff"),
|
|
wantInterfaceValue: SimpleValue(255),
|
|
wantValues: []interface{}{
|
|
SimpleValue(255),
|
|
uint8(255),
|
|
uint16(255),
|
|
uint32(255),
|
|
uint64(255),
|
|
uint(255),
|
|
int16(255),
|
|
int32(255),
|
|
int64(255),
|
|
int(255),
|
|
float32(255),
|
|
float64(255),
|
|
bigIntOrPanic("255"),
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeByteSlice,
|
|
typeString,
|
|
typeBool,
|
|
typeByteArray,
|
|
typeIntSlice,
|
|
typeMapStringInt,
|
|
typeTag,
|
|
typeRawTag,
|
|
typeByteString,
|
|
},
|
|
},
|
|
|
|
// More testcases not covered by https://tools.ietf.org/html/rfc7049#appendix-A.
|
|
{
|
|
data: hexDecode("5fff"), // empty indefinite length byte string
|
|
wantInterfaceValue: []byte{},
|
|
wantValues: []interface{}{
|
|
[]byte{},
|
|
[0]byte{},
|
|
[1]byte{0x00},
|
|
ByteString(""),
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeUint32,
|
|
typeUint64,
|
|
typeInt8,
|
|
typeInt16,
|
|
typeInt32,
|
|
typeInt64,
|
|
typeFloat32,
|
|
typeFloat64,
|
|
typeBool,
|
|
typeIntSlice,
|
|
typeMapStringInt,
|
|
typeTag,
|
|
typeRawTag,
|
|
typeBigInt,
|
|
typeSimpleValue,
|
|
},
|
|
},
|
|
{
|
|
data: hexDecode("7fff"), // empty indefinite length text string
|
|
wantInterfaceValue: "",
|
|
wantValues: []interface{}{""},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeUint32,
|
|
typeUint64,
|
|
typeInt8,
|
|
typeInt16,
|
|
typeInt32,
|
|
typeInt64,
|
|
typeFloat32,
|
|
typeFloat64,
|
|
typeBool,
|
|
typeByteArray,
|
|
typeIntSlice,
|
|
typeMapStringInt,
|
|
typeTag,
|
|
typeRawTag,
|
|
typeBigInt,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
},
|
|
{
|
|
data: hexDecode("bfff"), // empty indefinite length map
|
|
wantInterfaceValue: map[interface{}]interface{}{},
|
|
wantValues: []interface{}{
|
|
map[interface{}]interface{}{},
|
|
map[string]bool{},
|
|
map[string]int{},
|
|
map[int]string{},
|
|
map[int]bool{},
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeUint32,
|
|
typeUint64,
|
|
typeInt8,
|
|
typeInt16,
|
|
typeInt32,
|
|
typeInt64,
|
|
typeFloat32,
|
|
typeFloat64,
|
|
typeByteArray,
|
|
typeByteSlice,
|
|
typeString,
|
|
typeBool,
|
|
typeIntSlice,
|
|
typeTag,
|
|
typeRawTag,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
},
|
|
|
|
// More test data with tags
|
|
{
|
|
data: hexDecode("c13a0177f2cf"), // 1969-03-21T20:04:00Z, tag 1 with negative integer as epoch time
|
|
wantInterfaceValue: time.Date(1969, 3, 21, 20, 4, 0, 0, time.UTC),
|
|
wantValues: []interface{}{
|
|
int32(-24638160),
|
|
int64(-24638160),
|
|
int32(-24638160),
|
|
int64(-24638160),
|
|
float32(-24638160),
|
|
float64(-24638160),
|
|
time.Date(1969, 3, 21, 20, 4, 0, 0, time.UTC),
|
|
Tag{1, int64(-24638160)},
|
|
RawTag{1, hexDecode("3a0177f2cf")}, bigIntOrPanic("-24638160"),
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeInt8,
|
|
typeInt16,
|
|
typeByteSlice,
|
|
typeString,
|
|
typeBool,
|
|
typeByteArray,
|
|
typeIntSlice,
|
|
typeMapStringInt,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
},
|
|
{
|
|
data: hexDecode("d83dd183010203"), // 61(17([1, 2, 3])), nested tags 61 and 17
|
|
wantInterfaceValue: Tag{61, Tag{17, []interface{}{uint64(1), uint64(2), uint64(3)}}},
|
|
wantValues: []interface{}{
|
|
[]interface{}{uint64(1), uint64(2), uint64(3)},
|
|
[]byte{1, 2, 3},
|
|
[0]byte{},
|
|
[1]byte{1},
|
|
[3]byte{1, 2, 3},
|
|
[5]byte{1, 2, 3, 0, 0},
|
|
[]int{1, 2, 3},
|
|
[]uint{1, 2, 3},
|
|
[...]int{1, 2, 3},
|
|
[]float32{1, 2, 3},
|
|
[]float64{1, 2, 3},
|
|
Tag{61, Tag{17, []interface{}{uint64(1), uint64(2), uint64(3)}}},
|
|
RawTag{61, hexDecode("d183010203")},
|
|
},
|
|
wrongTypes: []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeUint32,
|
|
typeUint64,
|
|
typeInt8,
|
|
typeInt16,
|
|
typeInt32,
|
|
typeInt64,
|
|
typeFloat32,
|
|
typeFloat64,
|
|
typeString,
|
|
typeBool,
|
|
typeStringSlice,
|
|
typeMapStringInt,
|
|
reflect.TypeOf([3]string{}),
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
},
|
|
},
|
|
}
|
|
|
|
type unmarshalFloatTest struct {
|
|
data []byte
|
|
wantInterfaceValue interface{}
|
|
wantValues []interface{}
|
|
equalityThreshold float64 // Not used for +inf, -inf, and NaN.
|
|
}
|
|
|
|
var unmarshalFloatWrongTypes = []reflect.Type{
|
|
typeUint8,
|
|
typeUint16,
|
|
typeUint32,
|
|
typeUint64,
|
|
typeInt8,
|
|
typeInt16,
|
|
typeInt32,
|
|
typeInt64,
|
|
typeByteArray,
|
|
typeByteSlice,
|
|
typeString,
|
|
typeBool,
|
|
typeIntSlice,
|
|
typeMapStringInt,
|
|
typeTag,
|
|
typeRawTag,
|
|
typeBigInt,
|
|
typeByteString,
|
|
typeSimpleValue,
|
|
}
|
|
|
|
// unmarshalFloatTests includes test values for float16, float32, and float64.
|
|
// Note: the function for float16 to float32 conversion was tested with all
|
|
// 65536 values, which is too many to include here.
|
|
var unmarshalFloatTests = []unmarshalFloatTest{
|
|
// CBOR test data are from https://tools.ietf.org/html/rfc7049#appendix-A.
|
|
|
|
// float16
|
|
{
|
|
data: hexDecode("f90000"),
|
|
wantInterfaceValue: float64(0.0),
|
|
wantValues: []interface{}{float32(0.0), float64(0.0)},
|
|
},
|
|
{
|
|
data: hexDecode("f98000"),
|
|
wantInterfaceValue: float64(-0.0), //nolint:staticcheck // we know -0.0 is 0.0 in Go
|
|
wantValues: []interface{}{float32(-0.0), float64(-0.0)}, //nolint:staticcheck // we know -0.0 is 0.0 in Go
|
|
},
|
|
{
|
|
data: hexDecode("f93c00"),
|
|
wantInterfaceValue: float64(1.0),
|
|
wantValues: []interface{}{float32(1.0), float64(1.0)},
|
|
},
|
|
{
|
|
data: hexDecode("f93e00"),
|
|
wantInterfaceValue: float64(1.5),
|
|
wantValues: []interface{}{float32(1.5), float64(1.5)},
|
|
},
|
|
{
|
|
data: hexDecode("f97bff"),
|
|
wantInterfaceValue: float64(65504.0),
|
|
wantValues: []interface{}{float32(65504.0), float64(65504.0)},
|
|
},
|
|
{
|
|
data: hexDecode("f90001"), // float16 subnormal value
|
|
wantInterfaceValue: float64(5.960464477539063e-08),
|
|
wantValues: []interface{}{float32(5.960464477539063e-08), float64(5.960464477539063e-08)},
|
|
equalityThreshold: 1e-16,
|
|
},
|
|
{
|
|
data: hexDecode("f90400"),
|
|
wantInterfaceValue: float64(6.103515625e-05),
|
|
wantValues: []interface{}{float32(6.103515625e-05), float64(6.103515625e-05)},
|
|
equalityThreshold: 1e-16,
|
|
},
|
|
{
|
|
data: hexDecode("f9c400"),
|
|
wantInterfaceValue: float64(-4.0),
|
|
wantValues: []interface{}{float32(-4.0), float64(-4.0)},
|
|
},
|
|
{
|
|
data: hexDecode("f97c00"),
|
|
wantInterfaceValue: math.Inf(1),
|
|
wantValues: []interface{}{math.Float32frombits(0x7f800000), math.Inf(1)},
|
|
},
|
|
{
|
|
data: hexDecode("f97e00"),
|
|
wantInterfaceValue: math.NaN(),
|
|
wantValues: []interface{}{math.Float32frombits(0x7fc00000), math.NaN()},
|
|
},
|
|
{
|
|
data: hexDecode("f9fc00"),
|
|
wantInterfaceValue: math.Inf(-1),
|
|
wantValues: []interface{}{math.Float32frombits(0xff800000), math.Inf(-1)},
|
|
},
|
|
|
|
// float32
|
|
{
|
|
data: hexDecode("fa47c35000"),
|
|
wantInterfaceValue: float64(100000.0),
|
|
wantValues: []interface{}{float32(100000.0), float64(100000.0)},
|
|
},
|
|
{
|
|
data: hexDecode("fa7f7fffff"),
|
|
wantInterfaceValue: float64(3.4028234663852886e+38),
|
|
wantValues: []interface{}{float32(3.4028234663852886e+38), float64(3.4028234663852886e+38)},
|
|
equalityThreshold: 1e-9,
|
|
},
|
|
{
|
|
data: hexDecode("fa7f800000"),
|
|
wantInterfaceValue: math.Inf(1),
|
|
wantValues: []interface{}{math.Float32frombits(0x7f800000), math.Inf(1)},
|
|
},
|
|
{
|
|
data: hexDecode("fa7fc00000"),
|
|
wantInterfaceValue: math.NaN(),
|
|
wantValues: []interface{}{math.Float32frombits(0x7fc00000), math.NaN()},
|
|
},
|
|
{
|
|
data: hexDecode("faff800000"),
|
|
wantInterfaceValue: math.Inf(-1),
|
|
wantValues: []interface{}{math.Float32frombits(0xff800000), math.Inf(-1)},
|
|
},
|
|
|
|
// float64
|
|
{
|
|
data: hexDecode("fb3ff199999999999a"),
|
|
wantInterfaceValue: float64(1.1),
|
|
wantValues: []interface{}{float32(1.1), float64(1.1)},
|
|
},
|
|
{
|
|
data: hexDecode("fb7e37e43c8800759c"),
|
|
wantInterfaceValue: float64(1.0e+300),
|
|
wantValues: []interface{}{float64(1.0e+300)},
|
|
equalityThreshold: 1e-9,
|
|
},
|
|
{
|
|
data: hexDecode("fbc010666666666666"),
|
|
wantInterfaceValue: float64(-4.1),
|
|
wantValues: []interface{}{float32(-4.1), float64(-4.1)},
|
|
},
|
|
{
|
|
data: hexDecode("fb7ff0000000000000"),
|
|
wantInterfaceValue: math.Inf(1),
|
|
wantValues: []interface{}{math.Float32frombits(0x7f800000), math.Inf(1)},
|
|
},
|
|
{
|
|
data: hexDecode("fb7ff8000000000000"),
|
|
wantInterfaceValue: math.NaN(),
|
|
wantValues: []interface{}{math.Float32frombits(0x7fc00000), math.NaN()},
|
|
},
|
|
{
|
|
data: hexDecode("fbfff0000000000000"),
|
|
wantInterfaceValue: math.Inf(-1),
|
|
wantValues: []interface{}{math.Float32frombits(0xff800000), math.Inf(-1)},
|
|
},
|
|
|
|
// float16 test data from https://en.wikipedia.org/wiki/Half-precision_floating-point_format
|
|
{
|
|
data: hexDecode("f903ff"),
|
|
wantInterfaceValue: float64(0.000060976),
|
|
wantValues: []interface{}{float32(0.000060976), float64(0.000060976)},
|
|
equalityThreshold: 1e-9,
|
|
},
|
|
{
|
|
data: hexDecode("f93bff"),
|
|
wantInterfaceValue: float64(0.999511719),
|
|
wantValues: []interface{}{float32(0.999511719), float64(0.999511719)},
|
|
equalityThreshold: 1e-9,
|
|
},
|
|
{
|
|
data: hexDecode("f93c01"),
|
|
wantInterfaceValue: float64(1.000976563),
|
|
wantValues: []interface{}{float32(1.000976563), float64(1.000976563)},
|
|
equalityThreshold: 1e-9,
|
|
},
|
|
{
|
|
data: hexDecode("f93555"),
|
|
wantInterfaceValue: float64(0.333251953125),
|
|
wantValues: []interface{}{float32(0.333251953125), float64(0.333251953125)},
|
|
equalityThreshold: 1e-9,
|
|
},
|
|
|
|
// CBOR test data "canonNums" are from https://github.com/cbor-wg/cbor-test-vectors
|
|
{
|
|
data: hexDecode("f9bd00"),
|
|
wantInterfaceValue: float64(-1.25),
|
|
wantValues: []interface{}{float32(-1.25), float64(-1.25)},
|
|
},
|
|
{
|
|
data: hexDecode("f93e00"),
|
|
wantInterfaceValue: float64(1.5),
|
|
wantValues: []interface{}{float32(1.5), float64(1.5)},
|
|
},
|
|
{
|
|
data: hexDecode("fb4024333333333333"),
|
|
wantInterfaceValue: float64(10.1),
|
|
wantValues: []interface{}{float32(10.1), float64(10.1)},
|
|
},
|
|
{
|
|
data: hexDecode("f90001"),
|
|
wantInterfaceValue: float64(5.960464477539063e-8),
|
|
wantValues: []interface{}{float32(5.960464477539063e-8), float64(5.960464477539063e-8)},
|
|
},
|
|
{
|
|
data: hexDecode("fa7f7fffff"),
|
|
wantInterfaceValue: float64(3.4028234663852886e+38),
|
|
wantValues: []interface{}{float32(3.4028234663852886e+38), float64(3.4028234663852886e+38)},
|
|
},
|
|
{
|
|
data: hexDecode("f90400"),
|
|
wantInterfaceValue: float64(0.00006103515625),
|
|
wantValues: []interface{}{float32(0.00006103515625), float64(0.00006103515625)},
|
|
},
|
|
{
|
|
data: hexDecode("f933ff"),
|
|
wantInterfaceValue: float64(0.2498779296875),
|
|
wantValues: []interface{}{float32(0.2498779296875), float64(0.2498779296875)},
|
|
},
|
|
{
|
|
data: hexDecode("fa33000000"),
|
|
wantInterfaceValue: float64(2.9802322387695312e-8),
|
|
wantValues: []interface{}{float32(2.9802322387695312e-8), float64(2.9802322387695312e-8)},
|
|
},
|
|
{
|
|
data: hexDecode("fa33333866"),
|
|
wantInterfaceValue: float64(4.1727979294137185e-8),
|
|
wantValues: []interface{}{float32(4.1727979294137185e-8), float64(4.1727979294137185e-8)},
|
|
},
|
|
{
|
|
data: hexDecode("fa37002000"),
|
|
wantInterfaceValue: float64(0.000007636845111846924),
|
|
wantValues: []interface{}{float32(0.000007636845111846924), float64(0.000007636845111846924)},
|
|
},
|
|
}
|
|
|
|
const invalidUTF8ErrorMsg = "cbor: invalid UTF-8 string"
|
|
|
|
func hexDecode(s string) []byte {
|
|
data, err := hex.DecodeString(s)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return data
|
|
}
|
|
|
|
func bigIntOrPanic(s string) big.Int {
|
|
bi, ok := new(big.Int).SetString(s, 10)
|
|
if !ok {
|
|
panic("failed to convert " + s + " to big.Int")
|
|
}
|
|
return *bi
|
|
}
|
|
|
|
func TestUnmarshalToEmptyInterface(t *testing.T) {
|
|
for _, tc := range unmarshalTests {
|
|
var v interface{}
|
|
if err := Unmarshal(tc.data, &v); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", tc.data, err)
|
|
continue
|
|
}
|
|
compareNonFloats(t, tc.data, v, tc.wantInterfaceValue)
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalToRawMessage(t *testing.T) {
|
|
for _, tc := range unmarshalTests {
|
|
testUnmarshalToRawMessage(t, tc.data)
|
|
}
|
|
}
|
|
|
|
func testUnmarshalToRawMessage(t *testing.T, data []byte) {
|
|
cborNil := isCBORNil(data)
|
|
|
|
// Decode to RawMessage
|
|
var r RawMessage
|
|
if err := Unmarshal(data, &r); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", data, err)
|
|
} else if !bytes.Equal(r, data) {
|
|
t.Errorf("Unmarshal(0x%x) returned RawMessage %v, want %v", data, r, data)
|
|
}
|
|
|
|
// Decode to *RawMesage (pr is nil)
|
|
var pr *RawMessage
|
|
if err := Unmarshal(data, &pr); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", data, err)
|
|
} else {
|
|
if cborNil {
|
|
if pr != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned RawMessage %v, want nil *RawMessage", data, *pr)
|
|
}
|
|
} else {
|
|
if !bytes.Equal(*pr, data) {
|
|
t.Errorf("Unmarshal(0x%x) returned RawMessage %v, want %v", data, *pr, data)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Decode to *RawMessage (pr is not nil)
|
|
var ir RawMessage
|
|
pr = &ir
|
|
if err := Unmarshal(data, &pr); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", data, err)
|
|
} else {
|
|
if cborNil {
|
|
if pr != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned RawMessage %v, want nil *RawMessage", data, *pr)
|
|
}
|
|
} else {
|
|
if !bytes.Equal(*pr, data) {
|
|
t.Errorf("Unmarshal(0x%x) returned RawMessage %v, want %v", data, *pr, data)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalToCompatibleTypes(t *testing.T) {
|
|
for _, tc := range unmarshalTests {
|
|
for _, wantValue := range tc.wantValues {
|
|
testUnmarshalToCompatibleType(t, tc.data, wantValue, func(gotValue interface{}) {
|
|
compareNonFloats(t, tc.data, gotValue, wantValue)
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
func testUnmarshalToCompatibleType(t *testing.T, data []byte, wantValue interface{}, compare func(gotValue interface{})) {
|
|
var rv reflect.Value
|
|
|
|
cborNil := isCBORNil(data)
|
|
wantType := reflect.TypeOf(wantValue)
|
|
|
|
// Decode to wantType, same as:
|
|
// var v wantType
|
|
// Unmarshal(tc.data, &v)
|
|
|
|
rv = reflect.New(wantType)
|
|
if err := Unmarshal(data, rv.Interface()); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", data, err)
|
|
return
|
|
}
|
|
compare(rv.Elem().Interface())
|
|
|
|
// Decode to *wantType (pv is nil), same as:
|
|
// var pv *wantType
|
|
// Unmarshal(tc.data, &pv)
|
|
|
|
rv = reflect.New(reflect.PtrTo(wantType))
|
|
if err := Unmarshal(data, rv.Interface()); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", data, err)
|
|
return
|
|
}
|
|
if cborNil {
|
|
if !rv.Elem().IsNil() {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want nil", data, rv.Elem().Interface(), rv.Elem().Interface())
|
|
}
|
|
} else {
|
|
compare(rv.Elem().Elem().Interface())
|
|
}
|
|
|
|
// Decode to *wantType (pv is not nil), same as:
|
|
// var v wantType
|
|
// pv := &v
|
|
// Unmarshal(tc.data, &pv)
|
|
|
|
irv := reflect.New(wantType)
|
|
rv = reflect.New(reflect.PtrTo(wantType))
|
|
rv.Elem().Set(irv)
|
|
if err := Unmarshal(data, rv.Interface()); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", data, err)
|
|
return
|
|
}
|
|
if cborNil {
|
|
if !rv.Elem().IsNil() {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want nil", data, rv.Elem().Interface(), rv.Elem().Interface())
|
|
}
|
|
} else {
|
|
compare(rv.Elem().Elem().Interface())
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalToIncompatibleTypes(t *testing.T) {
|
|
for _, tc := range unmarshalTests {
|
|
for _, wrongType := range tc.wrongTypes {
|
|
testUnmarshalToIncompatibleType(t, tc.data, wrongType)
|
|
}
|
|
}
|
|
}
|
|
|
|
func testUnmarshalToIncompatibleType(t *testing.T, data []byte, wrongType reflect.Type) {
|
|
var rv reflect.Value
|
|
|
|
// Decode to wrongType, same as:
|
|
// var v wrongType
|
|
// Unmarshal(tc.data, &v)
|
|
|
|
rv = reflect.New(wrongType)
|
|
if err := Unmarshal(data, rv.Interface()); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error", data)
|
|
} else if _, ok := err.(*UnmarshalTypeError); !ok {
|
|
t.Errorf("Unmarshal(0x%x) returned wrong error type %T, want (*UnmarshalTypeError)", data, err)
|
|
}
|
|
|
|
// Decode to *wrongType (pv is nil), same as:
|
|
// var pv *wrongType
|
|
// Unmarshal(tc.data, &pv)
|
|
|
|
rv = reflect.New(reflect.PtrTo(wrongType))
|
|
if err := Unmarshal(data, rv.Interface()); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error", data)
|
|
} else if _, ok := err.(*UnmarshalTypeError); !ok {
|
|
t.Errorf("Unmarshal(0x%x) returned wrong error type %T, want (*UnmarshalTypeError)", data, err)
|
|
}
|
|
|
|
// Decode to *wrongType (pv is not nil), same as:
|
|
// var v wrongType
|
|
// pv := &v
|
|
// Unmarshal(tc.data, &pv)
|
|
|
|
irv := reflect.New(wrongType)
|
|
rv = reflect.New(reflect.PtrTo(wrongType))
|
|
rv.Elem().Set(irv)
|
|
|
|
if err := Unmarshal(data, rv.Interface()); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error", data)
|
|
} else if _, ok := err.(*UnmarshalTypeError); !ok {
|
|
t.Errorf("Unmarshal(0x%x) returned wrong error type %T, want (*UnmarshalTypeError)", data, err)
|
|
}
|
|
}
|
|
|
|
func compareNonFloats(t *testing.T, data []byte, got interface{}, want interface{}) {
|
|
switch tm := want.(type) {
|
|
case time.Time:
|
|
if vt, ok := got.(time.Time); !ok || !tm.Equal(vt) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", data, got, got, want, want)
|
|
}
|
|
|
|
default:
|
|
if !reflect.DeepEqual(got, want) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", data, got, got, want, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalFloatToEmptyInterface(t *testing.T) {
|
|
for _, tc := range unmarshalFloatTests {
|
|
var v interface{}
|
|
if err := Unmarshal(tc.data, &v); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", tc.data, err)
|
|
continue
|
|
}
|
|
compareFloats(t, tc.data, v, tc.wantInterfaceValue, tc.equalityThreshold)
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalFloatToRawMessage(t *testing.T) {
|
|
for _, tc := range unmarshalFloatTests {
|
|
testUnmarshalToRawMessage(t, tc.data)
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalFloatToCompatibleTypes(t *testing.T) {
|
|
for _, tc := range unmarshalFloatTests {
|
|
for _, wantValue := range tc.wantValues {
|
|
testUnmarshalToCompatibleType(t, tc.data, wantValue, func(gotValue interface{}) {
|
|
compareFloats(t, tc.data, gotValue, wantValue, tc.equalityThreshold)
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalFloatToIncompatibleTypes(t *testing.T) {
|
|
for _, tc := range unmarshalFloatTests {
|
|
for _, wrongType := range unmarshalFloatWrongTypes {
|
|
testUnmarshalToIncompatibleType(t, tc.data, wrongType)
|
|
}
|
|
}
|
|
}
|
|
|
|
func compareFloats(t *testing.T, data []byte, got interface{}, want interface{}, equalityThreshold float64) {
|
|
var gotFloat64, wantFloat64 float64
|
|
|
|
switch want := want.(type) {
|
|
case float32:
|
|
f, ok := got.(float32)
|
|
if !ok {
|
|
t.Errorf("Unmarshal(0x%x) returned value of type %T, want float32", data, f)
|
|
return
|
|
}
|
|
gotFloat64, wantFloat64 = float64(f), float64(want)
|
|
|
|
case float64:
|
|
f, ok := got.(float64)
|
|
if !ok {
|
|
t.Errorf("Unmarshal(0x%x) returned value of type %T, want float64", data, f)
|
|
return
|
|
}
|
|
gotFloat64, wantFloat64 = f, want
|
|
}
|
|
|
|
switch {
|
|
case math.IsNaN(wantFloat64):
|
|
if !math.IsNaN(gotFloat64) {
|
|
t.Errorf("Unmarshal(0x%x) = %f, want NaN", data, gotFloat64)
|
|
}
|
|
|
|
case math.IsInf(wantFloat64, 0):
|
|
if gotFloat64 != wantFloat64 {
|
|
t.Errorf("Unmarshal(0x%x) = %f, want %f", data, gotFloat64, wantFloat64)
|
|
}
|
|
|
|
default:
|
|
if math.Abs(gotFloat64-wantFloat64) > equalityThreshold {
|
|
t.Errorf("Unmarshal(0x%x) = %.18f, want %.18f, diff %.18f > threshold %.18f", data, gotFloat64, wantFloat64, math.Abs(gotFloat64-wantFloat64), equalityThreshold)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestNegIntOverflow(t *testing.T) {
|
|
data := hexDecode("3bffffffffffffffff") // -18446744073709551616
|
|
|
|
// Decode CBOR neg int that overflows Go int64 to empty interface
|
|
var v1 interface{}
|
|
wantObj := bigIntOrPanic("-18446744073709551616")
|
|
if err := Unmarshal(data, &v1); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %+v", data, err)
|
|
} else if !reflect.DeepEqual(v1, wantObj) {
|
|
t.Errorf("Unmarshal(0x%x) returned %v (%T), want %v (%T)", data, v1, v1, wantObj, wantObj)
|
|
}
|
|
|
|
// Decode CBOR neg int that overflows Go int64 to big.Int
|
|
var v2 big.Int
|
|
if err := Unmarshal(data, &v2); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %+v", data, err)
|
|
} else if !reflect.DeepEqual(v2, wantObj) {
|
|
t.Errorf("Unmarshal(0x%x) returned %v (%T), want %v (%T)", data, v2, v2, wantObj, wantObj)
|
|
}
|
|
|
|
// Decode CBOR neg int that overflows Go int64 to int64
|
|
var v3 int64
|
|
if err := Unmarshal(data, &v3); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error", data)
|
|
} else if _, ok := err.(*UnmarshalTypeError); !ok {
|
|
t.Errorf("Unmarshal(0x%x) returned wrong error type %T, want (*UnmarshalTypeError)", data, err)
|
|
} else if !strings.Contains(err.Error(), "cannot unmarshal") {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want error containing %q", data, err.Error(), "cannot unmarshal")
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalIntoPtrPrimitives(t *testing.T) {
|
|
cborDataInt := hexDecode("1818") // 24
|
|
cborDataString := hexDecode("7f657374726561646d696e67ff") // "streaming"
|
|
|
|
const wantInt = 24
|
|
const wantString = "streaming"
|
|
|
|
var p1 *int
|
|
var p2 *string
|
|
var p3 *RawMessage
|
|
|
|
var i int
|
|
pi := &i
|
|
ppi := &pi
|
|
|
|
var s string
|
|
ps := &s
|
|
pps := &ps
|
|
|
|
var r RawMessage
|
|
pr := &r
|
|
ppr := &pr
|
|
|
|
// Unmarshal CBOR integer into a non-nil pointer.
|
|
if err := Unmarshal(cborDataInt, &ppi); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", cborDataInt, err)
|
|
} else if i != wantInt {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %d", cborDataInt, i, i, wantInt)
|
|
}
|
|
// Unmarshal CBOR integer into a nil pointer.
|
|
if err := Unmarshal(cborDataInt, &p1); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", cborDataInt, err)
|
|
} else if *p1 != wantInt {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %d", cborDataInt, *pi, pi, wantInt)
|
|
}
|
|
|
|
// Unmarshal CBOR string into a non-nil pointer.
|
|
if err := Unmarshal(cborDataString, &pps); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", cborDataString, err)
|
|
} else if s != wantString {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v", cborDataString, s, s, wantString)
|
|
}
|
|
// Unmarshal CBOR string into a nil pointer.
|
|
if err := Unmarshal(cborDataString, &p2); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", cborDataString, err)
|
|
} else if *p2 != wantString {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v", cborDataString, *p2, p2, wantString)
|
|
}
|
|
|
|
// Unmarshal CBOR string into a non-nil RawMessage.
|
|
if err := Unmarshal(cborDataString, &ppr); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", cborDataString, err)
|
|
} else if !bytes.Equal(r, cborDataString) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v", cborDataString, r, r, cborDataString)
|
|
}
|
|
// Unmarshal CBOR string into a nil pointer to RawMessage.
|
|
if err := Unmarshal(cborDataString, &p3); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", cborDataString, err)
|
|
} else if !bytes.Equal(*p3, cborDataString) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v", cborDataString, *p3, p3, cborDataString)
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalIntoPtrArrayPtrElem(t *testing.T) {
|
|
data := hexDecode("83010203") // []int{1, 2, 3}
|
|
|
|
n1, n2, n3 := 1, 2, 3
|
|
|
|
wantArray := []*int{&n1, &n2, &n3}
|
|
|
|
var p *[]*int
|
|
|
|
var slc []*int
|
|
pslc := &slc
|
|
ppslc := &pslc
|
|
|
|
// Unmarshal CBOR array into a non-nil pointer.
|
|
if err := Unmarshal(data, &ppslc); err != nil {
|
|
t.Errorf("Unmarshal(0x%x, %s) returned error %v", data, reflect.TypeOf(ppslc), err)
|
|
} else if !reflect.DeepEqual(slc, wantArray) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v", data, slc, slc, wantArray)
|
|
}
|
|
// Unmarshal CBOR array into a nil pointer.
|
|
if err := Unmarshal(data, &p); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", data, err)
|
|
} else if !reflect.DeepEqual(*p, wantArray) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v", data, *p, p, wantArray)
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalIntoPtrMapPtrElem(t *testing.T) {
|
|
data := hexDecode("a201020304") // {1: 2, 3: 4}
|
|
|
|
n1, n2, n3, n4 := 1, 2, 3, 4
|
|
|
|
wantMap := map[int]*int{n1: &n2, n3: &n4}
|
|
|
|
var p *map[int]*int
|
|
|
|
var m map[int]*int
|
|
pm := &m
|
|
ppm := &pm
|
|
|
|
// Unmarshal CBOR map into a non-nil pointer.
|
|
if err := Unmarshal(data, &ppm); err != nil {
|
|
t.Errorf("Unmarshal(0x%x, %s) returned error %v", data, reflect.TypeOf(ppm), err)
|
|
} else if !reflect.DeepEqual(m, wantMap) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v", data, m, m, wantMap)
|
|
}
|
|
// Unmarshal CBOR map into a nil pointer.
|
|
if err := Unmarshal(data, &p); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", data, err)
|
|
} else if !reflect.DeepEqual(*p, wantMap) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v", data, *p, p, wantMap)
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalIntoPtrStructPtrElem(t *testing.T) {
|
|
type s1 struct {
|
|
A *string `cbor:"a"`
|
|
B *string `cbor:"b"`
|
|
C *string `cbor:"c"`
|
|
D *string `cbor:"d"`
|
|
E *string `cbor:"e"`
|
|
}
|
|
|
|
data := hexDecode("a56161614161626142616361436164614461656145") // map[string]string{"a": "A", "b": "B", "c": "C", "d": "D", "e": "E"}
|
|
|
|
a, b, c, d, e := "A", "B", "C", "D", "E"
|
|
wantObj := s1{A: &a, B: &b, C: &c, D: &d, E: &e}
|
|
|
|
var p *s1
|
|
|
|
var s s1
|
|
ps := &s
|
|
pps := &ps
|
|
|
|
// Unmarshal CBOR map into a non-nil pointer.
|
|
if err := Unmarshal(data, &pps); err != nil {
|
|
t.Errorf("Unmarshal(0x%x, %s) returned error %v", data, reflect.TypeOf(pps), err)
|
|
} else if !reflect.DeepEqual(s, wantObj) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v", data, s, s, wantObj)
|
|
}
|
|
// Unmarshal CBOR map into a nil pointer.
|
|
if err := Unmarshal(data, &p); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", data, err)
|
|
} else if !reflect.DeepEqual(*p, wantObj) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v", data, *p, p, wantObj)
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalIntoArray(t *testing.T) {
|
|
data := hexDecode("83010203") // []int{1, 2, 3}
|
|
|
|
// Unmarshal CBOR array into Go array.
|
|
var arr1 [3]int
|
|
if err := Unmarshal(data, &arr1); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", data, err)
|
|
} else if arr1 != [3]int{1, 2, 3} {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want [3]int{1, 2, 3}", data, arr1, arr1)
|
|
}
|
|
|
|
// Unmarshal CBOR array into Go array with more elements.
|
|
var arr2 [5]int
|
|
if err := Unmarshal(data, &arr2); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", data, err)
|
|
} else if arr2 != [5]int{1, 2, 3, 0, 0} {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want [5]int{1, 2, 3, 0, 0}", data, arr2, arr2)
|
|
}
|
|
|
|
// Unmarshal CBOR array into Go array with less elements.
|
|
var arr3 [1]int
|
|
if err := Unmarshal(data, &arr3); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", data, err)
|
|
} else if arr3 != [1]int{1} {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want [0]int{1}", data, arr3, arr3)
|
|
}
|
|
}
|
|
|
|
type nilUnmarshaler string
|
|
|
|
func (s *nilUnmarshaler) UnmarshalCBOR(data []byte) error {
|
|
if len(data) == 1 && (data[0] == 0xf6 || data[0] == 0xf7) {
|
|
*s = "null"
|
|
} else {
|
|
*s = nilUnmarshaler(data)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func TestUnmarshalNil(t *testing.T) {
|
|
type T struct {
|
|
I int
|
|
}
|
|
|
|
data := [][]byte{hexDecode("f6"), hexDecode("f7")} // CBOR null and undefined values
|
|
|
|
testCases := []struct {
|
|
name string
|
|
value interface{}
|
|
wantValue interface{}
|
|
}{
|
|
// Unmarshalling CBOR null to the following types is a no-op.
|
|
{"bool", true, true},
|
|
{"int", int(-1), int(-1)},
|
|
{"int8", int8(-2), int8(-2)},
|
|
{"int16", int16(-3), int16(-3)},
|
|
{"int32", int32(-4), int32(-4)},
|
|
{"int64", int64(-5), int64(-5)},
|
|
{"uint", uint(1), uint(1)},
|
|
{"uint8", uint8(2), uint8(2)},
|
|
{"uint16", uint16(3), uint16(3)},
|
|
{"uint32", uint32(4), uint32(4)},
|
|
{"uint64", uint64(5), uint64(5)},
|
|
{"float32", float32(1.23), float32(1.23)},
|
|
{"float64", float64(4.56), float64(4.56)},
|
|
{"string", "hello", "hello"},
|
|
{"array", [3]int{1, 2, 3}, [3]int{1, 2, 3}},
|
|
|
|
// Unmarshalling CBOR null to slice/map sets Go values to nil.
|
|
{"[]byte", []byte{1, 2, 3}, []byte(nil)},
|
|
{"slice", []string{"hello", "world"}, []string(nil)},
|
|
{"map", map[string]bool{"hello": true, "goodbye": false}, map[string]bool(nil)},
|
|
|
|
// Unmarshalling CBOR null to ByteString (string wrapper for []byte) resets ByteString to empty string.
|
|
{"cbor.ByteString", ByteString("\x01\x02\x03"), ByteString("")},
|
|
|
|
// Unmarshalling CBOR null to time.Time is a no-op.
|
|
{"time.Time", time.Date(2020, time.January, 2, 3, 4, 5, 6, time.UTC), time.Date(2020, time.January, 2, 3, 4, 5, 6, time.UTC)},
|
|
|
|
// Unmarshalling CBOR null to big.Int is a no-op.
|
|
{"big.Int", bigIntOrPanic("123"), bigIntOrPanic("123")},
|
|
|
|
// Unmarshalling CBOR null to user defined struct types is a no-op.
|
|
{"user defined struct", T{I: 123}, T{I: 123}},
|
|
|
|
// Unmarshalling CBOR null to cbor.Tag and cbor.RawTag is a no-op.
|
|
{"cbor.RawTag", RawTag{123, []byte{4, 5, 6}}, RawTag{123, []byte{4, 5, 6}}},
|
|
{"cbor.Tag", Tag{123, "hello world"}, Tag{123, "hello world"}},
|
|
|
|
// Unmarshalling to cbor.RawMessage sets cbor.RawMessage to raw CBOR bytes (0xf6 or 0xf7).
|
|
// It's tested in TestUnmarshal().
|
|
|
|
// Unmarshalling to types implementing cbor.BinaryUnmarshaler is a no-op.
|
|
{"cbor.BinaryUnmarshaler", number(456), number(456)},
|
|
|
|
// When unmarshalling to types implementing cbor.Unmarshaler,
|
|
{"cbor.Unmarshaler", nilUnmarshaler("hello world"), nilUnmarshaler("null")},
|
|
}
|
|
|
|
// Unmarshalling to values of specified Go types.
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
for _, data := range data {
|
|
v := reflect.New(reflect.TypeOf(tc.value))
|
|
v.Elem().Set(reflect.ValueOf(tc.value))
|
|
|
|
if err := Unmarshal(data, v.Interface()); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) to %T returned error %v", data, v.Elem().Interface(), err)
|
|
} else if !reflect.DeepEqual(v.Elem().Interface(), tc.wantValue) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", data, v.Elem().Interface(), v.Elem().Interface(), tc.wantValue, tc.wantValue)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
var invalidUnmarshalTests = []struct {
|
|
name string
|
|
v interface{}
|
|
wantErrorMsg string
|
|
}{
|
|
{"unmarshal into nil interface{}", nil, "cbor: Unmarshal(nil)"},
|
|
{"unmarshal into non-pointer value", 5, "cbor: Unmarshal(non-pointer int)"},
|
|
{"unmarshal into nil pointer", (*int)(nil), "cbor: Unmarshal(nil *int)"},
|
|
}
|
|
|
|
func TestInvalidUnmarshal(t *testing.T) {
|
|
data := []byte{0x00}
|
|
|
|
for _, tc := range invalidUnmarshalTests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
err := Unmarshal(data, tc.v)
|
|
if err == nil {
|
|
t.Errorf("Unmarshal(0x%x, %v) didn't return an error", data, tc.v)
|
|
} else if _, ok := err.(*InvalidUnmarshalError); !ok {
|
|
t.Errorf("Unmarshal(0x%x, %v) error type %T, want *InvalidUnmarshalError", data, tc.v, err)
|
|
} else if err.Error() != tc.wantErrorMsg {
|
|
t.Errorf("Unmarshal(0x%x, %v) error %q, want %q", data, tc.v, err.Error(), tc.wantErrorMsg)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
var invalidCBORUnmarshalTests = []struct {
|
|
name string
|
|
data []byte
|
|
wantErrorMsg string
|
|
errorMsgPartialMatch bool
|
|
}{
|
|
{"Nil data", []byte(nil), "EOF", false},
|
|
{"Empty data", []byte{}, "EOF", false},
|
|
{"Tag number not followed by tag content", []byte{0xc0}, "unexpected EOF", false},
|
|
{"Definite length strings with tagged chunk", hexDecode("5fc64401020304ff"), "cbor: wrong element type tag for indefinite-length byte string", false},
|
|
{"Definite length strings with tagged chunk", hexDecode("7fc06161ff"), "cbor: wrong element type tag for indefinite-length UTF-8 text string", false},
|
|
{"Indefinite length strings with invalid head", hexDecode("7f61"), "unexpected EOF", false},
|
|
{"Invalid nested tag number", hexDecode("d864dc1a514b67b0"), "cbor: invalid additional information", true},
|
|
// Data from 7049bis G.1
|
|
// Premature end of the input
|
|
{"End of input in a head", hexDecode("18"), "unexpected EOF", false},
|
|
{"End of input in a head", hexDecode("19"), "unexpected EOF", false},
|
|
{"End of input in a head", hexDecode("1a"), "unexpected EOF", false},
|
|
{"End of input in a head", hexDecode("1b"), "unexpected EOF", false},
|
|
{"End of input in a head", hexDecode("1901"), "unexpected EOF", false},
|
|
{"End of input in a head", hexDecode("1a0102"), "unexpected EOF", false},
|
|
{"End of input in a head", hexDecode("1b01020304050607"), "unexpected EOF", false},
|
|
{"End of input in a head", hexDecode("38"), "unexpected EOF", false},
|
|
{"End of input in a head", hexDecode("58"), "unexpected EOF", false},
|
|
{"End of input in a head", hexDecode("78"), "unexpected EOF", false},
|
|
{"End of input in a head", hexDecode("98"), "unexpected EOF", false},
|
|
{"End of input in a head", hexDecode("9a01ff00"), "unexpected EOF", false},
|
|
{"End of input in a head", hexDecode("b8"), "unexpected EOF", false},
|
|
{"End of input in a head", hexDecode("d8"), "unexpected EOF", false},
|
|
{"End of input in a head", hexDecode("f8"), "unexpected EOF", false},
|
|
{"End of input in a head", hexDecode("f900"), "unexpected EOF", false},
|
|
{"End of input in a head", hexDecode("fa0000"), "unexpected EOF", false},
|
|
{"End of input in a head", hexDecode("fb000000"), "unexpected EOF", false},
|
|
{"Definite length strings with short data", hexDecode("41"), "unexpected EOF", false},
|
|
{"Definite length strings with short data", hexDecode("61"), "unexpected EOF", false},
|
|
{"Definite length strings with short data", hexDecode("5affffffff00"), "unexpected EOF", false},
|
|
{"Definite length strings with short data", hexDecode("5bffffffffffffffff010203"), "cbor: byte string length 18446744073709551615 is too large, causing integer overflow", false},
|
|
{"Definite length strings with short data", hexDecode("7affffffff00"), "unexpected EOF", false},
|
|
{"Definite length strings with short data", hexDecode("7b7fffffffffffffff010203"), "unexpected EOF", false},
|
|
{"Definite length maps and arrays not closed with enough items", hexDecode("81"), "unexpected EOF", false},
|
|
{"Definite length maps and arrays not closed with enough items", hexDecode("818181818181818181"), "unexpected EOF", false},
|
|
{"Definite length maps and arrays not closed with enough items", hexDecode("8200"), "unexpected EOF", false},
|
|
{"Definite length maps and arrays not closed with enough items", hexDecode("a1"), "unexpected EOF", false},
|
|
{"Definite length maps and arrays not closed with enough items", hexDecode("a20102"), "unexpected EOF", false},
|
|
{"Definite length maps and arrays not closed with enough items", hexDecode("a100"), "unexpected EOF", false},
|
|
{"Definite length maps and arrays not closed with enough items", hexDecode("a2000000"), "unexpected EOF", false},
|
|
{"Indefinite length strings not closed by a break stop code", hexDecode("5f4100"), "unexpected EOF", false},
|
|
{"Indefinite length strings not closed by a break stop code", hexDecode("7f6100"), "unexpected EOF", false},
|
|
{"Indefinite length maps and arrays not closed by a break stop code", hexDecode("9f"), "unexpected EOF", false},
|
|
{"Indefinite length maps and arrays not closed by a break stop code", hexDecode("9f0102"), "unexpected EOF", false},
|
|
{"Indefinite length maps and arrays not closed by a break stop code", hexDecode("bf"), "unexpected EOF", false},
|
|
{"Indefinite length maps and arrays not closed by a break stop code", hexDecode("bf01020102"), "unexpected EOF", false},
|
|
{"Indefinite length maps and arrays not closed by a break stop code", hexDecode("819f"), "unexpected EOF", false},
|
|
{"Indefinite length maps and arrays not closed by a break stop code", hexDecode("9f8000"), "unexpected EOF", false},
|
|
{"Indefinite length maps and arrays not closed by a break stop code", hexDecode("9f9f9f9f9fffffffff"), "unexpected EOF", false},
|
|
{"Indefinite length maps and arrays not closed by a break stop code", hexDecode("9f819f819f9fffffff"), "unexpected EOF", false},
|
|
// Five subkinds of well-formedness error kind 3 (syntax error)
|
|
{"Reserved additional information values", hexDecode("3e"), "cbor: invalid additional information", true},
|
|
{"Reserved additional information values", hexDecode("5c"), "cbor: invalid additional information", true},
|
|
{"Reserved additional information values", hexDecode("5d"), "cbor: invalid additional information", true},
|
|
{"Reserved additional information values", hexDecode("5e"), "cbor: invalid additional information", true},
|
|
{"Reserved additional information values", hexDecode("7c"), "cbor: invalid additional information", true},
|
|
{"Reserved additional information values", hexDecode("7d"), "cbor: invalid additional information", true},
|
|
{"Reserved additional information values", hexDecode("7e"), "cbor: invalid additional information", true},
|
|
{"Reserved additional information values", hexDecode("9c"), "cbor: invalid additional information", true},
|
|
{"Reserved additional information values", hexDecode("9d"), "cbor: invalid additional information", true},
|
|
{"Reserved additional information values", hexDecode("9e"), "cbor: invalid additional information", true},
|
|
{"Reserved additional information values", hexDecode("bc"), "cbor: invalid additional information", true},
|
|
{"Reserved additional information values", hexDecode("bd"), "cbor: invalid additional information", true},
|
|
{"Reserved additional information values", hexDecode("be"), "cbor: invalid additional information", true},
|
|
{"Reserved additional information values", hexDecode("dc"), "cbor: invalid additional information", true},
|
|
{"Reserved additional information values", hexDecode("dd"), "cbor: invalid additional information", true},
|
|
{"Reserved additional information values", hexDecode("de"), "cbor: invalid additional information", true},
|
|
{"Reserved additional information values", hexDecode("fc"), "cbor: invalid additional information", true},
|
|
{"Reserved additional information values", hexDecode("fd"), "cbor: invalid additional information", true},
|
|
{"Reserved additional information values", hexDecode("fe"), "cbor: invalid additional information", true},
|
|
{"Reserved two-byte encodings of simple types", hexDecode("f800"), "cbor: invalid simple value 0 for type primitives", true},
|
|
{"Reserved two-byte encodings of simple types", hexDecode("f801"), "cbor: invalid simple value 1 for type primitives", true},
|
|
{"Reserved two-byte encodings of simple types", hexDecode("f818"), "cbor: invalid simple value 24 for type primitives", true},
|
|
{"Reserved two-byte encodings of simple types", hexDecode("f81f"), "cbor: invalid simple value 31 for type primitives", true},
|
|
{"Indefinite length string chunks not of the correct type", hexDecode("5f00ff"), "cbor: wrong element type positive integer for indefinite-length byte string", false},
|
|
{"Indefinite length string chunks not of the correct type", hexDecode("5f21ff"), "cbor: wrong element type negative integer for indefinite-length byte string", false},
|
|
{"Indefinite length string chunks not of the correct type", hexDecode("5f6100ff"), "cbor: wrong element type UTF-8 text string for indefinite-length byte string", false},
|
|
{"Indefinite length string chunks not of the correct type", hexDecode("5f80ff"), "cbor: wrong element type array for indefinite-length byte string", false},
|
|
{"Indefinite length string chunks not of the correct type", hexDecode("5fa0ff"), "cbor: wrong element type map for indefinite-length byte string", false},
|
|
{"Indefinite length string chunks not of the correct type", hexDecode("5fc000ff"), "cbor: wrong element type tag for indefinite-length byte string", false},
|
|
{"Indefinite length string chunks not of the correct type", hexDecode("5fe0ff"), "cbor: wrong element type primitives for indefinite-length byte string", false},
|
|
{"Indefinite length string chunks not of the correct type", hexDecode("7f4100ff"), "cbor: wrong element type byte string for indefinite-length UTF-8 text string", false},
|
|
{"Indefinite length string chunks not definite length", hexDecode("5f5f4100ffff"), "cbor: indefinite-length byte string chunk is not definite-length", false},
|
|
{"Indefinite length string chunks not definite length", hexDecode("7f7f6100ffff"), "cbor: indefinite-length UTF-8 text string chunk is not definite-length", false},
|
|
{"Break occurring on its own outside of an indefinite length item", hexDecode("ff"), "cbor: unexpected \"break\" code", true},
|
|
{"Break occurring in a definite length array or map or a tag", hexDecode("81ff"), "cbor: unexpected \"break\" code", true},
|
|
{"Break occurring in a definite length array or map or a tag", hexDecode("8200ff"), "cbor: unexpected \"break\" code", true},
|
|
{"Break occurring in a definite length array or map or a tag", hexDecode("a1ff"), "cbor: unexpected \"break\" code", true},
|
|
{"Break occurring in a definite length array or map or a tag", hexDecode("a1ff00"), "cbor: unexpected \"break\" code", true},
|
|
{"Break occurring in a definite length array or map or a tag", hexDecode("a100ff"), "cbor: unexpected \"break\" code", true},
|
|
{"Break occurring in a definite length array or map or a tag", hexDecode("a20000ff"), "cbor: unexpected \"break\" code", true},
|
|
{"Break occurring in a definite length array or map or a tag", hexDecode("9f81ff"), "cbor: unexpected \"break\" code", true},
|
|
{"Break occurring in a definite length array or map or a tag", hexDecode("9f829f819f9fffffffff"), "cbor: unexpected \"break\" code", true},
|
|
{"Break in indefinite length map would lead to odd number of items (break in a value position)", hexDecode("bf00ff"), "cbor: unexpected \"break\" code", true},
|
|
{"Break in indefinite length map would lead to odd number of items (break in a value position)", hexDecode("bf000000ff"), "cbor: unexpected \"break\" code", true},
|
|
{"Major type 0 with additional information 31", hexDecode("1f"), "cbor: invalid additional information 31 for type positive integer", true},
|
|
{"Major type 1 with additional information 31", hexDecode("3f"), "cbor: invalid additional information 31 for type negative integer", true},
|
|
{"Major type 6 with additional information 31", hexDecode("df"), "cbor: invalid additional information 31 for type tag", true},
|
|
// Extraneous data
|
|
{"two ints", hexDecode("0001"), "cbor: 1 bytes of extraneous data starting at index 1", false},
|
|
{"two arrays", hexDecode("830102038104"), "cbor: 2 bytes of extraneous data starting at index 4", false},
|
|
{"int and partial array", hexDecode("00830102"), "cbor: 3 bytes of extraneous data starting at index 1", false},
|
|
}
|
|
|
|
func TestInvalidCBORUnmarshal(t *testing.T) {
|
|
for _, tc := range invalidCBORUnmarshalTests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
var i interface{}
|
|
err := Unmarshal(tc.data, &i)
|
|
if err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error", tc.data)
|
|
} else if !tc.errorMsgPartialMatch && err.Error() != tc.wantErrorMsg {
|
|
t.Errorf("Unmarshal(0x%x) error %q, want %q", tc.data, err.Error(), tc.wantErrorMsg)
|
|
} else if tc.errorMsgPartialMatch && !strings.Contains(err.Error(), tc.wantErrorMsg) {
|
|
t.Errorf("Unmarshal(0x%x) error %q, want %q", tc.data, err.Error(), tc.wantErrorMsg)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestValidUTF8String(t *testing.T) {
|
|
dmRejectInvalidUTF8, err := DecOptions{UTF8: UTF8RejectInvalid}.DecMode()
|
|
if err != nil {
|
|
t.Errorf("DecMode() returned an error %+v", err)
|
|
}
|
|
dmDecodeInvalidUTF8, err := DecOptions{UTF8: UTF8DecodeInvalid}.DecMode()
|
|
if err != nil {
|
|
t.Errorf("DecMode() returned an error %+v", err)
|
|
}
|
|
|
|
testCases := []struct {
|
|
name string
|
|
data []byte
|
|
dm DecMode
|
|
wantObj interface{}
|
|
}{
|
|
{
|
|
name: "with UTF8RejectInvalid",
|
|
data: hexDecode("6973747265616d696e67"),
|
|
dm: dmRejectInvalidUTF8,
|
|
wantObj: "streaming",
|
|
},
|
|
{
|
|
name: "with UTF8DecodeInvalid",
|
|
data: hexDecode("6973747265616d696e67"),
|
|
dm: dmDecodeInvalidUTF8,
|
|
wantObj: "streaming",
|
|
},
|
|
{
|
|
name: "indef length with UTF8RejectInvalid",
|
|
data: hexDecode("7f657374726561646d696e67ff"),
|
|
dm: dmRejectInvalidUTF8,
|
|
wantObj: "streaming",
|
|
},
|
|
{
|
|
name: "indef length with UTF8DecodeInvalid",
|
|
data: hexDecode("7f657374726561646d696e67ff"),
|
|
dm: dmDecodeInvalidUTF8,
|
|
wantObj: "streaming",
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
// Decode to empty interface
|
|
var i interface{}
|
|
err = tc.dm.Unmarshal(tc.data, &i)
|
|
if err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q", tc.data, err)
|
|
}
|
|
if !reflect.DeepEqual(i, tc.wantObj) {
|
|
t.Errorf("Unmarshal(0x%x) returned %v (%T), want %v (%T)", tc.data, i, i, tc.wantObj, tc.wantObj)
|
|
}
|
|
|
|
// Decode to string
|
|
var v string
|
|
err = tc.dm.Unmarshal(tc.data, &v)
|
|
if err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q", tc.data, err)
|
|
}
|
|
if !reflect.DeepEqual(v, tc.wantObj) {
|
|
t.Errorf("Unmarshal(0x%x) returned %v (%T), want %v (%T)", tc.data, v, v, tc.wantObj, tc.wantObj)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestInvalidUTF8String(t *testing.T) {
|
|
dmRejectInvalidUTF8, err := DecOptions{UTF8: UTF8RejectInvalid}.DecMode()
|
|
if err != nil {
|
|
t.Errorf("DecMode() returned an error %+v", err)
|
|
}
|
|
dmDecodeInvalidUTF8, err := DecOptions{UTF8: UTF8DecodeInvalid}.DecMode()
|
|
if err != nil {
|
|
t.Errorf("DecMode() returned an error %+v", err)
|
|
}
|
|
|
|
testCases := []struct {
|
|
name string
|
|
data []byte
|
|
dm DecMode
|
|
wantObj interface{}
|
|
wantErrorMsg string
|
|
}{
|
|
{
|
|
name: "with UTF8RejectInvalid",
|
|
data: hexDecode("61fe"),
|
|
dm: dmRejectInvalidUTF8,
|
|
wantErrorMsg: invalidUTF8ErrorMsg,
|
|
},
|
|
{
|
|
name: "with UTF8DecodeInvalid",
|
|
data: hexDecode("61fe"),
|
|
dm: dmDecodeInvalidUTF8,
|
|
wantObj: string([]byte{0xfe}),
|
|
},
|
|
{
|
|
name: "indef length with UTF8RejectInvalid",
|
|
data: hexDecode("7f62e6b061b4ff"),
|
|
dm: dmRejectInvalidUTF8,
|
|
wantErrorMsg: invalidUTF8ErrorMsg,
|
|
},
|
|
{
|
|
name: "indef length with UTF8DecodeInvalid",
|
|
data: hexDecode("7f62e6b061b4ff"),
|
|
dm: dmDecodeInvalidUTF8,
|
|
wantObj: string([]byte{0xe6, 0xb0, 0xb4}),
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
// Decode to empty interface
|
|
var v interface{}
|
|
err = tc.dm.Unmarshal(tc.data, &v)
|
|
if tc.wantErrorMsg != "" {
|
|
if err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return error", tc.data)
|
|
} else if !strings.Contains(err.Error(), tc.wantErrorMsg) {
|
|
t.Errorf("Unmarshal(0x%x) error %q, want %q", tc.data, err.Error(), tc.wantErrorMsg)
|
|
}
|
|
} else {
|
|
if err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q", tc.data, err)
|
|
}
|
|
if !reflect.DeepEqual(v, tc.wantObj) {
|
|
t.Errorf("Unmarshal(0x%x) returned %v (%T), want %v (%T)", tc.data, v, v, tc.wantObj, tc.wantObj)
|
|
}
|
|
}
|
|
|
|
// Decode to string
|
|
var s string
|
|
err = tc.dm.Unmarshal(tc.data, &s)
|
|
if tc.wantErrorMsg != "" {
|
|
if err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return error", tc.data)
|
|
} else if !strings.Contains(err.Error(), tc.wantErrorMsg) {
|
|
t.Errorf("Unmarshal(0x%x) error %q, want %q", tc.data, err.Error(), tc.wantErrorMsg)
|
|
}
|
|
} else {
|
|
if err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q", tc.data, err)
|
|
}
|
|
if !reflect.DeepEqual(s, tc.wantObj) {
|
|
t.Errorf("Unmarshal(0x%x) returned %v (%T), want %v (%T)", tc.data, s, s, tc.wantObj, tc.wantObj)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
// Test decoding of mixed invalid text string and valid text string
|
|
// with UTF8RejectInvalid option (default)
|
|
data := hexDecode("7f62e6b061b4ff7f657374726561646d696e67ff")
|
|
dec := NewDecoder(bytes.NewReader(data))
|
|
var s string
|
|
if err := dec.Decode(&s); err == nil {
|
|
t.Errorf("Decode() didn't return an error")
|
|
} else if s != "" {
|
|
t.Errorf("Decode() returned %q, want %q", s, "")
|
|
}
|
|
if err := dec.Decode(&s); err != nil {
|
|
t.Errorf("Decode() returned error %v", err)
|
|
} else if s != "streaming" {
|
|
t.Errorf("Decode() returned %q, want %q", s, "streaming")
|
|
}
|
|
|
|
// Test decoding of mixed invalid text string and valid text string
|
|
// with UTF8DecodeInvalid option
|
|
dec = dmDecodeInvalidUTF8.NewDecoder(bytes.NewReader(data))
|
|
if err := dec.Decode(&s); err != nil {
|
|
t.Errorf("Decode() returned error %q", err)
|
|
} else if s != string([]byte{0xe6, 0xb0, 0xb4}) {
|
|
t.Errorf("Decode() returned %q, want %q", s, string([]byte{0xe6, 0xb0, 0xb4}))
|
|
}
|
|
if err := dec.Decode(&s); err != nil {
|
|
t.Errorf("Decode() returned error %v", err)
|
|
} else if s != "streaming" {
|
|
t.Errorf("Decode() returned %q, want %q", s, "streaming")
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalStruct(t *testing.T) {
|
|
want := outer{
|
|
IntField: 123,
|
|
FloatField: 100000.0,
|
|
BoolField: true,
|
|
StringField: "test",
|
|
ByteStringField: []byte{1, 3, 5},
|
|
ArrayField: []string{"hello", "world"},
|
|
MapField: map[string]bool{"morning": true, "afternoon": false},
|
|
NestedStructField: &inner{X: 1000, Y: 1000000},
|
|
unexportedField: 0,
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
data []byte
|
|
want interface{}
|
|
}{
|
|
{"case-insensitive field name match", hexDecode("a868696e746669656c64187b6a666c6f61746669656c64fa47c3500069626f6f6c6669656c64f56b537472696e674669656c6464746573746f42797465537472696e674669656c64430103056a41727261794669656c64826568656c6c6f65776f726c64684d61704669656c64a2676d6f726e696e67f56961667465726e6f6f6ef4714e65737465645374727563744669656c64a261581903e861591a000f4240"), want},
|
|
{"exact field name match", hexDecode("a868496e744669656c64187b6a466c6f61744669656c64fa47c3500069426f6f6c4669656c64f56b537472696e674669656c6464746573746f42797465537472696e674669656c64430103056a41727261794669656c64826568656c6c6f65776f726c64684d61704669656c64a2676d6f726e696e67f56961667465726e6f6f6ef4714e65737465645374727563744669656c64a261581903e861591a000f4240"), want},
|
|
}
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
var v outer
|
|
if err := Unmarshal(tc.data, &v); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", tc.data, err)
|
|
} else if !reflect.DeepEqual(v, want) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", tc.data, v, v, want, want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalStructError1(t *testing.T) {
|
|
type outer2 struct {
|
|
IntField int
|
|
FloatField float32
|
|
BoolField bool
|
|
StringField string
|
|
ByteStringField []byte
|
|
ArrayField []int // wrong type
|
|
MapField map[string]bool
|
|
NestedStructField map[int]string // wrong type
|
|
unexportedField int64
|
|
}
|
|
want := outer2{
|
|
IntField: 123,
|
|
FloatField: 100000.0,
|
|
BoolField: true,
|
|
StringField: "test",
|
|
ByteStringField: []byte{1, 3, 5},
|
|
ArrayField: []int{0, 0},
|
|
MapField: map[string]bool{"morning": true, "afternoon": false},
|
|
NestedStructField: map[int]string{},
|
|
unexportedField: 0,
|
|
}
|
|
|
|
data := hexDecode("a868496e744669656c64187b6a466c6f61744669656c64fa47c3500069426f6f6c4669656c64f56b537472696e674669656c6464746573746f42797465537472696e674669656c64430103056a41727261794669656c64826568656c6c6f65776f726c64684d61704669656c64a2676d6f726e696e67f56961667465726e6f6f6ef4714e65737465645374727563744669656c64a261581903e861591a000f4240")
|
|
wantCBORType := "UTF-8 text string"
|
|
wantGoType := "int"
|
|
wantStructFieldName := "cbor.outer2.ArrayField"
|
|
wantErrorMsg := "cannot unmarshal UTF-8 text string into Go struct field cbor.outer2.ArrayField of type int"
|
|
|
|
var v outer2
|
|
if err := Unmarshal(data, &v); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error", data)
|
|
} else {
|
|
if typeError, ok := err.(*UnmarshalTypeError); !ok {
|
|
t.Errorf("Unmarshal(0x%x) returned wrong type of error %T, want (*UnmarshalTypeError)", data, err)
|
|
} else {
|
|
if typeError.CBORType != wantCBORType {
|
|
t.Errorf("Unmarshal(0x%x) returned (*UnmarshalTypeError).CBORType %s, want %s", data, typeError.CBORType, wantCBORType)
|
|
}
|
|
if typeError.GoType != wantGoType {
|
|
t.Errorf("Unmarshal(0x%x) returned (*UnmarshalTypeError).GoType %s, want %s", data, typeError.GoType, wantGoType)
|
|
}
|
|
if typeError.StructFieldName != wantStructFieldName {
|
|
t.Errorf("Unmarshal(0x%x) returned (*UnmarshalTypeError).StructFieldName %s, want %s", data, typeError.StructFieldName, wantStructFieldName)
|
|
}
|
|
if !strings.Contains(err.Error(), wantErrorMsg) {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want error containing %q", data, err.Error(), wantErrorMsg)
|
|
}
|
|
}
|
|
}
|
|
if !reflect.DeepEqual(v, want) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", data, v, v, want, want)
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalStructError2(t *testing.T) {
|
|
// Unmarshal integer and invalid UTF8 string as field name into struct
|
|
type strc struct {
|
|
A string `cbor:"a"`
|
|
B string `cbor:"b"`
|
|
C string `cbor:"c"`
|
|
}
|
|
want := strc{
|
|
A: "A",
|
|
}
|
|
|
|
// Unmarshal returns first error encountered, which is *UnmarshalTypeError (failed to unmarshal int into Go string)
|
|
data := hexDecode("a3fa47c35000026161614161fe6142") // {100000.0:2, "a":"A", 0xfe: B}
|
|
wantCBORType := "primitives"
|
|
wantGoType := "string"
|
|
wantErrorMsg := "cannot unmarshal primitives into Go value of type string"
|
|
|
|
v := strc{}
|
|
if err := Unmarshal(data, &v); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error", data)
|
|
} else {
|
|
if typeError, ok := err.(*UnmarshalTypeError); !ok {
|
|
t.Errorf("Unmarshal(0x%x) returned wrong type of error %T, want (*UnmarshalTypeError)", data, err)
|
|
} else {
|
|
if typeError.CBORType != wantCBORType {
|
|
t.Errorf("Unmarshal(0x%x) returned (*UnmarshalTypeError).CBORType %s, want %s", data, typeError.CBORType, wantCBORType)
|
|
}
|
|
if typeError.GoType != wantGoType {
|
|
t.Errorf("Unmarshal(0x%x) returned (*UnmarshalTypeError).GoType %s, want %s", data, typeError.GoType, wantGoType)
|
|
}
|
|
if !strings.Contains(err.Error(), wantErrorMsg) {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want error containing %q", data, err.Error(), wantErrorMsg)
|
|
}
|
|
}
|
|
}
|
|
if !reflect.DeepEqual(v, want) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", data, v, v, want, want)
|
|
}
|
|
|
|
// Unmarshal returns first error encountered, which is *cbor.SemanticError (invalid UTF8 string)
|
|
data = hexDecode("a361fe6142010261616141") // {0xfe: B, 1:2, "a":"A"}
|
|
v = strc{}
|
|
if err := Unmarshal(data, &v); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error", data)
|
|
} else {
|
|
if _, ok := err.(*SemanticError); !ok {
|
|
t.Errorf("Unmarshal(0x%x) returned wrong type of error %T, want (*SemanticError)", data, err)
|
|
} else if err.Error() != invalidUTF8ErrorMsg {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want error %q", data, err.Error(), invalidUTF8ErrorMsg)
|
|
}
|
|
}
|
|
if !reflect.DeepEqual(v, want) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", data, v, v, want, want)
|
|
}
|
|
|
|
// Unmarshal returns first error encountered, which is *cbor.SemanticError (invalid UTF8 string)
|
|
data = hexDecode("a3616261fe010261616141") // {"b": 0xfe, 1:2, "a":"A"}
|
|
v = strc{}
|
|
if err := Unmarshal(data, &v); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error", data)
|
|
} else {
|
|
if _, ok := err.(*SemanticError); !ok {
|
|
t.Errorf("Unmarshal(0x%x) returned wrong type of error %T, want (*SemanticError)", data, err)
|
|
} else if err.Error() != invalidUTF8ErrorMsg {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want error %q", data, err.Error(), invalidUTF8ErrorMsg)
|
|
}
|
|
}
|
|
if !reflect.DeepEqual(v, want) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", data, v, v, want, want)
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalPrefilledArray(t *testing.T) {
|
|
prefilledArr := []int{1, 2, 3, 4, 5}
|
|
want := []int{10, 11, 3, 4, 5}
|
|
data := hexDecode("820a0b") // []int{10, 11}
|
|
if err := Unmarshal(data, &prefilledArr); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", data, err)
|
|
}
|
|
if len(prefilledArr) != 2 || cap(prefilledArr) != 5 {
|
|
t.Errorf("Unmarshal(0x%x) = %v (len %d, cap %d), want len == 2, cap == 5", data, prefilledArr, len(prefilledArr), cap(prefilledArr))
|
|
}
|
|
if !reflect.DeepEqual(prefilledArr[:cap(prefilledArr)], want) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", data, prefilledArr, prefilledArr, want, want)
|
|
}
|
|
|
|
data = hexDecode("80") // empty array
|
|
if err := Unmarshal(data, &prefilledArr); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", data, err)
|
|
}
|
|
if len(prefilledArr) != 0 || cap(prefilledArr) != 0 {
|
|
t.Errorf("Unmarshal(0x%x) = %v (len %d, cap %d), want len == 0, cap == 0", data, prefilledArr, len(prefilledArr), cap(prefilledArr))
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalPrefilledMap(t *testing.T) {
|
|
prefilledMap := map[string]string{"key": "value", "a": "1"}
|
|
want := map[string]string{"key": "value", "a": "A", "b": "B", "c": "C", "d": "D", "e": "E"}
|
|
data := hexDecode("a56161614161626142616361436164614461656145") // map[string]string{"a": "A", "b": "B", "c": "C", "d": "D", "e": "E"}
|
|
if err := Unmarshal(data, &prefilledMap); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", data, err)
|
|
}
|
|
if !reflect.DeepEqual(prefilledMap, want) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", data, prefilledMap, prefilledMap, want, want)
|
|
}
|
|
|
|
prefilledMap = map[string]string{"key": "value"}
|
|
want = map[string]string{"key": "value"}
|
|
data = hexDecode("a0") // map[string]string{}
|
|
if err := Unmarshal(data, &prefilledMap); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", data, err)
|
|
}
|
|
if !reflect.DeepEqual(prefilledMap, want) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", data, prefilledMap, prefilledMap, want, want)
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalPrefilledStruct(t *testing.T) {
|
|
type s struct {
|
|
a int
|
|
B []int
|
|
C bool
|
|
}
|
|
prefilledStruct := s{a: 100, B: []int{200, 300, 400, 500}, C: true}
|
|
want := s{a: 100, B: []int{2, 3}, C: true}
|
|
data := hexDecode("a26161016162820203") // map[string]interface{} {"a": 1, "b": []int{2, 3}}
|
|
if err := Unmarshal(data, &prefilledStruct); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", data, err)
|
|
}
|
|
if !reflect.DeepEqual(prefilledStruct, want) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", data, prefilledStruct, prefilledStruct, want, want)
|
|
}
|
|
if len(prefilledStruct.B) != 2 || cap(prefilledStruct.B) != 4 {
|
|
t.Errorf("Unmarshal(0x%x) = %v (len %d, cap %d), want len == 2, cap == 5", data, prefilledStruct.B, len(prefilledStruct.B), cap(prefilledStruct.B))
|
|
}
|
|
if !reflect.DeepEqual(prefilledStruct.B[:cap(prefilledStruct.B)], []int{2, 3, 400, 500}) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", data, prefilledStruct.B, prefilledStruct.B, []int{2, 3, 400, 500}, []int{2, 3, 400, 500})
|
|
}
|
|
}
|
|
|
|
func TestStructFieldNil(t *testing.T) {
|
|
type TestStruct struct {
|
|
I int
|
|
PI *int
|
|
PPI **int
|
|
}
|
|
var struc TestStruct
|
|
data, err := Marshal(struc)
|
|
if err != nil {
|
|
t.Fatalf("Marshal(%+v) returned error %v", struc, err)
|
|
}
|
|
var struc2 TestStruct
|
|
err = Unmarshal(data, &struc2)
|
|
if err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", data, err)
|
|
} else if !reflect.DeepEqual(struc, struc2) {
|
|
t.Errorf("Unmarshal(0x%x) returned %+v, want %+v", data, struc2, struc)
|
|
}
|
|
}
|
|
|
|
func TestLengthOverflowsInt(t *testing.T) {
|
|
// Data is generating by go-fuzz.
|
|
// string/slice/map length in uint64 cast to int causes integer overflow.
|
|
data := [][]byte{
|
|
hexDecode("bbcf30303030303030cfd697829782"),
|
|
hexDecode("5bcf30303030303030cfd697829782"),
|
|
}
|
|
wantErrorMsg := "is too large"
|
|
for _, data := range data {
|
|
var intf interface{}
|
|
if err := Unmarshal(data, &intf); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error, want error containing substring %q", data, wantErrorMsg)
|
|
} else if !strings.Contains(err.Error(), wantErrorMsg) {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want error containing substring %q", data, err.Error(), wantErrorMsg)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestMapKeyUnhashable(t *testing.T) {
|
|
testCases := []struct {
|
|
name string
|
|
data []byte
|
|
wantErrorMsg string
|
|
}{
|
|
{"slice as map key", hexDecode("bf8030ff"), "cbor: invalid map key type: []interface {}"}, // {[]: -17}
|
|
{"slice as map key", hexDecode("a1813030"), "cbor: invalid map key type: []interface {}"}, // {[-17]: -17}
|
|
{"slice as map key", hexDecode("bfd1a388f730303030303030303030303030ff"), "cbor: invalid map key type: []interface {}"}, // {17({[undefined, -17, -17, -17, -17, -17, -17, -17]: -17, -17: -17}): -17}}
|
|
{"map as map key", hexDecode("bf30a1a030ff"), "cbor: invalid map key type: map"}, // {-17: {{}: -17}}, empty map as map key
|
|
{"map as map key", hexDecode("bfb0303030303030303030303030303030303030303030303030303030303030303030ff"), "cbor: invalid map key type: map"}, // {{-17: -17}: -17}, map as key
|
|
{"big.Int as map key", hexDecode("a13bbd3030303030303030"), "cbor: invalid map key type: big.Int"}, // {-13632449055575519281: -17}
|
|
{"tagged big.Int as map key", hexDecode("a1c24901000000000000000030"), "cbor: invalid map key type: big.Int"}, // {18446744073709551616: -17}
|
|
{"tagged big.Int as map key", hexDecode("a1c34901000000000000000030"), "cbor: invalid map key type: big.Int"}, // {-18446744073709551617: -17}
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
var v interface{}
|
|
if err := Unmarshal(tc.data, &v); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error, want %q", tc.data, tc.wantErrorMsg)
|
|
} else if !strings.Contains(err.Error(), tc.wantErrorMsg) {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want %q", tc.data, err.Error(), tc.wantErrorMsg)
|
|
}
|
|
if _, ok := v.(map[interface{}]interface{}); ok {
|
|
var v map[interface{}]interface{}
|
|
if err := Unmarshal(tc.data, &v); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error, want %q", tc.data, tc.wantErrorMsg)
|
|
} else if !strings.Contains(err.Error(), tc.wantErrorMsg) {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want %q", tc.data, err.Error(), tc.wantErrorMsg)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestMapKeyNaN(t *testing.T) {
|
|
// Data is generating by go-fuzz.
|
|
data := hexDecode("b0303030303030303030303030303030303038303030faffff30303030303030303030303030") // {-17: -17, NaN: -17}
|
|
var intf interface{}
|
|
if err := Unmarshal(data, &intf); err != nil {
|
|
t.Fatalf("Unmarshal(0x%x) returned error %v", data, err)
|
|
}
|
|
em, err := EncOptions{Sort: SortCanonical}.EncMode()
|
|
if err != nil {
|
|
t.Errorf("EncMode() returned an error %v", err)
|
|
}
|
|
if _, err := em.Marshal(intf); err != nil {
|
|
t.Errorf("Marshal(%v) returned error %v", intf, err)
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalUndefinedElement(t *testing.T) {
|
|
// Data is generating by go-fuzz.
|
|
data := hexDecode("bfd1a388f730303030303030303030303030ff") // {17({[undefined, -17, -17, -17, -17, -17, -17, -17]: -17, -17: -17}): -17}
|
|
var intf interface{}
|
|
wantErrorMsg := "invalid map key type"
|
|
if err := Unmarshal(data, &intf); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error, want error containing substring %q", data, wantErrorMsg)
|
|
} else if !strings.Contains(err.Error(), wantErrorMsg) {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want error containing substring %q", data, err.Error(), wantErrorMsg)
|
|
}
|
|
}
|
|
|
|
func TestMapKeyNil(t *testing.T) {
|
|
testData := [][]byte{
|
|
hexDecode("a1f630"), // {null: -17}
|
|
}
|
|
want := map[interface{}]interface{}{nil: int64(-17)}
|
|
for _, data := range testData {
|
|
var intf interface{}
|
|
if err := Unmarshal(data, &intf); err != nil {
|
|
t.Fatalf("Unmarshal(0x%x) returned error %v", data, err)
|
|
} else if !reflect.DeepEqual(intf, want) {
|
|
t.Errorf("Unmarshal(0x%x) returned %+v, want %+v", data, intf, want)
|
|
}
|
|
if _, err := Marshal(intf); err != nil {
|
|
t.Errorf("Marshal(%v) returned error %v", intf, err)
|
|
}
|
|
|
|
var v map[interface{}]interface{}
|
|
if err := Unmarshal(data, &v); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", data, err)
|
|
} else if !reflect.DeepEqual(v, want) {
|
|
t.Errorf("Unmarshal(0x%x) returned %+v, want %+v", data, v, want)
|
|
}
|
|
if _, err := Marshal(v); err != nil {
|
|
t.Errorf("Marshal(%v) returned error %v", v, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestDecodeTime(t *testing.T) {
|
|
unmodified := time.Now()
|
|
|
|
testCases := []struct {
|
|
name string
|
|
cborRFC3339Time []byte
|
|
cborUnixTime []byte
|
|
wantTime time.Time
|
|
}{
|
|
// Decoding untagged CBOR null/defined to time.Time is no-op. See TestUnmarshalNil.
|
|
{
|
|
name: "null within unrecognized tag", // no-op in DecTagIgnored
|
|
cborRFC3339Time: hexDecode("dadeadbeeff6"),
|
|
cborUnixTime: hexDecode("dadeadbeeff6"),
|
|
wantTime: unmodified,
|
|
},
|
|
{
|
|
name: "undefined within unrecognized tag", // no-op in DecTagIgnored
|
|
cborRFC3339Time: hexDecode("dadeadbeeff7"),
|
|
cborUnixTime: hexDecode("dadeadbeeff7"),
|
|
wantTime: unmodified,
|
|
},
|
|
{
|
|
name: "NaN",
|
|
cborRFC3339Time: hexDecode("f97e00"),
|
|
cborUnixTime: hexDecode("f97e00"),
|
|
wantTime: time.Time{},
|
|
},
|
|
{
|
|
name: "positive infinity",
|
|
cborRFC3339Time: hexDecode("f97c00"),
|
|
cborUnixTime: hexDecode("f97c00"),
|
|
wantTime: time.Time{},
|
|
},
|
|
{
|
|
name: "negative infinity",
|
|
cborRFC3339Time: hexDecode("f9fc00"),
|
|
cborUnixTime: hexDecode("f9fc00"),
|
|
wantTime: time.Time{},
|
|
},
|
|
{
|
|
name: "time without fractional seconds", // positive integer
|
|
cborRFC3339Time: hexDecode("74323031332d30332d32315432303a30343a30305a"),
|
|
cborUnixTime: hexDecode("1a514b67b0"),
|
|
wantTime: parseTime(time.RFC3339Nano, "2013-03-21T20:04:00Z"),
|
|
},
|
|
{
|
|
name: "time with fractional seconds", // float
|
|
cborRFC3339Time: hexDecode("7819313937302d30312d30315432313a34363a34302d30363a3030"),
|
|
cborUnixTime: hexDecode("fa47c35000"),
|
|
wantTime: parseTime(time.RFC3339Nano, "1970-01-01T21:46:40-06:00"),
|
|
},
|
|
{
|
|
name: "time with fractional seconds", // float
|
|
cborRFC3339Time: hexDecode("76323031332d30332d32315432303a30343a30302e355a"),
|
|
cborUnixTime: hexDecode("fb41d452d9ec200000"),
|
|
wantTime: parseTime(time.RFC3339Nano, "2013-03-21T20:04:00.5Z"),
|
|
},
|
|
{
|
|
name: "time before January 1, 1970 UTC without fractional seconds", // negative integer
|
|
cborRFC3339Time: hexDecode("74313936392d30332d32315432303a30343a30305a"),
|
|
cborUnixTime: hexDecode("3a0177f2cf"),
|
|
wantTime: parseTime(time.RFC3339Nano, "1969-03-21T20:04:00Z"),
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
tm := unmodified
|
|
if err := Unmarshal(tc.cborRFC3339Time, &tm); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", tc.cborRFC3339Time, err)
|
|
} else if !tc.wantTime.Equal(tm) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", tc.cborRFC3339Time, tm, tm, tc.wantTime, tc.wantTime)
|
|
}
|
|
tm = unmodified
|
|
if err := Unmarshal(tc.cborUnixTime, &tm); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", tc.cborUnixTime, err)
|
|
} else if !tc.wantTime.Equal(tm) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", tc.cborUnixTime, tm, tm, tc.wantTime, tc.wantTime)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDecodeTimeWithTag(t *testing.T) {
|
|
testCases := []struct {
|
|
name string
|
|
cborRFC3339Time []byte
|
|
cborUnixTime []byte
|
|
wantTime time.Time
|
|
}{
|
|
{
|
|
name: "time without fractional seconds", // positive integer
|
|
cborRFC3339Time: hexDecode("c074323031332d30332d32315432303a30343a30305a"),
|
|
cborUnixTime: hexDecode("c11a514b67b0"),
|
|
wantTime: parseTime(time.RFC3339Nano, "2013-03-21T20:04:00Z"),
|
|
},
|
|
{
|
|
name: "time with fractional seconds", // float
|
|
cborRFC3339Time: hexDecode("c076323031332d30332d32315432303a30343a30302e355a"),
|
|
cborUnixTime: hexDecode("c1fb41d452d9ec200000"),
|
|
wantTime: parseTime(time.RFC3339Nano, "2013-03-21T20:04:00.5Z"),
|
|
},
|
|
{
|
|
name: "time before January 1, 1970 UTC without fractional seconds", // negative integer
|
|
cborRFC3339Time: hexDecode("c074313936392d30332d32315432303a30343a30305a"),
|
|
cborUnixTime: hexDecode("c13a0177f2cf"),
|
|
wantTime: parseTime(time.RFC3339Nano, "1969-03-21T20:04:00Z"),
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
tm := time.Now()
|
|
if err := Unmarshal(tc.cborRFC3339Time, &tm); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", tc.cborRFC3339Time, err)
|
|
} else if !tc.wantTime.Equal(tm) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", tc.cborRFC3339Time, tm, tm, tc.wantTime, tc.wantTime)
|
|
}
|
|
tm = time.Now()
|
|
if err := Unmarshal(tc.cborUnixTime, &tm); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", tc.cborUnixTime, err)
|
|
} else if !tc.wantTime.Equal(tm) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", tc.cborUnixTime, tm, tm, tc.wantTime, tc.wantTime)
|
|
}
|
|
|
|
var v interface{}
|
|
if err := Unmarshal(tc.cborRFC3339Time, &v); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", tc.cborRFC3339Time, err)
|
|
} else if tm, ok := v.(time.Time); !ok || !tc.wantTime.Equal(tm) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", tc.cborRFC3339Time, v, v, tc.wantTime, tc.wantTime)
|
|
}
|
|
v = nil
|
|
if err := Unmarshal(tc.cborUnixTime, &v); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", tc.cborUnixTime, err)
|
|
} else if tm, ok := v.(time.Time); !ok || !tc.wantTime.Equal(tm) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", tc.cborUnixTime, v, v, tc.wantTime, tc.wantTime)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDecodeTimeError(t *testing.T) {
|
|
testCases := []struct {
|
|
name string
|
|
opts DecOptions
|
|
data []byte
|
|
wantErrorMsg string
|
|
}{
|
|
{
|
|
name: "invalid RFC3339 time string",
|
|
data: hexDecode("7f657374726561646d696e67ff"),
|
|
wantErrorMsg: "cbor: cannot set streaming for time.Time",
|
|
},
|
|
{
|
|
name: "byte string data cannot be decoded into time.Time",
|
|
data: hexDecode("4f013030303030303030e03031ed3030"),
|
|
wantErrorMsg: "cbor: cannot unmarshal byte string into Go value of type time.Time",
|
|
},
|
|
{
|
|
name: "bool cannot be decoded into time.Time",
|
|
data: hexDecode("f4"),
|
|
wantErrorMsg: "cbor: cannot unmarshal primitives into Go value of type time.Time",
|
|
},
|
|
{
|
|
name: "invalid UTF-8 string",
|
|
data: hexDecode("7f62e6b061b4ff"),
|
|
wantErrorMsg: "cbor: invalid UTF-8 string",
|
|
},
|
|
{
|
|
name: "negative integer overflow",
|
|
data: hexDecode("3bffffffffffffffff"),
|
|
wantErrorMsg: "cbor: cannot unmarshal negative integer into Go value of type time.Time",
|
|
},
|
|
{
|
|
name: "untagged byte string content cannot be decoded into time.Time with DefaultByteStringType string",
|
|
opts: DecOptions{
|
|
TimeTag: DecTagOptional,
|
|
DefaultByteStringType: reflect.TypeOf(""),
|
|
},
|
|
data: hexDecode("54323031332d30332d32315432303a30343a30305a"),
|
|
wantErrorMsg: "cbor: cannot unmarshal byte string into Go value of type time.Time",
|
|
},
|
|
{
|
|
name: "time tag is validated when enclosed in unrecognized tag",
|
|
data: hexDecode("dadeadbeefc001"),
|
|
wantErrorMsg: "cbor: tag number 0 must be followed by text string, got positive integer",
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
dm, err := tc.opts.DecMode()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
tm := time.Now()
|
|
if err := dm.Unmarshal(tc.data, &tm); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error, want error msg %q", tc.data, tc.wantErrorMsg)
|
|
} else if !strings.Contains(err.Error(), tc.wantErrorMsg) {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want %q", tc.data, err.Error(), tc.wantErrorMsg)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDecodeInvalidTagTime(t *testing.T) {
|
|
typeTimeSlice := reflect.TypeOf([]time.Time{})
|
|
|
|
testCases := []struct {
|
|
name string
|
|
data []byte
|
|
decodeToTypes []reflect.Type
|
|
wantErrorMsg string
|
|
}{
|
|
{
|
|
name: "Tag 0 with invalid RFC3339 time string",
|
|
data: hexDecode("c07f657374726561646d696e67ff"),
|
|
decodeToTypes: []reflect.Type{typeIntf, typeTime},
|
|
wantErrorMsg: "cbor: cannot set streaming for time.Time",
|
|
},
|
|
{
|
|
name: "Tag 0 with invalid UTF-8 string",
|
|
data: hexDecode("c07f62e6b061b4ff"),
|
|
decodeToTypes: []reflect.Type{typeIntf, typeTime},
|
|
wantErrorMsg: "cbor: invalid UTF-8 string",
|
|
},
|
|
{
|
|
name: "Tag 0 with integer content",
|
|
data: hexDecode("c01a514b67b0"),
|
|
decodeToTypes: []reflect.Type{typeIntf, typeTime},
|
|
wantErrorMsg: "cbor: tag number 0 must be followed by text string, got positive integer",
|
|
},
|
|
{
|
|
name: "Tag 0 with byte string content",
|
|
data: hexDecode("c04f013030303030303030e03031ed3030"),
|
|
decodeToTypes: []reflect.Type{typeIntf, typeTime},
|
|
wantErrorMsg: "cbor: tag number 0 must be followed by text string, got byte string",
|
|
},
|
|
{
|
|
name: "Tag 0 with integer content as array element",
|
|
data: hexDecode("81c01a514b67b0"),
|
|
decodeToTypes: []reflect.Type{typeIntf, typeTimeSlice},
|
|
wantErrorMsg: "cbor: tag number 0 must be followed by text string, got positive integer",
|
|
},
|
|
{
|
|
name: "Tag 1 with negative integer overflow",
|
|
data: hexDecode("c13bffffffffffffffff"),
|
|
decodeToTypes: []reflect.Type{typeIntf, typeTime},
|
|
wantErrorMsg: "cbor: cannot unmarshal negative integer into Go value of type time.Time (-18446744073709551616 overflows Go's int64)",
|
|
},
|
|
{
|
|
name: "Tag 1 with string content",
|
|
data: hexDecode("c174323031332d30332d32315432303a30343a30305a"),
|
|
decodeToTypes: []reflect.Type{typeIntf, typeTime},
|
|
wantErrorMsg: "cbor: tag number 1 must be followed by integer or floating-point number, got UTF-8 text string",
|
|
},
|
|
{
|
|
name: "Tag 1 with simple value",
|
|
data: hexDecode("d801f6"), // 1(null)
|
|
decodeToTypes: []reflect.Type{typeIntf, typeTime},
|
|
wantErrorMsg: "cbor: tag number 1 must be followed by integer or floating-point number, got primitive",
|
|
},
|
|
{
|
|
name: "Tag 1 with string content as array element",
|
|
data: hexDecode("81c174323031332d30332d32315432303a30343a30305a"),
|
|
decodeToTypes: []reflect.Type{typeIntf, typeTimeSlice},
|
|
wantErrorMsg: "cbor: tag number 1 must be followed by integer or floating-point number, got UTF-8 text string",
|
|
},
|
|
}
|
|
dm, _ := DecOptions{TimeTag: DecTagOptional}.DecMode()
|
|
for _, tc := range testCases {
|
|
for _, decodeToType := range tc.decodeToTypes {
|
|
t.Run(tc.name+" decode to "+decodeToType.String(), func(t *testing.T) {
|
|
v := reflect.New(decodeToType)
|
|
if err := dm.Unmarshal(tc.data, v.Interface()); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return error, want error msg %q", tc.data, tc.wantErrorMsg)
|
|
} else if !strings.Contains(err.Error(), tc.wantErrorMsg) {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want %q", tc.data, err, tc.wantErrorMsg)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestDecodeTag0Error(t *testing.T) {
|
|
data := hexDecode("c01a514b67b0") // 0(1363896240)
|
|
wantErrorMsg := "cbor: tag number 0 must be followed by text string, got positive integer"
|
|
|
|
timeTagIgnoredDM, _ := DecOptions{TimeTag: DecTagIgnored}.DecMode()
|
|
timeTagOptionalDM, _ := DecOptions{TimeTag: DecTagOptional}.DecMode()
|
|
timeTagRequiredDM, _ := DecOptions{TimeTag: DecTagRequired}.DecMode()
|
|
|
|
testCases := []struct {
|
|
name string
|
|
dm DecMode
|
|
}{
|
|
{name: "DecTagIgnored", dm: timeTagIgnoredDM},
|
|
{name: "DecTagOptional", dm: timeTagOptionalDM},
|
|
{name: "DecTagRequired", dm: timeTagRequiredDM},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
// Decode to interface{}
|
|
var v interface{}
|
|
if err := tc.dm.Unmarshal(data, &v); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return error, want error msg %q", data, wantErrorMsg)
|
|
} else if !strings.Contains(err.Error(), wantErrorMsg) {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want %q", data, err, wantErrorMsg)
|
|
}
|
|
|
|
// Decode to time.Time
|
|
var tm time.Time
|
|
if err := tc.dm.Unmarshal(data, &tm); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return error, want error msg %q", data, wantErrorMsg)
|
|
} else if !strings.Contains(err.Error(), wantErrorMsg) {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want %q", data, err, wantErrorMsg)
|
|
}
|
|
|
|
// Decode to uint64
|
|
var ui uint64
|
|
if err := tc.dm.Unmarshal(data, &ui); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return error, want error msg %q", data, wantErrorMsg)
|
|
} else if !strings.Contains(err.Error(), wantErrorMsg) {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want %q", data, err, wantErrorMsg)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDecodeTag1Error(t *testing.T) {
|
|
data := hexDecode("c174323031332d30332d32315432303a30343a30305a") // 1("2013-03-21T20:04:00Z")
|
|
wantErrorMsg := "cbor: tag number 1 must be followed by integer or floating-point number, got UTF-8 text string"
|
|
|
|
timeTagIgnoredDM, _ := DecOptions{TimeTag: DecTagIgnored}.DecMode()
|
|
timeTagOptionalDM, _ := DecOptions{TimeTag: DecTagOptional}.DecMode()
|
|
timeTagRequiredDM, _ := DecOptions{TimeTag: DecTagRequired}.DecMode()
|
|
|
|
testCases := []struct {
|
|
name string
|
|
dm DecMode
|
|
}{
|
|
{name: "DecTagIgnored", dm: timeTagIgnoredDM},
|
|
{name: "DecTagOptional", dm: timeTagOptionalDM},
|
|
{name: "DecTagRequired", dm: timeTagRequiredDM},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
// Decode to interface{}
|
|
var v interface{}
|
|
if err := tc.dm.Unmarshal(data, &v); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return error, want error msg %q", data, wantErrorMsg)
|
|
} else if !strings.Contains(err.Error(), wantErrorMsg) {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want %q", data, err, wantErrorMsg)
|
|
}
|
|
|
|
// Decode to time.Time
|
|
var tm time.Time
|
|
if err := tc.dm.Unmarshal(data, &tm); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return error, want error msg %q", data, wantErrorMsg)
|
|
} else if !strings.Contains(err.Error(), wantErrorMsg) {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want %q", data, err, wantErrorMsg)
|
|
}
|
|
|
|
// Decode to string
|
|
var s string
|
|
if err := tc.dm.Unmarshal(data, &s); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return error, want error msg %q", data, wantErrorMsg)
|
|
} else if !strings.Contains(err.Error(), wantErrorMsg) {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want %q", data, err, wantErrorMsg)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDecodeTimeStreaming(t *testing.T) {
|
|
// Decoder decodes from mixed invalid and valid time.
|
|
testCases := []struct {
|
|
data []byte
|
|
wantErrorMsg string
|
|
wantObj time.Time
|
|
}{
|
|
{
|
|
data: hexDecode("c07f62e6b061b4ff"),
|
|
wantErrorMsg: "cbor: invalid UTF-8 string",
|
|
},
|
|
{
|
|
data: hexDecode("c074323031332d30332d32315432303a30343a30305a"),
|
|
wantObj: time.Date(2013, 3, 21, 20, 4, 0, 0, time.UTC),
|
|
},
|
|
{
|
|
data: hexDecode("c01a514b67b0"),
|
|
wantErrorMsg: "cbor: tag number 0 must be followed by text string, got positive integer",
|
|
},
|
|
{
|
|
data: hexDecode("c074323031332d30332d32315432303a30343a30305a"),
|
|
wantObj: time.Date(2013, 3, 21, 20, 4, 0, 0, time.UTC),
|
|
},
|
|
{
|
|
data: hexDecode("c13bffffffffffffffff"),
|
|
wantErrorMsg: "cbor: cannot unmarshal negative integer into Go value of type time.Time (-18446744073709551616 overflows Go's int64)",
|
|
},
|
|
{
|
|
data: hexDecode("c11a514b67b0"),
|
|
wantObj: time.Date(2013, 3, 21, 20, 4, 0, 0, time.UTC),
|
|
},
|
|
{
|
|
data: hexDecode("c174323031332d30332d32315432303a30343a30305a"),
|
|
wantErrorMsg: "tag number 1 must be followed by integer or floating-point number, got UTF-8 text string",
|
|
},
|
|
{
|
|
data: hexDecode("c11a514b67b0"),
|
|
wantObj: time.Date(2013, 3, 21, 20, 4, 0, 0, time.UTC),
|
|
},
|
|
}
|
|
// Data is a mixed stream of valid and invalid time data
|
|
var data []byte
|
|
for _, tc := range testCases {
|
|
data = append(data, tc.data...)
|
|
}
|
|
dm, _ := DecOptions{TimeTag: DecTagOptional}.DecMode()
|
|
dec := dm.NewDecoder(bytes.NewReader(data))
|
|
for _, tc := range testCases {
|
|
var v interface{}
|
|
err := dec.Decode(&v)
|
|
if tc.wantErrorMsg != "" {
|
|
if err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return error, want error msg %q", tc.data, tc.wantErrorMsg)
|
|
} else if !strings.Contains(err.Error(), tc.wantErrorMsg) {
|
|
t.Errorf("Unmarshal(0x%x) returned error msg %q, want %q", tc.data, err, tc.wantErrorMsg)
|
|
}
|
|
} else {
|
|
tm, ok := v.(time.Time)
|
|
if !ok {
|
|
t.Errorf("Unmarshal(0x%x) returned %s (%T), want time.Time", tc.data, v, v)
|
|
}
|
|
if !tc.wantObj.Equal(tm) {
|
|
t.Errorf("Unmarshal(0x%x) returned %s, want %s", tc.data, tm, tc.wantObj)
|
|
}
|
|
}
|
|
}
|
|
dec = dm.NewDecoder(bytes.NewReader(data))
|
|
for _, tc := range testCases {
|
|
var tm time.Time
|
|
err := dec.Decode(&tm)
|
|
if tc.wantErrorMsg != "" {
|
|
if err == nil {
|
|
t.Errorf("Unmarshal(0x%x) did't return error, want error msg %q", tc.data, tc.wantErrorMsg)
|
|
} else if !strings.Contains(err.Error(), tc.wantErrorMsg) {
|
|
t.Errorf("Unmarshal(0x%x) returned error msg %q, want %q", tc.data, err, tc.wantErrorMsg)
|
|
}
|
|
} else {
|
|
if !tc.wantObj.Equal(tm) {
|
|
t.Errorf("Unmarshal(0x%x) returned %s, want %s", tc.data, tm, tc.wantObj)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestDecTimeTagOption(t *testing.T) {
|
|
timeTagIgnoredDecMode, _ := DecOptions{TimeTag: DecTagIgnored}.DecMode()
|
|
timeTagOptionalDecMode, _ := DecOptions{TimeTag: DecTagOptional}.DecMode()
|
|
timeTagRequiredDecMode, _ := DecOptions{TimeTag: DecTagRequired}.DecMode()
|
|
|
|
testCases := []struct {
|
|
name string
|
|
cborRFC3339Time []byte
|
|
cborUnixTime []byte
|
|
decMode DecMode
|
|
wantTime time.Time
|
|
wantErrorMsg string
|
|
}{
|
|
// not-tagged time CBOR data
|
|
{
|
|
name: "not-tagged data with DecTagIgnored option",
|
|
cborRFC3339Time: hexDecode("74323031332d30332d32315432303a30343a30305a"),
|
|
cborUnixTime: hexDecode("1a514b67b0"),
|
|
decMode: timeTagIgnoredDecMode,
|
|
wantTime: parseTime(time.RFC3339Nano, "2013-03-21T20:04:00Z"),
|
|
},
|
|
{
|
|
name: "not-tagged data with timeTagOptionalDecMode option",
|
|
cborRFC3339Time: hexDecode("74323031332d30332d32315432303a30343a30305a"),
|
|
cborUnixTime: hexDecode("1a514b67b0"),
|
|
decMode: timeTagOptionalDecMode,
|
|
wantTime: parseTime(time.RFC3339Nano, "2013-03-21T20:04:00Z"),
|
|
},
|
|
{
|
|
name: "not-tagged data with timeTagRequiredDecMode option",
|
|
cborRFC3339Time: hexDecode("74323031332d30332d32315432303a30343a30305a"),
|
|
cborUnixTime: hexDecode("1a514b67b0"),
|
|
decMode: timeTagRequiredDecMode,
|
|
wantErrorMsg: "expect CBOR tag value",
|
|
},
|
|
// tagged time CBOR data
|
|
{
|
|
name: "tagged data with timeTagIgnoredDecMode option",
|
|
cborRFC3339Time: hexDecode("c074323031332d30332d32315432303a30343a30305a"),
|
|
cborUnixTime: hexDecode("c11a514b67b0"),
|
|
decMode: timeTagIgnoredDecMode,
|
|
wantTime: parseTime(time.RFC3339Nano, "2013-03-21T20:04:00Z"),
|
|
},
|
|
{
|
|
name: "tagged data with timeTagOptionalDecMode option",
|
|
cborRFC3339Time: hexDecode("c074323031332d30332d32315432303a30343a30305a"),
|
|
cborUnixTime: hexDecode("c11a514b67b0"),
|
|
decMode: timeTagOptionalDecMode,
|
|
wantTime: parseTime(time.RFC3339Nano, "2013-03-21T20:04:00Z"),
|
|
},
|
|
{
|
|
name: "tagged data with timeTagRequiredDecMode option",
|
|
cborRFC3339Time: hexDecode("c074323031332d30332d32315432303a30343a30305a"),
|
|
cborUnixTime: hexDecode("c11a514b67b0"),
|
|
decMode: timeTagRequiredDecMode,
|
|
wantTime: parseTime(time.RFC3339Nano, "2013-03-21T20:04:00Z"),
|
|
},
|
|
// mis-tagged time CBOR data
|
|
{
|
|
name: "mis-tagged data with timeTagIgnoredDecMode option",
|
|
cborRFC3339Time: hexDecode("c8c974323031332d30332d32315432303a30343a30305a"),
|
|
cborUnixTime: hexDecode("c8c91a514b67b0"),
|
|
decMode: timeTagIgnoredDecMode,
|
|
wantTime: parseTime(time.RFC3339Nano, "2013-03-21T20:04:00Z"),
|
|
},
|
|
{
|
|
name: "mis-tagged data with timeTagOptionalDecMode option",
|
|
cborRFC3339Time: hexDecode("c8c974323031332d30332d32315432303a30343a30305a"),
|
|
cborUnixTime: hexDecode("c8c91a514b67b0"),
|
|
decMode: timeTagOptionalDecMode,
|
|
wantErrorMsg: "cbor: wrong tag number for time.Time, got 8, expect 0 or 1",
|
|
},
|
|
{
|
|
name: "mis-tagged data with timeTagRequiredDecMode option",
|
|
cborRFC3339Time: hexDecode("c8c974323031332d30332d32315432303a30343a30305a"),
|
|
cborUnixTime: hexDecode("c8c91a514b67b0"),
|
|
decMode: timeTagRequiredDecMode,
|
|
wantErrorMsg: "cbor: wrong tag number for time.Time, got 8, expect 0 or 1",
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
tm := time.Now()
|
|
err := tc.decMode.Unmarshal(tc.cborRFC3339Time, &tm)
|
|
if tc.wantErrorMsg != "" {
|
|
if err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return error", tc.cborRFC3339Time)
|
|
} else if !strings.Contains(err.Error(), tc.wantErrorMsg) {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want error containing %q", tc.cborRFC3339Time, err.Error(), tc.wantErrorMsg)
|
|
}
|
|
} else {
|
|
if !tc.wantTime.Equal(tm) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", tc.cborRFC3339Time, tm, tm, tc.wantTime, tc.wantTime)
|
|
}
|
|
}
|
|
|
|
tm = time.Now()
|
|
err = tc.decMode.Unmarshal(tc.cborUnixTime, &tm)
|
|
if tc.wantErrorMsg != "" {
|
|
if err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return error", tc.cborRFC3339Time)
|
|
} else if !strings.Contains(err.Error(), tc.wantErrorMsg) {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want error containing %q", tc.cborRFC3339Time, err.Error(), tc.wantErrorMsg)
|
|
}
|
|
} else {
|
|
if !tc.wantTime.Equal(tm) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", tc.cborRFC3339Time, tm, tm, tc.wantTime, tc.wantTime)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalStructTag1(t *testing.T) {
|
|
type strc struct {
|
|
A string `cbor:"a"`
|
|
B string `cbor:"b"`
|
|
C string `cbor:"c"`
|
|
}
|
|
want := strc{
|
|
A: "A",
|
|
B: "B",
|
|
C: "C",
|
|
}
|
|
data := hexDecode("a3616161416162614261636143") // {"a":"A", "b":"B", "c":"C"}
|
|
|
|
var v strc
|
|
if err := Unmarshal(data, &v); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", data, err)
|
|
}
|
|
if !reflect.DeepEqual(v, want) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", data, v, v, want, want)
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalStructTag2(t *testing.T) {
|
|
type strc struct {
|
|
A string `json:"a"`
|
|
B string `json:"b"`
|
|
C string `json:"c"`
|
|
}
|
|
want := strc{
|
|
A: "A",
|
|
B: "B",
|
|
C: "C",
|
|
}
|
|
data := hexDecode("a3616161416162614261636143") // {"a":"A", "b":"B", "c":"C"}
|
|
|
|
var v strc
|
|
if err := Unmarshal(data, &v); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", data, err)
|
|
}
|
|
if !reflect.DeepEqual(v, want) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", data, v, v, want, want)
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalStructTag3(t *testing.T) {
|
|
type strc struct {
|
|
A string `json:"x" cbor:"a"`
|
|
B string `json:"y" cbor:"b"`
|
|
C string `json:"z"`
|
|
}
|
|
want := strc{
|
|
A: "A",
|
|
B: "B",
|
|
C: "C",
|
|
}
|
|
data := hexDecode("a36161614161626142617a6143") // {"a":"A", "b":"B", "z":"C"}
|
|
|
|
var v strc
|
|
if err := Unmarshal(data, &v); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", data, err)
|
|
}
|
|
if !reflect.DeepEqual(v, want) {
|
|
t.Errorf("Unmarshal(0x%x) = %+v (%T), want %+v (%T)", data, v, v, want, want)
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalStructTag4(t *testing.T) {
|
|
type strc struct {
|
|
A string `json:"x" cbor:"a"`
|
|
B string `json:"y" cbor:"b"`
|
|
C string `json:"-"`
|
|
}
|
|
want := strc{
|
|
A: "A",
|
|
B: "B",
|
|
}
|
|
data := hexDecode("a3616161416162614261636143") // {"a":"A", "b":"B", "c":"C"}
|
|
|
|
var v strc
|
|
if err := Unmarshal(data, &v); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", data, err)
|
|
}
|
|
if !reflect.DeepEqual(v, want) {
|
|
t.Errorf("Unmarshal(0x%x) = %+v (%T), want %+v (%T)", data, v, v, want, want)
|
|
}
|
|
}
|
|
|
|
type number uint64
|
|
|
|
func (n number) MarshalBinary() (data []byte, err error) {
|
|
if n == 0 {
|
|
return []byte{}, nil
|
|
}
|
|
data = make([]byte, 8)
|
|
binary.BigEndian.PutUint64(data, uint64(n))
|
|
return
|
|
}
|
|
|
|
func (n *number) UnmarshalBinary(data []byte) (err error) {
|
|
if len(data) == 0 {
|
|
*n = 0
|
|
return nil
|
|
}
|
|
if len(data) != 8 {
|
|
return errors.New("number:UnmarshalBinary: invalid length")
|
|
}
|
|
*n = number(binary.BigEndian.Uint64(data))
|
|
return
|
|
}
|
|
|
|
type stru struct {
|
|
a, b, c string
|
|
}
|
|
|
|
func (s *stru) MarshalBinary() ([]byte, error) {
|
|
if s.a == "" && s.b == "" && s.c == "" {
|
|
return []byte{}, nil
|
|
}
|
|
return []byte(fmt.Sprintf("%s,%s,%s", s.a, s.b, s.c)), nil
|
|
}
|
|
|
|
func (s *stru) UnmarshalBinary(data []byte) (err error) {
|
|
if len(data) == 0 {
|
|
s.a, s.b, s.c = "", "", ""
|
|
return nil
|
|
}
|
|
ss := strings.Split(string(data), ",")
|
|
if len(ss) != 3 {
|
|
return errors.New("stru:UnmarshalBinary: invalid element count")
|
|
}
|
|
s.a, s.b, s.c = ss[0], ss[1], ss[2]
|
|
return
|
|
}
|
|
|
|
type marshalBinaryError string
|
|
|
|
func (n marshalBinaryError) MarshalBinary() (data []byte, err error) {
|
|
return nil, errors.New(string(n))
|
|
}
|
|
|
|
func TestBinaryMarshalerUnmarshaler(t *testing.T) {
|
|
testCases := []roundTripTest{
|
|
{
|
|
name: "primitive obj",
|
|
obj: number(1234567890),
|
|
wantCborData: hexDecode("4800000000499602d2"),
|
|
},
|
|
{
|
|
name: "struct obj",
|
|
obj: stru{a: "a", b: "b", c: "c"},
|
|
wantCborData: hexDecode("45612C622C63"),
|
|
},
|
|
}
|
|
em, _ := EncOptions{}.EncMode()
|
|
dm, _ := DecOptions{}.DecMode()
|
|
testRoundTrip(t, testCases, em, dm)
|
|
}
|
|
|
|
func TestBinaryUnmarshalerError(t *testing.T) { //nolint:dupl
|
|
testCases := []struct {
|
|
name string
|
|
typ reflect.Type
|
|
data []byte
|
|
wantErrorMsg string
|
|
}{
|
|
{
|
|
name: "primitive type",
|
|
typ: reflect.TypeOf(number(0)),
|
|
data: hexDecode("44499602d2"),
|
|
wantErrorMsg: "number:UnmarshalBinary: invalid length",
|
|
},
|
|
{
|
|
name: "struct type",
|
|
typ: reflect.TypeOf(stru{}),
|
|
data: hexDecode("47612C622C632C64"),
|
|
wantErrorMsg: "stru:UnmarshalBinary: invalid element count",
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
v := reflect.New(tc.typ)
|
|
if err := Unmarshal(tc.data, v.Interface()); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error, want error msg %q", tc.data, tc.wantErrorMsg)
|
|
} else if err.Error() != tc.wantErrorMsg {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want %q", tc.data, err.Error(), tc.wantErrorMsg)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestBinaryMarshalerError(t *testing.T) {
|
|
wantErrorMsg := "MarshalBinary: error"
|
|
v := marshalBinaryError(wantErrorMsg)
|
|
if _, err := Marshal(v); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error, want error msg %q", v, wantErrorMsg)
|
|
} else if err.Error() != wantErrorMsg {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want %q", v, err.Error(), wantErrorMsg)
|
|
}
|
|
}
|
|
|
|
type number2 uint64
|
|
|
|
func (n number2) MarshalCBOR() (data []byte, err error) {
|
|
m := map[string]uint64{"num": uint64(n)}
|
|
return Marshal(m)
|
|
}
|
|
|
|
func (n *number2) UnmarshalCBOR(data []byte) (err error) {
|
|
var v map[string]uint64
|
|
if err := Unmarshal(data, &v); err != nil {
|
|
return err
|
|
}
|
|
*n = number2(v["num"])
|
|
return nil
|
|
}
|
|
|
|
type stru2 struct {
|
|
a, b, c string
|
|
}
|
|
|
|
func (s *stru2) MarshalCBOR() ([]byte, error) {
|
|
v := []string{s.a, s.b, s.c}
|
|
return Marshal(v)
|
|
}
|
|
|
|
func (s *stru2) UnmarshalCBOR(data []byte) (err error) {
|
|
var v []string
|
|
if err := Unmarshal(data, &v); err != nil {
|
|
return err
|
|
}
|
|
if len(v) > 0 {
|
|
s.a = v[0]
|
|
}
|
|
if len(v) > 1 {
|
|
s.b = v[1]
|
|
}
|
|
if len(v) > 2 {
|
|
s.c = v[2]
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type marshalCBORError string
|
|
|
|
func (n marshalCBORError) MarshalCBOR() (data []byte, err error) {
|
|
return nil, errors.New(string(n))
|
|
}
|
|
|
|
func TestMarshalerUnmarshaler(t *testing.T) {
|
|
testCases := []roundTripTest{
|
|
{
|
|
name: "primitive obj",
|
|
obj: number2(1),
|
|
wantCborData: hexDecode("a1636e756d01"),
|
|
},
|
|
{
|
|
name: "struct obj",
|
|
obj: stru2{a: "a", b: "b", c: "c"},
|
|
wantCborData: hexDecode("83616161626163"),
|
|
},
|
|
}
|
|
em, _ := EncOptions{}.EncMode()
|
|
dm, _ := DecOptions{}.DecMode()
|
|
testRoundTrip(t, testCases, em, dm)
|
|
}
|
|
|
|
func TestUnmarshalerError(t *testing.T) { //nolint:dupl
|
|
testCases := []struct {
|
|
name string
|
|
typ reflect.Type
|
|
data []byte
|
|
wantErrorMsg string
|
|
}{
|
|
{
|
|
name: "primitive type",
|
|
typ: reflect.TypeOf(number2(0)),
|
|
data: hexDecode("44499602d2"),
|
|
wantErrorMsg: "cbor: cannot unmarshal byte string into Go value of type map[string]uint64",
|
|
},
|
|
{
|
|
name: "struct type",
|
|
typ: reflect.TypeOf(stru2{}),
|
|
data: hexDecode("47612C622C632C64"),
|
|
wantErrorMsg: "cbor: cannot unmarshal byte string into Go value of type []string",
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
v := reflect.New(tc.typ)
|
|
if err := Unmarshal(tc.data, v.Interface()); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error, want error msg %q", tc.data, tc.wantErrorMsg)
|
|
} else if err.Error() != tc.wantErrorMsg {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want %q", tc.data, err.Error(), tc.wantErrorMsg)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestMarshalerError(t *testing.T) {
|
|
wantErrorMsg := "MarshalCBOR: error"
|
|
v := marshalCBORError(wantErrorMsg)
|
|
if _, err := Marshal(v); err == nil {
|
|
t.Errorf("Marshal(%+v) didn't return an error, want error msg %q", v, wantErrorMsg)
|
|
} else if err.Error() != wantErrorMsg {
|
|
t.Errorf("Marshal(%+v) returned error %q, want %q", v, err.Error(), wantErrorMsg)
|
|
}
|
|
}
|
|
|
|
// Found at https://github.com/oasislabs/oasis-core/blob/master/go/common/cbor/cbor_test.go
|
|
func TestOutOfMem1(t *testing.T) {
|
|
data := []byte("\x9b\x00\x00000000")
|
|
var f []byte
|
|
if err := Unmarshal(data, &f); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error", data)
|
|
}
|
|
}
|
|
|
|
// Found at https://github.com/oasislabs/oasis-core/blob/master/go/common/cbor/cbor_test.go
|
|
func TestOutOfMem2(t *testing.T) {
|
|
data := []byte("\x9b\x00\x00\x81112233")
|
|
var f []byte
|
|
if err := Unmarshal(data, &f); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error", data)
|
|
}
|
|
}
|
|
|
|
// Found at https://github.com/cose-wg/Examples/tree/master/RFC8152
|
|
func TestCOSEExamples(t *testing.T) {
|
|
data := [][]byte{
|
|
hexDecode("D8608443A10101A1054C02D1F7E6F26C43D4868D87CE582464F84D913BA60A76070A9A48F26E97E863E2852948658F0811139868826E89218A75715B818440A101225818DBD43C4E9D719C27C6275C67D628D493F090593DB8218F11818344A1013818A220A401022001215820B2ADD44368EA6D641F9CA9AF308B4079AEB519F11E9B8A55A600B21233E86E6822F40458246D65726961646F632E6272616E64796275636B406275636B6C616E642E6578616D706C6540"),
|
|
hexDecode("D8628440A054546869732069732074686520636F6E74656E742E818343A10126A1044231315840E2AEAFD40D69D19DFE6E52077C5D7FF4E408282CBEFB5D06CBF414AF2E19D982AC45AC98B8544C908B4507DE1E90B717C3D34816FE926A2B98F53AFD2FA0F30A"),
|
|
hexDecode("D8628440A054546869732069732074686520636F6E74656E742E828343A10126A1044231315840E2AEAFD40D69D19DFE6E52077C5D7FF4E408282CBEFB5D06CBF414AF2E19D982AC45AC98B8544C908B4507DE1E90B717C3D34816FE926A2B98F53AFD2FA0F30A8344A1013823A104581E62696C626F2E62616767696E7340686F626269746F6E2E6578616D706C65588400A2D28A7C2BDB1587877420F65ADF7D0B9A06635DD1DE64BB62974C863F0B160DD2163734034E6AC003B01E8705524C5C4CA479A952F0247EE8CB0B4FB7397BA08D009E0C8BF482270CC5771AA143966E5A469A09F613488030C5B07EC6D722E3835ADB5B2D8C44E95FFB13877DD2582866883535DE3BB03D01753F83AB87BB4F7A0297"),
|
|
hexDecode("D8628440A1078343A10126A10442313158405AC05E289D5D0E1B0A7F048A5D2B643813DED50BC9E49220F4F7278F85F19D4A77D655C9D3B51E805A74B099E1E085AACD97FC29D72F887E8802BB6650CCEB2C54546869732069732074686520636F6E74656E742E818343A10126A1044231315840E2AEAFD40D69D19DFE6E52077C5D7FF4E408282CBEFB5D06CBF414AF2E19D982AC45AC98B8544C908B4507DE1E90B717C3D34816FE926A2B98F53AFD2FA0F30A"),
|
|
hexDecode("D8628456A2687265736572766564F40281687265736572766564A054546869732069732074686520636F6E74656E742E818343A10126A10442313158403FC54702AA56E1B2CB20284294C9106A63F91BAC658D69351210A031D8FC7C5FF3E4BE39445B1A3E83E1510D1ACA2F2E8A7C081C7645042B18ABA9D1FAD1BD9C"),
|
|
hexDecode("D28443A10126A10442313154546869732069732074686520636F6E74656E742E58408EB33E4CA31D1C465AB05AAC34CC6B23D58FEF5C083106C4D25A91AEF0B0117E2AF9A291AA32E14AB834DC56ED2A223444547E01F11D3B0916E5A4C345CACB36"),
|
|
hexDecode("D8608443A10101A1054CC9CF4DF2FE6C632BF788641358247ADBE2709CA818FB415F1E5DF66F4E1A51053BA6D65A1A0C52A357DA7A644B8070A151B0818344A1013818A220A40102200121582098F50A4FF6C05861C8860D13A638EA56C3F5AD7590BBFBF054E1C7B4D91D628022F50458246D65726961646F632E6272616E64796275636B406275636B6C616E642E6578616D706C6540"),
|
|
hexDecode("D8608443A1010AA1054D89F52F65A1C580933B5261A76C581C753548A19B1307084CA7B2056924ED95F2E3B17006DFE931B687B847818343A10129A2335061616262636364646565666667676868044A6F75722D73656372657440"),
|
|
hexDecode("D8608443A10101A2054CC9CF4DF2FE6C632BF7886413078344A1013823A104581E62696C626F2E62616767696E7340686F626269746F6E2E6578616D706C65588400929663C8789BB28177AE28467E66377DA12302D7F9594D2999AFA5DFA531294F8896F2B6CDF1740014F4C7F1A358E3A6CF57F4ED6FB02FCF8F7AA989F5DFD07F0700A3A7D8F3C604BA70FA9411BD10C2591B483E1D2C31DE003183E434D8FBA18F17A4C7E3DFA003AC1CF3D30D44D2533C4989D3AC38C38B71481CC3430C9D65E7DDFF58247ADBE2709CA818FB415F1E5DF66F4E1A51053BA6D65A1A0C52A357DA7A644B8070A151B0818344A1013818A220A40102200121582098F50A4FF6C05861C8860D13A638EA56C3F5AD7590BBFBF054E1C7B4D91D628022F50458246D65726961646F632E6272616E64796275636B406275636B6C616E642E6578616D706C6540"),
|
|
hexDecode("D8608443A10101A1054C02D1F7E6F26C43D4868D87CE582464F84D913BA60A76070A9A48F26E97E863E28529D8F5335E5F0165EEE976B4A5F6C6F09D818344A101381FA3225821706572656772696E2E746F6F6B407475636B626F726F7567682E6578616D706C650458246D65726961646F632E6272616E64796275636B406275636B6C616E642E6578616D706C6535420101581841E0D76F579DBD0D936A662D54D8582037DE2E366FDE1C62"),
|
|
hexDecode("D08343A1010AA1054D89F52F65A1C580933B5261A78C581C5974E1B99A3A4CC09A659AA2E9E7FFF161D38CE71CB45CE460FFB569"),
|
|
hexDecode("D08343A1010AA1064261A7581C252A8911D465C125B6764739700F0141ED09192DE139E053BD09ABCA"),
|
|
hexDecode("D8618543A1010FA054546869732069732074686520636F6E74656E742E489E1226BA1F81B848818340A20125044A6F75722D73656372657440"),
|
|
hexDecode("D8618543A10105A054546869732069732074686520636F6E74656E742E582081A03448ACD3D305376EAA11FB3FE416A955BE2CBE7EC96F012C994BC3F16A41818344A101381AA3225821706572656772696E2E746F6F6B407475636B626F726F7567682E6578616D706C650458246D65726961646F632E6272616E64796275636B406275636B6C616E642E6578616D706C653558404D8553E7E74F3C6A3A9DD3EF286A8195CBF8A23D19558CCFEC7D34B824F42D92BD06BD2C7F0271F0214E141FB779AE2856ABF585A58368B017E7F2A9E5CE4DB540"),
|
|
hexDecode("D8618543A1010EA054546869732069732074686520636F6E74656E742E4836F5AFAF0BAB5D43818340A2012404582430313863306165352D346439622D343731622D626664362D6565663331346263373033375818711AB0DC2FC4585DCE27EFFA6781C8093EBA906F227B6EB0"),
|
|
hexDecode("D8618543A10105A054546869732069732074686520636F6E74656E742E5820BF48235E809B5C42E995F2B7D5FA13620E7ED834E337F6AA43DF161E49E9323E828344A101381CA220A4010220032158420043B12669ACAC3FD27898FFBA0BCD2E6C366D53BC4DB71F909A759304ACFB5E18CDC7BA0B13FF8C7636271A6924B1AC63C02688075B55EF2D613574E7DC242F79C322F504581E62696C626F2E62616767696E7340686F626269746F6E2E6578616D706C655828339BC4F79984CDC6B3E6CE5F315A4C7D2B0AC466FCEA69E8C07DFBCA5BB1F661BC5F8E0DF9E3EFF58340A2012404582430313863306165352D346439622D343731622D626664362D65656633313462633730333758280B2C7CFCE04E98276342D6476A7723C090DFDD15F9A518E7736549E998370695E6D6A83B4AE507BB"),
|
|
hexDecode("D18443A1010FA054546869732069732074686520636F6E74656E742E48726043745027214F"),
|
|
}
|
|
for _, d := range data {
|
|
var v interface{}
|
|
if err := Unmarshal(d, &v); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", d, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalStructKeyAsIntError(t *testing.T) {
|
|
type T1 struct {
|
|
F1 int `cbor:"1,keyasint"`
|
|
}
|
|
data := hexDecode("a13bffffffffffffffff01") // {1: -18446744073709551616}
|
|
var v T1
|
|
if err := Unmarshal(data, &v); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error", data)
|
|
} else if _, ok := err.(*UnmarshalTypeError); !ok {
|
|
t.Errorf("Unmarshal(0x%x) returned wrong error type %T, want (*UnmarshalTypeError)", data, err)
|
|
} else if !strings.Contains(err.Error(), "cannot unmarshal") {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want error containing %q", data, err.Error(), "cannot unmarshal")
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalArrayToStruct(t *testing.T) {
|
|
type T struct {
|
|
_ struct{} `cbor:",toarray"`
|
|
A int
|
|
B int
|
|
C int
|
|
}
|
|
testCases := []struct {
|
|
name string
|
|
data []byte
|
|
}{
|
|
{"definite length array", hexDecode("83010203")},
|
|
{"indefinite length array", hexDecode("9f010203ff")},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
var v T
|
|
if err := Unmarshal(tc.data, &v); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", tc.data, err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalArrayToStructNoToArrayOptionError(t *testing.T) {
|
|
type T struct {
|
|
A int
|
|
B int
|
|
C int
|
|
}
|
|
data := hexDecode("8301020383010203")
|
|
var v1 T
|
|
wantT := T{}
|
|
dec := NewDecoder(bytes.NewReader(data))
|
|
if err := dec.Decode(&v1); err == nil {
|
|
t.Errorf("Decode(%+v) didn't return an error", v1)
|
|
} else if _, ok := err.(*UnmarshalTypeError); !ok {
|
|
t.Errorf("Decode(%+v) returned wrong error type %T, want (*UnmarshalTypeError)", v1, err)
|
|
} else if !strings.Contains(err.Error(), "cannot unmarshal") {
|
|
t.Errorf("Decode(%+v) returned error %q, want error containing %q", err.Error(), v1, "cannot unmarshal")
|
|
}
|
|
if !reflect.DeepEqual(v1, wantT) {
|
|
t.Errorf("Decode() = %+v (%T), want %+v (%T)", v1, v1, wantT, wantT)
|
|
}
|
|
var v2 []int
|
|
want := []int{1, 2, 3}
|
|
if err := dec.Decode(&v2); err != nil {
|
|
t.Errorf("Decode() returned error %v", err)
|
|
}
|
|
if !reflect.DeepEqual(v2, want) {
|
|
t.Errorf("Decode() = %+v (%T), want %+v (%T)", v2, v2, want, want)
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalNonArrayDataToStructToArray(t *testing.T) {
|
|
type T struct {
|
|
_ struct{} `cbor:",toarray"`
|
|
A int
|
|
B int
|
|
C int
|
|
}
|
|
testCases := []struct {
|
|
name string
|
|
data []byte
|
|
}{
|
|
{"CBOR positive int", hexDecode("00")}, // 0
|
|
{"CBOR negative int", hexDecode("20")}, // -1
|
|
{"CBOR byte string", hexDecode("4401020304")}, // h`01020304`
|
|
{"CBOR text string", hexDecode("7f657374726561646d696e67ff")}, // streaming
|
|
{"CBOR map", hexDecode("a3614101614202614303")}, // {"A": 1, "B": 2, "C": 3}
|
|
{"CBOR bool", hexDecode("f5")}, // true
|
|
{"CBOR float", hexDecode("fa7f7fffff")}, // 3.4028234663852886e+38
|
|
}
|
|
wantT := T{}
|
|
wantErrorMsg := "cannot unmarshal"
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
var v T
|
|
if err := Unmarshal(tc.data, &v); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error", tc.data)
|
|
} else if _, ok := err.(*UnmarshalTypeError); !ok {
|
|
t.Errorf("Unmarshal(0x%x) returned wrong error type %T, want (*UnmarshalTypeError)", tc.data, err)
|
|
} else if !strings.Contains(err.Error(), wantErrorMsg) {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want error containing %q", tc.data, err.Error(), wantErrorMsg)
|
|
}
|
|
if !reflect.DeepEqual(v, wantT) {
|
|
t.Errorf("Unmarshal(0x%x) = %+v (%T), want %+v (%T)", tc.data, v, v, wantT, wantT)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalArrayToStructWrongSizeError(t *testing.T) {
|
|
type T struct {
|
|
_ struct{} `cbor:",toarray"`
|
|
A int
|
|
B int
|
|
}
|
|
data := hexDecode("8301020383010203")
|
|
var v1 T
|
|
wantT := T{}
|
|
dec := NewDecoder(bytes.NewReader(data))
|
|
if err := dec.Decode(&v1); err == nil {
|
|
t.Errorf("Decode(%+v) didn't return an error", v1)
|
|
} else if _, ok := err.(*UnmarshalTypeError); !ok {
|
|
t.Errorf("Decode(%+v) returned wrong error type %T, want (*UnmarshalTypeError)", v1, err)
|
|
} else if !strings.Contains(err.Error(), "cannot unmarshal") {
|
|
t.Errorf("Decode(%+v) returned error %q, want error containing %q", v1, err.Error(), "cannot unmarshal")
|
|
}
|
|
if !reflect.DeepEqual(v1, wantT) {
|
|
t.Errorf("Decode() = %+v (%T), want %+v (%T)", v1, v1, wantT, wantT)
|
|
}
|
|
var v2 []int
|
|
want := []int{1, 2, 3}
|
|
if err := dec.Decode(&v2); err != nil {
|
|
t.Errorf("Decode() returned error %v", err)
|
|
}
|
|
if !reflect.DeepEqual(v2, want) {
|
|
t.Errorf("Decode() = %+v (%T), want %+v (%T)", v2, v2, want, want)
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalArrayToStructWrongFieldTypeError(t *testing.T) {
|
|
type T struct {
|
|
_ struct{} `cbor:",toarray"`
|
|
A int
|
|
B string
|
|
C int
|
|
}
|
|
testCases := []struct {
|
|
name string
|
|
data []byte
|
|
wantErrorMsg string
|
|
wantV interface{}
|
|
}{
|
|
// [1, 2, 3]
|
|
{"wrong field type", hexDecode("83010203"), "cannot unmarshal", T{A: 1, C: 3}},
|
|
// [1, 0xfe, 3]
|
|
{"invalid UTF-8 string", hexDecode("830161fe03"), invalidUTF8ErrorMsg, T{A: 1, C: 3}},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
var v T
|
|
if err := Unmarshal(tc.data, &v); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error", tc.data)
|
|
} else if !strings.Contains(err.Error(), tc.wantErrorMsg) {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want error containing %q", tc.data, err.Error(), tc.wantErrorMsg)
|
|
}
|
|
if !reflect.DeepEqual(v, tc.wantV) {
|
|
t.Errorf("Unmarshal(0x%x) = %+v (%T), want %+v (%T)", tc.data, v, v, tc.wantV, tc.wantV)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalArrayToStructCannotSetEmbeddedPointerError(t *testing.T) {
|
|
type (
|
|
s1 struct {
|
|
x int //nolint:unused,structcheck
|
|
X int
|
|
}
|
|
S2 struct {
|
|
y int //nolint:unused,structcheck
|
|
Y int
|
|
}
|
|
S struct {
|
|
_ struct{} `cbor:",toarray"`
|
|
*s1
|
|
*S2
|
|
}
|
|
)
|
|
data := []byte{0x82, 0x02, 0x04} // [2, 4]
|
|
const wantErrorMsg = "cannot set embedded pointer to unexported struct"
|
|
wantV := S{S2: &S2{Y: 4}}
|
|
var v S
|
|
err := Unmarshal(data, &v)
|
|
if err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error, want error %q", data, wantErrorMsg)
|
|
} else if !strings.Contains(err.Error(), wantErrorMsg) {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want error %q", data, err.Error(), wantErrorMsg)
|
|
}
|
|
if !reflect.DeepEqual(v, wantV) {
|
|
t.Errorf("Decode() = %+v (%T), want %+v (%T)", v, v, wantV, wantV)
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalIntoSliceError(t *testing.T) {
|
|
data := []byte{0x83, 0x61, 0x61, 0x61, 0xfe, 0x61, 0x62} // ["a", 0xfe, "b"]
|
|
wantErrorMsg := invalidUTF8ErrorMsg
|
|
var want interface{}
|
|
|
|
// Unmarshal CBOR array into Go empty interface.
|
|
var v1 interface{}
|
|
want = []interface{}{"a", interface{}(nil), "b"}
|
|
if err := Unmarshal(data, &v1); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error, want %q", data, wantErrorMsg)
|
|
} else if err.Error() != wantErrorMsg {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want %q", data, err.Error(), wantErrorMsg)
|
|
}
|
|
if !reflect.DeepEqual(v1, want) {
|
|
t.Errorf("Unmarshal(0x%x) = %v, want %v", data, v1, want)
|
|
}
|
|
|
|
// Unmarshal CBOR array into Go slice.
|
|
var v2 []string
|
|
want = []string{"a", "", "b"}
|
|
if err := Unmarshal(data, &v2); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error, want %q", data, wantErrorMsg)
|
|
} else if err.Error() != wantErrorMsg {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want %q", data, err.Error(), wantErrorMsg)
|
|
}
|
|
if !reflect.DeepEqual(v2, want) {
|
|
t.Errorf("Unmarshal(0x%x) = %v, want %v", data, v2, want)
|
|
}
|
|
|
|
// Unmarshal CBOR array into Go array.
|
|
var v3 [3]string
|
|
want = [3]string{"a", "", "b"}
|
|
if err := Unmarshal(data, &v3); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error, want %q", data, wantErrorMsg)
|
|
} else if err.Error() != wantErrorMsg {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want %q", data, err.Error(), wantErrorMsg)
|
|
}
|
|
if !reflect.DeepEqual(v3, want) {
|
|
t.Errorf("Unmarshal(0x%x) = %v, want %v", data, v3, want)
|
|
}
|
|
|
|
// Unmarshal CBOR array into populated Go slice.
|
|
v4 := []string{"hello", "to", "you"}
|
|
want = []string{"a", "to", "b"}
|
|
if err := Unmarshal(data, &v4); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error, want %q", data, wantErrorMsg)
|
|
} else if err.Error() != wantErrorMsg {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want %q", data, err.Error(), wantErrorMsg)
|
|
}
|
|
if !reflect.DeepEqual(v4, want) {
|
|
t.Errorf("Unmarshal(0x%x) = %v, want %v", data, v4, want)
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalIntoMapError(t *testing.T) {
|
|
data := [][]byte{
|
|
{0xa3, 0x61, 0x61, 0x61, 0x41, 0x61, 0xfe, 0x61, 0x43, 0x61, 0x62, 0x61, 0x42}, // {"a":"A", 0xfe: "C", "b":"B"}
|
|
{0xa3, 0x61, 0x61, 0x61, 0x41, 0x61, 0x63, 0x61, 0xfe, 0x61, 0x62, 0x61, 0x42}, // {"a":"A", "c": 0xfe, "b":"B"}
|
|
}
|
|
wantErrorMsg := invalidUTF8ErrorMsg
|
|
var want interface{}
|
|
|
|
for _, data := range data {
|
|
// Unmarshal CBOR map into Go empty interface.
|
|
var v1 interface{}
|
|
want = map[interface{}]interface{}{"a": "A", "b": "B"}
|
|
if err := Unmarshal(data, &v1); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error, want %q", data, wantErrorMsg)
|
|
} else if err.Error() != wantErrorMsg {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want %q", data, err.Error(), wantErrorMsg)
|
|
}
|
|
if !reflect.DeepEqual(v1, want) {
|
|
t.Errorf("Unmarshal(0x%x) = %v, want %v", data, v1, want)
|
|
}
|
|
|
|
// Unmarshal CBOR map into Go map[interface{}]interface{}.
|
|
var v2 map[interface{}]interface{}
|
|
want = map[interface{}]interface{}{"a": "A", "b": "B"}
|
|
if err := Unmarshal(data, &v2); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error, want %q", data, wantErrorMsg)
|
|
} else if err.Error() != wantErrorMsg {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want %q", data, err.Error(), wantErrorMsg)
|
|
}
|
|
if !reflect.DeepEqual(v2, want) {
|
|
t.Errorf("Unmarshal(0x%x) = %v, want %v", data, v2, want)
|
|
}
|
|
|
|
// Unmarshal CBOR array into Go map[string]string.
|
|
var v3 map[string]string
|
|
want = map[string]string{"a": "A", "b": "B"}
|
|
if err := Unmarshal(data, &v3); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error, want %q", data, wantErrorMsg)
|
|
} else if err.Error() != wantErrorMsg {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want %q", data, err.Error(), wantErrorMsg)
|
|
}
|
|
if !reflect.DeepEqual(v3, want) {
|
|
t.Errorf("Unmarshal(0x%x) = %v, want %v", data, v3, want)
|
|
}
|
|
|
|
// Unmarshal CBOR array into populated Go map[string]string.
|
|
v4 := map[string]string{"c": "D"}
|
|
want = map[string]string{"a": "A", "b": "B", "c": "D"}
|
|
if err := Unmarshal(data, &v4); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error, want %q", data, wantErrorMsg)
|
|
} else if err.Error() != wantErrorMsg {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want %q", data, err.Error(), wantErrorMsg)
|
|
}
|
|
if !reflect.DeepEqual(v4, want) {
|
|
t.Errorf("Unmarshal(0x%x) = %v, want %v", data, v4, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestStructToArrayError(t *testing.T) {
|
|
type coseHeader struct {
|
|
Alg int `cbor:"1,keyasint,omitempty"`
|
|
Kid []byte `cbor:"4,keyasint,omitempty"`
|
|
IV []byte `cbor:"5,keyasint,omitempty"`
|
|
}
|
|
type nestedCWT struct {
|
|
_ struct{} `cbor:",toarray"`
|
|
Protected []byte
|
|
Unprotected coseHeader
|
|
Ciphertext []byte
|
|
}
|
|
for _, tc := range []struct {
|
|
data []byte
|
|
wantErrorMsg string
|
|
}{
|
|
// [-17, [-17, -17], -17]
|
|
{hexDecode("9f3082303030ff"), "cbor: cannot unmarshal negative integer into Go struct field cbor.nestedCWT.Protected of type []uint8"},
|
|
// [[], [], ["\x930000", -17]]
|
|
{hexDecode("9f9fff9fff9f65933030303030ffff"), "cbor: cannot unmarshal array into Go struct field cbor.nestedCWT.Unprotected of type cbor.coseHeader (cannot decode CBOR array to struct without toarray option)"},
|
|
} {
|
|
var v nestedCWT
|
|
if err := Unmarshal(tc.data, &v); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error, want %q", tc.data, tc.wantErrorMsg)
|
|
} else if err.Error() != tc.wantErrorMsg {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want %q", tc.data, err.Error(), tc.wantErrorMsg)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestStructKeyAsIntError(t *testing.T) {
|
|
type claims struct {
|
|
Iss string `cbor:"1,keyasint"`
|
|
Sub string `cbor:"2,keyasint"`
|
|
Aud string `cbor:"3,keyasint"`
|
|
Exp float64 `cbor:"4,keyasint"`
|
|
Nbf float64 `cbor:"5,keyasint"`
|
|
Iat float64 `cbor:"6,keyasint"`
|
|
Cti []byte `cbor:"7,keyasint"`
|
|
}
|
|
data := hexDecode("bf0783e662f03030ff") // {7: [simple(6), "\xF00", -17]}
|
|
wantErrorMsg := invalidUTF8ErrorMsg
|
|
wantV := claims{Cti: []byte{6, 0, 0}}
|
|
var v claims
|
|
if err := Unmarshal(data, &v); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error, want %q", data, wantErrorMsg)
|
|
} else if err.Error() != wantErrorMsg {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want %q", data, err.Error(), wantErrorMsg)
|
|
}
|
|
if !reflect.DeepEqual(v, wantV) {
|
|
t.Errorf("Unmarshal(0x%x) = %v, want %v", data, v, wantV)
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalToNotNilInterface(t *testing.T) {
|
|
data := hexDecode("83010203") // []uint64{1, 2, 3}
|
|
s := "hello" //nolint:goconst
|
|
var v interface{} = s // Unmarshal() sees v as type interface{} and sets CBOR data as default Go type. s is unmodified. Same behavior as encoding/json.
|
|
wantV := []interface{}{uint64(1), uint64(2), uint64(3)}
|
|
if err := Unmarshal(data, &v); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", data, err)
|
|
} else if !reflect.DeepEqual(v, wantV) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", data, v, v, wantV, wantV)
|
|
} else if s != "hello" {
|
|
t.Errorf("Unmarshal(0x%x) modified s %q", data, s)
|
|
}
|
|
}
|
|
|
|
func TestDecOptions(t *testing.T) {
|
|
simpleValues, err := NewSimpleValueRegistryFromDefaults(WithRejectedSimpleValue(255))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
opts1 := DecOptions{
|
|
DupMapKey: DupMapKeyEnforcedAPF,
|
|
TimeTag: DecTagRequired,
|
|
MaxNestedLevels: 100,
|
|
MaxArrayElements: 102,
|
|
MaxMapPairs: 101,
|
|
IndefLength: IndefLengthForbidden,
|
|
TagsMd: TagsForbidden,
|
|
IntDec: IntDecConvertSigned,
|
|
MapKeyByteString: MapKeyByteStringForbidden,
|
|
ExtraReturnErrors: ExtraDecErrorUnknownField,
|
|
DefaultMapType: reflect.TypeOf(map[string]interface{}(nil)),
|
|
UTF8: UTF8DecodeInvalid,
|
|
FieldNameMatching: FieldNameMatchingCaseSensitive,
|
|
BigIntDec: BigIntDecodePointer,
|
|
DefaultByteStringType: reflect.TypeOf(""),
|
|
ByteStringToString: ByteStringToStringAllowed,
|
|
FieldNameByteString: FieldNameByteStringAllowed,
|
|
UnrecognizedTagToAny: UnrecognizedTagContentToAny,
|
|
TimeTagToAny: TimeTagToRFC3339,
|
|
SimpleValues: simpleValues,
|
|
NaN: NaNDecodeForbidden,
|
|
Inf: InfDecodeForbidden,
|
|
ByteStringToTime: ByteStringToTimeAllowed,
|
|
ByteStringExpectedFormat: ByteStringExpectedBase64URL,
|
|
BignumTag: BignumTagForbidden,
|
|
BinaryUnmarshaler: BinaryUnmarshalerNone,
|
|
}
|
|
ov := reflect.ValueOf(opts1)
|
|
for i := 0; i < ov.NumField(); i++ {
|
|
fv := ov.Field(i)
|
|
if fv.IsZero() {
|
|
t.Errorf("options field %q is unset or set to the zero value for its type", ov.Type().Field(i).Name)
|
|
}
|
|
}
|
|
dm, err := opts1.DecMode()
|
|
if err != nil {
|
|
t.Errorf("DecMode() returned an error %v", err)
|
|
} else {
|
|
opts2 := dm.DecOptions()
|
|
if !reflect.DeepEqual(opts1, opts2) {
|
|
t.Errorf("DecOptions->DecMode->DecOptions returned different values: %#v, %#v", opts1, opts2)
|
|
}
|
|
}
|
|
}
|
|
|
|
type roundTripTest struct {
|
|
name string
|
|
obj interface{}
|
|
wantCborData []byte
|
|
}
|
|
|
|
func testRoundTrip(t *testing.T, testCases []roundTripTest, em EncMode, dm DecMode) {
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
b, err := em.Marshal(tc.obj)
|
|
if err != nil {
|
|
t.Errorf("Marshal(%+v) returned error %v", tc.obj, err)
|
|
}
|
|
if !bytes.Equal(b, tc.wantCborData) {
|
|
t.Errorf("Marshal(%+v) = 0x%x, want 0x%x", tc.obj, b, tc.wantCborData)
|
|
}
|
|
v := reflect.New(reflect.TypeOf(tc.obj))
|
|
if err := dm.Unmarshal(b, v.Interface()); err != nil {
|
|
t.Errorf("Unmarshal() returned error %v", err)
|
|
}
|
|
if !reflect.DeepEqual(tc.obj, v.Elem().Interface()) {
|
|
t.Errorf("Marshal-Unmarshal returned different values: %v, %v", tc.obj, v.Elem().Interface())
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDecModeInvalidTimeTag(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
name string
|
|
opts DecOptions
|
|
wantErrorMsg string
|
|
}{
|
|
{
|
|
name: "below range of valid modes",
|
|
opts: DecOptions{TimeTag: -1},
|
|
wantErrorMsg: "cbor: invalid TimeTag -1",
|
|
},
|
|
{
|
|
name: "above range of valid modes",
|
|
opts: DecOptions{TimeTag: 101},
|
|
wantErrorMsg: "cbor: invalid TimeTag 101",
|
|
},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
_, err := tc.opts.DecMode()
|
|
if err == nil {
|
|
t.Errorf("DecMode() didn't return an error")
|
|
} else if err.Error() != tc.wantErrorMsg {
|
|
t.Errorf("DecMode() returned error %q, want %q", err.Error(), tc.wantErrorMsg)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDecModeInvalidDuplicateMapKey(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
name string
|
|
opts DecOptions
|
|
wantErrorMsg string
|
|
}{
|
|
{
|
|
name: "below range of valid modes",
|
|
opts: DecOptions{DupMapKey: -1},
|
|
wantErrorMsg: "cbor: invalid DupMapKey -1",
|
|
},
|
|
{
|
|
name: "above range of valid modes",
|
|
opts: DecOptions{DupMapKey: 101},
|
|
wantErrorMsg: "cbor: invalid DupMapKey 101",
|
|
},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
_, err := tc.opts.DecMode()
|
|
if err == nil {
|
|
t.Errorf("DecMode() didn't return an error")
|
|
} else if err.Error() != tc.wantErrorMsg {
|
|
t.Errorf("DecMode() returned error %q, want %q", err.Error(), tc.wantErrorMsg)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDecModeDefaultMaxNestedLevel(t *testing.T) {
|
|
dm, err := DecOptions{}.DecMode()
|
|
if err != nil {
|
|
t.Errorf("DecMode() returned error %v", err)
|
|
} else {
|
|
maxNestedLevels := dm.DecOptions().MaxNestedLevels
|
|
if maxNestedLevels != defaultMaxNestedLevels {
|
|
t.Errorf("DecOptions().MaxNestedLevels = %d, want %v", maxNestedLevels, defaultMaxNestedLevels)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestDecModeInvalidMaxNestedLevel(t *testing.T) {
|
|
testCases := []struct {
|
|
name string
|
|
opts DecOptions
|
|
wantErrorMsg string
|
|
}{
|
|
{
|
|
name: "MaxNestedLevels < 4",
|
|
opts: DecOptions{MaxNestedLevels: 1},
|
|
wantErrorMsg: "cbor: invalid MaxNestedLevels 1 (range is [4, 65535])",
|
|
},
|
|
{
|
|
name: "MaxNestedLevels > 65535",
|
|
opts: DecOptions{MaxNestedLevels: 65536},
|
|
wantErrorMsg: "cbor: invalid MaxNestedLevels 65536 (range is [4, 65535])",
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
_, err := tc.opts.DecMode()
|
|
if err == nil {
|
|
t.Errorf("DecMode() didn't return an error")
|
|
} else if err.Error() != tc.wantErrorMsg {
|
|
t.Errorf("DecMode() returned error %q, want %q", err.Error(), tc.wantErrorMsg)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDecModeDefaultMaxMapPairs(t *testing.T) {
|
|
dm, err := DecOptions{}.DecMode()
|
|
if err != nil {
|
|
t.Errorf("DecMode() returned error %v", err)
|
|
} else {
|
|
maxMapPairs := dm.DecOptions().MaxMapPairs
|
|
if maxMapPairs != defaultMaxMapPairs {
|
|
t.Errorf("DecOptions().MaxMapPairs = %d, want %v", maxMapPairs, defaultMaxMapPairs)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestDecModeInvalidMaxMapPairs(t *testing.T) {
|
|
testCases := []struct {
|
|
name string
|
|
opts DecOptions
|
|
wantErrorMsg string
|
|
}{
|
|
{
|
|
name: "MaxMapPairs < 16",
|
|
opts: DecOptions{MaxMapPairs: 1},
|
|
wantErrorMsg: "cbor: invalid MaxMapPairs 1 (range is [16, 2147483647])",
|
|
},
|
|
{
|
|
name: "MaxMapPairs > 2147483647",
|
|
opts: DecOptions{MaxMapPairs: 2147483648},
|
|
wantErrorMsg: "cbor: invalid MaxMapPairs 2147483648 (range is [16, 2147483647])",
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
_, err := tc.opts.DecMode()
|
|
if err == nil {
|
|
t.Errorf("DecMode() didn't return an error")
|
|
} else if err.Error() != tc.wantErrorMsg {
|
|
t.Errorf("DecMode() returned error %q, want %q", err.Error(), tc.wantErrorMsg)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDecModeDefaultMaxArrayElements(t *testing.T) {
|
|
dm, err := DecOptions{}.DecMode()
|
|
if err != nil {
|
|
t.Errorf("DecMode() returned error %v", err)
|
|
} else {
|
|
maxArrayElements := dm.DecOptions().MaxArrayElements
|
|
if maxArrayElements != defaultMaxArrayElements {
|
|
t.Errorf("DecOptions().MaxArrayElementsr = %d, want %v", maxArrayElements, defaultMaxArrayElements)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestDecModeInvalidMaxArrayElements(t *testing.T) {
|
|
testCases := []struct {
|
|
name string
|
|
opts DecOptions
|
|
wantErrorMsg string
|
|
}{
|
|
{
|
|
name: "MaxArrayElements < 16",
|
|
opts: DecOptions{MaxArrayElements: 1},
|
|
wantErrorMsg: "cbor: invalid MaxArrayElements 1 (range is [16, 2147483647])",
|
|
},
|
|
{
|
|
name: "MaxArrayElements > 2147483647",
|
|
opts: DecOptions{MaxArrayElements: 2147483648},
|
|
wantErrorMsg: "cbor: invalid MaxArrayElements 2147483648 (range is [16, 2147483647])",
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
_, err := tc.opts.DecMode()
|
|
if err == nil {
|
|
t.Errorf("DecMode() didn't return an error")
|
|
} else if err.Error() != tc.wantErrorMsg {
|
|
t.Errorf("DecMode() returned error %q, want %q", err.Error(), tc.wantErrorMsg)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDecModeInvalidIndefiniteLengthMode(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
name string
|
|
opts DecOptions
|
|
wantErrorMsg string
|
|
}{
|
|
{
|
|
name: "below range of valid modes",
|
|
opts: DecOptions{IndefLength: -1},
|
|
wantErrorMsg: "cbor: invalid IndefLength -1",
|
|
},
|
|
{
|
|
name: "above range of valid modes",
|
|
opts: DecOptions{IndefLength: 101},
|
|
wantErrorMsg: "cbor: invalid IndefLength 101",
|
|
},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
_, err := tc.opts.DecMode()
|
|
if err == nil {
|
|
t.Errorf("DecMode() didn't return an error")
|
|
} else if err.Error() != tc.wantErrorMsg {
|
|
t.Errorf("DecMode() returned error %q, want %q", err.Error(), tc.wantErrorMsg)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDecModeInvalidTagsMode(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
name string
|
|
opts DecOptions
|
|
wantErrorMsg string
|
|
}{
|
|
{
|
|
name: "below range of valid modes",
|
|
opts: DecOptions{TagsMd: -1},
|
|
wantErrorMsg: "cbor: invalid TagsMd -1",
|
|
},
|
|
{
|
|
name: "above range of valid modes",
|
|
opts: DecOptions{TagsMd: 101},
|
|
wantErrorMsg: "cbor: invalid TagsMd 101",
|
|
},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
_, err := tc.opts.DecMode()
|
|
if err == nil {
|
|
t.Errorf("DecMode() didn't return an error")
|
|
} else if err.Error() != tc.wantErrorMsg {
|
|
t.Errorf("DecMode() returned error %q, want %q", err.Error(), tc.wantErrorMsg)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalStructKeyAsIntNumError(t *testing.T) {
|
|
type T1 struct {
|
|
F1 int `cbor:"a,keyasint"`
|
|
}
|
|
type T2 struct {
|
|
F1 int `cbor:"-18446744073709551616,keyasint"`
|
|
}
|
|
testCases := []struct {
|
|
name string
|
|
data []byte
|
|
obj interface{}
|
|
wantErrorMsg string
|
|
}{
|
|
{
|
|
name: "string as key",
|
|
data: hexDecode("a1616101"),
|
|
obj: T1{},
|
|
wantErrorMsg: "cbor: failed to parse field name \"a\" to int",
|
|
},
|
|
{
|
|
name: "out of range int as key",
|
|
data: hexDecode("a13bffffffffffffffff01"),
|
|
obj: T2{},
|
|
wantErrorMsg: "cbor: failed to parse field name \"-18446744073709551616\" to int",
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
v := reflect.New(reflect.TypeOf(tc.obj))
|
|
err := Unmarshal(tc.data, v.Interface())
|
|
if err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error, want error %q", tc.data, tc.wantErrorMsg)
|
|
} else if !strings.Contains(err.Error(), tc.wantErrorMsg) {
|
|
t.Errorf("Unmarshal(0x%x) error %v, want %v", tc.data, err.Error(), tc.wantErrorMsg)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalEmptyMapWithDupMapKeyOpt(t *testing.T) {
|
|
testCases := []struct {
|
|
name string
|
|
data []byte
|
|
wantV interface{}
|
|
}{
|
|
{
|
|
name: "empty map",
|
|
data: hexDecode("a0"),
|
|
wantV: map[interface{}]interface{}{},
|
|
},
|
|
{
|
|
name: "indefinite empty map",
|
|
data: hexDecode("bfff"),
|
|
wantV: map[interface{}]interface{}{},
|
|
},
|
|
}
|
|
|
|
dm, err := DecOptions{DupMapKey: DupMapKeyEnforcedAPF}.DecMode()
|
|
if err != nil {
|
|
t.Errorf("DecMode() returned error %v", err)
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
var v interface{}
|
|
if err := dm.Unmarshal(tc.data, &v); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", tc.data, err)
|
|
}
|
|
if !reflect.DeepEqual(v, tc.wantV) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", tc.data, v, v, tc.wantV, tc.wantV)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalDupMapKeyToEmptyInterface(t *testing.T) {
|
|
data := hexDecode("a6616161416162614261636143616161466164614461656145") // {"a": "A", "b": "B", "c": "C", "a": "F", "d": "D", "e": "E"}
|
|
|
|
// Duplicate key overwrites previous value (default).
|
|
wantV := map[interface{}]interface{}{"a": "F", "b": "B", "c": "C", "d": "D", "e": "E"}
|
|
var v interface{}
|
|
if err := Unmarshal(data, &v); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", data, err)
|
|
}
|
|
if !reflect.DeepEqual(v, wantV) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", data, v, v, wantV, wantV)
|
|
}
|
|
|
|
// Duplicate key triggers error.
|
|
wantV = map[interface{}]interface{}{"a": nil, "b": "B", "c": "C"}
|
|
wantErrorMsg := "cbor: found duplicate map key \"a\" at map element index 3"
|
|
dm, _ := DecOptions{DupMapKey: DupMapKeyEnforcedAPF}.DecMode()
|
|
var v2 interface{}
|
|
if err := dm.Unmarshal(data, &v2); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error", data)
|
|
} else if _, ok := err.(*DupMapKeyError); !ok {
|
|
t.Errorf("Unmarshal(0x%x) returned wrong error type %T, want (*DupMapKeyError)", data, err)
|
|
} else if err.Error() != wantErrorMsg {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want error containing %q", data, err.Error(), wantErrorMsg)
|
|
}
|
|
if !reflect.DeepEqual(v2, wantV) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", data, v2, v2, wantV, wantV)
|
|
}
|
|
}
|
|
|
|
func TestStreamDupMapKeyToEmptyInterface(t *testing.T) {
|
|
data := hexDecode("a6616161416162614261636143616161466164614461656145") // map with duplicate key "c": {"a": "A", "b": "B", "c": "C", "a": "F", "d": "D", "e": "E"}
|
|
|
|
var b []byte
|
|
for i := 0; i < 3; i++ {
|
|
b = append(b, data...)
|
|
}
|
|
|
|
// Duplicate key overwrites previous value (default).
|
|
wantV := map[interface{}]interface{}{"a": "F", "b": "B", "c": "C", "d": "D", "e": "E"}
|
|
dec := NewDecoder(bytes.NewReader(b))
|
|
for i := 0; i < 3; i++ {
|
|
var v1 interface{}
|
|
if err := dec.Decode(&v1); err != nil {
|
|
t.Errorf("Decode() returned error %v", err)
|
|
}
|
|
if !reflect.DeepEqual(v1, wantV) {
|
|
t.Errorf("Decode() = %v (%T), want %v (%T)", v1, v1, wantV, wantV)
|
|
}
|
|
}
|
|
var v interface{}
|
|
if err := dec.Decode(&v); err != io.EOF {
|
|
t.Errorf("Decode() returned error %v, want %v", err, io.EOF)
|
|
}
|
|
|
|
// Duplicate key triggers error.
|
|
wantV = map[interface{}]interface{}{"a": nil, "b": "B", "c": "C"}
|
|
wantErrorMsg := "cbor: found duplicate map key \"a\" at map element index 3"
|
|
dm, _ := DecOptions{DupMapKey: DupMapKeyEnforcedAPF}.DecMode()
|
|
dec = dm.NewDecoder(bytes.NewReader(b))
|
|
for i := 0; i < 3; i++ {
|
|
var v2 interface{}
|
|
if err := dec.Decode(&v2); err == nil {
|
|
t.Errorf("Decode() didn't return an error")
|
|
} else if _, ok := err.(*DupMapKeyError); !ok {
|
|
t.Errorf("Decode() returned wrong error type %T, want (*DupMapKeyError)", err)
|
|
} else if err.Error() != wantErrorMsg {
|
|
t.Errorf("Decode() returned error %q, want error containing %q", err.Error(), wantErrorMsg)
|
|
}
|
|
if !reflect.DeepEqual(v2, wantV) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", data, v2, v2, wantV, wantV)
|
|
}
|
|
}
|
|
if err := dec.Decode(&v); err != io.EOF {
|
|
t.Errorf("Decode() returned error %v, want %v", err, io.EOF)
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalDupMapKeyToEmptyMap(t *testing.T) {
|
|
data := hexDecode("a6616161416162614261636143616161466164614461656145") // {"a": "A", "b": "B", "c": "C", "a": "F", "d": "D", "e": "E"}
|
|
|
|
// Duplicate key overwrites previous value (default).
|
|
wantM := map[string]string{"a": "F", "b": "B", "c": "C", "d": "D", "e": "E"}
|
|
var m map[string]string
|
|
if err := Unmarshal(data, &m); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", data, err)
|
|
}
|
|
if !reflect.DeepEqual(m, wantM) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", data, m, m, wantM, wantM)
|
|
}
|
|
|
|
// Duplicate key triggers error.
|
|
wantM = map[string]string{"a": "", "b": "B", "c": "C"}
|
|
wantErrorMsg := "cbor: found duplicate map key \"a\" at map element index 3"
|
|
dm, _ := DecOptions{DupMapKey: DupMapKeyEnforcedAPF}.DecMode()
|
|
var m2 map[string]string
|
|
if err := dm.Unmarshal(data, &m2); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error", data)
|
|
} else if _, ok := err.(*DupMapKeyError); !ok {
|
|
t.Errorf("Unmarshal(0x%x) returned wrong error type %T, want (*DupMapKeyError)", data, err)
|
|
} else if err.Error() != wantErrorMsg {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want error containing %q", data, err.Error(), wantErrorMsg)
|
|
}
|
|
if !reflect.DeepEqual(m2, wantM) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", data, m2, m2, wantM, wantM)
|
|
}
|
|
}
|
|
|
|
func TestStreamDupMapKeyToEmptyMap(t *testing.T) {
|
|
data := hexDecode("a6616161416162614261636143616161466164614461656145") // {"a": "A", "b": "B", "c": "C", "a": "F", "d": "D", "e": "E"}
|
|
|
|
var b []byte
|
|
for i := 0; i < 3; i++ {
|
|
b = append(b, data...)
|
|
}
|
|
|
|
// Duplicate key overwrites previous value (default).
|
|
wantM := map[string]string{"a": "F", "b": "B", "c": "C", "d": "D", "e": "E"}
|
|
dec := NewDecoder(bytes.NewReader(b))
|
|
for i := 0; i < 3; i++ {
|
|
var m1 map[string]string
|
|
if err := dec.Decode(&m1); err != nil {
|
|
t.Errorf("Decode() returned error %v", err)
|
|
}
|
|
if !reflect.DeepEqual(m1, wantM) {
|
|
t.Errorf("Decode() = %v (%T), want %v (%T)", m1, m1, wantM, wantM)
|
|
}
|
|
}
|
|
var v interface{}
|
|
if err := dec.Decode(&v); err != io.EOF {
|
|
t.Errorf("Decode() returned error %v, want %v", err, io.EOF)
|
|
}
|
|
|
|
// Duplicate key triggers error.
|
|
wantM = map[string]string{"a": "", "b": "B", "c": "C"}
|
|
wantErrorMsg := "cbor: found duplicate map key \"a\" at map element index 3"
|
|
dm, _ := DecOptions{DupMapKey: DupMapKeyEnforcedAPF}.DecMode()
|
|
dec = dm.NewDecoder(bytes.NewReader(b))
|
|
for i := 0; i < 3; i++ {
|
|
var m2 map[string]string
|
|
if err := dec.Decode(&m2); err == nil {
|
|
t.Errorf("Decode() didn't return an error")
|
|
} else if _, ok := err.(*DupMapKeyError); !ok {
|
|
t.Errorf("Decode() returned wrong error type %T, want (*DupMapKeyError)", err)
|
|
} else if err.Error() != wantErrorMsg {
|
|
t.Errorf("Decode() returned error %q, want error containing %q", err.Error(), wantErrorMsg)
|
|
}
|
|
if !reflect.DeepEqual(m2, wantM) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", data, m2, m2, wantM, wantM)
|
|
}
|
|
}
|
|
if err := dec.Decode(&v); err != io.EOF {
|
|
t.Errorf("Decode() returned error %v, want %v", err, io.EOF)
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalDupMapKeyToNotEmptyMap(t *testing.T) {
|
|
data := hexDecode("a6616161416162614261636143616161466164614461656145") // {"a": "A", "b": "B", "c": "C", "a": "F", "d": "D", "e": "E"}
|
|
|
|
// Duplicate key overwrites previous value (default).
|
|
m := map[string]string{"a": "Z", "b": "Z", "c": "Z", "d": "Z", "e": "Z", "f": "Z"}
|
|
wantM := map[string]string{"a": "F", "b": "B", "c": "C", "d": "D", "e": "E", "f": "Z"}
|
|
if err := Unmarshal(data, &m); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", data, err)
|
|
}
|
|
if !reflect.DeepEqual(m, wantM) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", data, m, m, wantM, wantM)
|
|
}
|
|
|
|
// Duplicate key triggers error.
|
|
m2 := map[string]string{"a": "Z", "b": "Z", "c": "Z", "d": "Z", "e": "Z", "f": "Z"}
|
|
wantM = map[string]string{"a": "", "b": "B", "c": "C", "d": "Z", "e": "Z", "f": "Z"}
|
|
wantErrorMsg := "cbor: found duplicate map key \"a\" at map element index 3"
|
|
dm, _ := DecOptions{DupMapKey: DupMapKeyEnforcedAPF}.DecMode()
|
|
if err := dm.Unmarshal(data, &m2); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error", data)
|
|
} else if _, ok := err.(*DupMapKeyError); !ok {
|
|
t.Errorf("Unmarshal(0x%x) returned wrong error type %T, want (*DupMapKeyError)", data, err)
|
|
} else if !strings.Contains(err.Error(), wantErrorMsg) {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want error containing %q", data, err.Error(), wantErrorMsg)
|
|
}
|
|
if !reflect.DeepEqual(m2, wantM) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", data, m2, m2, wantM, wantM)
|
|
}
|
|
}
|
|
|
|
func TestStreamDupMapKeyToNotEmptyMap(t *testing.T) {
|
|
data := hexDecode("a6616161416162614261636143616161466164614461656145") // {"a": "A", "b": "B", "c": "C", "a": "F", "d": "D", "e": "E"}
|
|
|
|
var b []byte
|
|
for i := 0; i < 3; i++ {
|
|
b = append(b, data...)
|
|
}
|
|
|
|
// Duplicate key overwrites previous value (default).
|
|
wantM := map[string]string{"a": "F", "b": "B", "c": "C", "d": "D", "e": "E", "f": "Z"}
|
|
dec := NewDecoder(bytes.NewReader(b))
|
|
for i := 0; i < 3; i++ {
|
|
m1 := map[string]string{"a": "Z", "b": "Z", "c": "Z", "d": "Z", "e": "Z", "f": "Z"}
|
|
if err := dec.Decode(&m1); err != nil {
|
|
t.Errorf("Decode() returned error %v", err)
|
|
}
|
|
if !reflect.DeepEqual(m1, wantM) {
|
|
t.Errorf("Decode() = %v (%T), want %v (%T)", m1, m1, wantM, wantM)
|
|
}
|
|
}
|
|
var v interface{}
|
|
if err := dec.Decode(&v); err != io.EOF {
|
|
t.Errorf("Decode() returned error %v, want %v", err, io.EOF)
|
|
}
|
|
|
|
// Duplicate key triggers error.
|
|
wantM = map[string]string{"a": "", "b": "B", "c": "C", "d": "Z", "e": "Z", "f": "Z"}
|
|
wantErrorMsg := "cbor: found duplicate map key \"a\" at map element index 3"
|
|
dm, _ := DecOptions{DupMapKey: DupMapKeyEnforcedAPF}.DecMode()
|
|
dec = dm.NewDecoder(bytes.NewReader(b))
|
|
for i := 0; i < 3; i++ {
|
|
m2 := map[string]string{"a": "Z", "b": "Z", "c": "Z", "d": "Z", "e": "Z", "f": "Z"}
|
|
if err := dec.Decode(&m2); err == nil {
|
|
t.Errorf("Decode() didn't return an error")
|
|
} else if _, ok := err.(*DupMapKeyError); !ok {
|
|
t.Errorf("Decode() returned wrong error type %T, want (*DupMapKeyError)", err)
|
|
} else if err.Error() != wantErrorMsg {
|
|
t.Errorf("Decode() returned error %q, want error containing %q", err.Error(), wantErrorMsg)
|
|
}
|
|
if !reflect.DeepEqual(m2, wantM) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", data, m2, m2, wantM, wantM)
|
|
}
|
|
}
|
|
if err := dec.Decode(&v); err != io.EOF {
|
|
t.Errorf("Decode() returned error %v, want %v", err, io.EOF)
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalDupMapKeyToStruct(t *testing.T) {
|
|
type s struct {
|
|
A string `cbor:"a"`
|
|
B string `cbor:"b"`
|
|
C string `cbor:"c"`
|
|
D string `cbor:"d"`
|
|
E string `cbor:"e"`
|
|
|
|
I string `cbor:"1,keyasint"`
|
|
}
|
|
|
|
for _, tc := range []struct {
|
|
name string
|
|
opts DecOptions
|
|
data []byte
|
|
want s
|
|
wantErr *DupMapKeyError
|
|
}{
|
|
{
|
|
name: "duplicate key does not overwrite previous value",
|
|
data: hexDecode("a6616161416162614261636143616161466164614461656145"), // {"a": "A", "b": "B", "c": "C", "a": "F", "d": "D", "e": "E"}
|
|
want: s{A: "A", B: "B", C: "C", D: "D", E: "E"},
|
|
},
|
|
{
|
|
name: "duplicate key triggers error",
|
|
opts: DecOptions{DupMapKey: DupMapKeyEnforcedAPF},
|
|
data: hexDecode("a6616161416162614261636143616161466164614461656145"), // {"a": "A", "b": "B", "c": "C", "a": "F", "d": "D", "e": "E"}
|
|
want: s{A: "A", B: "B", C: "C"},
|
|
wantErr: &DupMapKeyError{Key: "a", Index: 3},
|
|
},
|
|
{
|
|
name: "duplicate keys of comparable but disallowed cbor types skips remaining entries and returns error",
|
|
opts: DecOptions{DupMapKey: DupMapKeyEnforcedAPF},
|
|
data: hexDecode("a7616161416162614261636143d903e70100d903e701016164614461656145"), // {"a": "A", "b": "B", "c": "C", 999(1): 0, 999(1): 1, "d": "D", "e": "E"}
|
|
want: s{A: "A", B: "B", C: "C"},
|
|
wantErr: &DupMapKeyError{Key: Tag{Number: 999, Content: uint64(1)}, Index: 4},
|
|
},
|
|
{
|
|
name: "mixed-case duplicate key does not overwrite previous value",
|
|
data: hexDecode("a6616161416162614261636143614161466164614461656145"), // {"a": "A", "b": "B", "c": "C", "A": "F", "d": "D", "e": "E"}
|
|
want: s{A: "A", B: "B", C: "C", D: "D", E: "E"},
|
|
},
|
|
{
|
|
name: "mixed-case duplicate key triggers error",
|
|
opts: DecOptions{DupMapKey: DupMapKeyEnforcedAPF},
|
|
data: hexDecode("a6616161416162614261636143614161466164614461656145"), // {"a": "A", "b": "B", "c": "C", "A": "F", "d": "D", "e": "E"}
|
|
want: s{A: "A", B: "B", C: "C"},
|
|
wantErr: &DupMapKeyError{Key: "A", Index: 3},
|
|
},
|
|
{
|
|
name: "keyasint duplicate key does not overwrite previous value",
|
|
data: hexDecode("a36131616901614961616141"), // {"1": "i", 1: "I", "a": "A"}
|
|
want: s{I: "i", A: "A"},
|
|
},
|
|
{
|
|
name: "keyasint duplicate key triggers error",
|
|
opts: DecOptions{DupMapKey: DupMapKeyEnforcedAPF},
|
|
data: hexDecode("a36131616901614961616141"), // {"1": "i", 1: "I", "a": "A"}
|
|
want: s{I: "i"},
|
|
wantErr: &DupMapKeyError{Key: int64(1), Index: 1},
|
|
},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
dm, err := tc.opts.DecMode()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
var s1 s
|
|
if err := dm.Unmarshal(tc.data, &s1); err != nil {
|
|
if !reflect.DeepEqual(err, tc.wantErr) {
|
|
t.Errorf("got error: %v, wanted: %v", err, tc.wantErr)
|
|
}
|
|
} else {
|
|
if tc.wantErr != nil {
|
|
t.Errorf("got nil error, wanted: %v", tc.wantErr)
|
|
}
|
|
}
|
|
|
|
if !reflect.DeepEqual(s1, tc.want) {
|
|
t.Errorf("Unmarshal(0x%x) = %+v (%T), want %+v (%T)", tc.data, s1, s1, tc.want, tc.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestStreamDupMapKeyToStruct(t *testing.T) {
|
|
type s struct {
|
|
A string `cbor:"a"`
|
|
B string `cbor:"b"`
|
|
C string `cbor:"c"`
|
|
D string `cbor:"d"`
|
|
E string `cbor:"e"`
|
|
}
|
|
data := hexDecode("a6616161416162614261636143616161466164614461656145") // {"a": "A", "b": "B", "c": "C", "a": "F", "d": "D", "e": "E"}
|
|
|
|
var b []byte
|
|
for i := 0; i < 3; i++ {
|
|
b = append(b, data...)
|
|
}
|
|
|
|
// Duplicate key overwrites previous value (default).
|
|
wantS := s{A: "A", B: "B", C: "C", D: "D", E: "E"}
|
|
dec := NewDecoder(bytes.NewReader(b))
|
|
for i := 0; i < 3; i++ {
|
|
var s1 s
|
|
if err := dec.Decode(&s1); err != nil {
|
|
t.Errorf("Decode() returned error %v", err)
|
|
}
|
|
if !reflect.DeepEqual(s1, wantS) {
|
|
t.Errorf("Decode() = %v (%T), want %v (%T)", s1, s1, wantS, wantS)
|
|
}
|
|
}
|
|
var v interface{}
|
|
if err := dec.Decode(&v); err != io.EOF {
|
|
t.Errorf("Decode() returned error %v, want %v", err, io.EOF)
|
|
}
|
|
|
|
// Duplicate key triggers error.
|
|
wantS = s{A: "A", B: "B", C: "C"}
|
|
wantErrorMsg := "cbor: found duplicate map key \"a\" at map element index 3"
|
|
dm, _ := DecOptions{DupMapKey: DupMapKeyEnforcedAPF}.DecMode()
|
|
dec = dm.NewDecoder(bytes.NewReader(b))
|
|
for i := 0; i < 3; i++ {
|
|
var s2 s
|
|
if err := dec.Decode(&s2); err == nil {
|
|
t.Errorf("Decode() didn't return an error")
|
|
} else if _, ok := err.(*DupMapKeyError); !ok {
|
|
t.Errorf("Decode() returned wrong error type %T, want (*DupMapKeyError)", err)
|
|
} else if err.Error() != wantErrorMsg {
|
|
t.Errorf("Decode() returned error %q, want error containing %q", err.Error(), wantErrorMsg)
|
|
}
|
|
if !reflect.DeepEqual(s2, wantS) {
|
|
t.Errorf("Unmarshal(0x%x) = %+v (%T), want %+v (%T)", data, s2, s2, wantS, wantS)
|
|
}
|
|
}
|
|
if err := dec.Decode(&v); err != io.EOF {
|
|
t.Errorf("Decode() returned error %v, want %v", err, io.EOF)
|
|
}
|
|
}
|
|
|
|
// dupl map key is a struct field
|
|
func TestUnmarshalDupMapKeyToStructKeyAsInt(t *testing.T) {
|
|
type s struct {
|
|
A int `cbor:"1,keyasint"`
|
|
B int `cbor:"3,keyasint"`
|
|
C int `cbor:"5,keyasint"`
|
|
}
|
|
data := hexDecode("a40102030401030506") // {1:2, 3:4, 1:3, 5:6}
|
|
|
|
// Duplicate key doesn't overwrite previous value (default).
|
|
wantS := s{A: 2, B: 4, C: 6}
|
|
var s1 s
|
|
if err := Unmarshal(data, &s1); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", data, err)
|
|
}
|
|
if !reflect.DeepEqual(s1, wantS) {
|
|
t.Errorf("Unmarshal(0x%x) = %+v (%T), want %+v (%T)", data, s1, s1, wantS, wantS)
|
|
}
|
|
|
|
// Duplicate key triggers error.
|
|
wantS = s{A: 2, B: 4}
|
|
wantErrorMsg := "cbor: found duplicate map key \"1\" at map element index 2"
|
|
dm, _ := DecOptions{DupMapKey: DupMapKeyEnforcedAPF}.DecMode()
|
|
var s2 s
|
|
if err := dm.Unmarshal(data, &s2); err == nil {
|
|
t.Errorf("Unmarshal(0x%x, %s) didn't return an error", data, reflect.TypeOf(s2))
|
|
} else if _, ok := err.(*DupMapKeyError); !ok {
|
|
t.Errorf("Unmarshal(0x%x) returned wrong error type %T, want (*DupMapKeyError)", data, err)
|
|
} else if !strings.Contains(err.Error(), wantErrorMsg) {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want error containing %q", data, err.Error(), wantErrorMsg)
|
|
}
|
|
if !reflect.DeepEqual(s2, wantS) {
|
|
t.Errorf("Unmarshal(0x%x) = %+v (%T), want %+v (%T)", data, s2, s2, wantS, wantS)
|
|
}
|
|
}
|
|
|
|
func TestStreamDupMapKeyToStructKeyAsInt(t *testing.T) {
|
|
type s struct {
|
|
A int `cbor:"1,keyasint"`
|
|
B int `cbor:"3,keyasint"`
|
|
C int `cbor:"5,keyasint"`
|
|
}
|
|
data := hexDecode("a40102030401030506") // {1:2, 3:4, 1:3, 5:6}
|
|
|
|
var b []byte
|
|
for i := 0; i < 3; i++ {
|
|
b = append(b, data...)
|
|
}
|
|
|
|
// Duplicate key overwrites previous value (default).
|
|
wantS := s{A: 2, B: 4, C: 6}
|
|
dec := NewDecoder(bytes.NewReader(b))
|
|
for i := 0; i < 3; i++ {
|
|
var s1 s
|
|
if err := dec.Decode(&s1); err != nil {
|
|
t.Errorf("Decode() returned error %v", err)
|
|
}
|
|
if !reflect.DeepEqual(s1, wantS) {
|
|
t.Errorf("Decode() = %v (%T), want %v (%T)", s1, s1, wantS, wantS)
|
|
}
|
|
}
|
|
var v interface{}
|
|
if err := dec.Decode(&v); err != io.EOF {
|
|
t.Errorf("Decode() returned error %v, want %v", err, io.EOF)
|
|
}
|
|
|
|
// Duplicate key triggers error.
|
|
wantS = s{A: 2, B: 4}
|
|
wantErrorMsg := "cbor: found duplicate map key \"1\" at map element index 2"
|
|
dm, _ := DecOptions{DupMapKey: DupMapKeyEnforcedAPF}.DecMode()
|
|
dec = dm.NewDecoder(bytes.NewReader(b))
|
|
for i := 0; i < 3; i++ {
|
|
var s2 s
|
|
if err := dec.Decode(&s2); err == nil {
|
|
t.Errorf("Decode() didn't return an error")
|
|
} else if _, ok := err.(*DupMapKeyError); !ok {
|
|
t.Errorf("Decode() returned wrong error type %T, want (*DupMapKeyError)", err)
|
|
} else if err.Error() != wantErrorMsg {
|
|
t.Errorf("Decode() returned error %q, want error containing %q", err.Error(), wantErrorMsg)
|
|
}
|
|
if !reflect.DeepEqual(s2, wantS) {
|
|
t.Errorf("Unmarshal(0x%x) = %+v (%T), want %+v (%T)", data, s2, s2, wantS, wantS)
|
|
}
|
|
}
|
|
if err := dec.Decode(&v); err != io.EOF {
|
|
t.Errorf("Decode() returned error %v, want %v", err, io.EOF)
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalDupMapKeyToStructNoMatchingField(t *testing.T) {
|
|
type s struct {
|
|
B string `cbor:"b"`
|
|
C string `cbor:"c"`
|
|
D string `cbor:"d"`
|
|
E string `cbor:"e"`
|
|
}
|
|
data := hexDecode("a6616161416162614261636143616161466164614461656145") // {"a": "A", "b": "B", "c": "C", "a": "F", "d": "D", "e": "E"}
|
|
|
|
wantS := s{B: "B", C: "C", D: "D", E: "E"}
|
|
var s1 s
|
|
if err := Unmarshal(data, &s1); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", data, err)
|
|
}
|
|
if !reflect.DeepEqual(s1, wantS) {
|
|
t.Errorf("Unmarshal(0x%x) = %+v (%T), want %+v (%T)", data, s1, s1, wantS, wantS)
|
|
}
|
|
|
|
// Duplicate key triggers error even though map key "a" doesn't have a corresponding struct field.
|
|
wantS = s{B: "B", C: "C"}
|
|
wantErrorMsg := "cbor: found duplicate map key \"a\" at map element index 3"
|
|
dm, _ := DecOptions{DupMapKey: DupMapKeyEnforcedAPF}.DecMode()
|
|
var s2 s
|
|
if err := dm.Unmarshal(data, &s2); err == nil {
|
|
t.Errorf("Unmarshal(0x%x, %s) didn't return an error", data, reflect.TypeOf(s2))
|
|
} else if _, ok := err.(*DupMapKeyError); !ok {
|
|
t.Errorf("Unmarshal(0x%x) returned wrong error type %T, want (*DupMapKeyError)", data, err)
|
|
} else if !strings.Contains(err.Error(), wantErrorMsg) {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want error containing %q", data, err.Error(), wantErrorMsg)
|
|
}
|
|
if !reflect.DeepEqual(s2, wantS) {
|
|
t.Errorf("Unmarshal(0x%x) = %+v (%T), want %+v (%T)", data, s2, s2, wantS, wantS)
|
|
}
|
|
}
|
|
|
|
func TestStreamDupMapKeyToStructNoMatchingField(t *testing.T) {
|
|
type s struct {
|
|
B string `cbor:"b"`
|
|
C string `cbor:"c"`
|
|
D string `cbor:"d"`
|
|
E string `cbor:"e"`
|
|
}
|
|
data := hexDecode("a6616161416162614261636143616161466164614461656145") // {"a": "A", "b": "B", "c": "C", "a": "F", "d": "D", "e": "E"}
|
|
|
|
var b []byte
|
|
for i := 0; i < 3; i++ {
|
|
b = append(b, data...)
|
|
}
|
|
|
|
// Duplicate key overwrites previous value (default).
|
|
wantS := s{B: "B", C: "C", D: "D", E: "E"}
|
|
dec := NewDecoder(bytes.NewReader(b))
|
|
for i := 0; i < 3; i++ {
|
|
var s1 s
|
|
if err := dec.Decode(&s1); err != nil {
|
|
t.Errorf("Decode() returned error %v", err)
|
|
}
|
|
if !reflect.DeepEqual(s1, wantS) {
|
|
t.Errorf("Decode() = %v (%T), want %v (%T)", s1, s1, wantS, wantS)
|
|
}
|
|
}
|
|
var v interface{}
|
|
if err := dec.Decode(&v); err != io.EOF {
|
|
t.Errorf("Decode() returned error %v, want %v", err, io.EOF)
|
|
}
|
|
|
|
// Duplicate key triggers error.
|
|
wantS = s{B: "B", C: "C"}
|
|
wantErrorMsg := "cbor: found duplicate map key \"a\" at map element index 3"
|
|
dm, _ := DecOptions{DupMapKey: DupMapKeyEnforcedAPF}.DecMode()
|
|
dec = dm.NewDecoder(bytes.NewReader(b))
|
|
for i := 0; i < 3; i++ {
|
|
var s2 s
|
|
if err := dec.Decode(&s2); err == nil {
|
|
t.Errorf("Decode() didn't return an error")
|
|
} else if _, ok := err.(*DupMapKeyError); !ok {
|
|
t.Errorf("Decode() returned wrong error type %T, want (*DupMapKeyError)", err)
|
|
} else if err.Error() != wantErrorMsg {
|
|
t.Errorf("Decode() returned error %q, want error containing %q", err.Error(), wantErrorMsg)
|
|
}
|
|
if !reflect.DeepEqual(s2, wantS) {
|
|
t.Errorf("Decode() = %v (%T), want %v (%T)", s2, s2, wantS, wantS)
|
|
}
|
|
}
|
|
if err := dec.Decode(&v); err != io.EOF {
|
|
t.Errorf("Decode() returned error %v, want %v", err, io.EOF)
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalDupMapKeyToStructKeyAsIntNoMatchingField(t *testing.T) {
|
|
type s struct {
|
|
B int `cbor:"3,keyasint"`
|
|
C int `cbor:"5,keyasint"`
|
|
}
|
|
data := hexDecode("a40102030401030506") // {1:2, 3:4, 1:3, 5:6}
|
|
|
|
wantS := s{B: 4, C: 6}
|
|
var s1 s
|
|
if err := Unmarshal(data, &s1); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", data, err)
|
|
}
|
|
if !reflect.DeepEqual(s1, wantS) {
|
|
t.Errorf("Unmarshal(0x%x) = %+v (%T), want %+v (%T)", data, s1, s1, wantS, wantS)
|
|
}
|
|
|
|
// Duplicate key triggers error even though map key "a" doesn't have a corresponding struct field.
|
|
wantS = s{B: 4}
|
|
wantErrorMsg := "cbor: found duplicate map key \"1\" at map element index 2"
|
|
dm, _ := DecOptions{DupMapKey: DupMapKeyEnforcedAPF}.DecMode()
|
|
var s2 s
|
|
if err := dm.Unmarshal(data, &s2); err == nil {
|
|
t.Errorf("Unmarshal(0x%x, %s) didn't return an error", data, reflect.TypeOf(s2))
|
|
} else if _, ok := err.(*DupMapKeyError); !ok {
|
|
t.Errorf("Unmarshal(0x%x) returned wrong error type %T, want (*DupMapKeyError)", data, err)
|
|
} else if !strings.Contains(err.Error(), wantErrorMsg) {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want error containing %q", data, err.Error(), wantErrorMsg)
|
|
}
|
|
if !reflect.DeepEqual(s2, wantS) {
|
|
t.Errorf("Unmarshal(0x%x) = %+v (%T), want %+v (%T)", data, s2, s2, wantS, wantS)
|
|
}
|
|
}
|
|
|
|
func TestStreamDupMapKeyToStructKeyAsIntNoMatchingField(t *testing.T) {
|
|
type s struct {
|
|
B int `cbor:"3,keyasint"`
|
|
C int `cbor:"5,keyasint"`
|
|
}
|
|
data := hexDecode("a40102030401030506") // {1:2, 3:4, 1:3, 5:6}
|
|
|
|
var b []byte
|
|
for i := 0; i < 3; i++ {
|
|
b = append(b, data...)
|
|
}
|
|
|
|
// Duplicate key overwrites previous value (default).
|
|
wantS := s{B: 4, C: 6}
|
|
dec := NewDecoder(bytes.NewReader(b))
|
|
for i := 0; i < 3; i++ {
|
|
var s1 s
|
|
if err := dec.Decode(&s1); err != nil {
|
|
t.Errorf("Decode() returned error %v", err)
|
|
}
|
|
if !reflect.DeepEqual(s1, wantS) {
|
|
t.Errorf("Decode() = %v (%T), want %v (%T)", s1, s1, wantS, wantS)
|
|
}
|
|
}
|
|
var v interface{}
|
|
if err := dec.Decode(&v); err != io.EOF {
|
|
t.Errorf("Decode() returned error %v, want %v", err, io.EOF)
|
|
}
|
|
|
|
// Duplicate key triggers error.
|
|
wantS = s{B: 4}
|
|
wantErrorMsg := "cbor: found duplicate map key \"1\" at map element index 2"
|
|
dm, _ := DecOptions{DupMapKey: DupMapKeyEnforcedAPF}.DecMode()
|
|
dec = dm.NewDecoder(bytes.NewReader(b))
|
|
for i := 0; i < 3; i++ {
|
|
var s2 s
|
|
if err := dec.Decode(&s2); err == nil {
|
|
t.Errorf("Decode() didn't return an error")
|
|
} else if _, ok := err.(*DupMapKeyError); !ok {
|
|
t.Errorf("Decode() returned wrong error type %T, want (*DupMapKeyError)", err)
|
|
} else if err.Error() != wantErrorMsg {
|
|
t.Errorf("Decode() returned error %q, want error containing %q", err.Error(), wantErrorMsg)
|
|
}
|
|
if !reflect.DeepEqual(s2, wantS) {
|
|
t.Errorf("Decode() = %v (%T), want %v (%T)", s2, s2, wantS, wantS)
|
|
}
|
|
}
|
|
if err := dec.Decode(&v); err != io.EOF {
|
|
t.Errorf("Decode() returned error %v, want %v", err, io.EOF)
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalDupMapKeyToStructWrongType(t *testing.T) {
|
|
type s struct {
|
|
A string `cbor:"a"`
|
|
B string `cbor:"b"`
|
|
C string `cbor:"c"`
|
|
D string `cbor:"d"`
|
|
E string `cbor:"e"`
|
|
}
|
|
data := hexDecode("a861616141fa47c35000026162614261636143fa47c3500003616161466164614461656145") // {"a": "A", 100000.0:2, "b": "B", "c": "C", 100000.0:3, "a": "F", "d": "D", "e": "E"}
|
|
|
|
var s1 s
|
|
wantS := s{A: "A", B: "B", C: "C", D: "D", E: "E"}
|
|
wantErrorMsg := "cbor: cannot unmarshal"
|
|
if err := Unmarshal(data, &s1); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error", data)
|
|
} else if _, ok := err.(*UnmarshalTypeError); !ok {
|
|
t.Errorf("Unmarshal(0x%x) returned wrong error type %T, want (*UnmarshalTypeError)", data, err)
|
|
} else if !strings.Contains(err.Error(), wantErrorMsg) {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want error containing %q", data, err.Error(), wantErrorMsg)
|
|
}
|
|
if !reflect.DeepEqual(s1, wantS) {
|
|
t.Errorf("Unmarshal(0x%x) = %+v (%T), want %+v (%T)", data, s1, s1, wantS, wantS)
|
|
}
|
|
|
|
wantS = s{A: "A", B: "B", C: "C"}
|
|
wantErrorMsg = "cbor: found duplicate map key \"100000\" at map element index 4"
|
|
dm, _ := DecOptions{DupMapKey: DupMapKeyEnforcedAPF}.DecMode()
|
|
var s2 s
|
|
if err := dm.Unmarshal(data, &s2); err == nil {
|
|
t.Errorf("Unmarshal(0x%x, %s) didn't return an error", data, reflect.TypeOf(s2))
|
|
} else if _, ok := err.(*DupMapKeyError); !ok {
|
|
t.Errorf("Unmarshal(0x%x) returned wrong error type %T, want (*DupMapKeyError)", data, err)
|
|
} else if !strings.Contains(err.Error(), wantErrorMsg) {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want error containing %q", data, err.Error(), wantErrorMsg)
|
|
}
|
|
if !reflect.DeepEqual(s2, wantS) {
|
|
t.Errorf("Unmarshal(0x%x) = %+v (%T), want %+v (%T)", data, s2, s2, wantS, wantS)
|
|
}
|
|
}
|
|
|
|
func TestStreamDupMapKeyToStructWrongType(t *testing.T) {
|
|
type s struct {
|
|
A string `cbor:"a"`
|
|
B string `cbor:"b"`
|
|
C string `cbor:"c"`
|
|
D string `cbor:"d"`
|
|
E string `cbor:"e"`
|
|
}
|
|
data := hexDecode("a861616141fa47c35000026162614261636143fa47c3500003616161466164614461656145") // {"a": "A", 100000.0:2, "b": "B", "c": "C", 100000.0:3, "a": "F", "d": "D", "e": "E"}
|
|
|
|
var b []byte
|
|
for i := 0; i < 3; i++ {
|
|
b = append(b, data...)
|
|
}
|
|
|
|
wantS := s{A: "A", B: "B", C: "C", D: "D", E: "E"}
|
|
wantErrorMsg := "cbor: cannot unmarshal"
|
|
dec := NewDecoder(bytes.NewReader(b))
|
|
for i := 0; i < 3; i++ {
|
|
var s1 s
|
|
if err := dec.Decode(&s1); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error", data)
|
|
} else if _, ok := err.(*UnmarshalTypeError); !ok {
|
|
t.Errorf("Unmarshal(0x%x) returned wrong error type %T, want (*UnmarshalTypeError)", data, err)
|
|
} else if !strings.Contains(err.Error(), wantErrorMsg) {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want error containing %q", data, err.Error(), wantErrorMsg)
|
|
}
|
|
if !reflect.DeepEqual(s1, wantS) {
|
|
t.Errorf("Unmarshal(0x%x) = %+v (%T), want %+v (%T)", data, s1, s1, wantS, wantS)
|
|
}
|
|
}
|
|
var v interface{}
|
|
if err := dec.Decode(&v); err != io.EOF {
|
|
t.Errorf("Decode() returned error %v, want %v", err, io.EOF)
|
|
}
|
|
|
|
// Duplicate key triggers error.
|
|
wantS = s{A: "A", B: "B", C: "C"}
|
|
wantErrorMsg = "cbor: found duplicate map key \"100000\" at map element index 4"
|
|
dm, _ := DecOptions{DupMapKey: DupMapKeyEnforcedAPF}.DecMode()
|
|
dec = dm.NewDecoder(bytes.NewReader(b))
|
|
for i := 0; i < 3; i++ {
|
|
var s2 s
|
|
if err := dec.Decode(&s2); err == nil {
|
|
t.Errorf("Decode() didn't return an error")
|
|
} else if _, ok := err.(*DupMapKeyError); !ok {
|
|
t.Errorf("Decode() returned wrong error type %T, want (*DupMapKeyError)", err)
|
|
} else if err.Error() != wantErrorMsg {
|
|
t.Errorf("Decode() returned error %q, want error containing %q", err.Error(), wantErrorMsg)
|
|
}
|
|
if !reflect.DeepEqual(s2, wantS) {
|
|
t.Errorf("Unmarshal(0x%x) = %+v (%T), want %+v (%T)", data, s2, s2, wantS, wantS)
|
|
}
|
|
}
|
|
if err := dec.Decode(&v); err != io.EOF {
|
|
t.Errorf("Decode() returned error %v, want %v", err, io.EOF)
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalDupMapKeyToStructStringParseError(t *testing.T) {
|
|
type s struct {
|
|
A string `cbor:"a"`
|
|
B string `cbor:"b"`
|
|
C string `cbor:"c"`
|
|
D string `cbor:"d"`
|
|
E string `cbor:"e"`
|
|
}
|
|
data := hexDecode("a661fe6141616261426163614361fe61466164614461656145") // {"\xFE": "A", "b": "B", "c": "C", "\xFE": "F", "d": "D", "e": "E"}
|
|
wantS := s{A: "", B: "B", C: "C", D: "D", E: "E"}
|
|
wantErrorMsg := "cbor: invalid UTF-8 string"
|
|
|
|
// Duplicate key doesn't overwrite previous value (default).
|
|
var s1 s
|
|
if err := Unmarshal(data, &s1); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error", data)
|
|
} else if _, ok := err.(*SemanticError); !ok {
|
|
t.Errorf("Unmarshal(0x%x) returned wrong error type %T, want (*SemanticError)", data, err)
|
|
} else if !strings.Contains(err.Error(), wantErrorMsg) {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want error containing %q", data, err.Error(), wantErrorMsg)
|
|
}
|
|
if !reflect.DeepEqual(s1, wantS) {
|
|
t.Errorf("Unmarshal(0x%x) = %+v (%T), want %+v (%T)", data, s1, s1, wantS, wantS)
|
|
}
|
|
|
|
// Duplicate key triggers error.
|
|
dm, _ := DecOptions{DupMapKey: DupMapKeyEnforcedAPF}.DecMode()
|
|
var s2 s
|
|
if err := dm.Unmarshal(data, &s2); err == nil {
|
|
t.Errorf("Unmarshal(0x%x, %s) didn't return an error", data, reflect.TypeOf(s2))
|
|
} else if _, ok := err.(*SemanticError); !ok {
|
|
t.Errorf("Unmarshal(0x%x) returned wrong error type %T, want (*SemanticError)", data, err)
|
|
} else if !strings.Contains(err.Error(), wantErrorMsg) {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want error containing %q", data, err.Error(), wantErrorMsg)
|
|
}
|
|
if !reflect.DeepEqual(s2, wantS) {
|
|
t.Errorf("Unmarshal(0x%x) = %+v (%T), want %+v (%T)", data, s2, s2, wantS, wantS)
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalDupMapKeyToStructIntParseError(t *testing.T) {
|
|
type s struct {
|
|
A int `cbor:"1,keyasint"`
|
|
B int `cbor:"3,keyasint"`
|
|
C int `cbor:"5,keyasint"`
|
|
}
|
|
data := hexDecode("a43bffffffffffffffff0203043bffffffffffffffff030506") // {-18446744073709551616:2, 3:4, -18446744073709551616:3, 5:6}
|
|
|
|
// Duplicate key doesn't overwrite previous value (default).
|
|
wantS := s{B: 4, C: 6}
|
|
wantErrorMsg := "cbor: cannot unmarshal"
|
|
var s1 s
|
|
if err := Unmarshal(data, &s1); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error", data)
|
|
} else if _, ok := err.(*UnmarshalTypeError); !ok {
|
|
t.Errorf("Unmarshal(0x%x) returned wrong error type %T, want (*UnmarshalTypeError)", data, err)
|
|
} else if !strings.Contains(err.Error(), wantErrorMsg) {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want error containing %q", data, err.Error(), wantErrorMsg)
|
|
}
|
|
if !reflect.DeepEqual(s1, wantS) {
|
|
t.Errorf("Unmarshal(0x%x) = %+v (%T), want %+v (%T)", data, s1, s1, wantS, wantS)
|
|
}
|
|
|
|
// Duplicate key triggers error.
|
|
dm, _ := DecOptions{DupMapKey: DupMapKeyEnforcedAPF}.DecMode()
|
|
var s2 s
|
|
if err := dm.Unmarshal(data, &s2); err == nil {
|
|
t.Errorf("Unmarshal(0x%x, %s) didn't return an error", data, reflect.TypeOf(s2))
|
|
} else if _, ok := err.(*UnmarshalTypeError); !ok {
|
|
t.Errorf("Unmarshal(0x%x) returned wrong error type %T, want (*UnmarshalTypeError)", data, err)
|
|
} else if !strings.Contains(err.Error(), wantErrorMsg) {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want error containing %q", data, err.Error(), wantErrorMsg)
|
|
}
|
|
if !reflect.DeepEqual(s2, wantS) {
|
|
t.Errorf("Unmarshal(0x%x) = %+v (%T), want %+v (%T)", data, s2, s2, wantS, wantS)
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalDupMapKeyToStructWrongTypeParseError(t *testing.T) {
|
|
type s struct {
|
|
A string `cbor:"a"`
|
|
B string `cbor:"b"`
|
|
C string `cbor:"c"`
|
|
D string `cbor:"d"`
|
|
E string `cbor:"e"`
|
|
}
|
|
data := hexDecode("a68161fe614161626142616361438161fe61466164614461656145") // {["\xFE"]: "A", "b": "B", "c": "C", ["\xFE"]: "F", "d": "D", "e": "E"}
|
|
|
|
// Duplicate key doesn't overwrite previous value (default).
|
|
wantS := s{A: "", B: "B", C: "C", D: "D", E: "E"}
|
|
wantErrorMsg := "cbor: cannot unmarshal"
|
|
var s1 s
|
|
if err := Unmarshal(data, &s1); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error", data)
|
|
} else if _, ok := err.(*UnmarshalTypeError); !ok {
|
|
t.Errorf("Unmarshal(0x%x) returned wrong error type %T, want (*UnmarshalTypeError)", data, err)
|
|
} else if !strings.Contains(err.Error(), wantErrorMsg) {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want error containing %q", data, err.Error(), wantErrorMsg)
|
|
}
|
|
if !reflect.DeepEqual(s1, wantS) {
|
|
t.Errorf("Unmarshal(0x%x) = %+v (%T), want %+v (%T)", data, s1, s1, wantS, wantS)
|
|
}
|
|
|
|
// Duplicate key triggers error.
|
|
dm, _ := DecOptions{DupMapKey: DupMapKeyEnforcedAPF}.DecMode()
|
|
var s2 s
|
|
if err := dm.Unmarshal(data, &s2); err == nil {
|
|
t.Errorf("Unmarshal(0x%x, %s) didn't return an error", data, reflect.TypeOf(s2))
|
|
} else if _, ok := err.(*UnmarshalTypeError); !ok {
|
|
t.Errorf("Unmarshal(0x%x) returned wrong error type %T, want (*UnmarshalTypeError)", data, err)
|
|
} else if !strings.Contains(err.Error(), wantErrorMsg) {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want error containing %q", data, err.Error(), wantErrorMsg)
|
|
}
|
|
if !reflect.DeepEqual(s2, wantS) {
|
|
t.Errorf("Unmarshal(0x%x) = %+v (%T), want %+v (%T)", data, s2, s2, wantS, wantS)
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalDupMapKeyToStructWrongTypeUnhashableError(t *testing.T) {
|
|
type s struct {
|
|
A string `cbor:"a"`
|
|
B string `cbor:"b"`
|
|
C string `cbor:"c"`
|
|
D string `cbor:"d"`
|
|
E string `cbor:"e"`
|
|
}
|
|
data := hexDecode("a6810061416162614261636143810061466164614461656145") // {[0]: "A", "b": "B", "c": "C", [0]: "F", "d": "D", "e": "E"}
|
|
wantS := s{A: "", B: "B", C: "C", D: "D", E: "E"}
|
|
|
|
// Duplicate key doesn't overwrite previous value (default).
|
|
wantErrorMsg := "cbor: cannot unmarshal"
|
|
var s1 s
|
|
if err := Unmarshal(data, &s1); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error", data)
|
|
} else if _, ok := err.(*UnmarshalTypeError); !ok {
|
|
t.Errorf("Unmarshal(0x%x) returned wrong error type %T, want (*UnmarshalTypeError)", data, err)
|
|
} else if !strings.Contains(err.Error(), wantErrorMsg) {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want error containing %q", data, err.Error(), wantErrorMsg)
|
|
}
|
|
if !reflect.DeepEqual(s1, wantS) {
|
|
t.Errorf("Unmarshal(0x%x) = %+v (%T), want %+v (%T)", data, s1, s1, wantS, wantS)
|
|
}
|
|
|
|
// Duplicate key triggers error.
|
|
dm, _ := DecOptions{DupMapKey: DupMapKeyEnforcedAPF}.DecMode()
|
|
var s2 s
|
|
if err := dm.Unmarshal(data, &s2); err == nil {
|
|
t.Errorf("Unmarshal(0x%x, %s) didn't return an error", data, reflect.TypeOf(s2))
|
|
} else if _, ok := err.(*UnmarshalTypeError); !ok {
|
|
t.Errorf("Unmarshal(0x%x) returned wrong error type %T, want (*UnmarshalTypeError)", data, err)
|
|
} else if !strings.Contains(err.Error(), wantErrorMsg) {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want error containing %q", data, err.Error(), wantErrorMsg)
|
|
}
|
|
if !reflect.DeepEqual(s2, wantS) {
|
|
t.Errorf("Unmarshal(0x%x) = %+v (%T), want %+v (%T)", data, s2, s2, wantS, wantS)
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalDupMapKeyToStructTagTypeError(t *testing.T) {
|
|
type s struct {
|
|
A string `cbor:"a"`
|
|
B string `cbor:"b"`
|
|
C string `cbor:"c"`
|
|
D string `cbor:"d"`
|
|
E string `cbor:"e"`
|
|
}
|
|
data := hexDecode("a6c24901000000000000000061416162614261636143c24901000000000000000061466164614461656145") // {bignum(18446744073709551616): "A", "b": "B", "c": "C", bignum(18446744073709551616): "F", "d": "D", "e": "E"}
|
|
wantS := s{A: "", B: "B", C: "C", D: "D", E: "E"}
|
|
|
|
// Duplicate key doesn't overwrite previous value (default).
|
|
wantErrorMsg := "cbor: cannot unmarshal"
|
|
var s1 s
|
|
if err := Unmarshal(data, &s1); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error", data)
|
|
} else if _, ok := err.(*UnmarshalTypeError); !ok {
|
|
t.Errorf("Unmarshal(0x%x) returned wrong error type %T, want (*UnmarshalTypeError)", data, err)
|
|
} else if !strings.Contains(err.Error(), wantErrorMsg) {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want error containing %q", data, err.Error(), wantErrorMsg)
|
|
}
|
|
if !reflect.DeepEqual(s1, wantS) {
|
|
t.Errorf("Unmarshal(0x%x) = %+v (%T), want %+v (%T)", data, s1, s1, wantS, wantS)
|
|
}
|
|
|
|
// Duplicate key triggers error.
|
|
dm, _ := DecOptions{DupMapKey: DupMapKeyEnforcedAPF}.DecMode()
|
|
var s2 s
|
|
if err := dm.Unmarshal(data, &s2); err == nil {
|
|
t.Errorf("Unmarshal(0x%x, %s) didn't return an error", data, reflect.TypeOf(s2))
|
|
} else if _, ok := err.(*UnmarshalTypeError); !ok {
|
|
t.Errorf("Unmarshal(0x%x) returned wrong error type %T, want (*UnmarshalTypeError)", data, err)
|
|
} else if !strings.Contains(err.Error(), wantErrorMsg) {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want error containing %q", data, err.Error(), wantErrorMsg)
|
|
}
|
|
if !reflect.DeepEqual(s2, wantS) {
|
|
t.Errorf("Unmarshal(0x%x) = %+v (%T), want %+v (%T)", data, s2, s2, wantS, wantS)
|
|
}
|
|
}
|
|
|
|
func TestIndefiniteLengthArrayToArray(t *testing.T) {
|
|
testCases := []struct {
|
|
name string
|
|
data []byte
|
|
wantV interface{}
|
|
}{
|
|
{
|
|
name: "CBOR empty array to Go 5 elem array",
|
|
data: hexDecode("9fff"),
|
|
wantV: [5]byte{},
|
|
},
|
|
{
|
|
name: "CBOR 3 elem array to Go 5 elem array",
|
|
data: hexDecode("9f010203ff"),
|
|
wantV: [5]byte{1, 2, 3, 0, 0},
|
|
},
|
|
{
|
|
name: "CBOR 10 elem array to Go 5 elem array",
|
|
data: hexDecode("9f0102030405060708090aff"),
|
|
wantV: [5]byte{1, 2, 3, 4, 5},
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
v := reflect.New(reflect.TypeOf(tc.wantV))
|
|
if err := Unmarshal(tc.data, v.Interface()); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", tc.data, err)
|
|
}
|
|
if !reflect.DeepEqual(v.Elem().Interface(), tc.wantV) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", tc.data, v.Elem().Interface(), v.Elem().Interface(), tc.wantV, tc.wantV)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestExceedMaxArrayElements(t *testing.T) {
|
|
testCases := []struct {
|
|
name string
|
|
opts DecOptions
|
|
data []byte
|
|
wantErrorMsg string
|
|
}{
|
|
{
|
|
name: "array",
|
|
opts: DecOptions{MaxArrayElements: 16},
|
|
data: hexDecode("910101010101010101010101010101010101"),
|
|
wantErrorMsg: "cbor: exceeded max number of elements 16 for CBOR array",
|
|
},
|
|
{
|
|
name: "indefinite length array",
|
|
opts: DecOptions{MaxArrayElements: 16},
|
|
data: hexDecode("9f0101010101010101010101010101010101ff"),
|
|
wantErrorMsg: "cbor: exceeded max number of elements 16 for CBOR array",
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
dm, _ := tc.opts.DecMode()
|
|
var v interface{}
|
|
if err := dm.Unmarshal(tc.data, &v); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error", tc.data)
|
|
} else if err.Error() != tc.wantErrorMsg {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want %q", tc.data, err.Error(), tc.wantErrorMsg)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestExceedMaxMapPairs(t *testing.T) {
|
|
testCases := []struct {
|
|
name string
|
|
opts DecOptions
|
|
data []byte
|
|
wantErrorMsg string
|
|
}{
|
|
{
|
|
name: "array",
|
|
opts: DecOptions{MaxMapPairs: 16},
|
|
data: hexDecode("b101010101010101010101010101010101010101010101010101010101010101010101"),
|
|
wantErrorMsg: "cbor: exceeded max number of key-value pairs 16 for CBOR map",
|
|
},
|
|
{
|
|
name: "indefinite length array",
|
|
opts: DecOptions{MaxMapPairs: 16},
|
|
data: hexDecode("bf01010101010101010101010101010101010101010101010101010101010101010101ff"),
|
|
wantErrorMsg: "cbor: exceeded max number of key-value pairs 16 for CBOR map",
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
dm, _ := tc.opts.DecMode()
|
|
var v interface{}
|
|
if err := dm.Unmarshal(tc.data, &v); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error", tc.data)
|
|
} else if err.Error() != tc.wantErrorMsg {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want %q", tc.data, err.Error(), tc.wantErrorMsg)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDecIndefiniteLengthOption(t *testing.T) {
|
|
testCases := []struct {
|
|
name string
|
|
opts DecOptions
|
|
data []byte
|
|
wantErrorMsg string
|
|
}{
|
|
{
|
|
name: "byte string",
|
|
opts: DecOptions{IndefLength: IndefLengthForbidden},
|
|
data: hexDecode("5fff"),
|
|
wantErrorMsg: "cbor: indefinite-length byte string isn't allowed",
|
|
},
|
|
{
|
|
name: "text string",
|
|
opts: DecOptions{IndefLength: IndefLengthForbidden},
|
|
data: hexDecode("7fff"),
|
|
wantErrorMsg: "cbor: indefinite-length UTF-8 text string isn't allowed",
|
|
},
|
|
{
|
|
name: "array",
|
|
opts: DecOptions{IndefLength: IndefLengthForbidden},
|
|
data: hexDecode("9fff"),
|
|
wantErrorMsg: "cbor: indefinite-length array isn't allowed",
|
|
},
|
|
{
|
|
name: "indefinite length array",
|
|
opts: DecOptions{IndefLength: IndefLengthForbidden},
|
|
data: hexDecode("bfff"),
|
|
wantErrorMsg: "cbor: indefinite-length map isn't allowed",
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
// Default option allows indefinite length items
|
|
var v interface{}
|
|
if err := Unmarshal(tc.data, &v); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned an error %v", tc.data, err)
|
|
}
|
|
|
|
dm, _ := tc.opts.DecMode()
|
|
if err := dm.Unmarshal(tc.data, &v); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error", tc.data)
|
|
} else if err.Error() != tc.wantErrorMsg {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want %q", tc.data, err.Error(), tc.wantErrorMsg)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDecTagsMdOption(t *testing.T) {
|
|
data := hexDecode("c074323031332d30332d32315432303a30343a30305a")
|
|
wantErrorMsg := "cbor: CBOR tag isn't allowed"
|
|
|
|
// Default option allows CBOR tags
|
|
var v interface{}
|
|
if err := Unmarshal(data, &v); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned an error %v", data, err)
|
|
}
|
|
|
|
// Decoding CBOR tags with TagsForbidden option returns error
|
|
dm, _ := DecOptions{TagsMd: TagsForbidden}.DecMode()
|
|
if err := dm.Unmarshal(data, &v); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error", data)
|
|
} else if err.Error() != wantErrorMsg {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want %q", data, err.Error(), wantErrorMsg)
|
|
}
|
|
|
|
// Create DecMode with TagSet and TagsForbidden option returns error
|
|
wantErrorMsg = "cbor: cannot create DecMode with TagSet when TagsMd is TagsForbidden"
|
|
tags := NewTagSet()
|
|
_, err := DecOptions{TagsMd: TagsForbidden}.DecModeWithTags(tags)
|
|
if err == nil {
|
|
t.Errorf("DecModeWithTags() didn't return an error")
|
|
} else if err.Error() != wantErrorMsg {
|
|
t.Errorf("DecModeWithTags() returned error %q, want %q", err.Error(), wantErrorMsg)
|
|
}
|
|
_, err = DecOptions{TagsMd: TagsForbidden}.DecModeWithSharedTags(tags)
|
|
if err == nil {
|
|
t.Errorf("DecModeWithSharedTags() didn't return an error")
|
|
} else if err.Error() != wantErrorMsg {
|
|
t.Errorf("DecModeWithSharedTags() returned error %q, want %q", err.Error(), wantErrorMsg)
|
|
}
|
|
}
|
|
|
|
func TestDecModeInvalidIntDec(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
name string
|
|
opts DecOptions
|
|
wantErrorMsg string
|
|
}{
|
|
{
|
|
name: "below range of valid modes",
|
|
opts: DecOptions{IntDec: -1},
|
|
wantErrorMsg: "cbor: invalid IntDec -1",
|
|
},
|
|
{
|
|
name: "above range of valid modes",
|
|
opts: DecOptions{IntDec: 101},
|
|
wantErrorMsg: "cbor: invalid IntDec 101",
|
|
},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
_, err := tc.opts.DecMode()
|
|
if err == nil {
|
|
t.Errorf("DecMode() didn't return an error")
|
|
} else if err.Error() != tc.wantErrorMsg {
|
|
t.Errorf("DecMode() returned error %q, want %q", err.Error(), tc.wantErrorMsg)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestIntDecConvertNone(t *testing.T) {
|
|
dm, err := DecOptions{
|
|
IntDec: IntDecConvertNone,
|
|
BigIntDec: BigIntDecodePointer,
|
|
}.DecMode()
|
|
if err != nil {
|
|
t.Errorf("DecMode() returned an error %+v", err)
|
|
}
|
|
|
|
testCases := []struct {
|
|
name string
|
|
data []byte
|
|
wantObj interface{}
|
|
}{
|
|
{
|
|
name: "CBOR pos int",
|
|
data: hexDecode("1a000f4240"),
|
|
wantObj: uint64(1000000),
|
|
},
|
|
{
|
|
name: "CBOR pos int overflows int64",
|
|
data: hexDecode("1b8000000000000000"), // math.MaxInt64+1
|
|
wantObj: uint64(math.MaxInt64 + 1),
|
|
},
|
|
{
|
|
name: "CBOR neg int",
|
|
data: hexDecode("3903e7"),
|
|
wantObj: int64(-1000),
|
|
},
|
|
{
|
|
name: "CBOR neg int overflows int64",
|
|
data: hexDecode("3b8000000000000000"), // math.MinInt64-1
|
|
wantObj: new(big.Int).Sub(big.NewInt(math.MinInt64), big.NewInt(1)),
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
var v interface{}
|
|
err := dm.Unmarshal(tc.data, &v)
|
|
if err == nil {
|
|
if !reflect.DeepEqual(v, tc.wantObj) {
|
|
t.Errorf("Unmarshal(0x%x) return %v (%T), want %v (%T)", tc.data, v, v, tc.wantObj, tc.wantObj)
|
|
}
|
|
} else {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q", tc.data, err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestIntDecConvertSigned(t *testing.T) {
|
|
dm, err := DecOptions{
|
|
IntDec: IntDecConvertSigned,
|
|
BigIntDec: BigIntDecodePointer,
|
|
}.DecMode()
|
|
if err != nil {
|
|
t.Errorf("DecMode() returned an error %+v", err)
|
|
}
|
|
|
|
testCases := []struct {
|
|
name string
|
|
data []byte
|
|
wantObj interface{}
|
|
wantErrorMsg string
|
|
}{
|
|
{
|
|
name: "CBOR pos int",
|
|
data: hexDecode("1a000f4240"),
|
|
wantObj: int64(1000000),
|
|
},
|
|
{
|
|
name: "CBOR pos int overflows int64",
|
|
data: hexDecode("1b8000000000000000"), // math.MaxInt64+1
|
|
wantErrorMsg: "9223372036854775808 overflows Go's int64",
|
|
},
|
|
{
|
|
name: "CBOR neg int",
|
|
data: hexDecode("3903e7"),
|
|
wantObj: int64(-1000),
|
|
},
|
|
{
|
|
name: "CBOR neg int overflows int64",
|
|
data: hexDecode("3b8000000000000000"), // math.MinInt64-1
|
|
wantObj: new(big.Int).Sub(big.NewInt(math.MinInt64), big.NewInt(1)),
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
var v interface{}
|
|
err := dm.Unmarshal(tc.data, &v)
|
|
if err == nil {
|
|
if tc.wantErrorMsg != "" {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error, want %q", tc.data, tc.wantErrorMsg)
|
|
} else if !reflect.DeepEqual(v, tc.wantObj) {
|
|
t.Errorf("Unmarshal(0x%x) return %v (%T), want %v (%T)", tc.data, v, v, tc.wantObj, tc.wantObj)
|
|
}
|
|
} else {
|
|
if tc.wantErrorMsg == "" {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q", tc.data, err)
|
|
} else if !strings.Contains(err.Error(), tc.wantErrorMsg) {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want %q", tc.data, err.Error(), tc.wantErrorMsg)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestIntDecConvertSignedOrBigInt(t *testing.T) {
|
|
dm, err := DecOptions{
|
|
IntDec: IntDecConvertSignedOrBigInt,
|
|
BigIntDec: BigIntDecodePointer,
|
|
}.DecMode()
|
|
if err != nil {
|
|
t.Errorf("DecMode() returned an error %+v", err)
|
|
}
|
|
|
|
testCases := []struct {
|
|
name string
|
|
data []byte
|
|
wantObj interface{}
|
|
}{
|
|
{
|
|
name: "CBOR pos int",
|
|
data: hexDecode("1a000f4240"),
|
|
wantObj: int64(1000000),
|
|
},
|
|
{
|
|
name: "CBOR pos int overflows int64",
|
|
data: hexDecode("1b8000000000000000"),
|
|
wantObj: new(big.Int).Add(big.NewInt(math.MaxInt64), big.NewInt(1)),
|
|
},
|
|
{
|
|
name: "CBOR neg int",
|
|
data: hexDecode("3903e7"),
|
|
wantObj: int64(-1000),
|
|
},
|
|
{
|
|
name: "CBOR neg int overflows int64",
|
|
data: hexDecode("3b8000000000000000"),
|
|
wantObj: new(big.Int).Sub(big.NewInt(math.MinInt64), big.NewInt(1)),
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
var v interface{}
|
|
err := dm.Unmarshal(tc.data, &v)
|
|
if err == nil {
|
|
if !reflect.DeepEqual(v, tc.wantObj) {
|
|
t.Errorf("Unmarshal(0x%x) return %v (%T), want %v (%T)", tc.data, v, v, tc.wantObj, tc.wantObj)
|
|
}
|
|
} else {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q", tc.data, err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestIntDecConvertSignedOrError(t *testing.T) {
|
|
dm, err := DecOptions{
|
|
IntDec: IntDecConvertSignedOrFail,
|
|
BigIntDec: BigIntDecodePointer,
|
|
}.DecMode()
|
|
if err != nil {
|
|
t.Errorf("DecMode() returned an error %+v", err)
|
|
}
|
|
|
|
testCases := []struct {
|
|
name string
|
|
data []byte
|
|
wantObj interface{}
|
|
wantErrorMsg string
|
|
}{
|
|
{
|
|
name: "CBOR pos int",
|
|
data: hexDecode("1a000f4240"),
|
|
wantObj: int64(1000000),
|
|
},
|
|
{
|
|
name: "CBOR pos int overflows int64",
|
|
data: hexDecode("1b8000000000000000"), // math.MaxInt64+1
|
|
wantErrorMsg: "9223372036854775808 overflows Go's int64",
|
|
},
|
|
{
|
|
name: "CBOR neg int",
|
|
data: hexDecode("3903e7"),
|
|
wantObj: int64(-1000),
|
|
},
|
|
{
|
|
name: "CBOR neg int overflows int64",
|
|
data: hexDecode("3b8000000000000000"), // math.MinInt64-1
|
|
wantErrorMsg: "-9223372036854775809 overflows Go's int64",
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
var v interface{}
|
|
err := dm.Unmarshal(tc.data, &v)
|
|
if err == nil {
|
|
if tc.wantErrorMsg != "" {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error, want %q", tc.data, tc.wantErrorMsg)
|
|
} else if !reflect.DeepEqual(v, tc.wantObj) {
|
|
t.Errorf("Unmarshal(0x%x) return %v (%T), want %v (%T)", tc.data, v, v, tc.wantObj, tc.wantObj)
|
|
}
|
|
} else {
|
|
if tc.wantErrorMsg == "" {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q", tc.data, err)
|
|
} else if !strings.Contains(err.Error(), tc.wantErrorMsg) {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want %q", tc.data, err.Error(), tc.wantErrorMsg)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDecModeInvalidMapKeyByteString(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
name string
|
|
opts DecOptions
|
|
wantErrorMsg string
|
|
}{
|
|
{
|
|
name: "below range of valid modes",
|
|
opts: DecOptions{MapKeyByteString: -1},
|
|
wantErrorMsg: "cbor: invalid MapKeyByteString -1",
|
|
},
|
|
{
|
|
name: "above range of valid modes",
|
|
opts: DecOptions{MapKeyByteString: 101},
|
|
wantErrorMsg: "cbor: invalid MapKeyByteString 101",
|
|
},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
_, err := tc.opts.DecMode()
|
|
if err == nil {
|
|
t.Errorf("DecMode() didn't return an error")
|
|
} else if err.Error() != tc.wantErrorMsg {
|
|
t.Errorf("DecMode() returned error %q, want %q", err.Error(), tc.wantErrorMsg)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestMapKeyByteString(t *testing.T) {
|
|
bsForbiddenMode, err := DecOptions{MapKeyByteString: MapKeyByteStringForbidden}.DecMode()
|
|
if err != nil {
|
|
t.Errorf("DecMode() returned an error %+v", err)
|
|
}
|
|
|
|
bsAllowedMode, err := DecOptions{MapKeyByteString: MapKeyByteStringAllowed}.DecMode()
|
|
if err != nil {
|
|
t.Errorf("DecMode() returned an error %+v", err)
|
|
}
|
|
|
|
testCases := []struct {
|
|
name string
|
|
data []byte
|
|
wantObj interface{}
|
|
wantErrorMsg string
|
|
dm DecMode
|
|
}{
|
|
{
|
|
name: "byte string map key with MapKeyByteStringForbidden",
|
|
data: hexDecode("a143abcdef187b"),
|
|
wantErrorMsg: "cbor: invalid map key type: []uint8",
|
|
dm: bsForbiddenMode,
|
|
},
|
|
{
|
|
name: "tagged byte string map key with MapKeyByteStringForbidden",
|
|
data: hexDecode("a1d86443abcdef187b"),
|
|
wantErrorMsg: "cbor: invalid map key type: cbor.Tag",
|
|
dm: bsForbiddenMode,
|
|
},
|
|
{
|
|
name: "nested tagged byte string map key with MapKeyByteStringForbidden",
|
|
data: hexDecode("a1d865d86443abcdef187b"),
|
|
wantErrorMsg: "cbor: invalid map key type: cbor.Tag",
|
|
dm: bsForbiddenMode,
|
|
},
|
|
{
|
|
name: "byte string map key with MapKeyByteStringAllowed",
|
|
data: hexDecode("a143abcdef187b"),
|
|
wantObj: map[interface{}]interface{}{
|
|
ByteString("\xab\xcd\xef"): uint64(123),
|
|
},
|
|
dm: bsAllowedMode,
|
|
},
|
|
{
|
|
name: "tagged byte string map key with MapKeyByteStringAllowed",
|
|
data: hexDecode("a1d86443abcdef187b"),
|
|
wantObj: map[interface{}]interface{}{
|
|
Tag{Number: 100, Content: ByteString("\xab\xcd\xef")}: uint64(123),
|
|
},
|
|
dm: bsAllowedMode,
|
|
},
|
|
{
|
|
name: "nested tagged byte string map key with MapKeyByteStringAllowed",
|
|
data: hexDecode("a1d865d86443abcdef187b"),
|
|
wantObj: map[interface{}]interface{}{
|
|
Tag{Number: 101, Content: Tag{Number: 100, Content: ByteString("\xab\xcd\xef")}}: uint64(123),
|
|
},
|
|
dm: bsAllowedMode,
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
for _, typ := range []reflect.Type{typeIntf, typeMapIntfIntf} {
|
|
v := reflect.New(typ)
|
|
vPtr := v.Interface()
|
|
err = tc.dm.Unmarshal(tc.data, vPtr)
|
|
if err == nil {
|
|
if tc.wantErrorMsg != "" {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error, want %q", tc.data, tc.wantErrorMsg)
|
|
} else if !reflect.DeepEqual(v.Elem().Interface(), tc.wantObj) {
|
|
t.Errorf("Unmarshal(0x%x) return %v (%T), want %v (%T)", tc.data, v.Elem().Interface(), v.Elem().Interface(), tc.wantObj, tc.wantObj)
|
|
}
|
|
} else {
|
|
if tc.wantErrorMsg == "" {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q", tc.data, err)
|
|
} else if !strings.Contains(err.Error(), tc.wantErrorMsg) {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want %q", tc.data, err.Error(), tc.wantErrorMsg)
|
|
}
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDecModeInvalidExtraError(t *testing.T) {
|
|
wantErrorMsg := "cbor: invalid ExtraReturnErrors 3"
|
|
_, err := DecOptions{ExtraReturnErrors: 3}.DecMode()
|
|
if err == nil {
|
|
t.Errorf("DecMode() didn't return an error")
|
|
} else if err.Error() != wantErrorMsg {
|
|
t.Errorf("DecMode() returned error %q, want %q", err.Error(), wantErrorMsg)
|
|
}
|
|
}
|
|
|
|
func TestExtraErrorCondUnknownField(t *testing.T) {
|
|
type s struct {
|
|
A string
|
|
B string
|
|
C string
|
|
}
|
|
|
|
dm, _ := DecOptions{}.DecMode()
|
|
dmUnknownFieldError, _ := DecOptions{ExtraReturnErrors: ExtraDecErrorUnknownField}.DecMode()
|
|
|
|
testCases := []struct {
|
|
name string
|
|
data []byte
|
|
dm DecMode
|
|
wantObj interface{}
|
|
wantErrorMsg string
|
|
}{
|
|
{
|
|
name: "field by field match",
|
|
data: hexDecode("a3614161616142616261436163"), // map[string]string{"A": "a", "B": "b", "C": "c"}
|
|
dm: dm,
|
|
wantObj: s{A: "a", B: "b", C: "c"},
|
|
},
|
|
{
|
|
name: "field by field match with ExtraDecErrorUnknownField",
|
|
data: hexDecode("a3614161616142616261436163"), // map[string]string{"A": "a", "B": "b", "C": "c"}
|
|
dm: dmUnknownFieldError,
|
|
wantObj: s{A: "a", B: "b", C: "c"},
|
|
},
|
|
{
|
|
name: "CBOR map less field",
|
|
data: hexDecode("a26141616161426162"), // map[string]string{"A": "a", "B": "b"}
|
|
dm: dm,
|
|
wantObj: s{A: "a", B: "b", C: ""},
|
|
},
|
|
{
|
|
name: "CBOR map less field with ExtraDecErrorUnknownField",
|
|
data: hexDecode("a26141616161426162"), // map[string]string{"A": "a", "B": "b"}
|
|
dm: dmUnknownFieldError,
|
|
wantObj: s{A: "a", B: "b", C: ""},
|
|
},
|
|
{
|
|
name: "duplicate map keys matching known field with ExtraDecErrorUnknownField",
|
|
data: hexDecode("a26141616161416141"), // map[string]string{"A": "a", "A": "A"}
|
|
dm: dmUnknownFieldError,
|
|
wantObj: s{A: "a"},
|
|
},
|
|
{
|
|
name: "CBOR map unknown field",
|
|
data: hexDecode("a461416161614261626143616361446164"), // map[string]string{"A": "a", "B": "b", "C": "c", "D": "d"}
|
|
dm: dm,
|
|
wantObj: s{A: "a", B: "b", C: "c"},
|
|
},
|
|
{
|
|
name: "CBOR map unknown field with ExtraDecErrorUnknownField",
|
|
data: hexDecode("a461416161614261626143616361446164"), // map[string]string{"A": "a", "B": "b", "C": "c", "D": "d"}
|
|
dm: dmUnknownFieldError,
|
|
wantErrorMsg: "cbor: found unknown field at map element index 3",
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
var v s
|
|
err := tc.dm.Unmarshal(tc.data, &v)
|
|
if err == nil {
|
|
if tc.wantErrorMsg != "" {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error, want %q", tc.data, tc.wantErrorMsg)
|
|
} else if !reflect.DeepEqual(v, tc.wantObj) {
|
|
t.Errorf("Unmarshal(0x%x) return %v (%T), want %v (%T)", tc.data, v, v, tc.wantObj, tc.wantObj)
|
|
}
|
|
} else {
|
|
if tc.wantErrorMsg == "" {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q", tc.data, err)
|
|
} else if !strings.Contains(err.Error(), tc.wantErrorMsg) {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want %q", tc.data, err.Error(), tc.wantErrorMsg)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestInvalidUTF8Mode(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
name string
|
|
opts DecOptions
|
|
wantErrorMsg string
|
|
}{
|
|
{
|
|
name: "below range of valid modes",
|
|
opts: DecOptions{UTF8: -1},
|
|
wantErrorMsg: "cbor: invalid UTF8 -1",
|
|
},
|
|
{
|
|
name: "above range of valid modes",
|
|
opts: DecOptions{UTF8: 101},
|
|
wantErrorMsg: "cbor: invalid UTF8 101",
|
|
},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
_, err := tc.opts.DecMode()
|
|
if err == nil {
|
|
t.Errorf("DecMode() didn't return an error")
|
|
} else if err.Error() != tc.wantErrorMsg {
|
|
t.Errorf("DecMode() returned error %q, want %q", err.Error(), tc.wantErrorMsg)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestStreamExtraErrorCondUnknownField(t *testing.T) {
|
|
type s struct {
|
|
A string
|
|
B string
|
|
C string
|
|
}
|
|
|
|
data := hexDecode("a461416161614461646142616261436163a3614161616142616261436163") // map[string]string{"A": "a", "D": "d", "B": "b", "C": "c"}, map[string]string{"A": "a", "B": "b", "C": "c"}
|
|
wantErrorMsg := "cbor: found unknown field at map element index 1"
|
|
wantObj := s{A: "a", B: "b", C: "c"}
|
|
|
|
dmUnknownFieldError, _ := DecOptions{ExtraReturnErrors: ExtraDecErrorUnknownField}.DecMode()
|
|
dec := dmUnknownFieldError.NewDecoder(bytes.NewReader(data))
|
|
|
|
var v1 s
|
|
err := dec.Decode(&v1)
|
|
if err == nil {
|
|
t.Errorf("Decode() didn't return an error, want %q", wantErrorMsg)
|
|
} else if !strings.Contains(err.Error(), wantErrorMsg) {
|
|
t.Errorf("Decode() returned error %q, want %q", err.Error(), wantErrorMsg)
|
|
}
|
|
|
|
var v2 s
|
|
err = dec.Decode(&v2)
|
|
if err != nil {
|
|
t.Errorf("Decode() returned an error %v", err)
|
|
} else if !reflect.DeepEqual(v2, wantObj) {
|
|
t.Errorf("Decode() return %v (%T), want %v (%T)", v2, v2, wantObj, wantObj)
|
|
}
|
|
}
|
|
|
|
// TestUnmarshalTagNum55799 is identical to TestUnmarshal,
|
|
// except that CBOR test data is prefixed with tag number 55799 (0xd9d9f7).
|
|
func TestUnmarshalTagNum55799(t *testing.T) {
|
|
tagNum55799 := hexDecode("d9d9f7")
|
|
|
|
for _, tc := range unmarshalTests {
|
|
// Prefix tag number 55799 to CBOR test data
|
|
data := make([]byte, len(tc.data)+6)
|
|
copy(data, tagNum55799)
|
|
copy(data[3:], tagNum55799)
|
|
copy(data[6:], tc.data)
|
|
|
|
// Test unmarshalling CBOR into empty interface.
|
|
var v interface{}
|
|
if err := Unmarshal(data, &v); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", data, err)
|
|
} else {
|
|
if tm, ok := tc.wantInterfaceValue.(time.Time); ok {
|
|
if vt, ok := v.(time.Time); !ok || !tm.Equal(vt) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", data, v, v, tc.wantInterfaceValue, tc.wantInterfaceValue)
|
|
}
|
|
} else if !reflect.DeepEqual(v, tc.wantInterfaceValue) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", data, v, v, tc.wantInterfaceValue, tc.wantInterfaceValue)
|
|
}
|
|
}
|
|
|
|
// Test unmarshalling CBOR into RawMessage.
|
|
var r RawMessage
|
|
if err := Unmarshal(data, &r); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", data, err)
|
|
} else if !bytes.Equal(r, tc.data) {
|
|
t.Errorf("Unmarshal(0x%x) returned RawMessage %v, want %v", data, r, tc.data)
|
|
}
|
|
|
|
// Test unmarshalling CBOR into compatible data types.
|
|
for _, value := range tc.wantValues {
|
|
v := reflect.New(reflect.TypeOf(value))
|
|
vPtr := v.Interface()
|
|
if err := Unmarshal(data, vPtr); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", data, err)
|
|
} else {
|
|
if tm, ok := value.(time.Time); ok {
|
|
if vt, ok := v.Elem().Interface().(time.Time); !ok || !tm.Equal(vt) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", data, v.Elem().Interface(), v.Elem().Interface(), value, value)
|
|
}
|
|
} else if !reflect.DeepEqual(v.Elem().Interface(), value) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", data, v.Elem().Interface(), v.Elem().Interface(), value, value)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Test unmarshalling CBOR into incompatible data types.
|
|
for _, typ := range tc.wrongTypes {
|
|
v := reflect.New(typ)
|
|
vPtr := v.Interface()
|
|
if err := Unmarshal(data, vPtr); err == nil {
|
|
t.Errorf("Unmarshal(0x%x, %s) didn't return an error", data, typ.String())
|
|
} else if _, ok := err.(*UnmarshalTypeError); !ok {
|
|
t.Errorf("Unmarshal(0x%x) returned wrong error type %T, want (*UnmarshalTypeError)", data, err)
|
|
} else if !strings.Contains(err.Error(), "cannot unmarshal") {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want error containing %q", data, err.Error(), "cannot unmarshal")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestUnmarshalFloatWithTagNum55799 is identical to TestUnmarshalFloat,
|
|
// except that CBOR test data is prefixed with tag number 55799 (0xd9d9f7).
|
|
func TestUnmarshalFloatWithTagNum55799(t *testing.T) {
|
|
tagNum55799 := hexDecode("d9d9f7")
|
|
|
|
for _, tc := range unmarshalFloatTests {
|
|
// Prefix tag number 55799 to CBOR test data
|
|
data := make([]byte, len(tc.data)+3)
|
|
copy(data, tagNum55799)
|
|
copy(data[3:], tc.data)
|
|
|
|
// Test unmarshalling CBOR into empty interface.
|
|
var v interface{}
|
|
if err := Unmarshal(tc.data, &v); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", tc.data, err)
|
|
} else {
|
|
compareFloats(t, tc.data, v, tc.wantInterfaceValue, tc.equalityThreshold)
|
|
}
|
|
|
|
// Test unmarshalling CBOR into RawMessage.
|
|
var r RawMessage
|
|
if err := Unmarshal(tc.data, &r); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", tc.data, err)
|
|
} else if !bytes.Equal(r, tc.data) {
|
|
t.Errorf("Unmarshal(0x%x) returned RawMessage %v, want %v", tc.data, r, tc.data)
|
|
}
|
|
|
|
// Test unmarshalling CBOR into compatible data types.
|
|
for _, value := range tc.wantValues {
|
|
v := reflect.New(reflect.TypeOf(value))
|
|
vPtr := v.Interface()
|
|
if err := Unmarshal(tc.data, vPtr); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", tc.data, err)
|
|
} else {
|
|
compareFloats(t, tc.data, v.Elem().Interface(), value, tc.equalityThreshold)
|
|
}
|
|
}
|
|
|
|
// Test unmarshalling CBOR into incompatible data types.
|
|
for _, typ := range unmarshalFloatWrongTypes {
|
|
v := reflect.New(typ)
|
|
vPtr := v.Interface()
|
|
if err := Unmarshal(tc.data, vPtr); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error", tc.data)
|
|
} else if _, ok := err.(*UnmarshalTypeError); !ok {
|
|
t.Errorf("Unmarshal(0x%x) returned wrong error type %T, want (*UnmarshalTypeError)", tc.data, err)
|
|
} else if !strings.Contains(err.Error(), "cannot unmarshal") {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want error containing %q", tc.data, err.Error(), "cannot unmarshal")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalTagNum55799AsElement(t *testing.T) {
|
|
testCases := []struct {
|
|
name string
|
|
data []byte
|
|
emptyInterfaceValue interface{}
|
|
values []interface{}
|
|
wrongTypes []reflect.Type
|
|
}{
|
|
{
|
|
"array",
|
|
hexDecode("d9d9f783d9d9f701d9d9f702d9d9f703"), // 55799([55799(1), 55799(2), 55799(3)])
|
|
[]interface{}{uint64(1), uint64(2), uint64(3)},
|
|
[]interface{}{[]interface{}{uint64(1), uint64(2), uint64(3)}, []byte{1, 2, 3}, []int{1, 2, 3}, []uint{1, 2, 3}, [0]int{}, [1]int{1}, [3]int{1, 2, 3}, [5]int{1, 2, 3, 0, 0}, []float32{1, 2, 3}, []float64{1, 2, 3}},
|
|
[]reflect.Type{typeUint8, typeUint16, typeUint32, typeUint64, typeInt8, typeInt16, typeInt32, typeInt64, typeFloat32, typeFloat64, typeString, typeBool, typeStringSlice, typeMapStringInt, reflect.TypeOf([3]string{}), typeTag, typeRawTag},
|
|
},
|
|
{
|
|
"map",
|
|
hexDecode("d9d9f7a2d9d9f701d9d9f702d9d9f703d9d9f704"), // 55799({55799(1): 55799(2), 55799(3): 55799(4)})
|
|
map[interface{}]interface{}{uint64(1): uint64(2), uint64(3): uint64(4)},
|
|
[]interface{}{map[interface{}]interface{}{uint64(1): uint64(2), uint64(3): uint64(4)}, map[uint]int{1: 2, 3: 4}, map[int]uint{1: 2, 3: 4}},
|
|
[]reflect.Type{typeUint8, typeUint16, typeUint32, typeUint64, typeInt8, typeInt16, typeInt32, typeInt64, typeFloat32, typeFloat64, typeByteSlice, typeByteArray, typeString, typeBool, typeIntSlice, typeMapStringInt, typeTag, typeRawTag},
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
// Test unmarshalling CBOR into empty interface.
|
|
var v interface{}
|
|
if err := Unmarshal(tc.data, &v); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", tc.data, err)
|
|
} else {
|
|
if tm, ok := tc.emptyInterfaceValue.(time.Time); ok {
|
|
if vt, ok := v.(time.Time); !ok || !tm.Equal(vt) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", tc.data, v, v, tc.emptyInterfaceValue, tc.emptyInterfaceValue)
|
|
}
|
|
} else if !reflect.DeepEqual(v, tc.emptyInterfaceValue) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", tc.data, v, v, tc.emptyInterfaceValue, tc.emptyInterfaceValue)
|
|
}
|
|
}
|
|
|
|
// Test unmarshalling CBOR into compatible data types.
|
|
for _, value := range tc.values {
|
|
v := reflect.New(reflect.TypeOf(value))
|
|
vPtr := v.Interface()
|
|
if err := Unmarshal(tc.data, vPtr); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", tc.data, err)
|
|
} else {
|
|
if tm, ok := value.(time.Time); ok {
|
|
if vt, ok := v.Elem().Interface().(time.Time); !ok || !tm.Equal(vt) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", tc.data, v.Elem().Interface(), v.Elem().Interface(), value, value)
|
|
}
|
|
} else if !reflect.DeepEqual(v.Elem().Interface(), value) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", tc.data, v.Elem().Interface(), v.Elem().Interface(), value, value)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Test unmarshalling CBOR into incompatible data types.
|
|
for _, typ := range tc.wrongTypes {
|
|
v := reflect.New(typ)
|
|
vPtr := v.Interface()
|
|
if err := Unmarshal(tc.data, vPtr); err == nil {
|
|
t.Errorf("Unmarshal(0x%x, %s) didn't return an error", tc.data, typ.String())
|
|
} else if _, ok := err.(*UnmarshalTypeError); !ok {
|
|
t.Errorf("Unmarshal(0x%x) returned wrong error type %T, want (*UnmarshalTypeError)", tc.data, err)
|
|
} else if !strings.Contains(err.Error(), "cannot unmarshal") {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want error containing %q", tc.data, err.Error(), "cannot unmarshal")
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalTagNum55799ToBinaryUnmarshaler(t *testing.T) {
|
|
data := hexDecode("d9d9f74800000000499602d2") // 55799(h'00000000499602D2')
|
|
wantObj := number(1234567890)
|
|
|
|
var v number
|
|
if err := Unmarshal(data, &v); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", data, err)
|
|
} else if !reflect.DeepEqual(v, wantObj) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", data, v, v, wantObj, wantObj)
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalTagNum55799ToUnmarshaler(t *testing.T) {
|
|
data := hexDecode("d9d9f7d864a1636e756d01") // 55799(100({"num": 1}))
|
|
wantObj := number3(1)
|
|
|
|
var v number3
|
|
if err := Unmarshal(data, &v); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", data, err)
|
|
} else if !reflect.DeepEqual(v, wantObj) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", data, v, v, wantObj, wantObj)
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalTagNum55799ToRegisteredGoType(t *testing.T) {
|
|
type myInt int
|
|
typ := reflect.TypeOf(myInt(0))
|
|
|
|
tags := NewTagSet()
|
|
if err := tags.Add(TagOptions{EncTag: EncTagRequired, DecTag: DecTagRequired}, typ, 125); err != nil {
|
|
t.Fatalf("TagSet.Add(%s, %v) returned error %v", typ, 125, err)
|
|
}
|
|
|
|
dm, _ := DecOptions{}.DecModeWithTags(tags)
|
|
|
|
data := hexDecode("d9d9f7d87d01") // 55799(125(1))
|
|
wantObj := myInt(1)
|
|
|
|
var v myInt
|
|
if err := dm.Unmarshal(data, &v); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", data, err)
|
|
} else if !reflect.DeepEqual(v, wantObj) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", data, v, v, wantObj, wantObj)
|
|
}
|
|
}
|
|
|
|
// TODO: wait for clarification from 7049bis https://github.com/cbor-wg/CBORbis/issues/183
|
|
// Nested tag number 55799 may be stripeed as well depending on 7049bis clarification.
|
|
func TestUnmarshalNestedTagNum55799ToEmptyInterface(t *testing.T) {
|
|
data := hexDecode("d864d9d9f701") // 100(55799(1))
|
|
wantObj := Tag{100, Tag{55799, uint64(1)}}
|
|
|
|
var v interface{}
|
|
if err := Unmarshal(data, &v); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", data, err)
|
|
} else if !reflect.DeepEqual(v, wantObj) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", data, v, v, wantObj, wantObj)
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalNestedTagNum55799ToValue(t *testing.T) {
|
|
data := hexDecode("d864d9d9f701") // 100(55799(1))
|
|
wantObj := 1
|
|
|
|
var v int
|
|
if err := Unmarshal(data, &v); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", data, err)
|
|
} else if !reflect.DeepEqual(v, wantObj) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", data, v, v, wantObj, wantObj)
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalNestedTagNum55799ToTag(t *testing.T) {
|
|
data := hexDecode("d864d9d9f701") // 100(55799(1))
|
|
wantObj := Tag{100, Tag{55799, uint64(1)}}
|
|
|
|
var v Tag
|
|
if err := Unmarshal(data, &v); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", data, err)
|
|
} else if !reflect.DeepEqual(v, wantObj) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", data, v, v, wantObj, wantObj)
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalNestedTagNum55799ToTime(t *testing.T) {
|
|
data := hexDecode("c0d9d9f774323031332d30332d32315432303a30343a30305a") // 0(55799("2013-03-21T20:04:00Z"))
|
|
wantErrorMsg := "tag number 0 must be followed by text string, got tag"
|
|
|
|
var v time.Time
|
|
if err := Unmarshal(data, &v); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return error", data)
|
|
} else if !strings.Contains(err.Error(), wantErrorMsg) {
|
|
t.Errorf("Unmarshal(0x%x) returned error %s, want %s", data, err.Error(), wantErrorMsg)
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalNestedTagNum55799ToBinaryUnmarshaler(t *testing.T) {
|
|
data := hexDecode("d864d9d9f74800000000499602d2") // 100(55799(h'00000000499602D2'))
|
|
wantObj := number(1234567890)
|
|
|
|
var v number
|
|
if err := Unmarshal(data, &v); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", data, err)
|
|
} else if !reflect.DeepEqual(v, wantObj) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", data, v, v, wantObj, wantObj)
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalNestedTagNum55799ToUnmarshaler(t *testing.T) {
|
|
data := hexDecode("d864d9d9f7a1636e756d01") // 100(55799({"num": 1}))
|
|
wantErrorMsg := "wrong tag content type"
|
|
|
|
var v number3
|
|
if err := Unmarshal(data, &v); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return error", data)
|
|
} else if !strings.Contains(err.Error(), wantErrorMsg) {
|
|
t.Errorf("Unmarshal(0x%x) returned error %s, want %s", data, err.Error(), wantErrorMsg)
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalNestedTagNum55799ToRegisteredGoType(t *testing.T) {
|
|
type myInt int
|
|
typ := reflect.TypeOf(myInt(0))
|
|
|
|
tags := NewTagSet()
|
|
if err := tags.Add(TagOptions{EncTag: EncTagRequired, DecTag: DecTagRequired}, typ, 125); err != nil {
|
|
t.Fatalf("TagSet.Add(%s, %v) returned error %v", typ, 125, err)
|
|
}
|
|
|
|
dm, _ := DecOptions{}.DecModeWithTags(tags)
|
|
|
|
data := hexDecode("d87dd9d9f701") // 125(55799(1))
|
|
wantErrorMsg := "cbor: wrong tag number for cbor.myInt, got [125 55799], expected [125]"
|
|
|
|
var v myInt
|
|
if err := dm.Unmarshal(data, &v); err == nil {
|
|
t.Errorf("Unmarshal() didn't return error")
|
|
} else if !strings.Contains(err.Error(), wantErrorMsg) {
|
|
t.Errorf("Unmarshal(0x%x) returned error %s, want %s", data, err.Error(), wantErrorMsg)
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalPosIntToBigInt(t *testing.T) {
|
|
data := hexDecode("1bffffffffffffffff") // 18446744073709551615
|
|
wantEmptyInterfaceValue := uint64(18446744073709551615)
|
|
wantBigIntValue := bigIntOrPanic("18446744073709551615")
|
|
|
|
var v1 interface{}
|
|
if err := Unmarshal(data, &v1); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %+v", data, err)
|
|
} else if !reflect.DeepEqual(v1, wantEmptyInterfaceValue) {
|
|
t.Errorf("Unmarshal(0x%x) returned %v (%T), want %v (%T)", data, v1, v1, wantEmptyInterfaceValue, wantEmptyInterfaceValue)
|
|
}
|
|
|
|
var v2 big.Int
|
|
if err := Unmarshal(data, &v2); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %+v", data, err)
|
|
} else if !reflect.DeepEqual(v2, wantBigIntValue) {
|
|
t.Errorf("Unmarshal(0x%x) returned %v (%T), want %v (%T)", data, v2, v2, wantBigIntValue, wantBigIntValue)
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalNegIntToBigInt(t *testing.T) {
|
|
testCases := []struct {
|
|
name string
|
|
data []byte
|
|
wantEmptyInterfaceValue interface{}
|
|
wantBigIntValue big.Int
|
|
}{
|
|
{
|
|
name: "fit Go int64",
|
|
data: hexDecode("3b7fffffffffffffff"), // -9223372036854775808
|
|
wantEmptyInterfaceValue: int64(-9223372036854775808),
|
|
wantBigIntValue: bigIntOrPanic("-9223372036854775808"),
|
|
},
|
|
{
|
|
name: "overflow Go int64",
|
|
data: hexDecode("3b8000000000000000"), // -9223372036854775809
|
|
wantEmptyInterfaceValue: bigIntOrPanic("-9223372036854775809"),
|
|
wantBigIntValue: bigIntOrPanic("-9223372036854775809"),
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
var v1 interface{}
|
|
if err := Unmarshal(tc.data, &v1); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %+v", tc.data, err)
|
|
} else if !reflect.DeepEqual(v1, tc.wantEmptyInterfaceValue) {
|
|
t.Errorf("Unmarshal(0x%x) returned %v (%T), want %v (%T)", tc.data, v1, v1, tc.wantEmptyInterfaceValue, tc.wantEmptyInterfaceValue)
|
|
}
|
|
|
|
var v2 big.Int
|
|
if err := Unmarshal(tc.data, &v2); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %+v", tc.data, err)
|
|
} else if !reflect.DeepEqual(v2, tc.wantBigIntValue) {
|
|
t.Errorf("Unmarshal(0x%x) returned %v (%T), want %v (%T)", tc.data, v2, v2, tc.wantBigIntValue, tc.wantBigIntValue)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalTag2(t *testing.T) {
|
|
testCases := []struct {
|
|
name string
|
|
data []byte
|
|
wantEmptyInterfaceValue interface{}
|
|
wantValues []interface{}
|
|
}{
|
|
{
|
|
name: "fit Go int64",
|
|
data: hexDecode("c2430f4240"), // 2(1000000)
|
|
wantEmptyInterfaceValue: bigIntOrPanic("1000000"),
|
|
wantValues: []interface{}{
|
|
int64(1000000),
|
|
uint64(1000000),
|
|
float32(1000000),
|
|
float64(1000000),
|
|
bigIntOrPanic("1000000"),
|
|
},
|
|
},
|
|
{
|
|
name: "fit Go uint64",
|
|
data: hexDecode("c248ffffffffffffffff"), // 2(18446744073709551615)
|
|
wantEmptyInterfaceValue: bigIntOrPanic("18446744073709551615"),
|
|
wantValues: []interface{}{
|
|
uint64(18446744073709551615),
|
|
float32(18446744073709551615),
|
|
float64(18446744073709551615),
|
|
bigIntOrPanic("18446744073709551615"),
|
|
},
|
|
},
|
|
{
|
|
name: "fit Go uint64 with leading zeros",
|
|
data: hexDecode("c24900ffffffffffffffff"), // 2(18446744073709551615)
|
|
wantEmptyInterfaceValue: bigIntOrPanic("18446744073709551615"),
|
|
wantValues: []interface{}{
|
|
uint64(18446744073709551615),
|
|
float32(18446744073709551615),
|
|
float64(18446744073709551615),
|
|
bigIntOrPanic("18446744073709551615"),
|
|
},
|
|
},
|
|
{
|
|
name: "overflow Go uint64",
|
|
data: hexDecode("c249010000000000000000"), // 2(18446744073709551616)
|
|
wantEmptyInterfaceValue: bigIntOrPanic("18446744073709551616"),
|
|
wantValues: []interface{}{
|
|
bigIntOrPanic("18446744073709551616"),
|
|
},
|
|
},
|
|
{
|
|
name: "overflow Go uint64 with leading zeros",
|
|
data: hexDecode("c24b0000010000000000000000"), // 2(18446744073709551616)
|
|
wantEmptyInterfaceValue: bigIntOrPanic("18446744073709551616"),
|
|
wantValues: []interface{}{
|
|
bigIntOrPanic("18446744073709551616"),
|
|
},
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
var v1 interface{}
|
|
if err := Unmarshal(tc.data, &v1); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %+v", tc.data, err)
|
|
} else if !reflect.DeepEqual(v1, tc.wantEmptyInterfaceValue) {
|
|
t.Errorf("Unmarshal(0x%x) returned %v (%T), want %v (%T)", tc.data, v1, v1, tc.wantEmptyInterfaceValue, tc.wantEmptyInterfaceValue)
|
|
}
|
|
|
|
for _, wantValue := range tc.wantValues {
|
|
v := reflect.New(reflect.TypeOf(wantValue))
|
|
if err := Unmarshal(tc.data, v.Interface()); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %+v", tc.data, err)
|
|
} else if !reflect.DeepEqual(v.Elem().Interface(), wantValue) {
|
|
t.Errorf("Unmarshal(0x%x) returned %v (%T), want %v (%T)", tc.data, v.Elem().Interface(), v.Elem().Interface(), wantValue, wantValue)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalTag3(t *testing.T) {
|
|
testCases := []struct {
|
|
name string
|
|
data []byte
|
|
wantEmptyInterfaceValue interface{}
|
|
wantValues []interface{}
|
|
}{
|
|
{
|
|
name: "fit Go int64",
|
|
data: hexDecode("c3487fffffffffffffff"), // 3(-9223372036854775808)
|
|
wantEmptyInterfaceValue: bigIntOrPanic("-9223372036854775808"),
|
|
wantValues: []interface{}{
|
|
int64(-9223372036854775808),
|
|
float32(-9223372036854775808),
|
|
float64(-9223372036854775808),
|
|
bigIntOrPanic("-9223372036854775808"),
|
|
},
|
|
},
|
|
{
|
|
name: "fit Go int64 with leading zeros",
|
|
data: hexDecode("c349007fffffffffffffff"), // 3(-9223372036854775808)
|
|
wantEmptyInterfaceValue: bigIntOrPanic("-9223372036854775808"),
|
|
wantValues: []interface{}{
|
|
int64(-9223372036854775808),
|
|
float32(-9223372036854775808),
|
|
float64(-9223372036854775808),
|
|
bigIntOrPanic("-9223372036854775808"),
|
|
},
|
|
},
|
|
{
|
|
name: "overflow Go int64",
|
|
data: hexDecode("c349010000000000000000"), // 3(-18446744073709551617)
|
|
wantEmptyInterfaceValue: bigIntOrPanic("-18446744073709551617"),
|
|
wantValues: []interface{}{
|
|
bigIntOrPanic("-18446744073709551617"),
|
|
},
|
|
},
|
|
{
|
|
name: "overflow Go int64 with leading zeros",
|
|
data: hexDecode("c34b0000010000000000000000"), // 3(-18446744073709551617)
|
|
wantEmptyInterfaceValue: bigIntOrPanic("-18446744073709551617"),
|
|
wantValues: []interface{}{
|
|
bigIntOrPanic("-18446744073709551617"),
|
|
},
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
var v1 interface{}
|
|
if err := Unmarshal(tc.data, &v1); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %+v", tc.data, err)
|
|
} else if !reflect.DeepEqual(v1, tc.wantEmptyInterfaceValue) {
|
|
t.Errorf("Unmarshal(0x%x) returned %v (%T), want %v (%T)", tc.data, v1, v1, tc.wantEmptyInterfaceValue, tc.wantEmptyInterfaceValue)
|
|
}
|
|
|
|
for _, wantValue := range tc.wantValues {
|
|
v := reflect.New(reflect.TypeOf(wantValue))
|
|
if err := Unmarshal(tc.data, v.Interface()); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %+v", tc.data, err)
|
|
} else if !reflect.DeepEqual(v.Elem().Interface(), wantValue) {
|
|
t.Errorf("Unmarshal(0x%x) returned %v (%T), want %v (%T)", tc.data, v.Elem().Interface(), v.Elem().Interface(), wantValue, wantValue)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalInvalidTagBignum(t *testing.T) {
|
|
typeBigIntSlice := reflect.TypeOf([]big.Int{})
|
|
|
|
testCases := []struct {
|
|
name string
|
|
data []byte
|
|
decodeToTypes []reflect.Type
|
|
wantErrorMsg string
|
|
}{
|
|
{
|
|
name: "Tag 2 with string",
|
|
data: hexDecode("c27f657374726561646d696e67ff"),
|
|
decodeToTypes: []reflect.Type{typeIntf, typeBigInt},
|
|
wantErrorMsg: "cbor: tag number 2 or 3 must be followed by byte string, got UTF-8 text string",
|
|
},
|
|
{
|
|
name: "Tag 3 with string",
|
|
data: hexDecode("c37f657374726561646d696e67ff"),
|
|
decodeToTypes: []reflect.Type{typeIntf, typeBigInt},
|
|
wantErrorMsg: "cbor: tag number 2 or 3 must be followed by byte string, got UTF-8 text string",
|
|
},
|
|
{
|
|
name: "Tag 3 with negavtive int",
|
|
data: hexDecode("81C330"), // [3(-17)]
|
|
decodeToTypes: []reflect.Type{typeIntf, typeBigIntSlice},
|
|
wantErrorMsg: "cbor: tag number 2 or 3 must be followed by byte string, got negative integer",
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
for _, decodeToType := range tc.decodeToTypes {
|
|
t.Run(tc.name+" decode to "+decodeToType.String(), func(t *testing.T) {
|
|
v := reflect.New(decodeToType)
|
|
if err := Unmarshal(tc.data, v.Interface()); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return error, want error msg %q", tc.data, tc.wantErrorMsg)
|
|
} else if !strings.Contains(err.Error(), tc.wantErrorMsg) {
|
|
t.Errorf("Unmarshal(0x%x) returned error %q, want %q", tc.data, err, tc.wantErrorMsg)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
type Foo interface {
|
|
Foo() string
|
|
}
|
|
|
|
type UintFoo uint
|
|
|
|
func (f *UintFoo) Foo() string {
|
|
return fmt.Sprint(f)
|
|
}
|
|
|
|
type IntFoo int
|
|
|
|
func (f *IntFoo) Foo() string {
|
|
return fmt.Sprint(*f)
|
|
}
|
|
|
|
type ByteFoo []byte
|
|
|
|
func (f *ByteFoo) Foo() string {
|
|
return fmt.Sprint(*f)
|
|
}
|
|
|
|
type StringFoo string
|
|
|
|
func (f *StringFoo) Foo() string {
|
|
return string(*f)
|
|
}
|
|
|
|
type ArrayFoo []int
|
|
|
|
func (f *ArrayFoo) Foo() string {
|
|
return fmt.Sprint(*f)
|
|
}
|
|
|
|
type MapFoo map[int]int
|
|
|
|
func (f *MapFoo) Foo() string {
|
|
return fmt.Sprint(*f)
|
|
}
|
|
|
|
type StructFoo struct {
|
|
Value int `cbor:"1,keyasint"`
|
|
}
|
|
|
|
func (f *StructFoo) Foo() string {
|
|
return fmt.Sprint(*f)
|
|
}
|
|
|
|
type TestExample struct {
|
|
Message string `cbor:"1,keyasint"`
|
|
Foo Foo `cbor:"2,keyasint"`
|
|
}
|
|
|
|
func TestUnmarshalToInterface(t *testing.T) {
|
|
|
|
uintFoo, uintFoo123 := UintFoo(0), UintFoo(123)
|
|
intFoo, intFooNeg1 := IntFoo(0), IntFoo(-1)
|
|
byteFoo, byteFoo123 := ByteFoo(nil), ByteFoo([]byte{1, 2, 3})
|
|
stringFoo, stringFoo123 := StringFoo(""), StringFoo("123")
|
|
arrayFoo, arrayFoo123 := ArrayFoo(nil), ArrayFoo([]int{1, 2, 3})
|
|
mapFoo, mapFoo123 := MapFoo(nil), MapFoo(map[int]int{1: 1, 2: 2, 3: 3})
|
|
|
|
em, _ := EncOptions{Sort: SortCanonical}.EncMode()
|
|
|
|
testCases := []struct {
|
|
name string
|
|
data []byte
|
|
v *TestExample
|
|
unmarshalToObj *TestExample
|
|
}{
|
|
{
|
|
name: "uint",
|
|
data: hexDecode("a2016c736f6d65206d65737361676502187b"), // {1: "some message", 2: 123}
|
|
v: &TestExample{
|
|
Message: "some message",
|
|
Foo: &uintFoo123,
|
|
},
|
|
unmarshalToObj: &TestExample{Foo: &uintFoo},
|
|
},
|
|
{
|
|
name: "int",
|
|
data: hexDecode("a2016c736f6d65206d6573736167650220"), // {1: "some message", 2: -1}
|
|
v: &TestExample{
|
|
Message: "some message",
|
|
Foo: &intFooNeg1,
|
|
},
|
|
unmarshalToObj: &TestExample{Foo: &intFoo},
|
|
},
|
|
{
|
|
name: "bytes",
|
|
data: hexDecode("a2016c736f6d65206d6573736167650243010203"), // {1: "some message", 2: [1,2,3]}
|
|
v: &TestExample{
|
|
Message: "some message",
|
|
Foo: &byteFoo123,
|
|
},
|
|
unmarshalToObj: &TestExample{Foo: &byteFoo},
|
|
},
|
|
{
|
|
name: "string",
|
|
data: hexDecode("a2016c736f6d65206d6573736167650263313233"), // {1: "some message", 2: "123"}
|
|
v: &TestExample{
|
|
Message: "some message",
|
|
Foo: &stringFoo123,
|
|
},
|
|
unmarshalToObj: &TestExample{Foo: &stringFoo},
|
|
},
|
|
{
|
|
name: "array",
|
|
data: hexDecode("a2016c736f6d65206d6573736167650283010203"), // {1: "some message", 2: []int{1,2,3}}
|
|
v: &TestExample{
|
|
Message: "some message",
|
|
Foo: &arrayFoo123,
|
|
},
|
|
unmarshalToObj: &TestExample{Foo: &arrayFoo},
|
|
},
|
|
{
|
|
name: "map",
|
|
data: hexDecode("a2016c736f6d65206d65737361676502a3010102020303"), // {1: "some message", 2: map[int]int{1:1,2:2,3:3}}
|
|
v: &TestExample{
|
|
Message: "some message",
|
|
Foo: &mapFoo123,
|
|
},
|
|
unmarshalToObj: &TestExample{Foo: &mapFoo},
|
|
},
|
|
{
|
|
name: "struct",
|
|
data: hexDecode("a2016c736f6d65206d65737361676502a1011901c8"), // {1: "some message", 2: {1: 456}}
|
|
v: &TestExample{
|
|
Message: "some message",
|
|
Foo: &StructFoo{Value: 456},
|
|
},
|
|
unmarshalToObj: &TestExample{Foo: &StructFoo{}},
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
|
|
data, err := em.Marshal(tc.v)
|
|
if err != nil {
|
|
t.Errorf("Marshal(%+v) returned error %v", tc.v, err)
|
|
} else if !bytes.Equal(data, tc.data) {
|
|
t.Errorf("Marshal(%+v) = 0x%x, want 0x%x", tc.v, data, tc.data)
|
|
}
|
|
|
|
// Unmarshal to empty interface
|
|
var einterface TestExample
|
|
if err = Unmarshal(data, &einterface); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error, want error (*UnmarshalTypeError)", data)
|
|
} else if _, ok := err.(*UnmarshalTypeError); !ok {
|
|
t.Errorf("Unmarshal(0x%x) returned wrong type of error %T, want (*UnmarshalTypeError)", data, err)
|
|
}
|
|
|
|
// Unmarshal to interface value
|
|
err = Unmarshal(data, tc.unmarshalToObj)
|
|
if err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", data, err)
|
|
} else if !reflect.DeepEqual(tc.unmarshalToObj, tc.v) {
|
|
t.Errorf("Unmarshal(0x%x) = %v, want %v", data, tc.unmarshalToObj, tc.v)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
type Bar struct {
|
|
I int
|
|
}
|
|
|
|
func (b *Bar) Foo() string {
|
|
return fmt.Sprint(*b)
|
|
}
|
|
|
|
type FooStruct struct {
|
|
Foos []Foo
|
|
}
|
|
|
|
func TestUnmarshalTaggedDataToInterface(t *testing.T) {
|
|
|
|
var tags = NewTagSet()
|
|
err := tags.Add(
|
|
TagOptions{EncTag: EncTagRequired, DecTag: DecTagRequired},
|
|
reflect.TypeOf(&Bar{}),
|
|
4,
|
|
)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
v := &FooStruct{
|
|
Foos: []Foo{&Bar{1}},
|
|
}
|
|
|
|
want := hexDecode("a164466f6f7381c4a1614901") // {"Foos": [4({"I": 1})]}
|
|
|
|
em, _ := EncOptions{}.EncModeWithTags(tags)
|
|
data, err := em.Marshal(v)
|
|
if err != nil {
|
|
t.Errorf("Marshal(%+v) returned error %v", v, err)
|
|
} else if !bytes.Equal(data, want) {
|
|
t.Errorf("Marshal(%+v) = 0x%x, want 0x%x", v, data, want)
|
|
}
|
|
|
|
dm, _ := DecOptions{}.DecModeWithTags(tags)
|
|
|
|
// Unmarshal to empty interface
|
|
var v1 Bar
|
|
if err = dm.Unmarshal(data, &v1); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error, want error (*UnmarshalTypeError)", data)
|
|
} else if _, ok := err.(*UnmarshalTypeError); !ok {
|
|
t.Errorf("Unmarshal(0x%x) returned wrong type of error %T, want (*UnmarshalTypeError)", data, err)
|
|
}
|
|
|
|
// Unmarshal to interface value
|
|
v2 := &FooStruct{
|
|
Foos: []Foo{&Bar{}},
|
|
}
|
|
err = dm.Unmarshal(data, v2)
|
|
if err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", data, err)
|
|
} else if !reflect.DeepEqual(v2, v) {
|
|
t.Errorf("Unmarshal(0x%x) = %v, want %v", data, v2, v)
|
|
}
|
|
}
|
|
|
|
type B interface {
|
|
Foo()
|
|
}
|
|
|
|
type C struct {
|
|
Field int
|
|
}
|
|
|
|
func (c *C) Foo() {}
|
|
|
|
type D struct {
|
|
Field string
|
|
}
|
|
|
|
func (d *D) Foo() {}
|
|
|
|
type A1 struct {
|
|
Field B
|
|
}
|
|
|
|
type A2 struct {
|
|
Fields []B
|
|
}
|
|
|
|
func TestUnmarshalRegisteredTagToConcreteType(t *testing.T) {
|
|
var err error
|
|
tags := NewTagSet()
|
|
err = tags.Add(TagOptions{EncTag: EncTagRequired, DecTag: DecTagRequired}, reflect.TypeOf(C{}), 279)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
err = tags.Add(TagOptions{EncTag: EncTagRequired, DecTag: DecTagRequired}, reflect.TypeOf(D{}), 280)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
encMode, _ := PreferredUnsortedEncOptions().EncModeWithTags(tags)
|
|
decMode, _ := DecOptions{}.DecModeWithTags(tags)
|
|
|
|
v1 := A1{Field: &C{Field: 5}}
|
|
data1, err := encMode.Marshal(v1)
|
|
if err != nil {
|
|
t.Fatalf("Marshal(%+v) returned error %v", v1, err)
|
|
}
|
|
|
|
testCases := []struct {
|
|
name string
|
|
data []byte
|
|
unmarshalToObj interface{}
|
|
wantValue interface{}
|
|
}{
|
|
{
|
|
name: "concrete type",
|
|
data: data1,
|
|
unmarshalToObj: &A1{Field: &C{}},
|
|
wantValue: &v1,
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
err = decMode.Unmarshal(tc.data, tc.unmarshalToObj)
|
|
if err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", tc.data, err)
|
|
}
|
|
if !reflect.DeepEqual(tc.unmarshalToObj, tc.wantValue) {
|
|
t.Errorf("Unmarshal(0x%x) = %v, want %v", tc.data, tc.unmarshalToObj, tc.wantValue)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDecModeInvalidDefaultMapType(t *testing.T) {
|
|
testCases := []struct {
|
|
name string
|
|
opts DecOptions
|
|
wantErrorMsg string
|
|
}{
|
|
{
|
|
name: "byte slice",
|
|
opts: DecOptions{DefaultMapType: reflect.TypeOf([]byte(nil))},
|
|
wantErrorMsg: "cbor: invalid DefaultMapType []uint8",
|
|
},
|
|
{
|
|
name: "int slice",
|
|
opts: DecOptions{DefaultMapType: reflect.TypeOf([]int(nil))},
|
|
wantErrorMsg: "cbor: invalid DefaultMapType []int",
|
|
},
|
|
{
|
|
name: "string",
|
|
opts: DecOptions{DefaultMapType: reflect.TypeOf("")},
|
|
wantErrorMsg: "cbor: invalid DefaultMapType string",
|
|
},
|
|
{
|
|
name: "unnamed struct type",
|
|
opts: DecOptions{DefaultMapType: reflect.TypeOf(struct{}{})},
|
|
wantErrorMsg: "cbor: invalid DefaultMapType struct {}",
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
_, err := tc.opts.DecMode()
|
|
if err == nil {
|
|
t.Errorf("DecMode() didn't return an error")
|
|
} else if err.Error() != tc.wantErrorMsg {
|
|
t.Errorf("DecMode() returned error %q, want %q", err.Error(), tc.wantErrorMsg)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalToDefaultMapType(t *testing.T) {
|
|
|
|
cborDataMapIntInt := hexDecode("a201020304") // {1: 2, 3: 4}
|
|
cborDataMapStringInt := hexDecode("a2616101616202") // {"a": 1, "b": 2}
|
|
cborDataArrayOfMapStringint := hexDecode("82a2616101616202a2616303616404") // [{"a": 1, "b": 2}, {"c": 3, "d": 4}]
|
|
cborDataNestedMap := hexDecode("a268496e744669656c6401684d61704669656c64a2616101616202") // {"IntField": 1, "MapField": {"a": 1, "b": 2}}
|
|
|
|
decOptionsDefault := DecOptions{}
|
|
decOptionsMapIntfIntfType := DecOptions{DefaultMapType: reflect.TypeOf(map[interface{}]interface{}(nil))}
|
|
decOptionsMapStringIntType := DecOptions{DefaultMapType: reflect.TypeOf(map[string]int(nil))}
|
|
decOptionsMapStringIntfType := DecOptions{DefaultMapType: reflect.TypeOf(map[string]interface{}(nil))}
|
|
|
|
testCases := []struct {
|
|
name string
|
|
opts DecOptions
|
|
data []byte
|
|
wantValue interface{}
|
|
wantErrorMsg string
|
|
}{
|
|
// Decode CBOR map to map[interface{}]interface{} using default options
|
|
{
|
|
name: "decode CBOR map[int]int to Go map[interface{}]interface{} (default)",
|
|
opts: decOptionsDefault,
|
|
data: cborDataMapIntInt,
|
|
wantValue: map[interface{}]interface{}{uint64(1): uint64(2), uint64(3): uint64(4)},
|
|
},
|
|
{
|
|
name: "decode CBOR map[string]int to Go map[interface{}]interface{} (default)",
|
|
opts: decOptionsDefault,
|
|
data: cborDataMapStringInt,
|
|
wantValue: map[interface{}]interface{}{"a": uint64(1), "b": uint64(2)},
|
|
},
|
|
{
|
|
name: "decode CBOR array of map[string]int to Go []map[interface{}]interface{} (default)",
|
|
opts: decOptionsDefault,
|
|
data: cborDataArrayOfMapStringint,
|
|
wantValue: []interface{}{
|
|
map[interface{}]interface{}{"a": uint64(1), "b": uint64(2)},
|
|
map[interface{}]interface{}{"c": uint64(3), "d": uint64(4)},
|
|
},
|
|
},
|
|
{
|
|
name: "decode CBOR nested map to Go map[interface{}]interface{} (default)",
|
|
opts: decOptionsDefault,
|
|
data: cborDataNestedMap,
|
|
wantValue: map[interface{}]interface{}{
|
|
"IntField": uint64(1),
|
|
"MapField": map[interface{}]interface{}{"a": uint64(1), "b": uint64(2)},
|
|
},
|
|
},
|
|
// Decode CBOR map to map[interface{}]interface{} using default map type option
|
|
{
|
|
name: "decode CBOR map[int]int to Go map[interface{}]interface{}",
|
|
opts: decOptionsMapIntfIntfType,
|
|
data: cborDataMapIntInt,
|
|
wantValue: map[interface{}]interface{}{uint64(1): uint64(2), uint64(3): uint64(4)},
|
|
},
|
|
{
|
|
name: "decode CBOR map[string]int to Go map[interface{}]interface{}",
|
|
opts: decOptionsMapIntfIntfType,
|
|
data: cborDataMapStringInt,
|
|
wantValue: map[interface{}]interface{}{"a": uint64(1), "b": uint64(2)},
|
|
},
|
|
{
|
|
name: "decode CBOR array of map[string]int to Go []map[interface{}]interface{}",
|
|
opts: decOptionsMapIntfIntfType,
|
|
data: cborDataArrayOfMapStringint,
|
|
wantValue: []interface{}{
|
|
map[interface{}]interface{}{"a": uint64(1), "b": uint64(2)},
|
|
map[interface{}]interface{}{"c": uint64(3), "d": uint64(4)},
|
|
},
|
|
},
|
|
{
|
|
name: "decode CBOR nested map to Go map[interface{}]interface{}",
|
|
opts: decOptionsMapIntfIntfType,
|
|
data: cborDataNestedMap,
|
|
wantValue: map[interface{}]interface{}{
|
|
"IntField": uint64(1),
|
|
"MapField": map[interface{}]interface{}{"a": uint64(1), "b": uint64(2)},
|
|
},
|
|
},
|
|
// Decode CBOR map to map[string]interface{} using default map type option
|
|
{
|
|
name: "decode CBOR map[int]int to Go map[string]interface{}",
|
|
opts: decOptionsMapStringIntfType,
|
|
data: cborDataMapIntInt,
|
|
wantErrorMsg: "cbor: cannot unmarshal positive integer into Go value of type string",
|
|
},
|
|
{
|
|
name: "decode CBOR map[string]int to Go map[string]interface{}",
|
|
opts: decOptionsMapStringIntfType,
|
|
data: cborDataMapStringInt,
|
|
wantValue: map[string]interface{}{"a": uint64(1), "b": uint64(2)},
|
|
},
|
|
{
|
|
name: "decode CBOR array of map[string]int to Go []map[string]interface{}",
|
|
opts: decOptionsMapStringIntfType,
|
|
data: cborDataArrayOfMapStringint,
|
|
wantValue: []interface{}{
|
|
map[string]interface{}{"a": uint64(1), "b": uint64(2)},
|
|
map[string]interface{}{"c": uint64(3), "d": uint64(4)},
|
|
},
|
|
},
|
|
{
|
|
name: "decode CBOR nested map to Go map[string]interface{}",
|
|
opts: decOptionsMapStringIntfType,
|
|
data: cborDataNestedMap,
|
|
wantValue: map[string]interface{}{
|
|
"IntField": uint64(1),
|
|
"MapField": map[string]interface{}{"a": uint64(1), "b": uint64(2)},
|
|
},
|
|
},
|
|
// Decode CBOR map to map[string]int using default map type option
|
|
{
|
|
name: "decode CBOR map[int]int to Go map[string]int",
|
|
opts: decOptionsMapStringIntType,
|
|
data: cborDataMapIntInt,
|
|
wantErrorMsg: "cbor: cannot unmarshal positive integer into Go value of type string",
|
|
},
|
|
{
|
|
name: "decode CBOR map[string]int to Go map[string]int",
|
|
opts: decOptionsMapStringIntType,
|
|
data: cborDataMapStringInt,
|
|
wantValue: map[string]int{"a": 1, "b": 2},
|
|
},
|
|
{
|
|
name: "decode CBOR array of map[string]int to Go []map[string]int",
|
|
opts: decOptionsMapStringIntType,
|
|
data: cborDataArrayOfMapStringint,
|
|
wantValue: []interface{}{
|
|
map[string]int{"a": 1, "b": 2},
|
|
map[string]int{"c": 3, "d": 4},
|
|
},
|
|
},
|
|
{
|
|
name: "decode CBOR nested map to Go map[string]int",
|
|
opts: decOptionsMapStringIntType,
|
|
data: cborDataNestedMap,
|
|
wantErrorMsg: "cbor: cannot unmarshal map into Go value of type int",
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
decMode, _ := tc.opts.DecMode()
|
|
|
|
var v interface{}
|
|
err := decMode.Unmarshal(tc.data, &v)
|
|
if err != nil {
|
|
if tc.wantErrorMsg == "" {
|
|
t.Errorf("Unmarshal(0x%x) to empty interface returned error %v", tc.data, err)
|
|
} else if tc.wantErrorMsg != err.Error() {
|
|
t.Errorf("Unmarshal(0x%x) error %q, want %q", tc.data, err.Error(), tc.wantErrorMsg)
|
|
}
|
|
} else {
|
|
if tc.wantValue == nil {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want error %q", tc.data, v, v, tc.wantErrorMsg)
|
|
} else if !reflect.DeepEqual(v, tc.wantValue) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", tc.data, v, v, tc.wantValue, tc.wantValue)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalFirstNoTrailing(t *testing.T) {
|
|
for _, tc := range unmarshalTests {
|
|
var v interface{}
|
|
if rest, err := UnmarshalFirst(tc.data, &v); err != nil {
|
|
t.Errorf("UnmarshalFirst(0x%x) returned error %v", tc.data, err)
|
|
} else {
|
|
if len(rest) != 0 {
|
|
t.Errorf("UnmarshalFirst(0x%x) returned rest %x (want [])", tc.data, rest)
|
|
}
|
|
// Check the value as well, although this is covered by other tests
|
|
if tm, ok := tc.wantInterfaceValue.(time.Time); ok {
|
|
if vt, ok := v.(time.Time); !ok || !tm.Equal(vt) {
|
|
t.Errorf("UnmarshalFirst(0x%x) = %v (%T), want %v (%T)", tc.data, v, v, tc.wantInterfaceValue, tc.wantInterfaceValue)
|
|
}
|
|
} else if !reflect.DeepEqual(v, tc.wantInterfaceValue) {
|
|
t.Errorf("UnmarshalFirst(0x%x) = %v (%T), want %v (%T)", tc.data, v, v, tc.wantInterfaceValue, tc.wantInterfaceValue)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalfirstTrailing(t *testing.T) {
|
|
// Random trailing data
|
|
trailingData := hexDecode("4a6b0f4718c73f391091ea1c")
|
|
for _, tc := range unmarshalTests {
|
|
data := make([]byte, 0, len(tc.data)+len(trailingData))
|
|
data = append(data, tc.data...)
|
|
data = append(data, trailingData...)
|
|
var v interface{}
|
|
if rest, err := UnmarshalFirst(data, &v); err != nil {
|
|
t.Errorf("UnmarshalFirst(0x%x) returned error %v", data, err)
|
|
} else {
|
|
if !bytes.Equal(trailingData, rest) {
|
|
t.Errorf("UnmarshalFirst(0x%x) returned rest %x (want %x)", data, rest, trailingData)
|
|
}
|
|
// Check the value as well, although this is covered by other tests
|
|
if tm, ok := tc.wantInterfaceValue.(time.Time); ok {
|
|
if vt, ok := v.(time.Time); !ok || !tm.Equal(vt) {
|
|
t.Errorf("UnmarshalFirst(0x%x) = %v (%T), want %v (%T)", data, v, v, tc.wantInterfaceValue, tc.wantInterfaceValue)
|
|
}
|
|
} else if !reflect.DeepEqual(v, tc.wantInterfaceValue) {
|
|
t.Errorf("UnmarshalFirst(0x%x) = %v (%T), want %v (%T)", data, v, v, tc.wantInterfaceValue, tc.wantInterfaceValue)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalFirstInvalidItem(t *testing.T) {
|
|
// UnmarshalFirst should not return "rest" if the item was not well-formed
|
|
invalidCBOR := hexDecode("83FF20030102")
|
|
var v interface{}
|
|
rest, err := UnmarshalFirst(invalidCBOR, &v)
|
|
if rest != nil || err == nil {
|
|
t.Errorf("UnmarshalFirst(0x%x) = (%x, %v), want (nil, err)", invalidCBOR, rest, err)
|
|
}
|
|
}
|
|
|
|
func TestDecModeInvalidFieldNameMatchingMode(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
name string
|
|
opts DecOptions
|
|
wantErrorMsg string
|
|
}{
|
|
{
|
|
name: "below range of valid modes",
|
|
opts: DecOptions{FieldNameMatching: -1},
|
|
wantErrorMsg: "cbor: invalid FieldNameMatching -1",
|
|
},
|
|
{
|
|
name: "above range of valid modes",
|
|
opts: DecOptions{FieldNameMatching: 101},
|
|
wantErrorMsg: "cbor: invalid FieldNameMatching 101",
|
|
},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
_, err := tc.opts.DecMode()
|
|
if err == nil {
|
|
t.Errorf("DecMode() didn't return an error")
|
|
} else if err.Error() != tc.wantErrorMsg {
|
|
t.Errorf("DecMode() returned error %q, want %q", err.Error(), tc.wantErrorMsg)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDecodeFieldNameMatching(t *testing.T) {
|
|
type s struct {
|
|
LowerA int `cbor:"a"`
|
|
UpperB int `cbor:"B"`
|
|
LowerB int `cbor:"b"`
|
|
}
|
|
|
|
testCases := []struct {
|
|
name string
|
|
opts DecOptions
|
|
data []byte
|
|
wantValue s
|
|
}{
|
|
{
|
|
name: "case-insensitive match",
|
|
data: hexDecode("a1614101"), // {"A": 1}
|
|
wantValue: s{LowerA: 1},
|
|
},
|
|
{
|
|
name: "ignore case-insensitive match",
|
|
opts: DecOptions{FieldNameMatching: FieldNameMatchingCaseSensitive},
|
|
data: hexDecode("a1614101"), // {"A": 1}
|
|
wantValue: s{},
|
|
},
|
|
{
|
|
name: "exact match before case-insensitive match",
|
|
data: hexDecode("a2616101614102"), // {"a": 1, "A": 2}
|
|
wantValue: s{LowerA: 1},
|
|
},
|
|
{
|
|
name: "case-insensitive match before exact match",
|
|
data: hexDecode("a2614101616102"), // {"A": 1, "a": 2}
|
|
wantValue: s{LowerA: 1},
|
|
},
|
|
{
|
|
name: "ignore case-insensitive match before exact match",
|
|
opts: DecOptions{FieldNameMatching: FieldNameMatchingCaseSensitive},
|
|
data: hexDecode("a2614101616102"), // {"A": 1, "a": 2}
|
|
wantValue: s{LowerA: 2},
|
|
},
|
|
{
|
|
name: "earliest exact match wins",
|
|
opts: DecOptions{FieldNameMatching: FieldNameMatchingCaseSensitive},
|
|
data: hexDecode("a2616101616102"), // {"a": 1, "a": 2} (invalid)
|
|
wantValue: s{LowerA: 1},
|
|
},
|
|
{
|
|
// the field tags themselves are case-insensitive matches for each other
|
|
name: "duplicate key does not fall back to case-insensitive match",
|
|
data: hexDecode("a2614201614202"), // {"B": 1, "B": 2} (invalid)
|
|
wantValue: s{UpperB: 1},
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
decMode, _ := tc.opts.DecMode()
|
|
|
|
var dst s
|
|
err := decMode.Unmarshal(tc.data, &dst)
|
|
if err != nil {
|
|
t.Fatalf("Unmarshal(0x%x) returned unexpected error %v", tc.data, err)
|
|
}
|
|
|
|
if !reflect.DeepEqual(dst, tc.wantValue) {
|
|
t.Errorf("Unmarshal(0x%x) = %#v, want %#v", tc.data, dst, tc.wantValue)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestInvalidBigIntDecMode(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
name string
|
|
opts DecOptions
|
|
wantErrorMsg string
|
|
}{
|
|
{
|
|
name: "below range of valid modes",
|
|
opts: DecOptions{BigIntDec: -1},
|
|
wantErrorMsg: "cbor: invalid BigIntDec -1",
|
|
},
|
|
{
|
|
name: "above range of valid modes",
|
|
opts: DecOptions{BigIntDec: 101},
|
|
wantErrorMsg: "cbor: invalid BigIntDec 101",
|
|
},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
_, err := tc.opts.DecMode()
|
|
if err == nil {
|
|
t.Errorf("DecMode() didn't return an error")
|
|
} else if err.Error() != tc.wantErrorMsg {
|
|
t.Errorf("DecMode() returned error %q, want %q", err.Error(), tc.wantErrorMsg)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDecodeBignumToEmptyInterface(t *testing.T) {
|
|
decOptionsDecodeToBigIntValue := DecOptions{BigIntDec: BigIntDecodeValue}
|
|
decOptionsDecodeToBigIntPointer := DecOptions{BigIntDec: BigIntDecodePointer}
|
|
|
|
cborDataPositiveBignum := hexDecode("c249010000000000000000") // positive bignum: 18446744073709551616
|
|
pbn, _ := new(big.Int).SetString("18446744073709551616", 10)
|
|
|
|
cborDataNegativeBignum := hexDecode("c349010000000000000000") // negative bignum: -18446744073709551617
|
|
nbn, _ := new(big.Int).SetString("-18446744073709551617", 10)
|
|
|
|
cborDataLargeNegativeInt := hexDecode("3bffffffffffffffff") // -18446744073709551616
|
|
ni, _ := new(big.Int).SetString("-18446744073709551616", 10)
|
|
|
|
testCases := []struct {
|
|
name string
|
|
opts DecOptions
|
|
data []byte
|
|
wantValue interface{}
|
|
}{
|
|
{
|
|
name: "decode positive bignum to big.Int",
|
|
opts: decOptionsDecodeToBigIntValue,
|
|
data: cborDataPositiveBignum,
|
|
wantValue: *pbn,
|
|
},
|
|
{
|
|
name: "decode negative bignum to big.Int",
|
|
opts: decOptionsDecodeToBigIntValue,
|
|
data: cborDataNegativeBignum,
|
|
wantValue: *nbn,
|
|
},
|
|
{
|
|
name: "decode large negative int to big.Int",
|
|
opts: decOptionsDecodeToBigIntValue,
|
|
data: cborDataLargeNegativeInt,
|
|
wantValue: *ni,
|
|
},
|
|
{
|
|
name: "decode positive bignum to *big.Int",
|
|
opts: decOptionsDecodeToBigIntPointer,
|
|
data: cborDataPositiveBignum,
|
|
wantValue: pbn,
|
|
},
|
|
{
|
|
name: "decode negative bignum to *big.Int",
|
|
opts: decOptionsDecodeToBigIntPointer,
|
|
data: cborDataNegativeBignum,
|
|
wantValue: nbn,
|
|
},
|
|
{
|
|
name: "decode large negative int to *big.Int",
|
|
opts: decOptionsDecodeToBigIntPointer,
|
|
data: cborDataLargeNegativeInt,
|
|
wantValue: ni,
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
decMode, _ := tc.opts.DecMode()
|
|
|
|
var v interface{}
|
|
err := decMode.Unmarshal(tc.data, &v)
|
|
if err != nil {
|
|
t.Errorf("Unmarshal(0x%x) to empty interface returned error %v", tc.data, err)
|
|
} else { //nolint:gocritic // ignore elseif
|
|
if !reflect.DeepEqual(v, tc.wantValue) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", tc.data, v, v, tc.wantValue, tc.wantValue)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDecModeInvalidDefaultByteStringType(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
name string
|
|
opts DecOptions
|
|
wantErrorMsg string
|
|
}{
|
|
{
|
|
name: "neither slice nor string",
|
|
opts: DecOptions{DefaultByteStringType: reflect.TypeOf(int(42))},
|
|
wantErrorMsg: "cbor: invalid DefaultByteStringType: int is not of kind string or []uint8",
|
|
},
|
|
{
|
|
name: "slice of non-byte",
|
|
opts: DecOptions{DefaultByteStringType: reflect.TypeOf([]int{})},
|
|
wantErrorMsg: "cbor: invalid DefaultByteStringType: []int is not of kind string or []uint8",
|
|
},
|
|
{
|
|
name: "pointer to byte array",
|
|
opts: DecOptions{DefaultByteStringType: reflect.TypeOf(&[42]byte{})},
|
|
wantErrorMsg: "cbor: invalid DefaultByteStringType: *[42]uint8 is not of kind string or []uint8",
|
|
},
|
|
{
|
|
name: "byte array",
|
|
opts: DecOptions{DefaultByteStringType: reflect.TypeOf([42]byte{})},
|
|
wantErrorMsg: "cbor: invalid DefaultByteStringType: [42]uint8 is not of kind string or []uint8",
|
|
},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
_, err := tc.opts.DecMode()
|
|
if err == nil {
|
|
t.Errorf("DecMode() didn't return an error")
|
|
} else if err.Error() != tc.wantErrorMsg {
|
|
t.Errorf("DecMode() returned error %q, want %q", err.Error(), tc.wantErrorMsg)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalDefaultByteStringType(t *testing.T) {
|
|
type namedByteSliceType []byte
|
|
|
|
for _, tc := range []struct {
|
|
name string
|
|
opts DecOptions
|
|
in []byte
|
|
want interface{}
|
|
}{
|
|
{
|
|
name: "default to []byte",
|
|
opts: DecOptions{},
|
|
in: hexDecode("43414243"),
|
|
want: []byte("ABC"),
|
|
},
|
|
{
|
|
name: "explicitly []byte",
|
|
opts: DecOptions{DefaultByteStringType: reflect.TypeOf([]byte(nil))},
|
|
in: hexDecode("43414243"),
|
|
want: []byte("ABC"),
|
|
},
|
|
{
|
|
name: "string",
|
|
opts: DecOptions{DefaultByteStringType: reflect.TypeOf("")},
|
|
in: hexDecode("43414243"),
|
|
want: "ABC",
|
|
},
|
|
{
|
|
name: "ByteString",
|
|
opts: DecOptions{DefaultByteStringType: reflect.TypeOf(ByteString(""))},
|
|
in: hexDecode("43414243"),
|
|
want: ByteString("ABC"),
|
|
},
|
|
{
|
|
name: "named []byte type",
|
|
opts: DecOptions{DefaultByteStringType: reflect.TypeOf(namedByteSliceType(nil))},
|
|
in: hexDecode("43414243"),
|
|
want: namedByteSliceType("ABC"),
|
|
},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
dm, err := tc.opts.DecMode()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
var got interface{}
|
|
if err := dm.Unmarshal(tc.in, &got); err != nil {
|
|
t.Errorf("unexpected error: %v", err)
|
|
}
|
|
|
|
if !reflect.DeepEqual(tc.want, got) {
|
|
t.Errorf("got %#v, want %#v", got, tc.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDecModeInvalidByteStringToStringMode(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
name string
|
|
opts DecOptions
|
|
wantErrorMsg string
|
|
}{
|
|
{
|
|
name: "below range of valid modes",
|
|
opts: DecOptions{ByteStringToString: -1},
|
|
wantErrorMsg: "cbor: invalid ByteStringToString -1",
|
|
},
|
|
{
|
|
name: "above range of valid modes",
|
|
opts: DecOptions{ByteStringToString: 101},
|
|
wantErrorMsg: "cbor: invalid ByteStringToString 101",
|
|
},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
_, err := tc.opts.DecMode()
|
|
if err == nil {
|
|
t.Errorf("DecMode() didn't return an error")
|
|
} else if err.Error() != tc.wantErrorMsg {
|
|
t.Errorf("DecMode() returned error %q, want %q", err.Error(), tc.wantErrorMsg)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalByteStringToString(t *testing.T) {
|
|
var s string
|
|
|
|
derror, err := DecOptions{ByteStringToString: ByteStringToStringForbidden}.DecMode()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if err = derror.Unmarshal(hexDecode("43414243"), &s); err == nil {
|
|
t.Error("expected non-nil error from Unmarshal")
|
|
}
|
|
|
|
if s != "" {
|
|
t.Errorf("expected destination string to be empty, got %q", s)
|
|
}
|
|
|
|
dallow, err := DecOptions{ByteStringToString: ByteStringToStringAllowed}.DecMode()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if err = dallow.Unmarshal(hexDecode("43414243"), &s); err != nil {
|
|
t.Errorf("expected nil error from Unmarshal, got: %v", err)
|
|
}
|
|
|
|
if s != "ABC" {
|
|
t.Errorf("expected destination string to be \"ABC\", got %q", s)
|
|
}
|
|
}
|
|
|
|
func TestDecModeInvalidFieldNameByteStringMode(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
name string
|
|
opts DecOptions
|
|
wantErrorMsg string
|
|
}{
|
|
{
|
|
name: "below range of valid modes",
|
|
opts: DecOptions{FieldNameByteString: -1},
|
|
wantErrorMsg: "cbor: invalid FieldNameByteString -1",
|
|
},
|
|
{
|
|
name: "above range of valid modes",
|
|
opts: DecOptions{FieldNameByteString: 101},
|
|
wantErrorMsg: "cbor: invalid FieldNameByteString 101",
|
|
},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
_, err := tc.opts.DecMode()
|
|
if err == nil {
|
|
t.Errorf("DecMode() didn't return an error")
|
|
} else if err.Error() != tc.wantErrorMsg {
|
|
t.Errorf("DecMode() returned error %q, want %q", err.Error(), tc.wantErrorMsg)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalFieldNameByteString(t *testing.T) {
|
|
allowed, err := DecOptions{
|
|
FieldNameByteString: FieldNameByteStringAllowed,
|
|
}.DecMode()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
var s struct {
|
|
F int64 `json:"f"`
|
|
}
|
|
|
|
err = allowed.Unmarshal(hexDecode("a1414601"), &s) // {h'46': 1}
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if s.F != 1 {
|
|
t.Errorf("expected field F to be set to 1, got %d", s.F)
|
|
}
|
|
|
|
forbidden, err := DecOptions{
|
|
FieldNameByteString: FieldNameByteStringForbidden,
|
|
}.DecMode()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
const wantMsg = "cbor: cannot unmarshal byte string into Go value of type string (map key is of type byte string and cannot be used to match struct field name)"
|
|
if err := forbidden.Unmarshal(hexDecode("a1414601"), &s); err == nil {
|
|
t.Errorf("expected non-nil error")
|
|
} else if gotMsg := err.Error(); gotMsg != wantMsg {
|
|
t.Errorf("expected error %q, got %q", wantMsg, gotMsg)
|
|
}
|
|
}
|
|
|
|
func TestDecModeInvalidReturnTypeForEmptyInterface(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
name string
|
|
opts DecOptions
|
|
wantErrorMsg string
|
|
}{
|
|
{
|
|
name: "below range of valid modes",
|
|
opts: DecOptions{UnrecognizedTagToAny: -1},
|
|
wantErrorMsg: "cbor: invalid UnrecognizedTagToAnyMode -1",
|
|
},
|
|
{
|
|
name: "above range of valid modes",
|
|
opts: DecOptions{UnrecognizedTagToAny: 101},
|
|
wantErrorMsg: "cbor: invalid UnrecognizedTagToAnyMode 101",
|
|
},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
_, err := tc.opts.DecMode()
|
|
if err == nil {
|
|
t.Errorf("DecMode() didn't return an error")
|
|
} else if err.Error() != tc.wantErrorMsg {
|
|
t.Errorf("DecMode() returned error %q, want %q", err.Error(), tc.wantErrorMsg)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalWithUnrecognizedTagToAnyMode(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
name string
|
|
opts DecOptions
|
|
in []byte
|
|
want interface{}
|
|
}{
|
|
{
|
|
name: "default to value of type Tag",
|
|
opts: DecOptions{},
|
|
in: hexDecode("d8ff00"),
|
|
want: Tag{Number: uint64(255), Content: uint64(0)},
|
|
},
|
|
{
|
|
name: "Tag's content",
|
|
opts: DecOptions{UnrecognizedTagToAny: UnrecognizedTagContentToAny},
|
|
in: hexDecode("d8ff00"),
|
|
want: uint64(0),
|
|
},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
dm, err := tc.opts.DecMode()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
var got interface{}
|
|
if err := dm.Unmarshal(tc.in, &got); err != nil {
|
|
t.Errorf("unexpected error: %v", err)
|
|
}
|
|
|
|
if tc.want != got {
|
|
t.Errorf("got %s, want %s", got, tc.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalWithUnrecognizedTagToAnyModeForSupportedTags(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
name string
|
|
opts DecOptions
|
|
in []byte
|
|
want interface{}
|
|
}{
|
|
{
|
|
name: "Unmarshal with tag number 0 when UnrecognizedTagContentToAny option is not set",
|
|
opts: DecOptions{},
|
|
in: hexDecode("c074323031332d30332d32315432303a30343a30305a"),
|
|
want: time.Date(2013, 3, 21, 20, 4, 0, 0, time.UTC),
|
|
},
|
|
{
|
|
name: "Unmarshal with tag number 0 when UnrecognizedTagContentToAny option is set",
|
|
opts: DecOptions{UnrecognizedTagToAny: UnrecognizedTagContentToAny},
|
|
in: hexDecode("c074323031332d30332d32315432303a30343a30305a"),
|
|
want: time.Date(2013, 3, 21, 20, 4, 0, 0, time.UTC),
|
|
},
|
|
{
|
|
name: "Unmarshal with tag number 1 when UnrecognizedTagContentToAny option is not set",
|
|
opts: DecOptions{},
|
|
in: hexDecode("c11a514b67b0"),
|
|
want: time.Date(2013, 3, 21, 20, 4, 0, 0, time.UTC),
|
|
},
|
|
{
|
|
name: "Unmarshal with tag number 1 when UnrecognizedTagContentToAny option is set",
|
|
opts: DecOptions{UnrecognizedTagToAny: UnrecognizedTagContentToAny},
|
|
in: hexDecode("c11a514b67b0"),
|
|
want: time.Date(2013, 3, 21, 20, 4, 0, 0, time.UTC),
|
|
},
|
|
{
|
|
name: "Unmarshal with tag number 2 when UnrecognizedTagContentToAny option is not set",
|
|
opts: DecOptions{},
|
|
in: hexDecode("c249010000000000000000"),
|
|
want: bigIntOrPanic("18446744073709551616"),
|
|
},
|
|
{
|
|
name: "Unmarshal with tag number 2 when UnrecognizedTagContentToAny option is set",
|
|
opts: DecOptions{UnrecognizedTagToAny: UnrecognizedTagContentToAny},
|
|
in: hexDecode("c249010000000000000000"),
|
|
want: bigIntOrPanic("18446744073709551616"),
|
|
},
|
|
{
|
|
name: "Unmarshal with tag number 3 when UnrecognizedTagContentToAny option is not set",
|
|
opts: DecOptions{},
|
|
in: hexDecode("c349010000000000000000"),
|
|
want: bigIntOrPanic("-18446744073709551617"),
|
|
},
|
|
{
|
|
name: "Unmarshal with tag number 3 when UnrecognizedTagContentToAny option is set",
|
|
opts: DecOptions{UnrecognizedTagToAny: UnrecognizedTagContentToAny},
|
|
in: hexDecode("c349010000000000000000"),
|
|
want: bigIntOrPanic("-18446744073709551617"),
|
|
},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
dm, err := tc.opts.DecMode()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
var got interface{}
|
|
if err := dm.Unmarshal(tc.in, &got); err != nil {
|
|
t.Errorf("unexpected error: %v", err)
|
|
}
|
|
|
|
compareNonFloats(t, tc.in, got, tc.want)
|
|
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalWithUnrecognizedTagToAnyModeForSharedTag(t *testing.T) {
|
|
|
|
type myInt int
|
|
typ := reflect.TypeOf(myInt(0))
|
|
|
|
tags := NewTagSet()
|
|
if err := tags.Add(TagOptions{EncTag: EncTagRequired, DecTag: DecTagRequired}, typ, 125); err != nil {
|
|
t.Fatalf("TagSet.Add(%s, %v) returned error %v", typ, 125, err)
|
|
}
|
|
|
|
for _, tc := range []struct {
|
|
name string
|
|
opts DecOptions
|
|
in []byte
|
|
want interface{}
|
|
}{
|
|
{
|
|
name: "Unmarshal with a shared tag when UnrecognizedTagContentToAny option is not set",
|
|
opts: DecOptions{},
|
|
in: hexDecode("d9d9f7d87d01"), // 55799(125(1))
|
|
want: myInt(1),
|
|
},
|
|
{
|
|
name: "Unmarshal with a shared tag when UnrecognizedTagContentToAny option is set",
|
|
opts: DecOptions{UnrecognizedTagToAny: UnrecognizedTagContentToAny},
|
|
in: hexDecode("d9d9f7d87d01"), // 55799(125(1))
|
|
want: myInt(1),
|
|
},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
dm, err := tc.opts.DecModeWithTags(tags)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
var got interface{}
|
|
|
|
if err := dm.Unmarshal(tc.in, &got); err != nil {
|
|
t.Errorf("unexpected error: %v", err)
|
|
}
|
|
|
|
compareNonFloats(t, tc.in, got, tc.want)
|
|
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNewSimpleValueRegistry(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
name string
|
|
opts []func(*SimpleValueRegistry) error
|
|
wantErrorMsg string
|
|
}{
|
|
{
|
|
name: "min reserved",
|
|
opts: []func(*SimpleValueRegistry) error{WithRejectedSimpleValue(24)},
|
|
wantErrorMsg: "cbor: cannot set analog for reserved simple value 24",
|
|
},
|
|
{
|
|
name: "max reserved",
|
|
opts: []func(*SimpleValueRegistry) error{WithRejectedSimpleValue(31)},
|
|
wantErrorMsg: "cbor: cannot set analog for reserved simple value 31",
|
|
},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
_, err := NewSimpleValueRegistryFromDefaults(tc.opts...)
|
|
if err == nil {
|
|
t.Fatalf("got nil error, want: %s", tc.wantErrorMsg)
|
|
}
|
|
if got := err.Error(); got != tc.wantErrorMsg {
|
|
t.Errorf("want: %s, got: %s", tc.wantErrorMsg, got)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalSimpleValues(t *testing.T) {
|
|
assertNilError := func(t *testing.T, e error) {
|
|
if e != nil {
|
|
t.Errorf("expected nil error, got: %v", e)
|
|
}
|
|
}
|
|
|
|
assertExactError := func(want error) func(*testing.T, error) {
|
|
return func(t *testing.T, got error) {
|
|
targetErr := reflect.New(reflect.TypeOf(want)).Interface()
|
|
if !errors.As(got, &targetErr) ||
|
|
got.Error() != want.Error() {
|
|
t.Errorf("want %#v, got %#v", want, got)
|
|
}
|
|
}
|
|
}
|
|
|
|
for _, tc := range []struct {
|
|
name string
|
|
fns []func(*SimpleValueRegistry) error
|
|
in []byte
|
|
into reflect.Type
|
|
want interface{}
|
|
assertOnError func(t *testing.T, e error)
|
|
}{
|
|
{
|
|
name: "default false into interface{}",
|
|
fns: nil,
|
|
in: []byte{0xf4},
|
|
into: typeIntf,
|
|
want: false,
|
|
assertOnError: assertNilError,
|
|
},
|
|
{
|
|
name: "default false into bool",
|
|
fns: nil,
|
|
in: []byte{0xf4},
|
|
into: typeBool,
|
|
want: false,
|
|
assertOnError: assertNilError,
|
|
},
|
|
{
|
|
name: "default true into interface{}",
|
|
fns: nil,
|
|
in: []byte{0xf5},
|
|
into: typeIntf,
|
|
want: true,
|
|
assertOnError: assertNilError,
|
|
},
|
|
{
|
|
name: "default true into bool",
|
|
fns: nil,
|
|
in: []byte{0xf5},
|
|
into: typeBool,
|
|
want: true,
|
|
assertOnError: assertNilError,
|
|
},
|
|
{
|
|
name: "default null into interface{}",
|
|
fns: nil,
|
|
in: []byte{0xf6},
|
|
into: typeIntf,
|
|
want: nil,
|
|
assertOnError: assertNilError,
|
|
},
|
|
{
|
|
name: "default undefined into interface{}",
|
|
fns: nil,
|
|
in: []byte{0xf7},
|
|
into: typeIntf,
|
|
want: nil,
|
|
assertOnError: assertNilError,
|
|
},
|
|
{
|
|
name: "reject undefined into interface{}",
|
|
fns: []func(*SimpleValueRegistry) error{WithRejectedSimpleValue(23)},
|
|
in: []byte{0xf7},
|
|
into: typeIntf,
|
|
want: nil,
|
|
assertOnError: assertExactError(&UnacceptableDataItemError{
|
|
CBORType: "primitives",
|
|
Message: "simple value 23 is not recognized",
|
|
}),
|
|
},
|
|
{
|
|
name: "reject true into bool",
|
|
fns: []func(*SimpleValueRegistry) error{WithRejectedSimpleValue(21)},
|
|
in: []byte{0xf5},
|
|
into: typeBool,
|
|
want: false,
|
|
assertOnError: assertExactError(&UnacceptableDataItemError{
|
|
CBORType: "primitives",
|
|
Message: "simple value 21 is not recognized",
|
|
}),
|
|
},
|
|
{
|
|
name: "default unrecognized into uint64",
|
|
fns: nil,
|
|
in: []byte{0xf8, 0xc8},
|
|
into: typeUint64,
|
|
want: uint64(200),
|
|
assertOnError: assertNilError,
|
|
},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
r, err := NewSimpleValueRegistryFromDefaults(tc.fns...)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
decMode, err := DecOptions{SimpleValues: r}.DecMode()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
dst := reflect.New(tc.into)
|
|
err = decMode.Unmarshal(tc.in, dst.Interface())
|
|
tc.assertOnError(t, err)
|
|
|
|
if got := dst.Elem().Interface(); !reflect.DeepEqual(tc.want, got) {
|
|
t.Errorf("got: %#v\nwant: %#v\n", got, tc.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func isCBORNil(data []byte) bool {
|
|
return len(data) > 0 && (data[0] == 0xf6 || data[0] == 0xf7)
|
|
}
|
|
|
|
func TestDecModeInvalidTimeTagToAnyMode(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
name string
|
|
opts DecOptions
|
|
wantErrorMsg string
|
|
}{
|
|
{
|
|
name: "below range of valid modes",
|
|
opts: DecOptions{TimeTagToAny: -1},
|
|
wantErrorMsg: "cbor: invalid TimeTagToAny -1",
|
|
},
|
|
{
|
|
name: "above range of valid modes",
|
|
opts: DecOptions{TimeTagToAny: 4},
|
|
wantErrorMsg: "cbor: invalid TimeTagToAny 4",
|
|
},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
_, err := tc.opts.DecMode()
|
|
if err == nil {
|
|
t.Errorf("Expected non nil error from DecMode()")
|
|
} else if err.Error() != tc.wantErrorMsg {
|
|
t.Errorf("Expected error: %q, want: %q \n", tc.wantErrorMsg, err.Error())
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDecModeTimeTagToAny(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
name string
|
|
opts DecOptions
|
|
in []byte
|
|
want interface{}
|
|
wantErrMessage string
|
|
}{
|
|
{
|
|
name: "Unmarshal tag 0 data to time.Time when TimeTagToAny is not set",
|
|
opts: DecOptions{},
|
|
in: hexDecode("c074323031332d30332d32315432303a30343a30305a"),
|
|
want: time.Date(2013, 3, 21, 20, 4, 0, 0, time.UTC),
|
|
},
|
|
{
|
|
name: "Unmarshal tag 1 data to time.Time when TimeTagToAny is not set",
|
|
opts: DecOptions{},
|
|
in: hexDecode("c11a514b67b0"),
|
|
want: time.Date(2013, 3, 21, 20, 4, 0, 0, time.UTC),
|
|
},
|
|
{
|
|
name: "Unmarshal tag 0 data to RFC3339 string when TimeTagToAny is set",
|
|
opts: DecOptions{TimeTagToAny: TimeTagToRFC3339},
|
|
in: hexDecode("c074323031332d30332d32315432303a30343a30305a"),
|
|
want: "2013-03-21T20:04:00Z",
|
|
},
|
|
{
|
|
name: "Unmarshal tag 1 data to RFC3339 string when TimeTagToAny is set",
|
|
opts: DecOptions{TimeTagToAny: TimeTagToRFC3339},
|
|
in: hexDecode("c11a514b67b0"),
|
|
want: "2013-03-21T20:04:00Z",
|
|
},
|
|
{
|
|
name: "Unmarshal tag 0 data to RFC3339Nano string when TimeTagToAny is set",
|
|
opts: DecOptions{TimeTagToAny: TimeTagToRFC3339Nano},
|
|
in: hexDecode("c076323031332d30332d32315432303a30343a30302e355a"),
|
|
want: "2013-03-21T20:04:00.5Z",
|
|
},
|
|
{
|
|
name: "Unmarshal tag 1 data to RFC3339Nano string when TimeTagToAny is set",
|
|
opts: DecOptions{TimeTagToAny: TimeTagToRFC3339Nano},
|
|
in: hexDecode("c1fb41d452d9ec200000"),
|
|
want: "2013-03-21T20:04:00.5Z",
|
|
},
|
|
{
|
|
name: "error under TimeTagToRFC3339 when tag 0 contains an invalid RFC3339 timestamp",
|
|
opts: DecOptions{TimeTagToAny: TimeTagToRFC3339},
|
|
in: hexDecode("c07731303030302D30332D32315432303A30343A30302E355A"), // 0("10000-03-21T20:04:00.5Z")
|
|
wantErrMessage: `cbor: cannot set 10000-03-21T20:04:00.5Z for time.Time: parsing time "10000-03-21T20:04:00.5Z" as "2006-01-02T15:04:05Z07:00": cannot parse "0-03-21T20:04:00.5Z" as "-"`,
|
|
},
|
|
{
|
|
name: "error under TimeTagToRFC3339Nano when tag 0 contains an invalid RFC3339 timestamp",
|
|
opts: DecOptions{TimeTagToAny: TimeTagToRFC3339Nano},
|
|
in: hexDecode("c07731303030302D30332D32315432303A30343A30302E355A"), // 0("10000-03-21T20:04:00.5Z")
|
|
wantErrMessage: `cbor: cannot set 10000-03-21T20:04:00.5Z for time.Time: parsing time "10000-03-21T20:04:00.5Z" as "2006-01-02T15:04:05Z07:00": cannot parse "0-03-21T20:04:00.5Z" as "-"`,
|
|
},
|
|
{
|
|
name: "error under TimeTagToRFC3339 when tag 1 represents a time that can't be represented by valid RFC3339",
|
|
opts: DecOptions{TimeTagToAny: TimeTagToRFC3339},
|
|
in: hexDecode("c11b0000003afff44181"), // 1(253402300801)
|
|
wantErrMessage: "cbor: decoded time cannot be represented in RFC3339 format: Time.MarshalText: year outside of range [0,9999]",
|
|
},
|
|
{
|
|
name: "error under TimeTagToRFC3339Nano when tag 1 represents a time that can't be represented by valid RFC3339",
|
|
opts: DecOptions{TimeTagToAny: TimeTagToRFC3339Nano},
|
|
in: hexDecode("c11b0000003afff44181"), // 1(253402300801)
|
|
wantErrMessage: "cbor: decoded time cannot be represented in RFC3339 format with sub-second precision: Time.MarshalText: year outside of range [0,9999]",
|
|
},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
dm, err := tc.opts.DecMode()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
var got interface{}
|
|
if err := dm.Unmarshal(tc.in, &got); err != nil {
|
|
if tc.wantErrMessage == "" {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
} else if gotErrMessage := err.Error(); tc.wantErrMessage != gotErrMessage {
|
|
t.Fatalf("want error %q, got %q", tc.wantErrMessage, gotErrMessage)
|
|
}
|
|
} else if tc.wantErrMessage != "" {
|
|
t.Fatalf("got nil error, want %q", tc.wantErrMessage)
|
|
}
|
|
|
|
compareNonFloats(t, tc.in, got, tc.want)
|
|
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDecModeInvalidNaNDec(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
name string
|
|
opts DecOptions
|
|
wantErrorMsg string
|
|
}{
|
|
{
|
|
name: "below range of valid modes",
|
|
opts: DecOptions{NaN: -1},
|
|
wantErrorMsg: "cbor: invalid NaNDec -1",
|
|
},
|
|
{
|
|
name: "above range of valid modes",
|
|
opts: DecOptions{NaN: 101},
|
|
wantErrorMsg: "cbor: invalid NaNDec 101",
|
|
},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
_, err := tc.opts.DecMode()
|
|
if err == nil {
|
|
t.Errorf("DecMode() didn't return an error")
|
|
} else if err.Error() != tc.wantErrorMsg {
|
|
t.Errorf("DecMode() returned error %q, want %q", err.Error(), tc.wantErrorMsg)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNaNDecMode(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
opt NaNMode
|
|
src []byte
|
|
dst interface{}
|
|
reject bool
|
|
}{
|
|
{
|
|
opt: NaNDecodeForbidden,
|
|
src: hexDecode("197e00"),
|
|
dst: new(interface{}),
|
|
reject: false,
|
|
},
|
|
{
|
|
opt: NaNDecodeForbidden,
|
|
src: hexDecode("1a7fc00000"),
|
|
dst: new(interface{}),
|
|
reject: false,
|
|
},
|
|
{
|
|
opt: NaNDecodeForbidden,
|
|
src: hexDecode("1b7ff8000000000000"),
|
|
dst: new(interface{}),
|
|
reject: false,
|
|
},
|
|
{
|
|
opt: NaNDecodeForbidden,
|
|
src: hexDecode("f90000"), // 0.0
|
|
dst: new(interface{}),
|
|
reject: false,
|
|
},
|
|
{
|
|
opt: NaNDecodeForbidden,
|
|
src: hexDecode("f90000"), // 0.0
|
|
dst: new(float32),
|
|
reject: false,
|
|
},
|
|
{
|
|
opt: NaNDecodeForbidden,
|
|
src: hexDecode("f90000"), // 0.0
|
|
dst: new(float64),
|
|
reject: false,
|
|
},
|
|
{
|
|
opt: NaNDecodeForbidden,
|
|
src: hexDecode("f90000"), // 0.0
|
|
dst: new(time.Time),
|
|
reject: false,
|
|
},
|
|
{
|
|
opt: NaNDecodeForbidden,
|
|
src: hexDecode("fa47c35000"), // 100000.0
|
|
dst: new(interface{}),
|
|
reject: false,
|
|
},
|
|
{
|
|
opt: NaNDecodeForbidden,
|
|
src: hexDecode("fa47c35000"), // 100000.0
|
|
dst: new(float32),
|
|
reject: false,
|
|
},
|
|
{
|
|
opt: NaNDecodeForbidden,
|
|
src: hexDecode("fa47c35000"), // 100000.0
|
|
dst: new(float64),
|
|
reject: false,
|
|
},
|
|
{
|
|
opt: NaNDecodeForbidden,
|
|
src: hexDecode("fa47c35000"), // 100000.0
|
|
dst: new(time.Time),
|
|
reject: false,
|
|
},
|
|
{
|
|
opt: NaNDecodeForbidden,
|
|
src: hexDecode("fb3ff199999999999a"), // 1.1
|
|
dst: new(interface{}),
|
|
reject: false,
|
|
},
|
|
{
|
|
opt: NaNDecodeForbidden,
|
|
src: hexDecode("fb3ff199999999999a"), // 1.1
|
|
dst: new(float32),
|
|
reject: false,
|
|
},
|
|
{
|
|
opt: NaNDecodeForbidden,
|
|
src: hexDecode("fb3ff199999999999a"), // 1.1
|
|
dst: new(float64),
|
|
reject: false,
|
|
},
|
|
{
|
|
opt: NaNDecodeForbidden,
|
|
src: hexDecode("fb3ff199999999999a"), // 1.1
|
|
dst: new(time.Time),
|
|
reject: false,
|
|
},
|
|
{
|
|
opt: NaNDecodeForbidden,
|
|
src: hexDecode("f97e00"),
|
|
dst: new(interface{}),
|
|
reject: true,
|
|
},
|
|
{
|
|
opt: NaNDecodeForbidden,
|
|
src: hexDecode("f97e00"),
|
|
dst: new(float32),
|
|
reject: true,
|
|
},
|
|
{
|
|
opt: NaNDecodeForbidden,
|
|
src: hexDecode("f97e00"),
|
|
dst: new(float64),
|
|
reject: true,
|
|
},
|
|
{
|
|
opt: NaNDecodeForbidden,
|
|
src: hexDecode("f97e00"),
|
|
dst: new(time.Time),
|
|
reject: true,
|
|
},
|
|
{
|
|
opt: NaNDecodeForbidden,
|
|
src: hexDecode("fa7fc00000"),
|
|
dst: new(interface{}),
|
|
reject: true,
|
|
},
|
|
{
|
|
opt: NaNDecodeForbidden,
|
|
src: hexDecode("fa7fc00000"),
|
|
dst: new(float32),
|
|
reject: true,
|
|
},
|
|
{
|
|
opt: NaNDecodeForbidden,
|
|
src: hexDecode("fa7fc00000"),
|
|
dst: new(float64),
|
|
reject: true,
|
|
},
|
|
{
|
|
opt: NaNDecodeForbidden,
|
|
src: hexDecode("fa7fc00000"),
|
|
dst: new(time.Time),
|
|
reject: true,
|
|
},
|
|
{
|
|
opt: NaNDecodeForbidden,
|
|
src: hexDecode("fb7ff8000000000000"),
|
|
dst: new(interface{}),
|
|
reject: true,
|
|
},
|
|
{
|
|
opt: NaNDecodeForbidden,
|
|
src: hexDecode("fb7ff8000000000000"),
|
|
dst: new(float32),
|
|
reject: true,
|
|
},
|
|
{
|
|
opt: NaNDecodeForbidden,
|
|
src: hexDecode("fb7ff8000000000000"),
|
|
dst: new(float64),
|
|
reject: true,
|
|
},
|
|
{
|
|
opt: NaNDecodeForbidden,
|
|
src: hexDecode("fb7ff8000000000000"),
|
|
dst: new(time.Time),
|
|
reject: true,
|
|
},
|
|
} {
|
|
t.Run(fmt.Sprintf("mode=%d/0x%x into %s", tc.opt, tc.src, reflect.TypeOf(tc.dst).String()), func(t *testing.T) {
|
|
dm, err := DecOptions{NaN: tc.opt}.DecMode()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
want := &UnacceptableDataItemError{
|
|
CBORType: cborTypePrimitives.String(),
|
|
Message: "floating-point NaN",
|
|
}
|
|
if got := dm.Unmarshal(tc.src, tc.dst); got != nil {
|
|
if tc.reject {
|
|
if !reflect.DeepEqual(want, got) {
|
|
t.Errorf("want error: %v, got error: %v", want, got)
|
|
}
|
|
} else {
|
|
t.Errorf("unexpected error: %v", got)
|
|
}
|
|
} else if tc.reject {
|
|
t.Error("unexpected nil error")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDecModeInvalidInfDec(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
name string
|
|
opts DecOptions
|
|
wantErrorMsg string
|
|
}{
|
|
{
|
|
name: "below range of valid modes",
|
|
opts: DecOptions{Inf: -1},
|
|
wantErrorMsg: "cbor: invalid InfDec -1",
|
|
},
|
|
{
|
|
name: "above range of valid modes",
|
|
opts: DecOptions{Inf: 101},
|
|
wantErrorMsg: "cbor: invalid InfDec 101",
|
|
},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
_, err := tc.opts.DecMode()
|
|
if err == nil {
|
|
t.Errorf("DecMode() didn't return an error")
|
|
} else if err.Error() != tc.wantErrorMsg {
|
|
t.Errorf("DecMode() returned error %q, want %q", err.Error(), tc.wantErrorMsg)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestInfDecMode(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
opt InfMode
|
|
src []byte
|
|
dst interface{}
|
|
reject bool
|
|
}{
|
|
{
|
|
opt: InfDecodeForbidden,
|
|
src: hexDecode("197c00"),
|
|
dst: new(interface{}),
|
|
reject: false,
|
|
},
|
|
{
|
|
opt: InfDecodeForbidden,
|
|
src: hexDecode("1a7f800000"), // Infinity
|
|
dst: new(interface{}),
|
|
reject: false,
|
|
},
|
|
{
|
|
opt: InfDecodeForbidden,
|
|
src: hexDecode("1b7ff0000000000000"), // Infinity
|
|
dst: new(interface{}),
|
|
reject: false,
|
|
},
|
|
{
|
|
opt: InfDecodeForbidden,
|
|
src: hexDecode("f90000"), // 0.0
|
|
dst: new(interface{}),
|
|
reject: false,
|
|
},
|
|
{
|
|
opt: InfDecodeForbidden,
|
|
src: hexDecode("f90000"), // 0.0
|
|
dst: new(float32),
|
|
reject: false,
|
|
},
|
|
{
|
|
opt: InfDecodeForbidden,
|
|
src: hexDecode("f90000"), // 0.0
|
|
dst: new(float64),
|
|
reject: false,
|
|
},
|
|
{
|
|
opt: InfDecodeForbidden,
|
|
src: hexDecode("f90000"), // 0.0
|
|
dst: new(time.Time),
|
|
reject: false,
|
|
},
|
|
{
|
|
opt: InfDecodeForbidden,
|
|
src: hexDecode("fa47c35000"), // 100000.0
|
|
dst: new(interface{}),
|
|
reject: false,
|
|
},
|
|
{
|
|
opt: InfDecodeForbidden,
|
|
src: hexDecode("fa47c35000"), // 100000.0
|
|
dst: new(float32),
|
|
reject: false,
|
|
},
|
|
{
|
|
opt: InfDecodeForbidden,
|
|
src: hexDecode("fa47c35000"), // 100000.0
|
|
dst: new(float64),
|
|
reject: false,
|
|
},
|
|
{
|
|
opt: InfDecodeForbidden,
|
|
src: hexDecode("fa47c35000"), // 100000.0
|
|
dst: new(time.Time),
|
|
reject: false,
|
|
},
|
|
{
|
|
opt: InfDecodeForbidden,
|
|
src: hexDecode("fb3ff199999999999a"), // 1.1
|
|
dst: new(interface{}),
|
|
reject: false,
|
|
},
|
|
{
|
|
opt: InfDecodeForbidden,
|
|
src: hexDecode("fb3ff199999999999a"), // 1.1
|
|
dst: new(float32),
|
|
reject: false,
|
|
},
|
|
{
|
|
opt: InfDecodeForbidden,
|
|
src: hexDecode("fb3ff199999999999a"), // 1.1
|
|
dst: new(float64),
|
|
reject: false,
|
|
},
|
|
{
|
|
opt: InfDecodeForbidden,
|
|
src: hexDecode("fb3ff199999999999a"), // 1.1
|
|
dst: new(time.Time),
|
|
reject: false,
|
|
},
|
|
{
|
|
opt: InfDecodeForbidden,
|
|
src: hexDecode("f97c00"), // Infinity
|
|
dst: new(interface{}),
|
|
reject: true,
|
|
},
|
|
{
|
|
opt: InfDecodeForbidden,
|
|
src: hexDecode("f97c00"), // Infinity
|
|
dst: new(float32),
|
|
reject: true,
|
|
},
|
|
{
|
|
opt: InfDecodeForbidden,
|
|
src: hexDecode("f97c00"), // Infinity
|
|
dst: new(float64),
|
|
reject: true,
|
|
},
|
|
{
|
|
opt: InfDecodeForbidden,
|
|
src: hexDecode("f97c00"), // Infinity
|
|
dst: new(time.Time),
|
|
reject: true,
|
|
},
|
|
{
|
|
opt: InfDecodeForbidden,
|
|
src: hexDecode("f9fc00"), // -Infinity
|
|
dst: new(interface{}),
|
|
reject: true,
|
|
},
|
|
{
|
|
opt: InfDecodeForbidden,
|
|
src: hexDecode("f9fc00"), // -Infinity
|
|
dst: new(float32),
|
|
reject: true,
|
|
},
|
|
{
|
|
opt: InfDecodeForbidden,
|
|
src: hexDecode("f9fc00"), // -Infinity
|
|
dst: new(float64),
|
|
reject: true,
|
|
},
|
|
{
|
|
opt: InfDecodeForbidden,
|
|
src: hexDecode("f9fc00"), // -Infinity
|
|
dst: new(time.Time),
|
|
reject: true,
|
|
},
|
|
{
|
|
opt: InfDecodeForbidden,
|
|
src: hexDecode("fa7f800000"), // Infinity
|
|
dst: new(interface{}),
|
|
reject: true,
|
|
},
|
|
{
|
|
opt: InfDecodeForbidden,
|
|
src: hexDecode("fa7f800000"), // Infinity
|
|
dst: new(float32),
|
|
reject: true,
|
|
},
|
|
{
|
|
opt: InfDecodeForbidden,
|
|
src: hexDecode("fa7f800000"), // Infinity
|
|
dst: new(float64),
|
|
reject: true,
|
|
},
|
|
{
|
|
opt: InfDecodeForbidden,
|
|
src: hexDecode("fa7f800000"), // Infinity
|
|
dst: new(time.Time),
|
|
reject: true,
|
|
},
|
|
{
|
|
opt: InfDecodeForbidden,
|
|
src: hexDecode("faff800000"), // -Infinity
|
|
dst: new(interface{}),
|
|
reject: true,
|
|
},
|
|
{
|
|
opt: InfDecodeForbidden,
|
|
src: hexDecode("faff800000"), // -Infinity
|
|
dst: new(float32),
|
|
reject: true,
|
|
},
|
|
{
|
|
opt: InfDecodeForbidden,
|
|
src: hexDecode("faff800000"), // -Infinity
|
|
dst: new(float64),
|
|
reject: true,
|
|
},
|
|
{
|
|
opt: InfDecodeForbidden,
|
|
src: hexDecode("faff800000"), // -Infinity
|
|
dst: new(time.Time),
|
|
reject: true,
|
|
},
|
|
{
|
|
opt: InfDecodeForbidden,
|
|
src: hexDecode("fb7ff0000000000000"), // Infinity
|
|
dst: new(interface{}),
|
|
reject: true,
|
|
},
|
|
{
|
|
opt: InfDecodeForbidden,
|
|
src: hexDecode("fb7ff0000000000000"), // Infinity
|
|
dst: new(float32),
|
|
reject: true,
|
|
},
|
|
{
|
|
opt: InfDecodeForbidden,
|
|
src: hexDecode("fb7ff0000000000000"), // Infinity
|
|
dst: new(float64),
|
|
reject: true,
|
|
},
|
|
{
|
|
opt: InfDecodeForbidden,
|
|
src: hexDecode("fb7ff0000000000000"), // Infinity
|
|
dst: new(time.Time),
|
|
reject: true,
|
|
},
|
|
{
|
|
opt: InfDecodeForbidden,
|
|
src: hexDecode("fbfff0000000000000"), // -Infinity
|
|
dst: new(interface{}),
|
|
reject: true,
|
|
},
|
|
{
|
|
opt: InfDecodeForbidden,
|
|
src: hexDecode("fbfff0000000000000"), // -Infinity
|
|
dst: new(float32),
|
|
reject: true,
|
|
},
|
|
{
|
|
opt: InfDecodeForbidden,
|
|
src: hexDecode("fbfff0000000000000"), // -Infinity
|
|
dst: new(float64),
|
|
reject: true,
|
|
},
|
|
{
|
|
opt: InfDecodeForbidden,
|
|
src: hexDecode("fbfff0000000000000"), // -Infinity
|
|
dst: new(time.Time),
|
|
reject: true,
|
|
},
|
|
} {
|
|
t.Run(fmt.Sprintf("mode=%d/0x%x into %s", tc.opt, tc.src, tc.dst), func(t *testing.T) {
|
|
dm, err := DecOptions{Inf: tc.opt}.DecMode()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
want := &UnacceptableDataItemError{
|
|
CBORType: cborTypePrimitives.String(),
|
|
Message: "floating-point infinity",
|
|
}
|
|
if got := dm.Unmarshal(tc.src, tc.dst); got != nil {
|
|
if tc.reject {
|
|
if !reflect.DeepEqual(want, got) {
|
|
t.Errorf("want error: %v, got error: %v", want, got)
|
|
}
|
|
} else {
|
|
t.Errorf("unexpected error: %v", got)
|
|
}
|
|
} else if tc.reject {
|
|
t.Error("unexpected nil error")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDecModeInvalidByteStringToTimeMode(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
name string
|
|
opts DecOptions
|
|
wantErrorMsg string
|
|
}{
|
|
{
|
|
name: "below range of valid modes",
|
|
opts: DecOptions{ByteStringToTime: -1},
|
|
wantErrorMsg: "cbor: invalid ByteStringToTime -1",
|
|
},
|
|
{
|
|
name: "above range of valid modes",
|
|
opts: DecOptions{ByteStringToTime: 4},
|
|
wantErrorMsg: "cbor: invalid ByteStringToTime 4",
|
|
},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
_, err := tc.opts.DecMode()
|
|
if err == nil {
|
|
t.Errorf("Expected non nil error from DecMode()")
|
|
} else if err.Error() != tc.wantErrorMsg {
|
|
t.Errorf("Expected error: %q, want: %q \n", tc.wantErrorMsg, err.Error())
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDecModeByteStringToTime(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
name string
|
|
opts DecOptions
|
|
in []byte
|
|
want time.Time
|
|
wantErrorMsg string
|
|
}{
|
|
{
|
|
name: "Unmarshal byte string to time.Time when ByteStringToTime is not set",
|
|
opts: DecOptions{},
|
|
in: hexDecode("54323031332D30332D32315432303A30343A30305A"), // '2013-03-21T20:04:00Z'
|
|
wantErrorMsg: "cbor: cannot unmarshal byte string into Go value of type time.Time",
|
|
},
|
|
{
|
|
name: "Unmarshal byte string to time.Time when ByteStringToTime is set to ByteStringToTimeAllowed",
|
|
opts: DecOptions{ByteStringToTime: ByteStringToTimeAllowed},
|
|
in: hexDecode("54323031332D30332D32315432303A30343A30305A"), // '2013-03-21T20:04:00Z'
|
|
want: time.Date(2013, 3, 21, 20, 4, 0, 0, time.UTC),
|
|
},
|
|
{
|
|
name: "Unmarshal byte string to time.Time with nano when ByteStringToTime is set to ByteStringToTimeAllowed",
|
|
opts: DecOptions{ByteStringToTime: ByteStringToTimeAllowed},
|
|
in: hexDecode("56323031332D30332D32315432303A30343A30302E355A"), // '2013-03-21T20:04:00.5Z'
|
|
want: time.Date(2013, 3, 21, 20, 4, 0, 500000000, time.UTC),
|
|
},
|
|
{
|
|
name: "Unmarshal a byte string that is not a valid RFC3339 timestamp to time.Time when ByteStringToTime is set to ByteStringToTimeAllowed",
|
|
opts: DecOptions{ByteStringToTime: ByteStringToTimeAllowed},
|
|
in: hexDecode("4B696E76616C696454657874"), // 'invalidText'
|
|
wantErrorMsg: `cbor: cannot set "invalidText" for time.Time: parsing time "invalidText" as "2006-01-02T15:04:05Z07:00": cannot parse "invalidText" as "2006"`,
|
|
},
|
|
{
|
|
name: "Unmarshal a byte string that is not a valid utf8 sequence to time.Time when ByteStringToTime is set to ByteStringToTimeAllowed",
|
|
opts: DecOptions{ByteStringToTime: ByteStringToTimeAllowed},
|
|
in: hexDecode("54323031338030332D32315432303A30343A30305A"), // "2013\x8003-21T20:04:00Z" -- the first hyphen of a valid RFC3339 string is replaced by a continuation byte
|
|
wantErrorMsg: `cbor: cannot set "2013\x8003-21T20:04:00Z" for time.Time: parsing time "2013\x8003-21T20:04:00Z" as "2006-01-02T15:04:05Z07:00": cannot parse "\x8003-21T20:04:00Z" as "-"`,
|
|
},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
dm, err := tc.opts.DecMode()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
var got time.Time
|
|
if err := dm.Unmarshal(tc.in, &got); err != nil {
|
|
if tc.wantErrorMsg != err.Error() {
|
|
t.Errorf("unexpected error: got %v want %v", err, tc.wantErrorMsg)
|
|
}
|
|
} else {
|
|
compareNonFloats(t, tc.in, got, tc.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestInvalidByteSliceExpectedEncodingMode(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
name string
|
|
opts DecOptions
|
|
wantErrorMsg string
|
|
}{
|
|
{
|
|
name: "below range of valid modes",
|
|
opts: DecOptions{ByteStringExpectedFormat: -1},
|
|
wantErrorMsg: "cbor: invalid ByteStringExpectedFormat -1",
|
|
},
|
|
{
|
|
name: "above range of valid modes",
|
|
opts: DecOptions{ByteStringExpectedFormat: 101},
|
|
wantErrorMsg: "cbor: invalid ByteStringExpectedFormat 101",
|
|
},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
_, err := tc.opts.DecMode()
|
|
if err == nil {
|
|
t.Errorf("DecMode() didn't return an error")
|
|
} else if err.Error() != tc.wantErrorMsg {
|
|
t.Errorf("DecMode() returned error %q, want %q", err.Error(), tc.wantErrorMsg)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDecOptionsConflictWithRegisteredTags(t *testing.T) {
|
|
type empty struct{}
|
|
|
|
for _, tc := range []struct {
|
|
name string
|
|
opts DecOptions
|
|
tags func(TagSet) error
|
|
wantErr string
|
|
}{
|
|
{
|
|
name: "base64url encoding tag ignored by default",
|
|
opts: DecOptions{},
|
|
tags: func(tags TagSet) error {
|
|
return tags.Add(TagOptions{DecTag: DecTagOptional}, reflect.TypeOf(empty{}), 21)
|
|
},
|
|
wantErr: "",
|
|
},
|
|
{
|
|
name: "base64url encoding tag conflicts in ByteStringToStringAllowedWithExpectedLaterEncoding mode",
|
|
opts: DecOptions{ByteStringToString: ByteStringToStringAllowedWithExpectedLaterEncoding},
|
|
tags: func(tags TagSet) error {
|
|
return tags.Add(TagOptions{DecTag: DecTagOptional}, reflect.TypeOf(empty{}), 21)
|
|
},
|
|
wantErr: "cbor: DecMode with non-default StringExpectedEncoding or ByteSliceExpectedEncoding treats tag 21 as built-in and conflicts with the provided TagSet's registration of cbor.empty",
|
|
},
|
|
{
|
|
name: "base64url encoding tag conflicts with non-default ByteSliceExpectedEncoding option",
|
|
opts: DecOptions{ByteStringExpectedFormat: ByteStringExpectedBase16},
|
|
tags: func(tags TagSet) error {
|
|
return tags.Add(TagOptions{DecTag: DecTagOptional}, reflect.TypeOf(empty{}), 21)
|
|
},
|
|
wantErr: "cbor: DecMode with non-default StringExpectedEncoding or ByteSliceExpectedEncoding treats tag 21 as built-in and conflicts with the provided TagSet's registration of cbor.empty",
|
|
},
|
|
{
|
|
name: "base64 encoding tag ignored by default",
|
|
opts: DecOptions{},
|
|
tags: func(tags TagSet) error {
|
|
return tags.Add(TagOptions{DecTag: DecTagOptional}, reflect.TypeOf(empty{}), 22)
|
|
},
|
|
wantErr: "",
|
|
},
|
|
{
|
|
name: "base64 encoding tag conflicts in ByteStringToStringAllowedWithExpectedLaterEncoding mode",
|
|
opts: DecOptions{ByteStringToString: ByteStringToStringAllowedWithExpectedLaterEncoding},
|
|
tags: func(tags TagSet) error {
|
|
return tags.Add(TagOptions{DecTag: DecTagOptional}, reflect.TypeOf(empty{}), 22)
|
|
},
|
|
wantErr: "cbor: DecMode with non-default StringExpectedEncoding or ByteSliceExpectedEncoding treats tag 22 as built-in and conflicts with the provided TagSet's registration of cbor.empty",
|
|
},
|
|
{
|
|
name: "base64 encoding tag conflicts with non-default ByteSliceExpectedEncoding option",
|
|
opts: DecOptions{ByteStringExpectedFormat: ByteStringExpectedBase16},
|
|
tags: func(tags TagSet) error {
|
|
return tags.Add(TagOptions{DecTag: DecTagOptional}, reflect.TypeOf(empty{}), 22)
|
|
},
|
|
wantErr: "cbor: DecMode with non-default StringExpectedEncoding or ByteSliceExpectedEncoding treats tag 22 as built-in and conflicts with the provided TagSet's registration of cbor.empty",
|
|
},
|
|
{
|
|
name: "base16 encoding tag ignored by default",
|
|
opts: DecOptions{},
|
|
tags: func(tags TagSet) error {
|
|
return tags.Add(TagOptions{DecTag: DecTagOptional}, reflect.TypeOf(empty{}), 23)
|
|
},
|
|
wantErr: "",
|
|
},
|
|
{
|
|
name: "base16 encoding tag conflicts in ByteStringToStringAllowedWithExpectedLaterEncoding mode",
|
|
opts: DecOptions{ByteStringToString: ByteStringToStringAllowedWithExpectedLaterEncoding},
|
|
tags: func(tags TagSet) error {
|
|
return tags.Add(TagOptions{DecTag: DecTagOptional}, reflect.TypeOf(empty{}), 23)
|
|
},
|
|
wantErr: "cbor: DecMode with non-default StringExpectedEncoding or ByteSliceExpectedEncoding treats tag 23 as built-in and conflicts with the provided TagSet's registration of cbor.empty",
|
|
},
|
|
{
|
|
name: "base16 encoding tag conflicts with non-default ByteSliceExpectedEncoding option",
|
|
opts: DecOptions{ByteStringExpectedFormat: ByteStringExpectedBase16},
|
|
tags: func(tags TagSet) error {
|
|
return tags.Add(TagOptions{DecTag: DecTagOptional}, reflect.TypeOf(empty{}), 23)
|
|
},
|
|
wantErr: "cbor: DecMode with non-default StringExpectedEncoding or ByteSliceExpectedEncoding treats tag 23 as built-in and conflicts with the provided TagSet's registration of cbor.empty",
|
|
},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
tags := NewTagSet()
|
|
if err := tc.tags(tags); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if _, err := tc.opts.DecModeWithTags(tags); err == nil {
|
|
if tc.wantErr != "" {
|
|
t.Errorf("got nil error from DecModeWithTags, want %q", tc.wantErr)
|
|
}
|
|
} else if got := err.Error(); got != tc.wantErr {
|
|
if tc.wantErr != "" {
|
|
t.Errorf("unexpected error from DecModeWithTags, got %q want %q", got, tc.wantErr)
|
|
} else {
|
|
t.Errorf("want nil error from DecModeWithTags, got %q", got)
|
|
}
|
|
}
|
|
|
|
if _, err := tc.opts.DecModeWithSharedTags(tags); err == nil {
|
|
if tc.wantErr != "" {
|
|
t.Errorf("got nil error from DecModeWithSharedTags, want %q", tc.wantErr)
|
|
}
|
|
} else if got := err.Error(); got != tc.wantErr {
|
|
if tc.wantErr != "" {
|
|
t.Errorf("unexpected error from DecModeWithSharedTags, got %q want %q", got, tc.wantErr)
|
|
} else {
|
|
t.Errorf("want nil error from DecModeWithSharedTags, got %q", got)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalByteStringTextConversionError(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
name string
|
|
opts DecOptions
|
|
dstType reflect.Type
|
|
in []byte
|
|
wantErr string
|
|
}{
|
|
{
|
|
name: "reject untagged byte string containing invalid base64url",
|
|
opts: DecOptions{ByteStringExpectedFormat: ByteStringExpectedBase64URL},
|
|
dstType: reflect.TypeOf([]byte{}),
|
|
in: []byte{0x41, 0x00},
|
|
wantErr: "cbor: failed to decode base64url from byte string: illegal base64 data at input byte 0",
|
|
},
|
|
{
|
|
name: "reject untagged byte string containing invalid base64url",
|
|
opts: DecOptions{ByteStringExpectedFormat: ByteStringExpectedBase64},
|
|
dstType: reflect.TypeOf([]byte{}),
|
|
in: []byte{0x41, 0x00},
|
|
wantErr: "cbor: failed to decode base64 from byte string: illegal base64 data at input byte 0",
|
|
},
|
|
{
|
|
name: "reject untagged byte string containing invalid base16",
|
|
opts: DecOptions{ByteStringExpectedFormat: ByteStringExpectedBase16},
|
|
dstType: reflect.TypeOf([]byte{}),
|
|
in: []byte{0x41, 0x00},
|
|
wantErr: "cbor: failed to decode hex from byte string: encoding/hex: invalid byte: U+0000",
|
|
},
|
|
{
|
|
name: "accept tagged byte string containing invalid base64url",
|
|
opts: DecOptions{ByteStringExpectedFormat: ByteStringExpectedBase64URL},
|
|
dstType: reflect.TypeOf([]byte{}),
|
|
in: []byte{0xd5, 0x41, 0x00},
|
|
wantErr: "",
|
|
},
|
|
{
|
|
name: "accept tagged byte string containing invalid base64url",
|
|
opts: DecOptions{ByteStringExpectedFormat: ByteStringExpectedBase64},
|
|
dstType: reflect.TypeOf([]byte{}),
|
|
in: []byte{0xd5, 0x41, 0x00},
|
|
wantErr: "",
|
|
},
|
|
{
|
|
name: "accept tagged byte string containing invalid base16",
|
|
opts: DecOptions{ByteStringExpectedFormat: ByteStringExpectedBase16},
|
|
dstType: reflect.TypeOf([]byte{}),
|
|
in: []byte{0xd5, 0x41, 0x00},
|
|
wantErr: "",
|
|
},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
dm, err := tc.opts.DecMode()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if err := dm.Unmarshal(tc.in, reflect.New(tc.dstType).Interface()); err == nil {
|
|
if tc.wantErr != "" {
|
|
t.Errorf("got nil error, want %q", tc.wantErr)
|
|
}
|
|
} else if got := err.Error(); got != tc.wantErr {
|
|
if tc.wantErr == "" {
|
|
t.Errorf("expected nil error, got %q", got)
|
|
} else {
|
|
t.Errorf("unexpected error, got %q want %q", got, tc.wantErr)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalByteStringTextConversion(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
name string
|
|
opts DecOptions
|
|
dstType reflect.Type
|
|
in []byte
|
|
want interface{}
|
|
}{
|
|
{
|
|
name: "untagged into string",
|
|
opts: DecOptions{
|
|
ByteStringToString: ByteStringToStringAllowedWithExpectedLaterEncoding,
|
|
},
|
|
dstType: reflect.TypeOf(""),
|
|
in: []byte{0x41, 0xff}, // h'ff'
|
|
want: "\xff",
|
|
},
|
|
{
|
|
name: "tagged base64url into string",
|
|
opts: DecOptions{
|
|
ByteStringToString: ByteStringToStringAllowedWithExpectedLaterEncoding,
|
|
},
|
|
dstType: reflect.TypeOf(""),
|
|
in: []byte{0xd5, 0x41, 0xff}, // 21(h'ff')
|
|
want: "_w",
|
|
},
|
|
{
|
|
name: "indirectly tagged base64url into string",
|
|
opts: DecOptions{
|
|
ByteStringToString: ByteStringToStringAllowedWithExpectedLaterEncoding,
|
|
},
|
|
dstType: reflect.TypeOf(""),
|
|
in: []byte{0xd5, 0xd9, 0xd9, 0xf7, 0x41, 0xff}, // 21(55799(h'ff'))
|
|
want: "_w",
|
|
},
|
|
{
|
|
name: "tagged base64url into string tags ignored",
|
|
opts: DecOptions{
|
|
ByteStringToString: ByteStringToStringAllowed,
|
|
},
|
|
dstType: reflect.TypeOf(""),
|
|
in: []byte{0xd5, 0x41, 0xff}, // 21(h'ff')
|
|
want: "\xff",
|
|
},
|
|
{
|
|
name: "tagged into []byte with default encoding base64url",
|
|
opts: DecOptions{
|
|
ByteStringExpectedFormat: ByteStringExpectedBase64URL,
|
|
},
|
|
dstType: reflect.TypeOf([]byte{}),
|
|
in: []byte{0xd5, 0x41, 0xff}, // 21(h'ff')
|
|
want: []byte{0xff},
|
|
},
|
|
{
|
|
name: "indirectly tagged into []byte with default encoding base64url",
|
|
opts: DecOptions{
|
|
ByteStringExpectedFormat: ByteStringExpectedBase64URL,
|
|
},
|
|
dstType: reflect.TypeOf([]byte{}),
|
|
in: []byte{0xd5, 0xd9, 0xd9, 0xf7, 0x41, 0xff}, // 21(55799(h'ff'))
|
|
want: []byte{0xff},
|
|
},
|
|
{
|
|
name: "untagged base64url into []byte with default encoding base64url",
|
|
opts: DecOptions{
|
|
ByteStringExpectedFormat: ByteStringExpectedBase64URL,
|
|
},
|
|
dstType: reflect.TypeOf([]byte{}),
|
|
in: []byte{0x42, '_', 'w'}, // '_w'
|
|
want: []byte{0xff},
|
|
},
|
|
{
|
|
name: "tagged base64 into string",
|
|
opts: DecOptions{
|
|
ByteStringToString: ByteStringToStringAllowedWithExpectedLaterEncoding,
|
|
},
|
|
dstType: reflect.TypeOf(""),
|
|
in: []byte{0xd6, 0x41, 0xff}, // 22(h'ff')
|
|
want: "/w==",
|
|
},
|
|
{
|
|
name: "indirectly tagged base64 into string",
|
|
opts: DecOptions{
|
|
ByteStringToString: ByteStringToStringAllowedWithExpectedLaterEncoding,
|
|
},
|
|
dstType: reflect.TypeOf(""),
|
|
in: []byte{0xd6, 0xd9, 0xd9, 0xf7, 0x41, 0xff}, // 22(55799(h'ff'))
|
|
want: "/w==",
|
|
},
|
|
{
|
|
name: "tagged base64 into string tags ignored",
|
|
opts: DecOptions{
|
|
ByteStringToString: ByteStringToStringAllowed,
|
|
},
|
|
dstType: reflect.TypeOf(""),
|
|
in: []byte{0xd6, 0x41, 0xff}, // 22(h'ff')
|
|
want: "\xff",
|
|
},
|
|
{
|
|
name: "tagged into []byte with default encoding base64",
|
|
opts: DecOptions{
|
|
ByteStringExpectedFormat: ByteStringExpectedBase64,
|
|
},
|
|
dstType: reflect.TypeOf([]byte{}),
|
|
in: []byte{0xd6, 0x41, 0xff}, // 22(h'ff')
|
|
want: []byte{0xff},
|
|
},
|
|
{
|
|
name: "indirectly tagged into []byte with default encoding base64",
|
|
opts: DecOptions{
|
|
ByteStringExpectedFormat: ByteStringExpectedBase64,
|
|
},
|
|
dstType: reflect.TypeOf([]byte{}),
|
|
in: []byte{0xd6, 0xd9, 0xd9, 0xf7, 0x41, 0xff}, // 22(55799(h'ff'))
|
|
want: []byte{0xff},
|
|
},
|
|
{
|
|
name: "untagged base64 into []byte with default encoding base64",
|
|
opts: DecOptions{
|
|
ByteStringExpectedFormat: ByteStringExpectedBase64,
|
|
},
|
|
dstType: reflect.TypeOf([]byte{}),
|
|
in: []byte{0x44, '/', 'w', '=', '='}, // '/w=='
|
|
want: []byte{0xff},
|
|
},
|
|
{
|
|
name: "tagged base16 into string",
|
|
opts: DecOptions{
|
|
ByteStringToString: ByteStringToStringAllowedWithExpectedLaterEncoding,
|
|
},
|
|
dstType: reflect.TypeOf(""),
|
|
in: []byte{0xd7, 0x41, 0xff}, // 23(h'ff')
|
|
want: "ff",
|
|
},
|
|
{
|
|
name: "indirectly tagged base16 into string",
|
|
opts: DecOptions{
|
|
ByteStringToString: ByteStringToStringAllowedWithExpectedLaterEncoding,
|
|
},
|
|
dstType: reflect.TypeOf(""),
|
|
in: []byte{0xd7, 0xd9, 0xd9, 0xf7, 0x41, 0xff}, // 23(55799(h'ff'))
|
|
want: "ff",
|
|
},
|
|
{
|
|
name: "tagged base16 into string tags ignored",
|
|
opts: DecOptions{
|
|
ByteStringToString: ByteStringToStringAllowed,
|
|
},
|
|
dstType: reflect.TypeOf(""),
|
|
in: []byte{0xd7, 0x41, 0xff}, // 23(h'ff')
|
|
want: "\xff",
|
|
},
|
|
{
|
|
name: "tagged into []byte with default encoding base16",
|
|
opts: DecOptions{
|
|
ByteStringExpectedFormat: ByteStringExpectedBase16,
|
|
},
|
|
dstType: reflect.TypeOf([]byte{}),
|
|
in: []byte{0xd7, 0x41, 0xff}, // 23(h'ff')
|
|
want: []byte{0xff},
|
|
},
|
|
{
|
|
name: "indirectly tagged into []byte with default encoding base16",
|
|
opts: DecOptions{
|
|
ByteStringExpectedFormat: ByteStringExpectedBase16,
|
|
},
|
|
dstType: reflect.TypeOf([]byte{}),
|
|
in: []byte{0xd7, 0xd9, 0xd9, 0xf7, 0x41, 0xff}, // 23(55799(h'ff'))
|
|
want: []byte{0xff},
|
|
},
|
|
{
|
|
name: "untagged base16 into []byte with default encoding base16",
|
|
opts: DecOptions{
|
|
ByteStringExpectedFormat: ByteStringExpectedBase16,
|
|
},
|
|
dstType: reflect.TypeOf([]byte{}),
|
|
in: []byte{0x42, 'f', 'f'},
|
|
want: []byte{0xff},
|
|
},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
dm, err := tc.opts.DecMode()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
dstVal := reflect.New(tc.dstType)
|
|
if err := dm.Unmarshal(tc.in, dstVal.Interface()); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if dst := dstVal.Elem().Interface(); !reflect.DeepEqual(dst, tc.want) {
|
|
t.Errorf("got: %#v, want %#v", dst, tc.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDecModeInvalidBinaryUnmarshaler(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
name string
|
|
opts DecOptions
|
|
wantErrorMsg string
|
|
}{
|
|
{
|
|
name: "below range of valid modes",
|
|
opts: DecOptions{BinaryUnmarshaler: -1},
|
|
wantErrorMsg: "cbor: invalid BinaryUnmarshaler -1",
|
|
},
|
|
{
|
|
name: "above range of valid modes",
|
|
opts: DecOptions{BinaryUnmarshaler: 101},
|
|
wantErrorMsg: "cbor: invalid BinaryUnmarshaler 101",
|
|
},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
_, err := tc.opts.DecMode()
|
|
if err == nil {
|
|
t.Errorf("DecMode() didn't return an error")
|
|
} else if err.Error() != tc.wantErrorMsg {
|
|
t.Errorf("DecMode() returned error %q, want %q", err.Error(), tc.wantErrorMsg)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
type testBinaryUnmarshaler []byte
|
|
|
|
func (bu *testBinaryUnmarshaler) UnmarshalBinary(_ []byte) error {
|
|
*bu = []byte("UnmarshalBinary")
|
|
return nil
|
|
}
|
|
|
|
func TestBinaryUnmarshalerMode(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
name string
|
|
opts DecOptions
|
|
in []byte
|
|
want interface{}
|
|
}{
|
|
{
|
|
name: "UnmarshalBinary is called by default",
|
|
opts: DecOptions{},
|
|
in: []byte("\x45hello"), // 'hello'
|
|
want: testBinaryUnmarshaler("UnmarshalBinary"),
|
|
},
|
|
{
|
|
name: "UnmarshalBinary is called with BinaryUnmarshalerByteString",
|
|
opts: DecOptions{BinaryUnmarshaler: BinaryUnmarshalerByteString},
|
|
in: []byte("\x45hello"), // 'hello'
|
|
want: testBinaryUnmarshaler("UnmarshalBinary"),
|
|
},
|
|
{
|
|
name: "default byte slice unmarshaling behavior is used with BinaryUnmarshalerNone",
|
|
opts: DecOptions{BinaryUnmarshaler: BinaryUnmarshalerNone},
|
|
in: []byte("\x45hello"), // 'hello'
|
|
want: testBinaryUnmarshaler("hello"),
|
|
},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
dm, err := tc.opts.DecMode()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
gotrv := reflect.New(reflect.TypeOf(tc.want))
|
|
if err := dm.Unmarshal(tc.in, gotrv.Interface()); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
got := gotrv.Elem().Interface()
|
|
if !reflect.DeepEqual(tc.want, got) {
|
|
t.Errorf("want: %v, got: %v", tc.want, got)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDecModeInvalidBignumTag(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
name string
|
|
opts DecOptions
|
|
wantErrorMsg string
|
|
}{
|
|
{
|
|
name: "below range of valid modes",
|
|
opts: DecOptions{BignumTag: -1},
|
|
wantErrorMsg: "cbor: invalid BignumTag -1",
|
|
},
|
|
{
|
|
name: "above range of valid modes",
|
|
opts: DecOptions{BignumTag: 101},
|
|
wantErrorMsg: "cbor: invalid BignumTag 101",
|
|
},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
_, err := tc.opts.DecMode()
|
|
if err == nil {
|
|
t.Errorf("Expected non nil error from DecMode()")
|
|
} else if err.Error() != tc.wantErrorMsg {
|
|
t.Errorf("Expected error: %q, want: %q \n", tc.wantErrorMsg, err.Error())
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestBignumTagMode(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
name string
|
|
opt DecOptions
|
|
input []byte
|
|
wantErrMessage string // if "" then expect nil error
|
|
}{
|
|
{
|
|
name: "default options decode unsigned bignum without error",
|
|
opt: DecOptions{},
|
|
input: hexDecode("c240"), // 2(0) i.e. unsigned bignum 0
|
|
},
|
|
{
|
|
name: "default options decode negative bignum without error",
|
|
opt: DecOptions{},
|
|
input: hexDecode("c340"), // 3(0) i.e. negative bignum -1
|
|
},
|
|
{
|
|
name: "BignumTagForbidden returns UnacceptableDataItemError on unsigned bignum",
|
|
opt: DecOptions{BignumTag: BignumTagForbidden},
|
|
input: hexDecode("c240"), // 2(0) i.e. unsigned bignum 0
|
|
wantErrMessage: "cbor: data item of cbor type tag is not accepted by protocol: bignum",
|
|
},
|
|
{
|
|
name: "BignumTagForbidden returns UnacceptableDataItemError on negative bignum",
|
|
opt: DecOptions{BignumTag: BignumTagForbidden},
|
|
input: hexDecode("c340"), // 3(0) i.e. negative bignum -1
|
|
wantErrMessage: "cbor: data item of cbor type tag is not accepted by protocol: bignum",
|
|
},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
dm, err := tc.opt.DecMode()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
for _, dstType := range []reflect.Type{
|
|
typeInt64,
|
|
typeFloat64,
|
|
typeByteArray,
|
|
typeByteSlice,
|
|
typeBigInt,
|
|
typeIntf,
|
|
} {
|
|
t.Run(dstType.String(), func(t *testing.T) {
|
|
dstv := reflect.New(dstType)
|
|
err = dm.Unmarshal(tc.input, dstv.Interface())
|
|
if err != nil {
|
|
if tc.wantErrMessage == "" {
|
|
t.Errorf("want nil error, got: %v", err)
|
|
} else if gotErrMessage := err.Error(); gotErrMessage != tc.wantErrMessage {
|
|
t.Errorf("want error: %q, got error: %q", tc.wantErrMessage, gotErrMessage)
|
|
}
|
|
} else {
|
|
if tc.wantErrMessage != "" {
|
|
t.Errorf("got nil error, want: %s", tc.wantErrMessage)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
})
|
|
}
|
|
}
|