cbor/decode_test.go
Faye Amacker d50bec7bf5 Reduce DecOptions.MaxNestedLevels default (tinygo)
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).
2024-09-08 10:24:43 -05:00

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)
}
}
})
}
})
}
}