diff --git a/bench_test.go b/bench_test.go index 37293e40..09de2a1b 100644 --- a/bench_test.go +++ b/bench_test.go @@ -192,22 +192,22 @@ var decodeBenchmarks = []struct { decodeToTypes: []reflect.Type{typeIntf, typeFloat64}, }, // float64(-4.1) { - name: "bytes", + name: "byte string", data: mustHexDecode("581a0102030405060708090a0b0c0d0e0f101112131415161718191a"), decodeToTypes: []reflect.Type{typeIntf, typeByteSlice}, }, // []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, 26} { - name: "bytes indef len", + name: "indefinite-length byte string", data: mustHexDecode("5f410141024103410441054106410741084109410a410b410c410d410e410f4110411141124113411441154116411741184119411aff"), decodeToTypes: []reflect.Type{typeIntf, typeByteSlice}, }, // []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, 26} { - name: "text", + name: "text string", data: mustHexDecode("782b54686520717569636b2062726f776e20666f78206a756d7073206f76657220746865206c617a7920646f67"), decodeToTypes: []reflect.Type{typeIntf, typeString}, }, // "The quick brown fox jumps over the lazy dog" { - name: "text indef len", + name: "indefinite-length text string", data: mustHexDecode("7f61546168616561206171617561696163616b612061626172616f6177616e61206166616f61786120616a6175616d617061736120616f61766165617261206174616861656120616c6161617a617961206164616f6167ff"), decodeToTypes: []reflect.Type{typeIntf, typeString}, }, // "The quick brown fox jumps over the lazy dog" @@ -217,7 +217,7 @@ var decodeBenchmarks = []struct { decodeToTypes: []reflect.Type{typeIntf, typeIntSlice}, }, // []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, 26} { - name: "array indef len", + name: "indefinite-length array", data: mustHexDecode("9f0102030405060708090a0b0c0d0e0f101112131415161718181819181aff"), decodeToTypes: []reflect.Type{typeIntf, typeIntSlice}, }, // []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, 26} @@ -227,7 +227,7 @@ var decodeBenchmarks = []struct { decodeToTypes: []reflect.Type{typeIntf, typeMapStringIntf, typeMapStringString}, }, // map[string]string{"a": "A", "b": "B", "c": "C", "d": "D", "e": "E", "f": "F", "g": "G", "h": "H", "i": "I", "j": "J", "l": "L", "m": "M", "n": "N"}} { - name: "map indef len", + name: "indefinite-length map", data: mustHexDecode("bf616161416162614261636143616461446165614561666146616761476168614861696149616a614a616b614b616c614c616d614d616e614eff"), decodeToTypes: []reflect.Type{typeIntf, typeMapStringIntf, typeMapStringString}, }, // map[string]string{"a": "A", "b": "B", "c": "C", "d": "D", "e": "E", "f": "F", "g": "G", "h": "H", "i": "I", "j": "J", "l": "L", "m": "M", "n": "N"}} diff --git a/bytestring_test.go b/bytestring_test.go index 5ec738f2..20f6eb7a 100644 --- a/bytestring_test.go +++ b/bytestring_test.go @@ -4,6 +4,7 @@ package cbor import ( + "bytes" "io" "strings" "testing" @@ -26,7 +27,7 @@ func TestByteString(t *testing.T) { emptybs := ByteString("") bs := ByteString("\x01\x02\x03\x04") - testCases := []roundTripTest{ + testCases := []roundTripTestCase{ { name: "empty", obj: emptybs, @@ -106,78 +107,78 @@ func TestByteString(t *testing.T) { func TestUnmarshalByteStringOnBadData(t *testing.T) { testCases := []struct { - name string - data []byte - errMsg string + name string + data []byte + wantErrorMsg string }{ // Empty data { - name: "nil data", - data: nil, - errMsg: io.EOF.Error(), + name: "nil data", + data: nil, + wantErrorMsg: io.EOF.Error(), }, { - name: "empty data", - data: []byte{}, - errMsg: io.EOF.Error(), + name: "empty data", + data: []byte{}, + wantErrorMsg: io.EOF.Error(), }, // Wrong CBOR types { - name: "uint type", - data: mustHexDecode("01"), - errMsg: "cbor: cannot unmarshal positive integer into Go value of type cbor.ByteString", + name: "uint type", + data: mustHexDecode("01"), + wantErrorMsg: "cbor: cannot unmarshal positive integer into Go value of type cbor.ByteString", }, { - name: "int type", - data: mustHexDecode("20"), - errMsg: "cbor: cannot unmarshal negative integer into Go value of type cbor.ByteString", + name: "int type", + data: mustHexDecode("20"), + wantErrorMsg: "cbor: cannot unmarshal negative integer into Go value of type cbor.ByteString", }, { - name: "string type", - data: mustHexDecode("60"), - errMsg: "cbor: cannot unmarshal UTF-8 text string into Go value of type cbor.ByteString", + name: "string type", + data: mustHexDecode("60"), + wantErrorMsg: "cbor: cannot unmarshal UTF-8 text string into Go value of type cbor.ByteString", }, { - name: "array type", - data: mustHexDecode("80"), - errMsg: "cbor: cannot unmarshal array into Go value of type cbor.ByteString", + name: "array type", + data: mustHexDecode("80"), + wantErrorMsg: "cbor: cannot unmarshal array into Go value of type cbor.ByteString", }, { - name: "map type", - data: mustHexDecode("a0"), - errMsg: "cbor: cannot unmarshal map into Go value of type cbor.ByteString", + name: "map type", + data: mustHexDecode("a0"), + wantErrorMsg: "cbor: cannot unmarshal map into Go value of type cbor.ByteString", }, { - name: "tag type", - data: mustHexDecode("c074323031332d30332d32315432303a30343a30305a"), - errMsg: "cbor: cannot unmarshal tag into Go value of type cbor.ByteString", + name: "tag type", + data: mustHexDecode("c074323031332d30332d32315432303a30343a30305a"), + wantErrorMsg: "cbor: cannot unmarshal tag into Go value of type cbor.ByteString", }, { - name: "float type", - data: mustHexDecode("f90000"), - errMsg: "cbor: cannot unmarshal primitives into Go value of type cbor.ByteString", + name: "float type", + data: mustHexDecode("f90000"), + wantErrorMsg: "cbor: cannot unmarshal primitives into Go value of type cbor.ByteString", }, // Truncated CBOR data { - name: "truncated head", - data: mustHexDecode("18"), - errMsg: io.ErrUnexpectedEOF.Error(), + name: "truncated head", + data: mustHexDecode("18"), + wantErrorMsg: io.ErrUnexpectedEOF.Error(), }, // Truncated CBOR byte string { - name: "truncated byte string", - data: mustHexDecode("44010203"), - errMsg: io.ErrUnexpectedEOF.Error(), + name: "truncated byte string", + data: mustHexDecode("44010203"), + wantErrorMsg: io.ErrUnexpectedEOF.Error(), }, // Extraneous CBOR data { - name: "extraneous data", - data: mustHexDecode("c074323031332d30332d32315432303a30343a30305a00"), - errMsg: "cbor: 1 bytes of extraneous data starting at index 22", + name: "extraneous data", + data: mustHexDecode("c074323031332d30332d32315432303a30343a30305a00"), + wantErrorMsg: "cbor: 1 bytes of extraneous data starting at index 22", }, } @@ -191,8 +192,8 @@ func TestUnmarshalByteStringOnBadData(t *testing.T) { if err == nil { t.Errorf("UnmarshalCBOR(%x) didn't return error", tc.data) } - if !strings.HasPrefix(err.Error(), tc.errMsg) { - t.Errorf("UnmarshalCBOR(%x) returned error %q, want %q", tc.data, err.Error(), tc.errMsg) + if !strings.HasPrefix(err.Error(), tc.wantErrorMsg) { + t.Errorf("UnmarshalCBOR(%x) returned error %q, want %q", tc.data, err.Error(), tc.wantErrorMsg) } } // Test Unmarshal(data, *ByteString), which calls ByteString.unmarshalCBOR() under the hood @@ -203,10 +204,42 @@ func TestUnmarshalByteStringOnBadData(t *testing.T) { if err == nil { t.Errorf("Unmarshal(%x) didn't return error", tc.data) } - if !strings.HasPrefix(err.Error(), tc.errMsg) { - t.Errorf("Unmarshal(%x) returned error %q, want %q", tc.data, err.Error(), tc.errMsg) + if !strings.HasPrefix(err.Error(), tc.wantErrorMsg) { + t.Errorf("Unmarshal(%x) returned error %q, want %q", tc.data, err.Error(), tc.wantErrorMsg) } } }) } } + +func TestByteStringBytes(t *testing.T) { + testCases := []struct { + name string + bs ByteString + want []byte + }{ + { + name: "empty", + bs: ByteString(""), + want: []byte{}, + }, + { + name: "non-empty", + bs: ByteString("\x01\x02\x03\x04"), + want: []byte{0x01, 0x02, 0x03, 0x04}, + }, + { + name: "text content", + bs: ByteString("hello"), + want: []byte("hello"), + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + got := tc.bs.Bytes() + if !bytes.Equal(got, tc.want) { + t.Errorf("ByteString(%x).Bytes() = %x, want %x", string(tc.bs), got, tc.want) + } + }) + } +} diff --git a/cache.go b/cache.go index 5051f110..9d08cf58 100644 --- a/cache.go +++ b/cache.go @@ -98,21 +98,6 @@ type decodingStructType struct { toArray bool } -// The stdlib errors.Join was introduced in Go 1.20, and we still support Go 1.17, so instead, -// here's a very basic implementation of an aggregated error. -type multierror []error - -func (m multierror) Error() string { - var sb strings.Builder - for i, err := range m { - sb.WriteString(err.Error()) - if i < len(m)-1 { - sb.WriteString(", ") - } - } - return sb.String() -} - func getDecodingStructType(t reflect.Type) *decodingStructType { if v, _ := decodingStructTypeCache.Load(t); v != nil { return v.(*decodingStructType) @@ -145,20 +130,7 @@ func getDecodingStructType(t reflect.Type) *decodingStructType { fieldIndicesByName[fld.name] = i } - var err error - { - var multi multierror - for _, each := range errs { - if each != nil { - multi = append(multi, each) - } - } - if len(multi) == 1 { - err = multi[0] - } else if len(multi) > 1 { - err = multi - } - } + err := errors.Join(errs...) structType := &decodingStructType{ fields: flds, diff --git a/decode.go b/decode.go index f0bdc3b3..5a67c7f9 100644 --- a/decode.go +++ b/decode.go @@ -326,14 +326,14 @@ func (dmkm DupMapKeyMode) valid() bool { return dmkm >= 0 && dmkm < maxDupMapKeyMode } -// IndefLengthMode specifies whether to allow indefinite length items. +// IndefLengthMode specifies whether to allow indefinite-length items. type IndefLengthMode int const ( - // IndefLengthAllowed allows indefinite length items. + // IndefLengthAllowed allows indefinite-length items. IndefLengthAllowed IndefLengthMode = iota - // IndefLengthForbidden disallows indefinite length items. + // IndefLengthForbidden disallows indefinite-length items. IndefLengthForbidden maxIndefLengthMode @@ -811,7 +811,7 @@ type DecOptions struct { // Default is 128*1024=131072 and it can be set to [16, 2147483647] MaxMapPairs int - // IndefLength specifies whether to allow indefinite length CBOR items. + // IndefLength specifies whether to allow indefinite-length CBOR items. IndefLength IndefLengthMode // TagsMd specifies whether to allow CBOR tags (major type 6). @@ -1149,8 +1149,8 @@ func (opts DecOptions) decMode() (*decMode, error) { //nolint:gocritic // ignore unrecognizedTagToAny: opts.UnrecognizedTagToAny, timeTagToAny: opts.TimeTagToAny, simpleValues: simpleValues, - nanDec: opts.NaN, - infDec: opts.Inf, + nan: opts.NaN, + inf: opts.Inf, byteStringToTime: opts.ByteStringToTime, byteStringExpectedFormat: opts.ByteStringExpectedFormat, bignumTag: opts.BignumTag, @@ -1230,8 +1230,8 @@ type decMode struct { unrecognizedTagToAny UnrecognizedTagToAnyMode timeTagToAny TimeTagToAnyMode simpleValues *SimpleValueRegistry - nanDec NaNMode - infDec InfMode + nan NaNMode + inf InfMode byteStringToTime ByteStringToTimeMode byteStringExpectedFormat ByteStringExpectedFormatMode bignumTag BignumTagMode @@ -1272,8 +1272,8 @@ func (dm *decMode) DecOptions() DecOptions { UnrecognizedTagToAny: dm.unrecognizedTagToAny, TimeTagToAny: dm.timeTagToAny, SimpleValues: simpleValues, - NaN: dm.nanDec, - Inf: dm.infDec, + NaN: dm.nan, + Inf: dm.inf, ByteStringToTime: dm.byteStringToTime, ByteStringExpectedFormat: dm.byteStringExpectedFormat, BignumTag: dm.bignumTag, @@ -2206,7 +2206,7 @@ func (d *decoder) parseByteString() ([]byte, bool) { d.off += int(val) return b, false } - // Process indefinite length string chunks. + // Process indefinite-length string chunks. b := []byte{} for !d.foundBreak() { _, _, val = d.getHead() @@ -2307,7 +2307,7 @@ func (d *decoder) parseTextString() ([]byte, error) { } return b, nil } - // Process indefinite length string chunks. + // Process indefinite-length string chunks. b := []byte{} for !d.foundBreak() { _, _, val = d.getHead() diff --git a/decode_test.go b/decode_test.go index b3644787..4453b14d 100644 --- a/decode_test.go +++ b/decode_test.go @@ -40,14 +40,14 @@ var ( typeMapStringIntf = reflect.TypeOf(map[string]any{}) ) -type unmarshalTest struct { +type unmarshalTestCase struct { data []byte wantInterfaceValue any wantValues []any wrongTypes []reflect.Type } -var unmarshalTests = []unmarshalTest{ +var unmarshalTestCases = []unmarshalTestCase{ // CBOR test data are from https://tools.ietf.org/html/rfc7049#appendix-A. // unsigned integer @@ -1885,7 +1885,7 @@ var unmarshalTests = []unmarshalTest{ // More testcases not covered by https://tools.ietf.org/html/rfc7049#appendix-A. { - data: mustHexDecode("5fff"), // empty indefinite length byte string + data: mustHexDecode("5fff"), // empty indefinite-length byte string wantInterfaceValue: []byte{}, wantValues: []any{ []byte{}, @@ -1914,7 +1914,7 @@ var unmarshalTests = []unmarshalTest{ }, }, { - data: mustHexDecode("7fff"), // empty indefinite length text string + data: mustHexDecode("7fff"), // empty indefinite-length text string wantInterfaceValue: "", wantValues: []any{""}, wrongTypes: []reflect.Type{ @@ -1940,7 +1940,7 @@ var unmarshalTests = []unmarshalTest{ }, }, { - data: mustHexDecode("bfff"), // empty indefinite length map + data: mustHexDecode("bfff"), // empty indefinite-length map wantInterfaceValue: map[any]any{}, wantValues: []any{ map[any]any{}, @@ -2042,7 +2042,7 @@ var unmarshalTests = []unmarshalTest{ }, } -type unmarshalFloatTest struct { +type unmarshalFloatTestCase struct { data []byte wantInterfaceValue any wantValues []any @@ -2071,10 +2071,10 @@ var unmarshalFloatWrongTypes = []reflect.Type{ typeSimpleValue, } -// unmarshalFloatTests includes test values for float16, float32, and float64. +// unmarshalFloatTestCases 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{ +var unmarshalFloatTestCases = []unmarshalFloatTestCase{ // CBOR test data are from https://tools.ietf.org/html/rfc7049#appendix-A. // float16 @@ -2295,7 +2295,7 @@ func mustBigInt(s string) big.Int { } func TestUnmarshalToEmptyInterface(t *testing.T) { - for _, tc := range unmarshalTests { + for _, tc := range unmarshalTestCases { var v any if err := Unmarshal(tc.data, &v); err != nil { t.Errorf("Unmarshal(0x%x) returned error %v", tc.data, err) @@ -2306,7 +2306,7 @@ func TestUnmarshalToEmptyInterface(t *testing.T) { } func TestUnmarshalToRawMessage(t *testing.T) { - for _, tc := range unmarshalTests { + for _, tc := range unmarshalTestCases { testUnmarshalToRawMessage(t, tc.data) } } @@ -2357,7 +2357,7 @@ func testUnmarshalToRawMessage(t *testing.T, data []byte) { } func TestUnmarshalToCompatibleTypes(t *testing.T) { - for _, tc := range unmarshalTests { + for _, tc := range unmarshalTestCases { for _, wantValue := range tc.wantValues { testUnmarshalToCompatibleType(t, tc.data, wantValue, func(gotValue any) { compareNonFloats(t, tc.data, gotValue, wantValue) @@ -2422,7 +2422,7 @@ func testUnmarshalToCompatibleType(t *testing.T, data []byte, wantValue any, com } func TestUnmarshalToIncompatibleTypes(t *testing.T) { - for _, tc := range unmarshalTests { + for _, tc := range unmarshalTestCases { for _, wrongType := range tc.wrongTypes { testUnmarshalToIncompatibleType(t, tc.data, wrongType) } @@ -2485,7 +2485,7 @@ func compareNonFloats(t *testing.T, data []byte, got any, want any) { } func TestUnmarshalFloatToEmptyInterface(t *testing.T) { - for _, tc := range unmarshalFloatTests { + for _, tc := range unmarshalFloatTestCases { var v any if err := Unmarshal(tc.data, &v); err != nil { t.Errorf("Unmarshal(0x%x) returned error %v", tc.data, err) @@ -2496,13 +2496,13 @@ func TestUnmarshalFloatToEmptyInterface(t *testing.T) { } func TestUnmarshalFloatToRawMessage(t *testing.T) { - for _, tc := range unmarshalFloatTests { + for _, tc := range unmarshalFloatTestCases { testUnmarshalToRawMessage(t, tc.data) } } func TestUnmarshalFloatToCompatibleTypes(t *testing.T) { - for _, tc := range unmarshalFloatTests { + for _, tc := range unmarshalFloatTestCases { for _, wantValue := range tc.wantValues { testUnmarshalToCompatibleType(t, tc.data, wantValue, func(gotValue any) { compareFloats(t, tc.data, gotValue, wantValue, tc.equalityThreshold) @@ -2512,7 +2512,7 @@ func TestUnmarshalFloatToCompatibleTypes(t *testing.T) { } func TestUnmarshalFloatToIncompatibleTypes(t *testing.T) { - for _, tc := range unmarshalFloatTests { + for _, tc := range unmarshalFloatTestCases { for _, wrongType := range unmarshalFloatWrongTypes { testUnmarshalToIncompatibleType(t, tc.data, wrongType) } @@ -2960,7 +2960,7 @@ func TestUnmarshalNil(t *testing.T) { } } -var invalidUnmarshalTests = []struct { +var invalidUnmarshalTestCases = []struct { name string v any wantErrorMsg string @@ -2985,7 +2985,7 @@ var invalidUnmarshalTests = []struct { func TestInvalidUnmarshal(t *testing.T) { data := []byte{0x00} - for _, tc := range invalidUnmarshalTests { + for _, tc := range invalidUnmarshalTestCases { t.Run(tc.name, func(t *testing.T) { err := Unmarshal(data, tc.v) if err == nil { @@ -2999,510 +2999,521 @@ func TestInvalidUnmarshal(t *testing.T) { } } -var invalidCBORUnmarshalTests = []struct { +var invalidCBORUnmarshalTestCases = []struct { name string data []byte wantErrorMsg string }{ { - name: "Nil data", + name: "nil data", data: []byte(nil), wantErrorMsg: "EOF", }, { - name: "Empty data", + name: "empty data", data: []byte{}, wantErrorMsg: "EOF", }, { - name: "Tag number not followed by tag content", + name: "tag number not followed by tag content", data: []byte{0xc0}, wantErrorMsg: "unexpected EOF", }, { - name: "Indefinite length byte string with tagged chunk", + name: "indefinite-length byte string with tagged chunk", data: mustHexDecode("5fc64401020304ff"), wantErrorMsg: "cbor: wrong element type tag for indefinite-length byte string", }, { - name: "Indefinite length text string with tagged chunk", + name: "indefinite-length text string with tagged chunk", data: mustHexDecode("7fc06161ff"), wantErrorMsg: "cbor: wrong element type tag for indefinite-length UTF-8 text string", }, { - name: "Indefinite length strings with truncated text string", + name: "indefinite-length strings with truncated text string", data: mustHexDecode("7f61"), wantErrorMsg: "unexpected EOF", }, { - name: "Invalid nested tag number", + name: "invalid nested tag number", data: mustHexDecode("d864dc1a514b67b0"), wantErrorMsg: "cbor: invalid additional information 28 for type tag", }, // Data from 7049bis G.1 // Premature end of the input { - name: "End of input in a head", + name: "end of input in a head", data: mustHexDecode("18"), wantErrorMsg: "unexpected EOF", }, { - name: "End of input in a head", + name: "end of input in a head", data: mustHexDecode("19"), wantErrorMsg: "unexpected EOF", }, { - name: "End of input in a head", + name: "end of input in a head", data: mustHexDecode("1a"), wantErrorMsg: "unexpected EOF", }, { - name: "End of input in a head", + name: "end of input in a head", data: mustHexDecode("1b"), wantErrorMsg: "unexpected EOF", }, { - name: "End of input in a head", + name: "end of input in a head", data: mustHexDecode("1901"), wantErrorMsg: "unexpected EOF", }, { - name: "End of input in a head", + name: "end of input in a head", data: mustHexDecode("1a0102"), wantErrorMsg: "unexpected EOF", }, { - name: "End of input in a head", + name: "end of input in a head", data: mustHexDecode("1b01020304050607"), wantErrorMsg: "unexpected EOF", }, { - name: "End of input in a head", + name: "end of input in a head", data: mustHexDecode("38"), wantErrorMsg: "unexpected EOF", }, { - name: "End of input in a head", + name: "end of input in a head", data: mustHexDecode("58"), wantErrorMsg: "unexpected EOF", }, { - name: "End of input in a head", + name: "end of input in a head", data: mustHexDecode("78"), wantErrorMsg: "unexpected EOF", }, { - name: "End of input in a head", + name: "end of input in a head", data: mustHexDecode("98"), wantErrorMsg: "unexpected EOF", }, { - name: "End of input in a head", + name: "end of input in a head", data: mustHexDecode("9a01ff00"), wantErrorMsg: "unexpected EOF", }, { - name: "End of input in a head", + name: "end of input in a head", data: mustHexDecode("b8"), wantErrorMsg: "unexpected EOF", }, { - name: "End of input in a head", + name: "end of input in a head", data: mustHexDecode("d8"), wantErrorMsg: "unexpected EOF", }, { - name: "End of input in a head", + name: "end of input in a head", data: mustHexDecode("f8"), wantErrorMsg: "unexpected EOF", }, { - name: "End of input in a head", + name: "end of input in a head", data: mustHexDecode("f900"), wantErrorMsg: "unexpected EOF", }, { - name: "End of input in a head", + name: "end of input in a head", data: mustHexDecode("fa0000"), wantErrorMsg: "unexpected EOF", }, { - name: "End of input in a head", + name: "end of input in a head", data: mustHexDecode("fb000000"), wantErrorMsg: "unexpected EOF", }, { - name: "Definite length strings with short data", + name: "definite-length strings with short data", data: mustHexDecode("41"), wantErrorMsg: "unexpected EOF", }, { - name: "Definite length strings with short data", + name: "definite-length strings with short data", data: mustHexDecode("61"), wantErrorMsg: "unexpected EOF", }, { - name: "Definite length strings with short data", + name: "definite-length strings with short data", data: mustHexDecode("5affffffff00"), wantErrorMsg: "unexpected EOF", }, { - name: "Definite length strings with short data", + name: "definite-length strings with short data", data: mustHexDecode("5bffffffffffffffff010203"), wantErrorMsg: "cbor: byte string length 18446744073709551615 is too large, causing integer overflow", }, { - name: "Definite length strings with short data", + name: "definite-length strings with short data", data: mustHexDecode("7affffffff00"), wantErrorMsg: "unexpected EOF", }, { - name: "Definite length strings with short data", + name: "definite-length strings with short data", data: mustHexDecode("7b7fffffffffffffff010203"), wantErrorMsg: "unexpected EOF", }, { - name: "Definite length maps and arrays not closed with enough items", + name: "definite-length maps and arrays not closed with enough items", data: mustHexDecode("81"), wantErrorMsg: "unexpected EOF", }, { - name: "Definite length maps and arrays not closed with enough items", + name: "definite-length maps and arrays not closed with enough items", data: mustHexDecode("818181818181818181"), wantErrorMsg: "unexpected EOF", }, { - name: "Definite length maps and arrays not closed with enough items", + name: "definite-length maps and arrays not closed with enough items", data: mustHexDecode("8200"), wantErrorMsg: "unexpected EOF", }, { - name: "Definite length maps and arrays not closed with enough items", + name: "definite-length maps and arrays not closed with enough items", data: mustHexDecode("a1"), wantErrorMsg: "unexpected EOF", }, { - name: "Definite length maps and arrays not closed with enough items", + name: "definite-length maps and arrays not closed with enough items", data: mustHexDecode("a20102"), wantErrorMsg: "unexpected EOF", }, { - name: "Definite length maps and arrays not closed with enough items", + name: "definite-length maps and arrays not closed with enough items", data: mustHexDecode("a100"), wantErrorMsg: "unexpected EOF", }, { - name: "Definite length maps and arrays not closed with enough items", + name: "definite-length maps and arrays not closed with enough items", data: mustHexDecode("a2000000"), wantErrorMsg: "unexpected EOF", }, { - name: "Indefinite length strings not closed by a break stop code", + name: "indefinite-length strings not closed by a break stop code", data: mustHexDecode("5f4100"), wantErrorMsg: "unexpected EOF", }, { - name: "Indefinite length strings not closed by a break stop code", + name: "indefinite-length strings not closed by a break stop code", data: mustHexDecode("7f6100"), wantErrorMsg: "unexpected EOF", }, { - name: "Indefinite length maps and arrays not closed by a break stop code", + name: "indefinite-length maps and arrays not closed by a break stop code", data: mustHexDecode("9f"), wantErrorMsg: "unexpected EOF", }, { - name: "Indefinite length maps and arrays not closed by a break stop code", + name: "indefinite-length maps and arrays not closed by a break stop code", data: mustHexDecode("9f0102"), wantErrorMsg: "unexpected EOF", }, { - name: "Indefinite length maps and arrays not closed by a break stop code", + name: "indefinite-length maps and arrays not closed by a break stop code", data: mustHexDecode("bf"), wantErrorMsg: "unexpected EOF", }, { - name: "Indefinite length maps and arrays not closed by a break stop code", + name: "indefinite-length maps and arrays not closed by a break stop code", data: mustHexDecode("bf01020102"), wantErrorMsg: "unexpected EOF", }, { - name: "Indefinite length maps and arrays not closed by a break stop code", + name: "indefinite-length maps and arrays not closed by a break stop code", data: mustHexDecode("819f"), wantErrorMsg: "unexpected EOF", }, { - name: "Indefinite length maps and arrays not closed by a break stop code", + name: "indefinite-length maps and arrays not closed by a break stop code", data: mustHexDecode("9f8000"), wantErrorMsg: "unexpected EOF", }, { - name: "Indefinite length maps and arrays not closed by a break stop code", + name: "indefinite-length maps and arrays not closed by a break stop code", data: mustHexDecode("9f9f9f9f9fffffffff"), wantErrorMsg: "unexpected EOF", }, { - name: "Indefinite length maps and arrays not closed by a break stop code", + name: "indefinite-length maps and arrays not closed by a break stop code", data: mustHexDecode("9f819f819f9fffffff"), wantErrorMsg: "unexpected EOF", }, // Five subkinds of well-formedness error kind 3 (syntax error) { - name: "Reserved additional information values", + name: "reserved additional information values", data: mustHexDecode("3e"), wantErrorMsg: "cbor: invalid additional information 30 for type negative integer", }, { - name: "Reserved additional information values", + name: "reserved additional information values", data: mustHexDecode("5c"), wantErrorMsg: "cbor: invalid additional information 28 for type byte string", }, { - name: "Reserved additional information values", + name: "reserved additional information values", data: mustHexDecode("5d"), wantErrorMsg: "cbor: invalid additional information 29 for type byte string", }, { - name: "Reserved additional information values", + name: "reserved additional information values", data: mustHexDecode("5e"), wantErrorMsg: "cbor: invalid additional information 30 for type byte string", }, { - name: "Reserved additional information values", + name: "reserved additional information values", data: mustHexDecode("7c"), wantErrorMsg: "cbor: invalid additional information 28 for type UTF-8 text string", }, { - name: "Reserved additional information values", + name: "reserved additional information values", data: mustHexDecode("7d"), wantErrorMsg: "cbor: invalid additional information 29 for type UTF-8 text string", }, { - name: "Reserved additional information values", + name: "reserved additional information values", data: mustHexDecode("7e"), wantErrorMsg: "cbor: invalid additional information 30 for type UTF-8 text string", }, { - name: "Reserved additional information values", + name: "reserved additional information values", data: mustHexDecode("9c"), wantErrorMsg: "cbor: invalid additional information 28 for type array", }, { - name: "Reserved additional information values", + name: "reserved additional information values", data: mustHexDecode("9d"), wantErrorMsg: "cbor: invalid additional information 29 for type array", }, { - name: "Reserved additional information values", + name: "reserved additional information values", data: mustHexDecode("9e"), wantErrorMsg: "cbor: invalid additional information 30 for type array", }, { - name: "Reserved additional information values", + name: "reserved additional information values", data: mustHexDecode("bc"), wantErrorMsg: "cbor: invalid additional information 28 for type map", }, { - name: "Reserved additional information values", + name: "reserved additional information values", data: mustHexDecode("bd"), wantErrorMsg: "cbor: invalid additional information 29 for type map", }, { - name: "Reserved additional information values", + name: "reserved additional information values", data: mustHexDecode("be"), wantErrorMsg: "cbor: invalid additional information 30 for type map", }, { - name: "Reserved additional information values", + name: "reserved additional information values", data: mustHexDecode("dc"), wantErrorMsg: "cbor: invalid additional information 28 for type tag", }, { - name: "Reserved additional information values", + name: "reserved additional information values", data: mustHexDecode("dd"), wantErrorMsg: "cbor: invalid additional information 29 for type tag", }, { - name: "Reserved additional information values", + name: "reserved additional information values", data: mustHexDecode("de"), wantErrorMsg: "cbor: invalid additional information 30 for type tag", }, { - name: "Reserved additional information values", + name: "reserved additional information values", data: mustHexDecode("fc"), wantErrorMsg: "cbor: invalid additional information 28 for type primitives", }, { - name: "Reserved additional information values", + name: "reserved additional information values", data: mustHexDecode("fd"), wantErrorMsg: "cbor: invalid additional information 29 for type primitives", }, { - name: "Reserved additional information values", + name: "reserved additional information values", data: mustHexDecode("fe"), wantErrorMsg: "cbor: invalid additional information 30 for type primitives", }, { - name: "Reserved two-byte encodings of simple types", + name: "reserved two-byte encodings of simple types", data: mustHexDecode("f800"), wantErrorMsg: "cbor: invalid simple value 0 for type primitives", }, { - name: "Reserved two-byte encodings of simple types", + name: "reserved two-byte encodings of simple types", data: mustHexDecode("f801"), wantErrorMsg: "cbor: invalid simple value 1 for type primitives", }, { - name: "Reserved two-byte encodings of simple types", + name: "reserved two-byte encodings of simple types", data: mustHexDecode("f818"), wantErrorMsg: "cbor: invalid simple value 24 for type primitives", }, { - name: "Reserved two-byte encodings of simple types", + name: "reserved two-byte encodings of simple types", data: mustHexDecode("f81f"), wantErrorMsg: "cbor: invalid simple value 31 for type primitives", }, { - name: "Indefinite length string chunks not of the correct type", + name: "indefinite-length string chunks not of the correct type", data: mustHexDecode("5f00ff"), wantErrorMsg: "cbor: wrong element type positive integer for indefinite-length byte string", }, { - name: "Indefinite length string chunks not of the correct type", + name: "indefinite-length string chunks not of the correct type", data: mustHexDecode("5f21ff"), wantErrorMsg: "cbor: wrong element type negative integer for indefinite-length byte string", }, { - name: "Indefinite length string chunks not of the correct type", + name: "indefinite-length string chunks not of the correct type", data: mustHexDecode("5f6100ff"), wantErrorMsg: "cbor: wrong element type UTF-8 text string for indefinite-length byte string", }, { - name: "Indefinite length string chunks not of the correct type", + name: "indefinite-length string chunks not of the correct type", data: mustHexDecode("5f80ff"), wantErrorMsg: "cbor: wrong element type array for indefinite-length byte string", }, { - name: "Indefinite length string chunks not of the correct type", + name: "indefinite-length string chunks not of the correct type", data: mustHexDecode("5fa0ff"), wantErrorMsg: "cbor: wrong element type map for indefinite-length byte string", }, { - name: "Indefinite length string chunks not of the correct type", + name: "indefinite-length string chunks not of the correct type", data: mustHexDecode("5fc000ff"), wantErrorMsg: "cbor: wrong element type tag for indefinite-length byte string", }, { - name: "Indefinite length string chunks not of the correct type", + name: "indefinite-length string chunks not of the correct type", data: mustHexDecode("5fe0ff"), wantErrorMsg: "cbor: wrong element type primitives for indefinite-length byte string", }, { - name: "Indefinite length string chunks not of the correct type", + name: "indefinite-length string chunks not of the correct type", data: mustHexDecode("7f4100ff"), wantErrorMsg: "cbor: wrong element type byte string for indefinite-length UTF-8 text string", }, { - name: "Indefinite length string chunks not definite length", + name: "indefinite-length string chunks not definite-length", data: mustHexDecode("5f5f4100ffff"), wantErrorMsg: "cbor: indefinite-length byte string chunk is not definite-length", }, { - name: "Indefinite length string chunks not definite length", + name: "indefinite-length string chunks not definite-length", data: mustHexDecode("7f7f6100ffff"), wantErrorMsg: "cbor: indefinite-length UTF-8 text string chunk is not definite-length", }, { - name: "Break occurring on its own outside of an indefinite length item", + name: "break occurring on its own outside of an indefinite-length item", data: mustHexDecode("ff"), wantErrorMsg: "cbor: unexpected \"break\" code", }, { - name: "Break occurring in a definite length array or map or a tag", + name: "break occurring in a definite-length array or map or a tag", data: mustHexDecode("81ff"), wantErrorMsg: "cbor: unexpected \"break\" code", }, { - name: "Break occurring in a definite length array or map or a tag", + name: "break occurring in a definite-length array or map or a tag", data: mustHexDecode("8200ff"), wantErrorMsg: "cbor: unexpected \"break\" code", }, { - name: "Break occurring in a definite length array or map or a tag", + name: "break occurring in a definite-length array or map or a tag", data: mustHexDecode("a1ff"), wantErrorMsg: "cbor: unexpected \"break\" code", }, { - name: "Break occurring in a definite length array or map or a tag", + name: "break occurring in a definite-length array or map or a tag", data: mustHexDecode("a1ff00"), wantErrorMsg: "cbor: unexpected \"break\" code", }, { - name: "Break occurring in a definite length array or map or a tag", + name: "break occurring in a definite-length array or map or a tag", data: mustHexDecode("a100ff"), wantErrorMsg: "cbor: unexpected \"break\" code", }, { - name: "Break occurring in a definite length array or map or a tag", + name: "break occurring in a definite-length array or map or a tag", data: mustHexDecode("a20000ff"), wantErrorMsg: "cbor: unexpected \"break\" code", }, { - name: "Break occurring in a definite length array or map or a tag", + name: "break occurring in a definite-length array or map or a tag", data: mustHexDecode("9f81ff"), wantErrorMsg: "cbor: unexpected \"break\" code", }, { - name: "Break occurring in a definite length array or map or a tag", + name: "break occurring in a definite-length array or map or a tag", data: mustHexDecode("9f829f819f9fffffffff"), wantErrorMsg: "cbor: unexpected \"break\" code", }, { - name: "Break in indefinite length map would lead to odd number of items (break in a value position)", + name: "break in indefinite-length map would lead to odd number of items (break in a value position)", data: mustHexDecode("bf00ff"), wantErrorMsg: "cbor: unexpected \"break\" code", }, { - name: "Break in indefinite length map would lead to odd number of items (break in a value position)", + name: "break in indefinite-length map would lead to odd number of items (break in a value position)", data: mustHexDecode("bf000000ff"), wantErrorMsg: "cbor: unexpected \"break\" code", }, { - name: "Major type 0 with additional information 31", + name: "major type 0 with additional information 31", data: mustHexDecode("1f"), wantErrorMsg: "cbor: invalid additional information 31 for type positive integer", }, { - name: "Major type 1 with additional information 31", + name: "major type 1 with additional information 31", data: mustHexDecode("3f"), wantErrorMsg: "cbor: invalid additional information 31 for type negative integer", }, { - name: "Major type 6 with additional information 31", + name: "major type 6 with additional information 31", data: mustHexDecode("df"), wantErrorMsg: "cbor: invalid additional information 31 for type tag", }, // Extraneous data { - name: "Two ints", + name: "two ints", data: mustHexDecode("0001"), wantErrorMsg: "cbor: 1 bytes of extraneous data starting at index 1", }, { - name: "Two arrays", + name: "two arrays", data: mustHexDecode("830102038104"), wantErrorMsg: "cbor: 2 bytes of extraneous data starting at index 4", }, { - name: "Int and partial array", + name: "int and partial array", data: mustHexDecode("00830102"), wantErrorMsg: "cbor: 3 bytes of extraneous data starting at index 1", }, + // Indefinite-length map + { + name: "indefinite-length map with one key and no value", + data: []byte{0xbf, 0x61, 'a', 0xff}, + wantErrorMsg: `cbor: unexpected "break" code`, + }, + { + name: "indefinite-length map with two keys and one value", + data: []byte{0xbf, 0x61, 'a', 0x01, 0x61, 'b', 0xff}, + wantErrorMsg: `cbor: unexpected "break" code`, + }, } func TestInvalidCBORUnmarshal(t *testing.T) { - for _, tc := range invalidCBORUnmarshalTests { + for _, tc := range invalidCBORUnmarshalTestCases { t.Run(tc.name, func(t *testing.T) { var i any err := Unmarshal(tc.data, &i) @@ -3544,13 +3555,13 @@ func TestValidUTF8String(t *testing.T) { wantObj: "streaming", }, { - name: "indef length with UTF8RejectInvalid", + name: "indefinite-length with UTF8RejectInvalid", data: mustHexDecode("7f657374726561646d696e67ff"), dm: dmRejectInvalidUTF8, wantObj: "streaming", }, { - name: "indef length with UTF8DecodeInvalid", + name: "indefinite-length with UTF8DecodeInvalid", data: mustHexDecode("7f657374726561646d696e67ff"), dm: dmDecodeInvalidUTF8, wantObj: "streaming", @@ -3611,17 +3622,41 @@ func TestInvalidUTF8String(t *testing.T) { wantObj: string([]byte{0xfe}), }, { - name: "indef length with UTF8RejectInvalid", + name: "indefinite-length with UTF8RejectInvalid", data: mustHexDecode("7f62e6b061b4ff"), dm: dmRejectInvalidUTF8, wantErrorMsg: invalidUTF8ErrorMsg, }, { - name: "indef length with UTF8DecodeInvalid", + name: "indefinite-length with UTF8DecodeInvalid", data: mustHexDecode("7f62e6b061b4ff"), dm: dmDecodeInvalidUTF8, wantObj: string([]byte{0xe6, 0xb0, 0xb4}), }, + { + name: "indefinite-length invalid UTF-8 in the second chunk with UTF8RejectInvalid", + data: []byte{ + 0x7f, + 0x62, 'a', 'b', // valid UTF-8 + 0x62, 0x80, 0x81, // invalid UTF-8 + 0x62, 'c', 'd', // valid UTF-8 + 0xff, + }, + dm: dmRejectInvalidUTF8, + wantErrorMsg: invalidUTF8ErrorMsg, + }, + { + name: "indefinite-length invalid UTF-8 in the second chunk with dmDecodeInvalidUTF8", + data: []byte{ + 0x7f, + 0x62, 'a', 'b', // valid UTF-8 + 0x62, 0x80, 0x81, // invalid UTF-8 + 0x62, 'c', 'd', // valid UTF-8 + 0xff, + }, + dm: dmDecodeInvalidUTF8, + wantObj: string([]byte{'a', 'b', 0x80, 0x81, 'c', 'd'}), + }, } for _, tc := range testCases { @@ -3631,7 +3666,7 @@ func TestInvalidUTF8String(t *testing.T) { err = tc.dm.Unmarshal(tc.data, &v) if tc.wantErrorMsg != "" { if err == nil { - t.Errorf("Unmarshal(0x%x) didn't return error", tc.data) + 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) error %q, want %q", tc.data, err.Error(), tc.wantErrorMsg) } @@ -3649,7 +3684,7 @@ func TestInvalidUTF8String(t *testing.T) { err = tc.dm.Unmarshal(tc.data, &s) if tc.wantErrorMsg != "" { if err == nil { - t.Errorf("Unmarshal(0x%x) didn't return error", tc.data) + 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) error %q, want %q", tc.data, err.Error(), tc.wantErrorMsg) } @@ -3708,7 +3743,7 @@ func TestUnmarshalStruct(t *testing.T) { unexportedField: 0, } - tests := []struct { + testCases := []struct { name string data []byte want any @@ -3724,7 +3759,7 @@ func TestUnmarshalStruct(t *testing.T) { want: want, }, } - for _, tc := range tests { + for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { var v outer if err := Unmarshal(tc.data, &v); err != nil { @@ -4306,55 +4341,55 @@ func TestDecodeInvalidTagTime(t *testing.T) { wantErrorMsg string }{ { - name: "Tag 0 with invalid RFC3339 time string", + name: "tag 0 with invalid RFC3339 time string", data: mustHexDecode("c07f657374726561646d696e67ff"), decodeToTypes: []reflect.Type{typeIntf, typeTime}, wantErrorMsg: "cbor: cannot set streaming for time.Time", }, { - name: "Tag 0 with invalid UTF-8 string", + name: "tag 0 with invalid UTF-8 string", data: mustHexDecode("c07f62e6b061b4ff"), decodeToTypes: []reflect.Type{typeIntf, typeTime}, wantErrorMsg: "cbor: invalid UTF-8 string", }, { - name: "Tag 0 with integer content", + name: "tag 0 with integer content", data: mustHexDecode("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", + name: "tag 0 with byte string content", data: mustHexDecode("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", + name: "tag 0 with integer content as array element", data: mustHexDecode("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", + name: "tag 1 with negative integer overflow", data: mustHexDecode("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", + name: "tag 1 with string content", data: mustHexDecode("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", + name: "tag 1 with simple value", data: mustHexDecode("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", + name: "tag 1 with string content as array element", data: mustHexDecode("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", @@ -4366,7 +4401,7 @@ func TestDecodeInvalidTagTime(t *testing.T) { 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) + 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, tc.wantErrorMsg) } @@ -4397,7 +4432,7 @@ func TestDecodeTag0Error(t *testing.T) { // Decode to interface{} var v any if err := tc.dm.Unmarshal(data, &v); err == nil { - t.Errorf("Unmarshal(0x%x) didn't return error, want error msg %q", data, wantErrorMsg) + t.Errorf("Unmarshal(0x%x) didn't return an 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) } @@ -4405,7 +4440,7 @@ func TestDecodeTag0Error(t *testing.T) { // 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) + t.Errorf("Unmarshal(0x%x) didn't return an 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) } @@ -4413,7 +4448,7 @@ func TestDecodeTag0Error(t *testing.T) { // 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) + t.Errorf("Unmarshal(0x%x) didn't return an 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) } @@ -4443,7 +4478,7 @@ func TestDecodeTag1Error(t *testing.T) { // Decode to interface{} var v any if err := tc.dm.Unmarshal(data, &v); err == nil { - t.Errorf("Unmarshal(0x%x) didn't return error, want error msg %q", data, wantErrorMsg) + t.Errorf("Unmarshal(0x%x) didn't return an 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) } @@ -4451,7 +4486,7 @@ func TestDecodeTag1Error(t *testing.T) { // 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) + t.Errorf("Unmarshal(0x%x) didn't return an 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) } @@ -4459,7 +4494,7 @@ func TestDecodeTag1Error(t *testing.T) { // 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) + t.Errorf("Unmarshal(0x%x) didn't return an 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) } @@ -4519,7 +4554,7 @@ func TestDecodeTimeStreaming(t *testing.T) { 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) + 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 msg %q, want %q", tc.data, err, tc.wantErrorMsg) } @@ -4637,7 +4672,7 @@ func TestDecTimeTagOption(t *testing.T) { err := tc.decMode.Unmarshal(tc.cborRFC3339Time, &tm) if tc.wantErrorMsg != "" { if err == nil { - t.Errorf("Unmarshal(0x%x) didn't return error", tc.cborRFC3339Time) + t.Errorf("Unmarshal(0x%x) didn't return an 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) } @@ -4651,7 +4686,7 @@ func TestDecTimeTagOption(t *testing.T) { err = tc.decMode.Unmarshal(tc.cborUnixTime, &tm) if tc.wantErrorMsg != "" { if err == nil { - t.Errorf("Unmarshal(0x%x) didn't return error", tc.cborRFC3339Time) + t.Errorf("Unmarshal(0x%x) didn't return an 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) } @@ -4805,7 +4840,7 @@ func (n marshalBinaryError) MarshalBinary() (data []byte, err error) { } func TestBinaryMarshalerUnmarshaler(t *testing.T) { - testCases := []roundTripTest{ + testCases := []roundTripTestCase{ { name: "primitive obj", obj: number(1234567890), @@ -4913,7 +4948,7 @@ func (n marshalCBORError) MarshalCBOR() (data []byte, err error) { } func TestMarshalerUnmarshaler(t *testing.T) { - testCases := []roundTripTest{ + testCases := []roundTripTestCase{ { name: "primitive obj", obj: number2(1), @@ -5046,11 +5081,11 @@ func TestUnmarshalArrayToStruct(t *testing.T) { data []byte }{ { - name: "definite length array", + name: "definite-length array", data: mustHexDecode("83010203"), }, { - name: "indefinite length array", + name: "indefinite-length array", data: mustHexDecode("9f010203ff"), }, } @@ -5530,13 +5565,13 @@ func TestDecOptions(t *testing.T) { } } -type roundTripTest struct { +type roundTripTestCase struct { name string obj any wantCborData []byte } -func testRoundTrip(t *testing.T, testCases []roundTripTest, em EncMode, dm DecMode) { +func testRoundTrip(t *testing.T, testCases []roundTripTestCase, em EncMode, dm DecMode) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { b, err := em.Marshal(tc.obj) @@ -5799,6 +5834,9 @@ func TestUnmarshalStructKeyAsIntNumError(t *testing.T) { type T2 struct { F1 int `cbor:"-18446744073709551616,keyasint"` } + type T3 struct { + F1 int `cbor:"99999999999999999999,keyasint"` + } testCases := []struct { name string data []byte @@ -5812,11 +5850,17 @@ func TestUnmarshalStructKeyAsIntNumError(t *testing.T) { wantErrorMsg: "cbor: failed to parse field name \"a\" to int", }, { - name: "out of range int as key", + name: "int key < math.MinInt", data: mustHexDecode("a13bffffffffffffffff01"), obj: T2{}, wantErrorMsg: "cbor: failed to parse field name \"-18446744073709551616\" to int", }, + { + name: "int key > math.MaxInt", + data: mustHexDecode("a10001"), + obj: T3{}, + wantErrorMsg: "cbor: failed to parse field name \"99999999999999999999\" to int", + }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { @@ -6852,7 +6896,7 @@ func TestExceedMaxArrayElements(t *testing.T) { wantErrorMsg: "cbor: exceeded max number of elements 16 for CBOR array", }, { - name: "indefinite length array", + name: "indefinite-length array", opts: DecOptions{MaxArrayElements: 16}, data: mustHexDecode("9f0101010101010101010101010101010101ff"), wantErrorMsg: "cbor: exceeded max number of elements 16 for CBOR array", @@ -6879,13 +6923,13 @@ func TestExceedMaxMapPairs(t *testing.T) { wantErrorMsg string }{ { - name: "array", + name: "map", opts: DecOptions{MaxMapPairs: 16}, data: mustHexDecode("b101010101010101010101010101010101010101010101010101010101010101010101"), wantErrorMsg: "cbor: exceeded max number of key-value pairs 16 for CBOR map", }, { - name: "indefinite length array", + name: "indefinite-length map", opts: DecOptions{MaxMapPairs: 16}, data: mustHexDecode("bf01010101010101010101010101010101010101010101010101010101010101010101ff"), wantErrorMsg: "cbor: exceeded max number of key-value pairs 16 for CBOR map", @@ -6930,7 +6974,7 @@ func TestDecIndefiniteLengthOption(t *testing.T) { wantErrorMsg: "cbor: indefinite-length array isn't allowed", }, { - name: "indefinite length array", + name: "indefinite-length array", opts: DecOptions{IndefLength: IndefLengthForbidden}, data: mustHexDecode("bfff"), wantErrorMsg: "cbor: indefinite-length map isn't allowed", @@ -6938,7 +6982,7 @@ func TestDecIndefiniteLengthOption(t *testing.T) { } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - // Default option allows indefinite length items + // Default option allows indefinite-length items var v any if err := Unmarshal(tc.data, &v); err != nil { t.Errorf("Unmarshal(0x%x) returned an error %v", tc.data, err) @@ -7499,7 +7543,7 @@ func TestStreamExtraErrorCondUnknownField(t *testing.T) { func TestUnmarshalTagNum55799(t *testing.T) { tagNum55799 := mustHexDecode("d9d9f7") - for _, tc := range unmarshalTests { + for _, tc := range unmarshalTestCases { // Prefix tag number 55799 to CBOR test data data := make([]byte, len(tc.data)+6) copy(data, tagNum55799) @@ -7565,7 +7609,7 @@ func TestUnmarshalTagNum55799(t *testing.T) { func TestUnmarshalFloatWithTagNum55799(t *testing.T) { tagNum55799 := mustHexDecode("d9d9f7") - for _, tc := range unmarshalFloatTests { + for _, tc := range unmarshalFloatTestCases { // Prefix tag number 55799 to CBOR test data data := make([]byte, len(tc.data)+3) copy(data, tagNum55799) @@ -7775,7 +7819,7 @@ func TestUnmarshalNestedTagNum55799ToTime(t *testing.T) { var v time.Time if err := Unmarshal(data, &v); err == nil { - t.Errorf("Unmarshal(0x%x) didn't return error", data) + t.Errorf("Unmarshal(0x%x) didn't return an error", data) } else if !strings.Contains(err.Error(), wantErrorMsg) { t.Errorf("Unmarshal(0x%x) returned error %s, want %s", data, err.Error(), wantErrorMsg) } @@ -7799,7 +7843,7 @@ func TestUnmarshalNestedTagNum55799ToUnmarshaler(t *testing.T) { var v number3 if err := Unmarshal(data, &v); err == nil { - t.Errorf("Unmarshal(0x%x) didn't return error", data) + t.Errorf("Unmarshal(0x%x) didn't return an error", data) } else if !strings.Contains(err.Error(), wantErrorMsg) { t.Errorf("Unmarshal(0x%x) returned error %s, want %s", data, err.Error(), wantErrorMsg) } @@ -7821,7 +7865,7 @@ func TestUnmarshalNestedTagNum55799ToRegisteredGoType(t *testing.T) { var v myInt if err := dm.Unmarshal(data, &v); err == nil { - t.Errorf("Unmarshal() didn't return error") + t.Errorf("Unmarshal() didn't return an error") } else if !strings.Contains(err.Error(), wantErrorMsg) { t.Errorf("Unmarshal(0x%x) returned error %s, want %s", data, err.Error(), wantErrorMsg) } @@ -8042,19 +8086,19 @@ func TestUnmarshalInvalidTagBignum(t *testing.T) { wantErrorMsg string }{ { - name: "Tag 2 with string", + name: "tag 2 with string", data: mustHexDecode("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", + name: "tag 3 with string", data: mustHexDecode("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", + name: "tag 3 with negative integer", data: mustHexDecode("81C330"), // [3(-17)] decodeToTypes: []reflect.Type{typeIntf, typeBigIntSlice}, wantErrorMsg: "cbor: tag number 2 or 3 must be followed by byte string, got negative integer", @@ -8065,7 +8109,7 @@ func TestUnmarshalInvalidTagBignum(t *testing.T) { 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) + 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, tc.wantErrorMsg) } @@ -8593,7 +8637,7 @@ func TestUnmarshalToDefaultMapType(t *testing.T) { } func TestUnmarshalFirstNoTrailing(t *testing.T) { - for _, tc := range unmarshalTests { + for _, tc := range unmarshalTestCases { var v any if rest, err := UnmarshalFirst(tc.data, &v); err != nil { t.Errorf("UnmarshalFirst(0x%x) returned error %v", tc.data, err) @@ -8616,7 +8660,7 @@ func TestUnmarshalFirstNoTrailing(t *testing.T) { func TestUnmarshalfirstTrailing(t *testing.T) { // Random trailing data trailingData := mustHexDecode("4a6b0f4718c73f391091ea1c") - for _, tc := range unmarshalTests { + for _, tc := range unmarshalTestCases { data := make([]byte, 0, len(tc.data)+len(trailingData)) data = append(data, tc.data...) data = append(data, trailingData...) @@ -8894,37 +8938,37 @@ func TestUnmarshalDefaultByteStringType(t *testing.T) { for _, tc := range []struct { name string opts DecOptions - in []byte + data []byte want any }{ { name: "default to []byte", opts: DecOptions{}, - in: mustHexDecode("43414243"), + data: mustHexDecode("43414243"), want: []byte("ABC"), }, { name: "explicitly []byte", opts: DecOptions{DefaultByteStringType: reflect.TypeOf([]byte(nil))}, - in: mustHexDecode("43414243"), + data: mustHexDecode("43414243"), want: []byte("ABC"), }, { name: "string", opts: DecOptions{DefaultByteStringType: reflect.TypeOf("")}, - in: mustHexDecode("43414243"), + data: mustHexDecode("43414243"), want: "ABC", }, { name: "ByteString", opts: DecOptions{DefaultByteStringType: reflect.TypeOf(ByteString(""))}, - in: mustHexDecode("43414243"), + data: mustHexDecode("43414243"), want: ByteString("ABC"), }, { name: "named []byte type", opts: DecOptions{DefaultByteStringType: reflect.TypeOf(namedByteSliceType(nil))}, - in: mustHexDecode("43414243"), + data: mustHexDecode("43414243"), want: namedByteSliceType("ABC"), }, } { @@ -8935,7 +8979,7 @@ func TestUnmarshalDefaultByteStringType(t *testing.T) { } var got any - if err := dm.Unmarshal(tc.in, &got); err != nil { + if err := dm.Unmarshal(tc.data, &got); err != nil { t.Errorf("unexpected error: %v", err) } @@ -9100,19 +9144,19 @@ func TestUnmarshalWithUnrecognizedTagToAnyMode(t *testing.T) { for _, tc := range []struct { name string opts DecOptions - in []byte + data []byte want any }{ { name: "default to value of type Tag", opts: DecOptions{}, - in: mustHexDecode("d8ff00"), + data: mustHexDecode("d8ff00"), want: Tag{Number: uint64(255), Content: uint64(0)}, }, { name: "Tag's content", opts: DecOptions{UnrecognizedTagToAny: UnrecognizedTagContentToAny}, - in: mustHexDecode("d8ff00"), + data: mustHexDecode("d8ff00"), want: uint64(0), }, } { @@ -9123,7 +9167,7 @@ func TestUnmarshalWithUnrecognizedTagToAnyMode(t *testing.T) { } var got any - if err := dm.Unmarshal(tc.in, &got); err != nil { + if err := dm.Unmarshal(tc.data, &got); err != nil { t.Errorf("unexpected error: %v", err) } @@ -9138,55 +9182,55 @@ func TestUnmarshalWithUnrecognizedTagToAnyModeForSupportedTags(t *testing.T) { for _, tc := range []struct { name string opts DecOptions - in []byte + data []byte want any }{ { name: "Unmarshal with tag number 0 when UnrecognizedTagContentToAny option is not set", opts: DecOptions{}, - in: mustHexDecode("c074323031332d30332d32315432303a30343a30305a"), + data: mustHexDecode("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: mustHexDecode("c074323031332d30332d32315432303a30343a30305a"), + data: mustHexDecode("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: mustHexDecode("c11a514b67b0"), + data: mustHexDecode("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: mustHexDecode("c11a514b67b0"), + data: mustHexDecode("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: mustHexDecode("c249010000000000000000"), + data: mustHexDecode("c249010000000000000000"), want: mustBigInt("18446744073709551616"), }, { name: "Unmarshal with tag number 2 when UnrecognizedTagContentToAny option is set", opts: DecOptions{UnrecognizedTagToAny: UnrecognizedTagContentToAny}, - in: mustHexDecode("c249010000000000000000"), + data: mustHexDecode("c249010000000000000000"), want: mustBigInt("18446744073709551616"), }, { name: "Unmarshal with tag number 3 when UnrecognizedTagContentToAny option is not set", opts: DecOptions{}, - in: mustHexDecode("c349010000000000000000"), + data: mustHexDecode("c349010000000000000000"), want: mustBigInt("-18446744073709551617"), }, { name: "Unmarshal with tag number 3 when UnrecognizedTagContentToAny option is set", opts: DecOptions{UnrecognizedTagToAny: UnrecognizedTagContentToAny}, - in: mustHexDecode("c349010000000000000000"), + data: mustHexDecode("c349010000000000000000"), want: mustBigInt("-18446744073709551617"), }, } { @@ -9197,11 +9241,11 @@ func TestUnmarshalWithUnrecognizedTagToAnyModeForSupportedTags(t *testing.T) { } var got any - if err := dm.Unmarshal(tc.in, &got); err != nil { + if err := dm.Unmarshal(tc.data, &got); err != nil { t.Errorf("unexpected error: %v", err) } - compareNonFloats(t, tc.in, got, tc.want) + compareNonFloats(t, tc.data, got, tc.want) }) } @@ -9220,19 +9264,19 @@ func TestUnmarshalWithUnrecognizedTagToAnyModeForSharedTag(t *testing.T) { for _, tc := range []struct { name string opts DecOptions - in []byte + data []byte want any }{ { name: "Unmarshal with a shared tag when UnrecognizedTagContentToAny option is not set", opts: DecOptions{}, - in: mustHexDecode("d9d9f7d87d01"), // 55799(125(1)) + data: mustHexDecode("d9d9f7d87d01"), // 55799(125(1)) want: myInt(1), }, { name: "Unmarshal with a shared tag when UnrecognizedTagContentToAny option is set", opts: DecOptions{UnrecognizedTagToAny: UnrecognizedTagContentToAny}, - in: mustHexDecode("d9d9f7d87d01"), // 55799(125(1)) + data: mustHexDecode("d9d9f7d87d01"), // 55799(125(1)) want: myInt(1), }, } { @@ -9244,11 +9288,11 @@ func TestUnmarshalWithUnrecognizedTagToAnyModeForSharedTag(t *testing.T) { var got any - if err := dm.Unmarshal(tc.in, &got); err != nil { + if err := dm.Unmarshal(tc.data, &got); err != nil { t.Errorf("unexpected error: %v", err) } - compareNonFloats(t, tc.in, got, tc.want) + compareNonFloats(t, tc.data, got, tc.want) }) } @@ -9303,7 +9347,7 @@ func TestUnmarshalSimpleValues(t *testing.T) { for _, tc := range []struct { name string fns []func(*SimpleValueRegistry) error - in []byte + data []byte into reflect.Type want any assertOnError func(t *testing.T, e error) @@ -9311,7 +9355,7 @@ func TestUnmarshalSimpleValues(t *testing.T) { { name: "default false into interface{}", fns: nil, - in: []byte{0xf4}, + data: []byte{0xf4}, into: typeIntf, want: false, assertOnError: assertNilError, @@ -9319,7 +9363,7 @@ func TestUnmarshalSimpleValues(t *testing.T) { { name: "default false into bool", fns: nil, - in: []byte{0xf4}, + data: []byte{0xf4}, into: typeBool, want: false, assertOnError: assertNilError, @@ -9327,7 +9371,7 @@ func TestUnmarshalSimpleValues(t *testing.T) { { name: "default true into interface{}", fns: nil, - in: []byte{0xf5}, + data: []byte{0xf5}, into: typeIntf, want: true, assertOnError: assertNilError, @@ -9335,7 +9379,7 @@ func TestUnmarshalSimpleValues(t *testing.T) { { name: "default true into bool", fns: nil, - in: []byte{0xf5}, + data: []byte{0xf5}, into: typeBool, want: true, assertOnError: assertNilError, @@ -9343,7 +9387,7 @@ func TestUnmarshalSimpleValues(t *testing.T) { { name: "default null into interface{}", fns: nil, - in: []byte{0xf6}, + data: []byte{0xf6}, into: typeIntf, want: nil, assertOnError: assertNilError, @@ -9351,7 +9395,7 @@ func TestUnmarshalSimpleValues(t *testing.T) { { name: "default undefined into interface{}", fns: nil, - in: []byte{0xf7}, + data: []byte{0xf7}, into: typeIntf, want: nil, assertOnError: assertNilError, @@ -9359,7 +9403,7 @@ func TestUnmarshalSimpleValues(t *testing.T) { { name: "reject undefined into interface{}", fns: []func(*SimpleValueRegistry) error{WithRejectedSimpleValue(23)}, - in: []byte{0xf7}, + data: []byte{0xf7}, into: typeIntf, want: nil, assertOnError: assertExactError(&UnacceptableDataItemError{ @@ -9370,7 +9414,7 @@ func TestUnmarshalSimpleValues(t *testing.T) { { name: "reject true into bool", fns: []func(*SimpleValueRegistry) error{WithRejectedSimpleValue(21)}, - in: []byte{0xf5}, + data: []byte{0xf5}, into: typeBool, want: false, assertOnError: assertExactError(&UnacceptableDataItemError{ @@ -9381,7 +9425,7 @@ func TestUnmarshalSimpleValues(t *testing.T) { { name: "default unrecognized into uint64", fns: nil, - in: []byte{0xf8, 0xc8}, + data: []byte{0xf8, 0xc8}, into: typeUint64, want: uint64(200), assertOnError: assertNilError, @@ -9399,7 +9443,7 @@ func TestUnmarshalSimpleValues(t *testing.T) { } dst := reflect.New(tc.into) - err = decMode.Unmarshal(tc.in, dst.Interface()) + err = decMode.Unmarshal(tc.data, dst.Interface()) tc.assertOnError(t, err) if got := dst.Elem().Interface(); !reflect.DeepEqual(tc.want, got) { @@ -9443,71 +9487,71 @@ func TestDecModeInvalidTimeTagToAnyMode(t *testing.T) { func TestDecModeTimeTagToAny(t *testing.T) { for _, tc := range []struct { - name string - opts DecOptions - in []byte - want any - wantErrMessage string + name string + opts DecOptions + data []byte + want any + wantErrorMsg string }{ { name: "Unmarshal tag 0 data to time.Time when TimeTagToAny is not set", opts: DecOptions{}, - in: mustHexDecode("c074323031332d30332d32315432303a30343a30305a"), + data: mustHexDecode("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: mustHexDecode("c11a514b67b0"), + data: mustHexDecode("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: mustHexDecode("c074323031332d30332d32315432303a30343a30305a"), + data: mustHexDecode("c074323031332d30332d32315432303a30343a30305a"), want: "2013-03-21T20:04:00Z", }, { name: "Unmarshal tag 1 data to RFC3339 string when TimeTagToAny is set", opts: DecOptions{TimeTagToAny: TimeTagToRFC3339}, - in: mustHexDecode("c11a514b67b0"), + data: mustHexDecode("c11a514b67b0"), want: "2013-03-21T20:04:00Z", }, { name: "Unmarshal tag 0 data to RFC3339Nano string when TimeTagToAny is set", opts: DecOptions{TimeTagToAny: TimeTagToRFC3339Nano}, - in: mustHexDecode("c076323031332d30332d32315432303a30343a30302e355a"), + data: mustHexDecode("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: mustHexDecode("c1fb41d452d9ec200000"), + data: mustHexDecode("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: mustHexDecode("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 0 contains an invalid RFC3339 timestamp", + opts: DecOptions{TimeTagToAny: TimeTagToRFC3339}, + data: mustHexDecode("c07731303030302D30332D32315432303A30343A30302E355A"), // 0("10000-03-21T20:04:00.5Z") + wantErrorMsg: `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: mustHexDecode("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}, + data: mustHexDecode("c07731303030302D30332D32315432303A30343A30302E355A"), // 0("10000-03-21T20:04:00.5Z") + wantErrorMsg: `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: mustHexDecode("c11b0000003afff44181"), // 1(253402300801) - wantErrMessage: "cbor: decoded time cannot be represented in RFC3339 format: Time.MarshalText: year outside of range [0,9999]", + name: "error under TimeTagToRFC3339 when tag 1 represents a time that can't be represented by valid RFC3339", + opts: DecOptions{TimeTagToAny: TimeTagToRFC3339}, + data: mustHexDecode("c11b0000003afff44181"), // 1(253402300801) + wantErrorMsg: "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: mustHexDecode("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]", + name: "error under TimeTagToRFC3339Nano when tag 1 represents a time that can't be represented by valid RFC3339", + opts: DecOptions{TimeTagToAny: TimeTagToRFC3339Nano}, + data: mustHexDecode("c11b0000003afff44181"), // 1(253402300801) + wantErrorMsg: "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) { @@ -9517,17 +9561,17 @@ func TestDecModeTimeTagToAny(t *testing.T) { } var got any - if err := dm.Unmarshal(tc.in, &got); err != nil { - if tc.wantErrMessage == "" { + if err := dm.Unmarshal(tc.data, &got); err != nil { + if tc.wantErrorMsg == "" { 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 gotErrMessage := err.Error(); tc.wantErrorMsg != gotErrMessage { + t.Fatalf("want error %q, got %q", tc.wantErrorMsg, gotErrMessage) } - } else if tc.wantErrMessage != "" { - t.Fatalf("got nil error, want %q", tc.wantErrMessage) + } else if tc.wantErrorMsg != "" { + t.Fatalf("got nil error, want %q", tc.wantErrorMsg) } - compareNonFloats(t, tc.in, got, tc.want) + compareNonFloats(t, tc.data, got, tc.want) }) } @@ -9743,7 +9787,7 @@ func TestNaNDecMode(t *testing.T) { 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) + t.Errorf("Unmarshal() returned error %v, want %v", got, want) } } else { t.Errorf("unexpected error: %v", got) @@ -10037,7 +10081,7 @@ func TestInfDecMode(t *testing.T) { 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) + t.Errorf("Unmarshal() returned error %v, want %v", got, want) } } else { t.Errorf("unexpected error: %v", got) @@ -10081,38 +10125,38 @@ func TestDecModeByteStringToTime(t *testing.T) { for _, tc := range []struct { name string opts DecOptions - in []byte + data []byte want time.Time wantErrorMsg string }{ { name: "Unmarshal byte string to time.Time when ByteStringToTime is not set", opts: DecOptions{}, - in: mustHexDecode("54323031332D30332D32315432303A30343A30305A"), // '2013-03-21T20:04:00Z' + data: mustHexDecode("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: mustHexDecode("54323031332D30332D32315432303A30343A30305A"), // '2013-03-21T20:04:00Z' + data: mustHexDecode("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: mustHexDecode("56323031332D30332D32315432303A30343A30302E355A"), // '2013-03-21T20:04:00.5Z' + data: mustHexDecode("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: mustHexDecode("4B696E76616C696454657874"), // 'invalidText' + data: mustHexDecode("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: mustHexDecode("54323031338030332D32315432303A30343A30305A"), // "2013\x8003-21T20:04:00Z" -- the first hyphen of a valid RFC3339 string is replaced by a continuation byte + data: mustHexDecode("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 "-"`, }, } { @@ -10123,12 +10167,12 @@ func TestDecModeByteStringToTime(t *testing.T) { } var got time.Time - if err := dm.Unmarshal(tc.in, &got); err != nil { + if err := dm.Unmarshal(tc.data, &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) + compareNonFloats(t, tc.data, got, tc.want) } }) } @@ -10166,10 +10210,10 @@ func TestDecOptionsConflictWithRegisteredTags(t *testing.T) { type empty struct{} for _, tc := range []struct { - name string - opts DecOptions - tags func(TagSet) error - wantErr string + name string + opts DecOptions + tags func(TagSet) error + wantErrorMsg string }{ { name: "base64url encoding tag ignored by default", @@ -10177,7 +10221,7 @@ func TestDecOptionsConflictWithRegisteredTags(t *testing.T) { tags: func(tags TagSet) error { return tags.Add(TagOptions{DecTag: DecTagOptional}, reflect.TypeOf(empty{}), 21) }, - wantErr: "", + wantErrorMsg: "", }, { name: "base64url encoding tag conflicts in ByteStringToStringAllowedWithExpectedLaterEncoding mode", @@ -10185,7 +10229,7 @@ func TestDecOptionsConflictWithRegisteredTags(t *testing.T) { 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", + wantErrorMsg: "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", @@ -10193,7 +10237,7 @@ func TestDecOptionsConflictWithRegisteredTags(t *testing.T) { 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", + wantErrorMsg: "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", @@ -10201,7 +10245,7 @@ func TestDecOptionsConflictWithRegisteredTags(t *testing.T) { tags: func(tags TagSet) error { return tags.Add(TagOptions{DecTag: DecTagOptional}, reflect.TypeOf(empty{}), 22) }, - wantErr: "", + wantErrorMsg: "", }, { name: "base64 encoding tag conflicts in ByteStringToStringAllowedWithExpectedLaterEncoding mode", @@ -10209,7 +10253,7 @@ func TestDecOptionsConflictWithRegisteredTags(t *testing.T) { 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", + wantErrorMsg: "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", @@ -10217,7 +10261,7 @@ func TestDecOptionsConflictWithRegisteredTags(t *testing.T) { 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", + wantErrorMsg: "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", @@ -10225,7 +10269,7 @@ func TestDecOptionsConflictWithRegisteredTags(t *testing.T) { tags: func(tags TagSet) error { return tags.Add(TagOptions{DecTag: DecTagOptional}, reflect.TypeOf(empty{}), 23) }, - wantErr: "", + wantErrorMsg: "", }, { name: "base16 encoding tag conflicts in ByteStringToStringAllowedWithExpectedLaterEncoding mode", @@ -10233,7 +10277,7 @@ func TestDecOptionsConflictWithRegisteredTags(t *testing.T) { 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", + wantErrorMsg: "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", @@ -10241,7 +10285,7 @@ func TestDecOptionsConflictWithRegisteredTags(t *testing.T) { 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", + wantErrorMsg: "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) { @@ -10251,24 +10295,24 @@ func TestDecOptionsConflictWithRegisteredTags(t *testing.T) { } if _, err := tc.opts.DecModeWithTags(tags); err == nil { - if tc.wantErr != "" { - t.Errorf("got nil error from DecModeWithTags, want %q", tc.wantErr) + if tc.wantErrorMsg != "" { + t.Errorf("got nil error from DecModeWithTags, want %q", tc.wantErrorMsg) } - } 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 if got := err.Error(); got != tc.wantErrorMsg { + if tc.wantErrorMsg != "" { + t.Errorf("unexpected error from DecModeWithTags, got %q want %q", got, tc.wantErrorMsg) } 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) + if tc.wantErrorMsg != "" { + t.Errorf("got nil error from DecModeWithSharedTags, want %q", tc.wantErrorMsg) } - } 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 if got := err.Error(); got != tc.wantErrorMsg { + if tc.wantErrorMsg != "" { + t.Errorf("unexpected error from DecModeWithSharedTags, got %q want %q", got, tc.wantErrorMsg) } else { t.Errorf("want nil error from DecModeWithSharedTags, got %q", got) } @@ -10279,53 +10323,53 @@ func TestDecOptionsConflictWithRegisteredTags(t *testing.T) { func TestUnmarshalByteStringTextConversionError(t *testing.T) { for _, tc := range []struct { - name string - opts DecOptions - dstType reflect.Type - in []byte - wantErr string + name string + opts DecOptions + dstType reflect.Type + data []byte + wantErrorMsg 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: ByteStringExpectedBase64URL}, + dstType: reflect.TypeOf([]byte{}), + data: []byte{0x41, 0x00}, + wantErrorMsg: "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 base64url", + opts: DecOptions{ByteStringExpectedFormat: ByteStringExpectedBase64}, + dstType: reflect.TypeOf([]byte{}), + data: []byte{0x41, 0x00}, + wantErrorMsg: "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: "reject untagged byte string containing invalid base16", + opts: DecOptions{ByteStringExpectedFormat: ByteStringExpectedBase16}, + dstType: reflect.TypeOf([]byte{}), + data: []byte{0x41, 0x00}, + wantErrorMsg: "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: ByteStringExpectedBase64URL}, + dstType: reflect.TypeOf([]byte{}), + data: []byte{0xd5, 0x41, 0x00}, + wantErrorMsg: "", }, { - 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 base64url", + opts: DecOptions{ByteStringExpectedFormat: ByteStringExpectedBase64}, + dstType: reflect.TypeOf([]byte{}), + data: []byte{0xd5, 0x41, 0x00}, + wantErrorMsg: "", }, { - name: "accept tagged byte string containing invalid base16", - opts: DecOptions{ByteStringExpectedFormat: ByteStringExpectedBase16}, - 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{}), + data: []byte{0xd5, 0x41, 0x00}, + wantErrorMsg: "", }, } { t.Run(tc.name, func(t *testing.T) { @@ -10334,15 +10378,15 @@ func TestUnmarshalByteStringTextConversionError(t *testing.T) { 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) + if err := dm.Unmarshal(tc.data, reflect.New(tc.dstType).Interface()); err == nil { + if tc.wantErrorMsg != "" { + t.Errorf("got nil error, want %q", tc.wantErrorMsg) } - } else if got := err.Error(); got != tc.wantErr { - if tc.wantErr == "" { + } else if got := err.Error(); got != tc.wantErrorMsg { + if tc.wantErrorMsg == "" { t.Errorf("expected nil error, got %q", got) } else { - t.Errorf("unexpected error, got %q want %q", got, tc.wantErr) + t.Errorf("unexpected error, got %q want %q", got, tc.wantErrorMsg) } } }) @@ -10354,7 +10398,7 @@ func TestUnmarshalByteStringTextConversion(t *testing.T) { name string opts DecOptions dstType reflect.Type - in []byte + data []byte want any }{ { @@ -10363,7 +10407,7 @@ func TestUnmarshalByteStringTextConversion(t *testing.T) { ByteStringToString: ByteStringToStringAllowedWithExpectedLaterEncoding, }, dstType: reflect.TypeOf(""), - in: []byte{0x41, 0xff}, // h'ff' + data: []byte{0x41, 0xff}, // h'ff' want: "\xff", }, { @@ -10372,7 +10416,7 @@ func TestUnmarshalByteStringTextConversion(t *testing.T) { ByteStringToString: ByteStringToStringAllowedWithExpectedLaterEncoding, }, dstType: reflect.TypeOf(""), - in: []byte{0xd5, 0x41, 0xff}, // 21(h'ff') + data: []byte{0xd5, 0x41, 0xff}, // 21(h'ff') want: "_w", }, { @@ -10381,7 +10425,7 @@ func TestUnmarshalByteStringTextConversion(t *testing.T) { ByteStringToString: ByteStringToStringAllowedWithExpectedLaterEncoding, }, dstType: reflect.TypeOf(""), - in: []byte{0xd5, 0xd9, 0xd9, 0xf7, 0x41, 0xff}, // 21(55799(h'ff')) + data: []byte{0xd5, 0xd9, 0xd9, 0xf7, 0x41, 0xff}, // 21(55799(h'ff')) want: "_w", }, { @@ -10390,7 +10434,7 @@ func TestUnmarshalByteStringTextConversion(t *testing.T) { ByteStringToString: ByteStringToStringAllowed, }, dstType: reflect.TypeOf(""), - in: []byte{0xd5, 0x41, 0xff}, // 21(h'ff') + data: []byte{0xd5, 0x41, 0xff}, // 21(h'ff') want: "\xff", }, { @@ -10399,7 +10443,7 @@ func TestUnmarshalByteStringTextConversion(t *testing.T) { ByteStringExpectedFormat: ByteStringExpectedBase64URL, }, dstType: reflect.TypeOf([]byte{}), - in: []byte{0xd5, 0x41, 0xff}, // 21(h'ff') + data: []byte{0xd5, 0x41, 0xff}, // 21(h'ff') want: []byte{0xff}, }, { @@ -10408,7 +10452,7 @@ func TestUnmarshalByteStringTextConversion(t *testing.T) { ByteStringExpectedFormat: ByteStringExpectedBase64URL, }, dstType: reflect.TypeOf([]byte{}), - in: []byte{0xd5, 0xd9, 0xd9, 0xf7, 0x41, 0xff}, // 21(55799(h'ff')) + data: []byte{0xd5, 0xd9, 0xd9, 0xf7, 0x41, 0xff}, // 21(55799(h'ff')) want: []byte{0xff}, }, { @@ -10417,7 +10461,7 @@ func TestUnmarshalByteStringTextConversion(t *testing.T) { ByteStringExpectedFormat: ByteStringExpectedBase64URL, }, dstType: reflect.TypeOf([]byte{}), - in: []byte{0x42, '_', 'w'}, // '_w' + data: []byte{0x42, '_', 'w'}, // '_w' want: []byte{0xff}, }, { @@ -10426,7 +10470,7 @@ func TestUnmarshalByteStringTextConversion(t *testing.T) { ByteStringToString: ByteStringToStringAllowedWithExpectedLaterEncoding, }, dstType: reflect.TypeOf(""), - in: []byte{0xd6, 0x41, 0xff}, // 22(h'ff') + data: []byte{0xd6, 0x41, 0xff}, // 22(h'ff') want: "/w==", }, { @@ -10435,7 +10479,7 @@ func TestUnmarshalByteStringTextConversion(t *testing.T) { ByteStringToString: ByteStringToStringAllowedWithExpectedLaterEncoding, }, dstType: reflect.TypeOf(""), - in: []byte{0xd6, 0xd9, 0xd9, 0xf7, 0x41, 0xff}, // 22(55799(h'ff')) + data: []byte{0xd6, 0xd9, 0xd9, 0xf7, 0x41, 0xff}, // 22(55799(h'ff')) want: "/w==", }, { @@ -10444,7 +10488,7 @@ func TestUnmarshalByteStringTextConversion(t *testing.T) { ByteStringToString: ByteStringToStringAllowed, }, dstType: reflect.TypeOf(""), - in: []byte{0xd6, 0x41, 0xff}, // 22(h'ff') + data: []byte{0xd6, 0x41, 0xff}, // 22(h'ff') want: "\xff", }, { @@ -10453,7 +10497,7 @@ func TestUnmarshalByteStringTextConversion(t *testing.T) { ByteStringExpectedFormat: ByteStringExpectedBase64, }, dstType: reflect.TypeOf([]byte{}), - in: []byte{0xd6, 0x41, 0xff}, // 22(h'ff') + data: []byte{0xd6, 0x41, 0xff}, // 22(h'ff') want: []byte{0xff}, }, { @@ -10462,7 +10506,7 @@ func TestUnmarshalByteStringTextConversion(t *testing.T) { ByteStringExpectedFormat: ByteStringExpectedBase64, }, dstType: reflect.TypeOf([]byte{}), - in: []byte{0xd6, 0xd9, 0xd9, 0xf7, 0x41, 0xff}, // 22(55799(h'ff')) + data: []byte{0xd6, 0xd9, 0xd9, 0xf7, 0x41, 0xff}, // 22(55799(h'ff')) want: []byte{0xff}, }, { @@ -10471,7 +10515,7 @@ func TestUnmarshalByteStringTextConversion(t *testing.T) { ByteStringExpectedFormat: ByteStringExpectedBase64, }, dstType: reflect.TypeOf([]byte{}), - in: []byte{0x44, '/', 'w', '=', '='}, // '/w==' + data: []byte{0x44, '/', 'w', '=', '='}, // '/w==' want: []byte{0xff}, }, { @@ -10480,7 +10524,7 @@ func TestUnmarshalByteStringTextConversion(t *testing.T) { ByteStringToString: ByteStringToStringAllowedWithExpectedLaterEncoding, }, dstType: reflect.TypeOf(""), - in: []byte{0xd7, 0x41, 0xff}, // 23(h'ff') + data: []byte{0xd7, 0x41, 0xff}, // 23(h'ff') want: "ff", }, { @@ -10489,7 +10533,7 @@ func TestUnmarshalByteStringTextConversion(t *testing.T) { ByteStringToString: ByteStringToStringAllowedWithExpectedLaterEncoding, }, dstType: reflect.TypeOf(""), - in: []byte{0xd7, 0xd9, 0xd9, 0xf7, 0x41, 0xff}, // 23(55799(h'ff')) + data: []byte{0xd7, 0xd9, 0xd9, 0xf7, 0x41, 0xff}, // 23(55799(h'ff')) want: "ff", }, { @@ -10498,7 +10542,7 @@ func TestUnmarshalByteStringTextConversion(t *testing.T) { ByteStringToString: ByteStringToStringAllowed, }, dstType: reflect.TypeOf(""), - in: []byte{0xd7, 0x41, 0xff}, // 23(h'ff') + data: []byte{0xd7, 0x41, 0xff}, // 23(h'ff') want: "\xff", }, { @@ -10507,7 +10551,7 @@ func TestUnmarshalByteStringTextConversion(t *testing.T) { ByteStringExpectedFormat: ByteStringExpectedBase16, }, dstType: reflect.TypeOf([]byte{}), - in: []byte{0xd7, 0x41, 0xff}, // 23(h'ff') + data: []byte{0xd7, 0x41, 0xff}, // 23(h'ff') want: []byte{0xff}, }, { @@ -10516,7 +10560,7 @@ func TestUnmarshalByteStringTextConversion(t *testing.T) { ByteStringExpectedFormat: ByteStringExpectedBase16, }, dstType: reflect.TypeOf([]byte{}), - in: []byte{0xd7, 0xd9, 0xd9, 0xf7, 0x41, 0xff}, // 23(55799(h'ff')) + data: []byte{0xd7, 0xd9, 0xd9, 0xf7, 0x41, 0xff}, // 23(55799(h'ff')) want: []byte{0xff}, }, { @@ -10525,9 +10569,27 @@ func TestUnmarshalByteStringTextConversion(t *testing.T) { ByteStringExpectedFormat: ByteStringExpectedBase16, }, dstType: reflect.TypeOf([]byte{}), - in: []byte{0x42, 'f', 'f'}, + data: []byte{0x42, 'f', 'f'}, want: []byte{0xff}, }, + { + name: "tag 21 wrapping tag 22", + opts: DecOptions{ + ByteStringToString: ByteStringToStringAllowedWithExpectedLaterEncoding, + }, + dstType: reflect.TypeOf(""), + data: []byte{0xd5, 0xd6, 0x42, 0x01, 0x02}, // 21(22(h'0102')) + want: "AQI=", // base64 of [0x01, 0x02] with padding + }, + { + name: "tag 22 wrapping tag 21", + opts: DecOptions{ + ByteStringToString: ByteStringToStringAllowedWithExpectedLaterEncoding, + }, + dstType: reflect.TypeOf(""), + data: []byte{0xd6, 0xd5, 0x42, 0x01, 0x02}, // 22(21(h'0102')) + want: "AQI", // base64 of [0x01, 0x02] without padding + }, } { t.Run(tc.name, func(t *testing.T) { dm, err := tc.opts.DecMode() @@ -10536,7 +10598,7 @@ func TestUnmarshalByteStringTextConversion(t *testing.T) { } dstVal := reflect.New(tc.dstType) - if err := dm.Unmarshal(tc.in, dstVal.Interface()); err != nil { + if err := dm.Unmarshal(tc.data, dstVal.Interface()); err != nil { t.Fatal(err) } @@ -10586,25 +10648,25 @@ func TestBinaryUnmarshalerMode(t *testing.T) { for _, tc := range []struct { name string opts DecOptions - in []byte + data []byte want any }{ { name: "UnmarshalBinary is called by default", opts: DecOptions{}, - in: []byte("\x45hello"), // 'hello' + data: []byte("\x45hello"), // 'hello' want: testBinaryUnmarshaler("UnmarshalBinary"), }, { name: "UnmarshalBinary is called with BinaryUnmarshalerByteString", opts: DecOptions{BinaryUnmarshaler: BinaryUnmarshalerByteString}, - in: []byte("\x45hello"), // 'hello' + data: []byte("\x45hello"), // 'hello' want: testBinaryUnmarshaler("UnmarshalBinary"), }, { name: "default byte slice unmarshaling behavior is used with BinaryUnmarshalerNone", opts: DecOptions{BinaryUnmarshaler: BinaryUnmarshalerNone}, - in: []byte("\x45hello"), // 'hello' + data: []byte("\x45hello"), // 'hello' want: testBinaryUnmarshaler("hello"), }, } { @@ -10615,7 +10677,7 @@ func TestBinaryUnmarshalerMode(t *testing.T) { } gotrv := reflect.New(reflect.TypeOf(tc.want)) - if err := dm.Unmarshal(tc.in, gotrv.Interface()); err != nil { + if err := dm.Unmarshal(tc.data, gotrv.Interface()); err != nil { t.Fatal(err) } @@ -10657,10 +10719,10 @@ func TestDecModeInvalidBignumTag(t *testing.T) { func TestBignumTagMode(t *testing.T) { for _, tc := range []struct { - name string - opt DecOptions - input []byte - wantErrMessage string // if "" then expect nil error + name string + opt DecOptions + input []byte + wantErrorMsg string // if "" then expect nil error }{ { name: "default options decode unsigned bignum without error", @@ -10673,16 +10735,16 @@ func TestBignumTagMode(t *testing.T) { input: mustHexDecode("c340"), // 3(0) i.e. negative bignum -1 }, { - name: "BignumTagForbidden returns UnacceptableDataItemError on unsigned bignum", - opt: DecOptions{BignumTag: BignumTagForbidden}, - input: mustHexDecode("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 unsigned bignum", + opt: DecOptions{BignumTag: BignumTagForbidden}, + input: mustHexDecode("c240"), // 2(0) i.e. unsigned bignum 0 + wantErrorMsg: "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: mustHexDecode("c340"), // 3(0) i.e. negative bignum -1 - 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: mustHexDecode("c340"), // 3(0) i.e. negative bignum -1 + wantErrorMsg: "cbor: data item of cbor type tag is not accepted by protocol: bignum", }, } { t.Run(tc.name, func(t *testing.T) { @@ -10703,14 +10765,14 @@ func TestBignumTagMode(t *testing.T) { dstv := reflect.New(dstType) err = dm.Unmarshal(tc.input, dstv.Interface()) if err != nil { - if tc.wantErrMessage == "" { + if tc.wantErrorMsg == "" { 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 gotErrMessage := err.Error(); gotErrMessage != tc.wantErrorMsg { + t.Errorf("Unmarshal() returned error %q, want %q", gotErrMessage, tc.wantErrorMsg) } } else { - if tc.wantErrMessage != "" { - t.Errorf("got nil error, want: %s", tc.wantErrMessage) + if tc.wantErrorMsg != "" { + t.Errorf("got nil error, want: %s", tc.wantErrorMsg) } } }) @@ -10758,25 +10820,25 @@ func TestTextUnmarshalerMode(t *testing.T) { for _, tc := range []struct { name string opts DecOptions - in []byte + data []byte want any }{ { name: "UnmarshalText is not called by default", opts: DecOptions{}, - in: []byte("\x65hello"), // "hello" + data: []byte("\x65hello"), // "hello" want: testTextUnmarshaler("hello"), }, { name: "UnmarshalText is called with TextUnmarshalerTextString", opts: DecOptions{TextUnmarshaler: TextUnmarshalerTextString}, - in: []byte("\x65hello"), // "hello" + data: []byte("\x65hello"), // "hello" want: testTextUnmarshaler("UnmarshalText"), }, { name: "default text string unmarshaling behavior is used with TextUnmarshalerNone", opts: DecOptions{TextUnmarshaler: TextUnmarshalerNone}, - in: []byte("\x65hello"), // "hello" + data: []byte("\x65hello"), // "hello" want: testTextUnmarshaler("hello"), }, { @@ -10785,7 +10847,7 @@ func TestTextUnmarshalerMode(t *testing.T) { TextUnmarshaler: TextUnmarshalerTextString, ByteStringToString: ByteStringToStringAllowed, }, - in: []byte("\x45hello"), // 'hello' + data: []byte("\x45hello"), // 'hello' want: testTextUnmarshaler("UnmarshalText"), }, } { @@ -10796,7 +10858,7 @@ func TestTextUnmarshalerMode(t *testing.T) { } gotrv := reflect.New(reflect.TypeOf(tc.want)) - if err := dm.Unmarshal(tc.in, gotrv.Interface()); err != nil { + if err := dm.Unmarshal(tc.data, gotrv.Interface()); err != nil { t.Fatal(err) } @@ -10833,7 +10895,7 @@ func TestTextUnmarshalerModeError(t *testing.T) { func TestJSONUnmarshalerTranscoder(t *testing.T) { for _, tc := range []struct { name string - in []byte + data []byte transcodeInput []byte transcodeOutput []byte @@ -10844,7 +10906,7 @@ func TestJSONUnmarshalerTranscoder(t *testing.T) { }{ { name: "successful transcode", - in: []byte{0xf5}, + data: []byte{0xf5}, transcodeInput: []byte{0xf5}, transcodeOutput: []byte("true"), @@ -10853,7 +10915,7 @@ func TestJSONUnmarshalerTranscoder(t *testing.T) { }, { name: "transcode returns non-nil error", - in: []byte{0xf5}, + data: []byte{0xf5}, transcodeInput: []byte{0xf5}, transcodeError: errors.New("test"), @@ -10892,21 +10954,39 @@ func TestJSONUnmarshalerTranscoder(t *testing.T) { } gotrv := reflect.New(reflect.TypeOf(tc.want)) - err = dec.Unmarshal(tc.in, gotrv.Interface()) + err = dec.Unmarshal(tc.data, gotrv.Interface()) if tc.wantErrorMsg != "" { if err == nil { - t.Errorf("Unmarshal(0x%x) didn't return an error, want error %q", tc.in, tc.wantErrorMsg) + t.Errorf("Unmarshal(0x%x) didn't return an error, want error %q", tc.data, tc.wantErrorMsg) } else if gotErrorMsg := err.Error(); gotErrorMsg != tc.wantErrorMsg { - t.Errorf("Unmarshal(0x%x) returned error %q, want %q", tc.in, gotErrorMsg, tc.wantErrorMsg) + t.Errorf("Unmarshal(0x%x) returned error %q, want %q", tc.data, gotErrorMsg, tc.wantErrorMsg) } } else { if err != nil { - t.Errorf("Unmarshal(0x%x) returned non-nil error %v", tc.in, err) + t.Errorf("Unmarshal(0x%x) returned non-nil error %v", tc.data, err) } else if got := gotrv.Elem().Interface(); !reflect.DeepEqual(tc.want, got) { - t.Errorf("Unmarshal(0x%x): %v, want %v", tc.in, got, tc.want) + t.Errorf("Unmarshal(0x%x): %v, want %v", tc.data, got, tc.want) } } }) } } + +func TestByteStringExpectedFormatErrorUnwrap(t *testing.T) { + innerErr := errors.New("test error") + err := newByteStringExpectedFormatError(ByteStringExpectedBase64URL, innerErr) + if unwrapped := err.Unwrap(); unwrapped != innerErr { + t.Errorf("Unwrap() = %v, want %v", unwrapped, innerErr) + } +} + +func TestByteStringExpectedFormatErrorDefaultCase(t *testing.T) { + innerErr := errors.New("test error") + err := &ByteStringExpectedFormatError{expectedFormatOption: 99, err: innerErr} + got := err.Error() + want := "cbor: failed to decode byte string in expected format 99: test error" + if got != want { + t.Errorf("Error() = %q, want %q", got, want) + } +} diff --git a/diagnose.go b/diagnose.go index 44afb866..caa9aa9c 100644 --- a/diagnose.go +++ b/diagnose.go @@ -51,11 +51,8 @@ const ( maxByteStringEncoding ) -func (bse ByteStringEncoding) valid() error { - if bse >= maxByteStringEncoding { - return errors.New("cbor: invalid ByteStringEncoding " + strconv.Itoa(int(bse))) - } - return nil +func (bse ByteStringEncoding) valid() bool { + return bse < maxByteStringEncoding } // DiagOptions specifies Diag options. @@ -104,8 +101,8 @@ func (opts DiagOptions) DiagMode() (DiagMode, error) { } func (opts DiagOptions) diagMode() (*diagMode, error) { - if err := opts.ByteStringEncoding.valid(); err != nil { - return nil, err + if !opts.ByteStringEncoding.valid() { + return nil, errors.New("cbor: invalid ByteStringEncoding " + strconv.Itoa(int(opts.ByteStringEncoding))) } decMode, err := DecOptions{ diff --git a/diagnose_test.go b/diagnose_test.go index e723ff98..2ea776c1 100644 --- a/diagnose_test.go +++ b/diagnose_test.go @@ -15,355 +15,355 @@ import ( func TestDiagnosticNotationExamples(t *testing.T) { // https://www.rfc-editor.org/rfc/rfc8949.html#name-examples-of-encoded-cbor-da testCases := []struct { - cbor []byte - diag string + data []byte + wantDiag string }{ { - cbor: mustHexDecode("00"), - diag: `0`, + data: mustHexDecode("00"), + wantDiag: `0`, }, { - cbor: mustHexDecode("01"), - diag: `1`, + data: mustHexDecode("01"), + wantDiag: `1`, }, { - cbor: mustHexDecode("0a"), - diag: `10`, + data: mustHexDecode("0a"), + wantDiag: `10`, }, { - cbor: mustHexDecode("17"), - diag: `23`, + data: mustHexDecode("17"), + wantDiag: `23`, }, { - cbor: mustHexDecode("1818"), - diag: `24`, + data: mustHexDecode("1818"), + wantDiag: `24`, }, { - cbor: mustHexDecode("1819"), - diag: `25`, + data: mustHexDecode("1819"), + wantDiag: `25`, }, { - cbor: mustHexDecode("1864"), - diag: `100`, + data: mustHexDecode("1864"), + wantDiag: `100`, }, { - cbor: mustHexDecode("1903e8"), - diag: `1000`, + data: mustHexDecode("1903e8"), + wantDiag: `1000`, }, { - cbor: mustHexDecode("1a000f4240"), - diag: `1000000`, + data: mustHexDecode("1a000f4240"), + wantDiag: `1000000`, }, { - cbor: mustHexDecode("1b000000e8d4a51000"), - diag: `1000000000000`, + data: mustHexDecode("1b000000e8d4a51000"), + wantDiag: `1000000000000`, }, { - cbor: mustHexDecode("1bffffffffffffffff"), - diag: `18446744073709551615`, + data: mustHexDecode("1bffffffffffffffff"), + wantDiag: `18446744073709551615`, }, { - cbor: mustHexDecode("c249010000000000000000"), - diag: `18446744073709551616`, + data: mustHexDecode("c249010000000000000000"), + wantDiag: `18446744073709551616`, }, { - cbor: mustHexDecode("3bffffffffffffffff"), - diag: `-18446744073709551616`, + data: mustHexDecode("3bffffffffffffffff"), + wantDiag: `-18446744073709551616`, }, { - cbor: mustHexDecode("c349010000000000000000"), - diag: `-18446744073709551617`, + data: mustHexDecode("c349010000000000000000"), + wantDiag: `-18446744073709551617`, }, { - cbor: mustHexDecode("20"), - diag: `-1`, + data: mustHexDecode("20"), + wantDiag: `-1`, }, { - cbor: mustHexDecode("29"), - diag: `-10`, + data: mustHexDecode("29"), + wantDiag: `-10`, }, { - cbor: mustHexDecode("3863"), - diag: `-100`, + data: mustHexDecode("3863"), + wantDiag: `-100`, }, { - cbor: mustHexDecode("3903e7"), - diag: `-1000`, + data: mustHexDecode("3903e7"), + wantDiag: `-1000`, }, { - cbor: mustHexDecode("f90000"), - diag: `0.0`, + data: mustHexDecode("f90000"), + wantDiag: `0.0`, }, { - cbor: mustHexDecode("f98000"), - diag: `-0.0`, + data: mustHexDecode("f98000"), + wantDiag: `-0.0`, }, { - cbor: mustHexDecode("f93c00"), - diag: `1.0`, + data: mustHexDecode("f93c00"), + wantDiag: `1.0`, }, { - cbor: mustHexDecode("fb3ff199999999999a"), - diag: `1.1`, + data: mustHexDecode("fb3ff199999999999a"), + wantDiag: `1.1`, }, { - cbor: mustHexDecode("f93e00"), - diag: `1.5`, + data: mustHexDecode("f93e00"), + wantDiag: `1.5`, }, { - cbor: mustHexDecode("f97bff"), - diag: `65504.0`, + data: mustHexDecode("f97bff"), + wantDiag: `65504.0`, }, { - cbor: mustHexDecode("fa47c35000"), - diag: `100000.0`, + data: mustHexDecode("fa47c35000"), + wantDiag: `100000.0`, }, { - cbor: mustHexDecode("fa7f7fffff"), - diag: `3.4028234663852886e+38`, + data: mustHexDecode("fa7f7fffff"), + wantDiag: `3.4028234663852886e+38`, }, { - cbor: mustHexDecode("fb7e37e43c8800759c"), - diag: `1.0e+300`, + data: mustHexDecode("fb7e37e43c8800759c"), + wantDiag: `1.0e+300`, }, { - cbor: mustHexDecode("f90001"), - diag: `5.960464477539063e-8`, + data: mustHexDecode("f90001"), + wantDiag: `5.960464477539063e-8`, }, { - cbor: mustHexDecode("f90400"), - diag: `0.00006103515625`, + data: mustHexDecode("f90400"), + wantDiag: `0.00006103515625`, }, { - cbor: mustHexDecode("f9c400"), - diag: `-4.0`, + data: mustHexDecode("f9c400"), + wantDiag: `-4.0`, }, { - cbor: mustHexDecode("fbc010666666666666"), - diag: `-4.1`, + data: mustHexDecode("fbc010666666666666"), + wantDiag: `-4.1`, }, { - cbor: mustHexDecode("f97c00"), - diag: `Infinity`, + data: mustHexDecode("f97c00"), + wantDiag: `Infinity`, }, { - cbor: mustHexDecode("f97e00"), - diag: `NaN`, + data: mustHexDecode("f97e00"), + wantDiag: `NaN`, }, { - cbor: mustHexDecode("f9fc00"), - diag: `-Infinity`, + data: mustHexDecode("f9fc00"), + wantDiag: `-Infinity`, }, { - cbor: mustHexDecode("fa7f800000"), - diag: `Infinity`, + data: mustHexDecode("fa7f800000"), + wantDiag: `Infinity`, }, { - cbor: mustHexDecode("fa7fc00000"), - diag: `NaN`, + data: mustHexDecode("fa7fc00000"), + wantDiag: `NaN`, }, { - cbor: mustHexDecode("faff800000"), - diag: `-Infinity`, + data: mustHexDecode("faff800000"), + wantDiag: `-Infinity`, }, { - cbor: mustHexDecode("fb7ff0000000000000"), - diag: `Infinity`, + data: mustHexDecode("fb7ff0000000000000"), + wantDiag: `Infinity`, }, { - cbor: mustHexDecode("fb7ff8000000000000"), - diag: `NaN`, + data: mustHexDecode("fb7ff8000000000000"), + wantDiag: `NaN`, }, { - cbor: mustHexDecode("fbfff0000000000000"), - diag: `-Infinity`, + data: mustHexDecode("fbfff0000000000000"), + wantDiag: `-Infinity`, }, { - cbor: mustHexDecode("f4"), - diag: `false`, + data: mustHexDecode("f4"), + wantDiag: `false`, }, { - cbor: mustHexDecode("f5"), - diag: `true`, + data: mustHexDecode("f5"), + wantDiag: `true`, }, { - cbor: mustHexDecode("f6"), - diag: `null`, + data: mustHexDecode("f6"), + wantDiag: `null`, }, { - cbor: mustHexDecode("f7"), - diag: `undefined`, + data: mustHexDecode("f7"), + wantDiag: `undefined`, }, { - cbor: mustHexDecode("f0"), - diag: `simple(16)`, + data: mustHexDecode("f0"), + wantDiag: `simple(16)`, }, { - cbor: mustHexDecode("f8ff"), - diag: `simple(255)`, + data: mustHexDecode("f8ff"), + wantDiag: `simple(255)`, }, { - cbor: mustHexDecode("c074323031332d30332d32315432303a30343a30305a"), - diag: `0("2013-03-21T20:04:00Z")`, + data: mustHexDecode("c074323031332d30332d32315432303a30343a30305a"), + wantDiag: `0("2013-03-21T20:04:00Z")`, }, { - cbor: mustHexDecode("c11a514b67b0"), - diag: `1(1363896240)`, + data: mustHexDecode("c11a514b67b0"), + wantDiag: `1(1363896240)`, }, { - cbor: mustHexDecode("c1fb41d452d9ec200000"), - diag: `1(1363896240.5)`, + data: mustHexDecode("c1fb41d452d9ec200000"), + wantDiag: `1(1363896240.5)`, }, { - cbor: mustHexDecode("d74401020304"), - diag: `23(h'01020304')`, + data: mustHexDecode("d74401020304"), + wantDiag: `23(h'01020304')`, }, { - cbor: mustHexDecode("d818456449455446"), - diag: `24(h'6449455446')`, + data: mustHexDecode("d818456449455446"), + wantDiag: `24(h'6449455446')`, }, { - cbor: mustHexDecode("d82076687474703a2f2f7777772e6578616d706c652e636f6d"), - diag: `32("http://www.example.com")`, + data: mustHexDecode("d82076687474703a2f2f7777772e6578616d706c652e636f6d"), + wantDiag: `32("http://www.example.com")`, }, { - cbor: mustHexDecode("40"), - diag: `h''`, + data: mustHexDecode("40"), + wantDiag: `h''`, }, { - cbor: mustHexDecode("4401020304"), - diag: `h'01020304'`, + data: mustHexDecode("4401020304"), + wantDiag: `h'01020304'`, }, { - cbor: mustHexDecode("60"), - diag: `""`, + data: mustHexDecode("60"), + wantDiag: `""`, }, { - cbor: mustHexDecode("6161"), - diag: `"a"`, + data: mustHexDecode("6161"), + wantDiag: `"a"`, }, { - cbor: mustHexDecode("6449455446"), - diag: `"IETF"`, + data: mustHexDecode("6449455446"), + wantDiag: `"IETF"`, }, { - cbor: mustHexDecode("62225c"), - diag: `"\"\\"`, + data: mustHexDecode("62225c"), + wantDiag: `"\"\\"`, }, { - cbor: mustHexDecode("62c3bc"), - diag: `"\u00fc"`, + data: mustHexDecode("62c3bc"), + wantDiag: `"\u00fc"`, }, { - cbor: mustHexDecode("63e6b0b4"), - diag: `"\u6c34"`, + data: mustHexDecode("63e6b0b4"), + wantDiag: `"\u6c34"`, }, { - cbor: mustHexDecode("64f0908591"), - diag: `"\ud800\udd51"`, + data: mustHexDecode("64f0908591"), + wantDiag: `"\ud800\udd51"`, }, { - cbor: mustHexDecode("80"), - diag: `[]`, + data: mustHexDecode("80"), + wantDiag: `[]`, }, { - cbor: mustHexDecode("83010203"), - diag: `[1, 2, 3]`, + data: mustHexDecode("83010203"), + wantDiag: `[1, 2, 3]`, }, { - cbor: mustHexDecode("8301820203820405"), - diag: `[1, [2, 3], [4, 5]]`, + data: mustHexDecode("8301820203820405"), + wantDiag: `[1, [2, 3], [4, 5]]`, }, { - cbor: mustHexDecode("98190102030405060708090a0b0c0d0e0f101112131415161718181819"), - diag: `[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]`, + data: mustHexDecode("98190102030405060708090a0b0c0d0e0f101112131415161718181819"), + wantDiag: `[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]`, }, { - cbor: mustHexDecode("a0"), - diag: `{}`, + data: mustHexDecode("a0"), + wantDiag: `{}`, }, { - cbor: mustHexDecode("a201020304"), - diag: `{1: 2, 3: 4}`, + data: mustHexDecode("a201020304"), + wantDiag: `{1: 2, 3: 4}`, }, { - cbor: mustHexDecode("a26161016162820203"), - diag: `{"a": 1, "b": [2, 3]}`, + data: mustHexDecode("a26161016162820203"), + wantDiag: `{"a": 1, "b": [2, 3]}`, }, { - cbor: mustHexDecode("826161a161626163"), - diag: `["a", {"b": "c"}]`, + data: mustHexDecode("826161a161626163"), + wantDiag: `["a", {"b": "c"}]`, }, { - cbor: mustHexDecode("a56161614161626142616361436164614461656145"), - diag: `{"a": "A", "b": "B", "c": "C", "d": "D", "e": "E"}`, + data: mustHexDecode("a56161614161626142616361436164614461656145"), + wantDiag: `{"a": "A", "b": "B", "c": "C", "d": "D", "e": "E"}`, }, { - cbor: mustHexDecode("5f42010243030405ff"), - diag: `(_ h'0102', h'030405')`, + data: mustHexDecode("5f42010243030405ff"), + wantDiag: `(_ h'0102', h'030405')`, }, { - cbor: mustHexDecode("7f657374726561646d696e67ff"), - diag: `(_ "strea", "ming")`, + data: mustHexDecode("7f657374726561646d696e67ff"), + wantDiag: `(_ "strea", "ming")`, }, { - cbor: mustHexDecode("9fff"), - diag: `[_ ]`, + data: mustHexDecode("9fff"), + wantDiag: `[_ ]`, }, { - cbor: mustHexDecode("9f018202039f0405ffff"), - diag: `[_ 1, [2, 3], [_ 4, 5]]`, + data: mustHexDecode("9f018202039f0405ffff"), + wantDiag: `[_ 1, [2, 3], [_ 4, 5]]`, }, { - cbor: mustHexDecode("9f01820203820405ff"), - diag: `[_ 1, [2, 3], [4, 5]]`, + data: mustHexDecode("9f01820203820405ff"), + wantDiag: `[_ 1, [2, 3], [4, 5]]`, }, { - cbor: mustHexDecode("83018202039f0405ff"), - diag: `[1, [2, 3], [_ 4, 5]]`, + data: mustHexDecode("83018202039f0405ff"), + wantDiag: `[1, [2, 3], [_ 4, 5]]`, }, { - cbor: mustHexDecode("83019f0203ff820405"), - diag: `[1, [_ 2, 3], [4, 5]]`, + data: mustHexDecode("83019f0203ff820405"), + wantDiag: `[1, [_ 2, 3], [4, 5]]`, }, { - cbor: mustHexDecode("9f0102030405060708090a0b0c0d0e0f101112131415161718181819ff"), - diag: `[_ 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]`, + data: mustHexDecode("9f0102030405060708090a0b0c0d0e0f101112131415161718181819ff"), + wantDiag: `[_ 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]`, }, { - cbor: mustHexDecode("bf61610161629f0203ffff"), - diag: `{_ "a": 1, "b": [_ 2, 3]}`, + data: mustHexDecode("bf61610161629f0203ffff"), + wantDiag: `{_ "a": 1, "b": [_ 2, 3]}`, }, { - cbor: mustHexDecode("826161bf61626163ff"), - diag: `["a", {_ "b": "c"}]`, + data: mustHexDecode("826161bf61626163ff"), + wantDiag: `["a", {_ "b": "c"}]`, }, { - cbor: mustHexDecode("bf6346756ef563416d7421ff"), - diag: `{_ "Fun": true, "Amt": -2}`, + data: mustHexDecode("bf6346756ef563416d7421ff"), + wantDiag: `{_ "Fun": true, "Amt": -2}`, }, } for i, tc := range testCases { t.Run(fmt.Sprintf("Diagnostic %d", i), func(t *testing.T) { - str, err := Diagnose(tc.cbor) + str, err := Diagnose(tc.data) if err != nil { - t.Errorf("Diagnostic(0x%x) returned error %q", tc.cbor, err) - } else if str != tc.diag { - t.Errorf("Diagnostic(0x%x) returned `%s`, want `%s`", tc.cbor, str, tc.diag) + t.Errorf("Diagnostic(0x%x) returned error %q", tc.data, err) + } else if str != tc.wantDiag { + t.Errorf("Diagnostic(0x%x) returned `%s`, want `%s`", tc.data, str, tc.wantDiag) } - str, rest, err := DiagnoseFirst(tc.cbor) + str, rest, err := DiagnoseFirst(tc.data) if err != nil { - t.Errorf("Diagnostic(0x%x) returned error %q", tc.cbor, err) - } else if str != tc.diag { - t.Errorf("Diagnostic(0x%x) returned `%s`, want `%s`", tc.cbor, str, tc.diag) + t.Errorf("Diagnostic(0x%x) returned error %q", tc.data, err) + } else if str != tc.wantDiag { + t.Errorf("Diagnostic(0x%x) returned `%s`, want `%s`", tc.data, str, tc.wantDiag) } if rest == nil { - t.Errorf("Diagnostic(0x%x) returned nil rest", tc.cbor) + t.Errorf("Diagnostic(0x%x) returned nil rest", tc.data) } else if len(rest) != 0 { - t.Errorf("Diagnostic(0x%x) returned non-empty rest '%x'", tc.cbor, rest) + t.Errorf("Diagnostic(0x%x) returned non-empty rest '%x'", tc.data, rest) } }) } @@ -371,164 +371,164 @@ func TestDiagnosticNotationExamples(t *testing.T) { func TestDiagnoseByteString(t *testing.T) { testCases := []struct { - title string - cbor []byte - diag string - opts *DiagOptions + name string + data []byte + wantDiag string + opts *DiagOptions }{ { - title: "base16", - cbor: mustHexDecode("4412345678"), - diag: `h'12345678'`, + name: "base16", + data: mustHexDecode("4412345678"), + wantDiag: `h'12345678'`, opts: &DiagOptions{ ByteStringEncoding: ByteStringBase16Encoding, }, }, { - title: "base32", - cbor: mustHexDecode("4412345678"), - diag: `b32'CI2FM6A'`, + name: "base32", + data: mustHexDecode("4412345678"), + wantDiag: `b32'CI2FM6A'`, opts: &DiagOptions{ ByteStringEncoding: ByteStringBase32Encoding, }, }, { - title: "base32hex", - cbor: mustHexDecode("4412345678"), - diag: `h32'28Q5CU0'`, + name: "base32hex", + data: mustHexDecode("4412345678"), + wantDiag: `h32'28Q5CU0'`, opts: &DiagOptions{ ByteStringEncoding: ByteStringBase32HexEncoding, }, }, { - title: "base64", - cbor: mustHexDecode("4412345678"), - diag: `b64'EjRWeA'`, + name: "base64", + data: mustHexDecode("4412345678"), + wantDiag: `b64'EjRWeA'`, opts: &DiagOptions{ ByteStringEncoding: ByteStringBase64Encoding, }, }, { - title: "without ByteStringHexWhitespace option", - cbor: mustHexDecode("4b48656c6c6f20776f726c64"), - diag: `h'48656c6c6f20776f726c64'`, + name: "without ByteStringHexWhitespace option", + data: mustHexDecode("4b48656c6c6f20776f726c64"), + wantDiag: `h'48656c6c6f20776f726c64'`, opts: &DiagOptions{ ByteStringHexWhitespace: false, }, }, { - title: "with ByteStringHexWhitespace option", - cbor: mustHexDecode("4b48656c6c6f20776f726c64"), - diag: `h'48 65 6c 6c 6f 20 77 6f 72 6c 64'`, + name: "with ByteStringHexWhitespace option", + data: mustHexDecode("4b48656c6c6f20776f726c64"), + wantDiag: `h'48 65 6c 6c 6f 20 77 6f 72 6c 64'`, opts: &DiagOptions{ ByteStringHexWhitespace: true, }, }, { - title: "without ByteStringText option", - cbor: mustHexDecode("4b68656c6c6f20776f726c64"), - diag: `h'68656c6c6f20776f726c64'`, + name: "without ByteStringText option", + data: mustHexDecode("4b68656c6c6f20776f726c64"), + wantDiag: `h'68656c6c6f20776f726c64'`, opts: &DiagOptions{ ByteStringText: false, }, }, { - title: "with ByteStringText option", - cbor: mustHexDecode("4b68656c6c6f20776f726c64"), - diag: `'hello world'`, + name: "with ByteStringText option", + data: mustHexDecode("4b68656c6c6f20776f726c64"), + wantDiag: `'hello world'`, opts: &DiagOptions{ ByteStringText: true, }, }, { - title: "without ByteStringText option and with ByteStringHexWhitespace option", - cbor: mustHexDecode("4b68656c6c6f20776f726c64"), - diag: `h'68 65 6c 6c 6f 20 77 6f 72 6c 64'`, + name: "without ByteStringText option and with ByteStringHexWhitespace option", + data: mustHexDecode("4b68656c6c6f20776f726c64"), + wantDiag: `h'68 65 6c 6c 6f 20 77 6f 72 6c 64'`, opts: &DiagOptions{ ByteStringText: false, ByteStringHexWhitespace: true, }, }, { - title: "without ByteStringEmbeddedCBOR", - cbor: mustHexDecode("4101"), - diag: `h'01'`, + name: "without ByteStringEmbeddedCBOR", + data: mustHexDecode("4101"), + wantDiag: `h'01'`, opts: &DiagOptions{ ByteStringEmbeddedCBOR: false, }, }, { - title: "with ByteStringEmbeddedCBOR", - cbor: mustHexDecode("4101"), - diag: `<<1>>`, + name: "with ByteStringEmbeddedCBOR", + data: mustHexDecode("4101"), + wantDiag: `<<1>>`, opts: &DiagOptions{ ByteStringEmbeddedCBOR: true, }, }, { - title: "multi CBOR items without ByteStringEmbeddedCBOR", - cbor: mustHexDecode("420102"), - diag: `h'0102'`, + name: "multi CBOR items without ByteStringEmbeddedCBOR", + data: mustHexDecode("420102"), + wantDiag: `h'0102'`, opts: &DiagOptions{ ByteStringEmbeddedCBOR: false, }, }, { - title: "multi CBOR items with ByteStringEmbeddedCBOR", - cbor: mustHexDecode("420102"), - diag: `<<1, 2>>`, + name: "multi CBOR items with ByteStringEmbeddedCBOR", + data: mustHexDecode("420102"), + wantDiag: `<<1, 2>>`, opts: &DiagOptions{ ByteStringEmbeddedCBOR: true, }, }, { - title: "multi CBOR items with ByteStringEmbeddedCBOR", - cbor: mustHexDecode("4563666F6FF6"), - diag: `h'63666f6ff6'`, + name: "multi CBOR items with ByteStringEmbeddedCBOR", + data: mustHexDecode("4563666F6FF6"), + wantDiag: `h'63666f6ff6'`, opts: &DiagOptions{ ByteStringEmbeddedCBOR: false, }, }, { - title: "multi CBOR items with ByteStringEmbeddedCBOR", - cbor: mustHexDecode("4563666F6FF6"), - diag: `<<"foo", null>>`, + name: "multi CBOR items with ByteStringEmbeddedCBOR", + data: mustHexDecode("4563666F6FF6"), + wantDiag: `<<"foo", null>>`, opts: &DiagOptions{ ByteStringEmbeddedCBOR: true, }, }, { - title: "indefinite length byte string with no chunks", - cbor: mustHexDecode("5fff"), - diag: `''_`, - opts: &DiagOptions{}, + name: "indefinite-length byte string with no chunks", + data: mustHexDecode("5fff"), + wantDiag: `''_`, + opts: &DiagOptions{}, }, { - title: "indefinite length byte string with a empty byte string", - cbor: mustHexDecode("5f40ff"), - diag: `(_ h'')`, // RFC 8949, Section 8.1 says `(_ '')` but it looks wrong and conflicts with Appendix A. - opts: &DiagOptions{}, + name: "indefinite-length byte string with a empty byte string", + data: mustHexDecode("5f40ff"), + wantDiag: `(_ h'')`, // RFC 8949, Section 8.1 says `(_ '')` but it looks wrong and conflicts with Appendix A. + opts: &DiagOptions{}, }, { - title: "indefinite length byte string with two empty byte string", - cbor: mustHexDecode("5f4040ff"), - diag: `(_ h'', h'')`, - opts: &DiagOptions{}, + name: "indefinite-length byte string with two empty byte string", + data: mustHexDecode("5f4040ff"), + wantDiag: `(_ h'', h'')`, + opts: &DiagOptions{}, }, } for _, tc := range testCases { - t.Run(tc.title, func(t *testing.T) { + t.Run(tc.name, func(t *testing.T) { dm, err := tc.opts.DiagMode() if err != nil { - t.Errorf("DiagMode() for 0x%x returned error %q", tc.cbor, err) + t.Errorf("DiagMode() for 0x%x returned error %q", tc.data, err) } - str, err := dm.Diagnose(tc.cbor) + str, err := dm.Diagnose(tc.data) if err != nil { - t.Errorf("Diagnose(0x%x) returned error %q", tc.cbor, err) - } else if str != tc.diag { - t.Errorf("Diagnose(0x%x) returned `%s`, want %s", tc.cbor, str, tc.diag) + t.Errorf("Diagnose(0x%x) returned error %q", tc.data, err) + } else if str != tc.wantDiag { + t.Errorf("Diagnose(0x%x) returned `%s`, want %s", tc.data, str, tc.wantDiag) } }) } @@ -536,109 +536,109 @@ func TestDiagnoseByteString(t *testing.T) { func TestDiagnoseTextString(t *testing.T) { testCases := []struct { - title string - cbor []byte - diag string - opts *DiagOptions + name string + data []byte + wantDiag string + opts *DiagOptions }{ { - title: "\t", - cbor: mustHexDecode("6109"), - diag: `"\t"`, - opts: &DiagOptions{}, + name: "\t", + data: mustHexDecode("6109"), + wantDiag: `"\t"`, + opts: &DiagOptions{}, }, { - title: "\r", - cbor: mustHexDecode("610d"), - diag: `"\r"`, - opts: &DiagOptions{}, + name: "\r", + data: mustHexDecode("610d"), + wantDiag: `"\r"`, + opts: &DiagOptions{}, }, { - title: "other ascii", - cbor: mustHexDecode("611b"), - diag: `"\u001b"`, - opts: &DiagOptions{}, + name: "other ascii", + data: mustHexDecode("611b"), + wantDiag: `"\u001b"`, + opts: &DiagOptions{}, }, { - title: "valid UTF-8 text in byte string", - cbor: mustHexDecode("4d68656c6c6f2c20e4bda0e5a5bd"), - diag: `'hello, \u4f60\u597d'`, + name: "valid UTF-8 text in byte string", + data: mustHexDecode("4d68656c6c6f2c20e4bda0e5a5bd"), + wantDiag: `'hello, \u4f60\u597d'`, opts: &DiagOptions{ ByteStringText: true, }, }, { - title: "valid UTF-8 text in text string", - cbor: mustHexDecode("6d68656c6c6f2c20e4bda0e5a5bd"), - diag: `"hello, \u4f60\u597d"`, // "hello, 你好" + name: "valid UTF-8 text in text string", + data: mustHexDecode("6d68656c6c6f2c20e4bda0e5a5bd"), + wantDiag: `"hello, \u4f60\u597d"`, // "hello, 你好" opts: &DiagOptions{ ByteStringText: true, }, }, { - title: "invalid UTF-8 text in byte string", - cbor: mustHexDecode("4d68656c6c6fffeee4bda0e5a5bd"), - diag: `h'68656c6c6fffeee4bda0e5a5bd'`, + name: "invalid UTF-8 text in byte string", + data: mustHexDecode("4d68656c6c6fffeee4bda0e5a5bd"), + wantDiag: `h'68656c6c6fffeee4bda0e5a5bd'`, opts: &DiagOptions{ ByteStringText: true, }, }, { - title: "valid grapheme cluster text in byte string", - cbor: mustHexDecode("583448656c6c6f2c2027e29da4efb88fe2808df09f94a5270ae4bda0e5a5bdefbc8c22f09fa791e2808df09fa49de2808df09fa79122"), - diag: `'Hello, \'\u2764\ufe0f\u200d\ud83d\udd25\'\n\u4f60\u597d\uff0c"\ud83e\uddd1\u200d\ud83e\udd1d\u200d\ud83e\uddd1"'`, + name: "valid grapheme cluster text in byte string", + data: mustHexDecode("583448656c6c6f2c2027e29da4efb88fe2808df09f94a5270ae4bda0e5a5bdefbc8c22f09fa791e2808df09fa49de2808df09fa79122"), + wantDiag: `'Hello, \'\u2764\ufe0f\u200d\ud83d\udd25\'\n\u4f60\u597d\uff0c"\ud83e\uddd1\u200d\ud83e\udd1d\u200d\ud83e\uddd1"'`, opts: &DiagOptions{ ByteStringText: true, }, }, { - title: "valid grapheme cluster text in text string", - cbor: mustHexDecode("783448656c6c6f2c2027e29da4efb88fe2808df09f94a5270ae4bda0e5a5bdefbc8c22f09fa791e2808df09fa49de2808df09fa79122"), - diag: `"Hello, '\u2764\ufe0f\u200d\ud83d\udd25'\n\u4f60\u597d\uff0c\"\ud83e\uddd1\u200d\ud83e\udd1d\u200d\ud83e\uddd1\""`, // "Hello, '❤️‍🔥'\n你好,\"🧑‍🤝‍🧑\"" + name: "valid grapheme cluster text in text string", + data: mustHexDecode("783448656c6c6f2c2027e29da4efb88fe2808df09f94a5270ae4bda0e5a5bdefbc8c22f09fa791e2808df09fa49de2808df09fa79122"), + wantDiag: `"Hello, '\u2764\ufe0f\u200d\ud83d\udd25'\n\u4f60\u597d\uff0c\"\ud83e\uddd1\u200d\ud83e\udd1d\u200d\ud83e\uddd1\""`, // "Hello, '❤️‍🔥'\n你好,\"🧑‍🤝‍🧑\"" opts: &DiagOptions{ ByteStringText: true, }, }, { - title: "invalid grapheme cluster text in byte string", - cbor: mustHexDecode("583448656c6c6feeff27e29da4efb88fe2808df09f94a5270de4bda0e5a5bdefbc8c22f09fa791e2808df09fa49de2808df09fa79122"), - diag: `h'48656c6c6feeff27e29da4efb88fe2808df09f94a5270de4bda0e5a5bdefbc8c22f09fa791e2808df09fa49de2808df09fa79122'`, + name: "invalid grapheme cluster text in byte string", + data: mustHexDecode("583448656c6c6feeff27e29da4efb88fe2808df09f94a5270de4bda0e5a5bdefbc8c22f09fa791e2808df09fa49de2808df09fa79122"), + wantDiag: `h'48656c6c6feeff27e29da4efb88fe2808df09f94a5270de4bda0e5a5bdefbc8c22f09fa791e2808df09fa49de2808df09fa79122'`, opts: &DiagOptions{ ByteStringText: true, }, }, { - title: "indefinite length text string with no chunks", - cbor: mustHexDecode("7fff"), - diag: `""_`, - opts: &DiagOptions{}, + name: "indefinite-length text string with no chunks", + data: mustHexDecode("7fff"), + wantDiag: `""_`, + opts: &DiagOptions{}, }, { - title: "indefinite length text string with a empty text string", - cbor: mustHexDecode("7f60ff"), - diag: `(_ "")`, - opts: &DiagOptions{}, + name: "indefinite-length text string with a empty text string", + data: mustHexDecode("7f60ff"), + wantDiag: `(_ "")`, + opts: &DiagOptions{}, }, { - title: "indefinite length text string with two empty text string", - cbor: mustHexDecode("7f6060ff"), - diag: `(_ "", "")`, - opts: &DiagOptions{}, + name: "indefinite-length text string with two empty text string", + data: mustHexDecode("7f6060ff"), + wantDiag: `(_ "", "")`, + opts: &DiagOptions{}, }, } for _, tc := range testCases { - t.Run(tc.title, func(t *testing.T) { + t.Run(tc.name, func(t *testing.T) { dm, err := tc.opts.DiagMode() if err != nil { - t.Errorf("DiagMode() for 0x%x returned error %q", tc.cbor, err) + t.Errorf("DiagMode() for 0x%x returned error %q", tc.data, err) } - str, err := dm.Diagnose(tc.cbor) + str, err := dm.Diagnose(tc.data) if err != nil { - t.Errorf("Diagnose(0x%x) returned error %q", tc.cbor, err) - } else if str != tc.diag { - t.Errorf("Diagnose(0x%x) returned `%s`, want %s", tc.cbor, str, tc.diag) + t.Errorf("Diagnose(0x%x) returned error %q", tc.data, err) + } else if str != tc.wantDiag { + t.Errorf("Diagnose(0x%x) returned `%s`, want %s", tc.data, str, tc.wantDiag) } }) } @@ -646,30 +646,30 @@ func TestDiagnoseTextString(t *testing.T) { func TestDiagnoseInvalidTextString(t *testing.T) { testCases := []struct { - title string - cbor []byte + name string + data []byte wantErrorMsg string opts *DiagOptions }{ { - title: "invalid UTF-8 text in text string", - cbor: mustHexDecode("6d68656c6c6fffeee4bda0e5a5bd"), + name: "invalid UTF-8 text in text string", + data: mustHexDecode("6d68656c6c6fffeee4bda0e5a5bd"), wantErrorMsg: "invalid UTF-8 string", opts: &DiagOptions{ ByteStringText: true, }, }, { - title: "invalid grapheme cluster text in text string", - cbor: mustHexDecode("783448656c6c6feeff27e29da4efb88fe2808df09f94a5270de4bda0e5a5bdefbc8c22f09fa791e2808df09fa49de2808df09fa79122"), + name: "invalid grapheme cluster text in text string", + data: mustHexDecode("783448656c6c6feeff27e29da4efb88fe2808df09f94a5270de4bda0e5a5bdefbc8c22f09fa791e2808df09fa49de2808df09fa79122"), wantErrorMsg: "invalid UTF-8 string", opts: &DiagOptions{ ByteStringText: true, }, }, { - title: "invalid indefinite length text string", - cbor: mustHexDecode("7f6040ff"), + name: "invalid indefinite-length text string", + data: mustHexDecode("7f6040ff"), wantErrorMsg: `wrong element type`, opts: &DiagOptions{ ByteStringText: true, @@ -678,17 +678,17 @@ func TestDiagnoseInvalidTextString(t *testing.T) { } for _, tc := range testCases { - t.Run(tc.title, func(t *testing.T) { + t.Run(tc.name, func(t *testing.T) { dm, err := tc.opts.DiagMode() if err != nil { - t.Errorf("DiagMode() for 0x%x returned error %q", tc.cbor, err) + t.Errorf("DiagMode() for 0x%x returned error %q", tc.data, err) } - _, err = dm.Diagnose(tc.cbor) + _, err = dm.Diagnose(tc.data) if err == nil { - t.Errorf("Diagnose(0x%x) didn't return error", tc.cbor) + t.Errorf("Diagnose(0x%x) didn't return an error", tc.data) } else if !strings.Contains(err.Error(), tc.wantErrorMsg) { - t.Errorf("Diagnose(0x%x) returned error %q", tc.cbor, err) + t.Errorf("Diagnose(0x%x) returned error %q", tc.data, err) } }) } @@ -696,63 +696,63 @@ func TestDiagnoseInvalidTextString(t *testing.T) { func TestDiagnoseFloatingPointNumber(t *testing.T) { testCases := []struct { - title string - cbor []byte - diag string - opts *DiagOptions + name string + data []byte + wantDiag string + opts *DiagOptions }{ { - title: "float16 without FloatPrecisionIndicator option", - cbor: mustHexDecode("f93e00"), - diag: `1.5`, + name: "float16 without FloatPrecisionIndicator option", + data: mustHexDecode("f93e00"), + wantDiag: `1.5`, opts: &DiagOptions{ FloatPrecisionIndicator: false, }, }, { - title: "float16 with FloatPrecisionIndicator option", - cbor: mustHexDecode("f93e00"), - diag: `1.5_1`, + name: "float16 with FloatPrecisionIndicator option", + data: mustHexDecode("f93e00"), + wantDiag: `1.5_1`, opts: &DiagOptions{ FloatPrecisionIndicator: true, }, }, { - title: "float32 without FloatPrecisionIndicator option", - cbor: mustHexDecode("fa47c35000"), - diag: `100000.0`, + name: "float32 without FloatPrecisionIndicator option", + data: mustHexDecode("fa47c35000"), + wantDiag: `100000.0`, opts: &DiagOptions{ FloatPrecisionIndicator: false, }, }, { - title: "float32 with FloatPrecisionIndicator option", - cbor: mustHexDecode("fa47c35000"), - diag: `100000.0_2`, + name: "float32 with FloatPrecisionIndicator option", + data: mustHexDecode("fa47c35000"), + wantDiag: `100000.0_2`, opts: &DiagOptions{ FloatPrecisionIndicator: true, }, }, { - title: "float64 without FloatPrecisionIndicator option", - cbor: mustHexDecode("fbc010666666666666"), - diag: `-4.1`, + name: "float64 without FloatPrecisionIndicator option", + data: mustHexDecode("fbc010666666666666"), + wantDiag: `-4.1`, opts: &DiagOptions{ FloatPrecisionIndicator: false, }, }, { - title: "float64 with FloatPrecisionIndicator option", - cbor: mustHexDecode("fbc010666666666666"), - diag: `-4.1_3`, + name: "float64 with FloatPrecisionIndicator option", + data: mustHexDecode("fbc010666666666666"), + wantDiag: `-4.1_3`, opts: &DiagOptions{ FloatPrecisionIndicator: true, }, }, { - title: "with FloatPrecisionIndicator option", - cbor: mustHexDecode("c1fb41d452d9ec200000"), - diag: `1(1363896240.5_3)`, + name: "with FloatPrecisionIndicator option", + data: mustHexDecode("c1fb41d452d9ec200000"), + wantDiag: `1(1363896240.5_3)`, opts: &DiagOptions{ FloatPrecisionIndicator: true, }, @@ -760,17 +760,17 @@ func TestDiagnoseFloatingPointNumber(t *testing.T) { } for _, tc := range testCases { - t.Run(tc.title, func(t *testing.T) { + t.Run(tc.name, func(t *testing.T) { dm, err := tc.opts.DiagMode() if err != nil { - t.Errorf("DiagMode() for 0x%x returned error %q", tc.cbor, err) + t.Errorf("DiagMode() for 0x%x returned error %q", tc.data, err) } - str, err := dm.Diagnose(tc.cbor) + str, err := dm.Diagnose(tc.data) if err != nil { - t.Errorf("Diagnose(0x%x) returned error %q", tc.cbor, err) - } else if str != tc.diag { - t.Errorf("Diagnose(0x%x) returned `%s`, want %s", tc.cbor, str, tc.diag) + t.Errorf("Diagnose(0x%x) returned error %q", tc.data, err) + } else if str != tc.wantDiag { + t.Errorf("Diagnose(0x%x) returned `%s`, want %s", tc.data, str, tc.wantDiag) } }) } @@ -778,62 +778,62 @@ func TestDiagnoseFloatingPointNumber(t *testing.T) { func TestDiagnoseFirst(t *testing.T) { testCases := []struct { - title string - cbor []byte - diag string + name string + data []byte + wantDiag string wantRest []byte wantErrorMsg string }{ { - title: "with no trailing data", - cbor: mustHexDecode("f93e00"), - diag: `1.5`, + name: "with no trailing data", + data: mustHexDecode("f93e00"), + wantDiag: `1.5`, wantRest: []byte{}, wantErrorMsg: "", }, { - title: "with CBOR Sequences", - cbor: mustHexDecode("f93e0064494554464401020304"), - diag: `1.5`, + name: "with CBOR Sequences", + data: mustHexDecode("f93e0064494554464401020304"), + wantDiag: `1.5`, wantRest: mustHexDecode("64494554464401020304"), wantErrorMsg: "", }, { - title: "with invalid CBOR trailing data", - cbor: mustHexDecode("f93e00ff494554464401020304"), - diag: `1.5`, + name: "with invalid CBOR trailing data", + data: mustHexDecode("f93e00ff494554464401020304"), + wantDiag: `1.5`, wantRest: mustHexDecode("ff494554464401020304"), wantErrorMsg: "", }, { - title: "with invalid CBOR data", - cbor: mustHexDecode("f93e"), - diag: ``, + name: "with invalid CBOR data", + data: mustHexDecode("f93e"), + wantDiag: ``, wantRest: nil, wantErrorMsg: "unexpected EOF", }, } for _, tc := range testCases { - t.Run(tc.title, func(t *testing.T) { - str, rest, err := DiagnoseFirst(tc.cbor) - if str != tc.diag { - t.Errorf("DiagnoseFirst(0x%x) returned `%s`, want %s", tc.cbor, str, tc.diag) + t.Run(tc.name, func(t *testing.T) { + str, rest, err := DiagnoseFirst(tc.data) + if str != tc.wantDiag { + t.Errorf("DiagnoseFirst(0x%x) returned `%s`, want %s", tc.data, str, tc.wantDiag) } if bytes.Equal(rest, tc.wantRest) == false { - if str != tc.diag { - t.Errorf("DiagnoseFirst(0x%x) returned rest `%x`, want rest %x", tc.cbor, rest, tc.wantRest) + if str != tc.wantDiag { + t.Errorf("DiagnoseFirst(0x%x) returned rest `%x`, want rest %x", tc.data, rest, tc.wantRest) } } switch { case tc.wantErrorMsg == "" && err != nil: - t.Errorf("DiagnoseFirst(0x%x) returned error %q", tc.cbor, err) + t.Errorf("DiagnoseFirst(0x%x) returned error %q", tc.data, err) case tc.wantErrorMsg != "" && err == nil: - t.Errorf("DiagnoseFirst(0x%x) returned nil error, want error %q", tc.cbor, err) + t.Errorf("DiagnoseFirst(0x%x) returned nil error, want error %q", tc.data, err) case tc.wantErrorMsg != "" && !strings.Contains(err.Error(), tc.wantErrorMsg): - t.Errorf("DiagnoseFirst(0x%x) returned error %q, want error %q", tc.cbor, err, tc.wantErrorMsg) + t.Errorf("DiagnoseFirst(0x%x) returned error %q, want error %q", tc.data, err, tc.wantErrorMsg) } }) } @@ -841,52 +841,52 @@ func TestDiagnoseFirst(t *testing.T) { func TestDiagnoseCBORSequences(t *testing.T) { testCases := []struct { - title string - cbor []byte - diag string + name string + data []byte + wantDiag string opts *DiagOptions returnError bool }{ { - title: "CBOR Sequences without CBORSequence option", - cbor: mustHexDecode("f93e0064494554464401020304"), - diag: ``, + name: "CBOR Sequences without CBORSequence option", + data: mustHexDecode("f93e0064494554464401020304"), + wantDiag: ``, opts: &DiagOptions{ CBORSequence: false, }, returnError: true, }, { - title: "CBOR Sequences with CBORSequence option", - cbor: mustHexDecode("f93e0064494554464401020304"), - diag: `1.5, "IETF", h'01020304'`, + name: "CBOR Sequences with CBORSequence option", + data: mustHexDecode("f93e0064494554464401020304"), + wantDiag: `1.5, "IETF", h'01020304'`, opts: &DiagOptions{ CBORSequence: true, }, returnError: false, }, { - title: "CBOR Sequences with CBORSequence option", - cbor: mustHexDecode("0102"), - diag: `1, 2`, + name: "CBOR Sequences with CBORSequence option", + data: mustHexDecode("0102"), + wantDiag: `1, 2`, opts: &DiagOptions{ CBORSequence: true, }, returnError: false, }, { - title: "CBOR Sequences with CBORSequence option", - cbor: mustHexDecode("63666F6FF6"), - diag: `"foo", null`, + name: "CBOR Sequences with CBORSequence option", + data: mustHexDecode("63666F6FF6"), + wantDiag: `"foo", null`, opts: &DiagOptions{ CBORSequence: true, }, returnError: false, }, { - title: "partial/incomplete CBOR Sequences", - cbor: mustHexDecode("f93e00644945544644010203"), - diag: `1.5, "IETF"`, + name: "partial/incomplete CBOR Sequences", + data: mustHexDecode("f93e00644945544644010203"), + wantDiag: `1.5, "IETF"`, opts: &DiagOptions{ CBORSequence: true, }, @@ -895,21 +895,21 @@ func TestDiagnoseCBORSequences(t *testing.T) { } for _, tc := range testCases { - t.Run(tc.title, func(t *testing.T) { + t.Run(tc.name, func(t *testing.T) { dm, err := tc.opts.DiagMode() if err != nil { - t.Errorf("DiagMode() for 0x%x returned error %q", tc.cbor, err) + t.Errorf("DiagMode() for 0x%x returned error %q", tc.data, err) } - str, err := dm.Diagnose(tc.cbor) + str, err := dm.Diagnose(tc.data) if tc.returnError && err == nil { - t.Errorf("Diagnose(0x%x) returned error %q", tc.cbor, err) + t.Errorf("Diagnose(0x%x) returned error %q", tc.data, err) } else if !tc.returnError && err != nil { - t.Errorf("Diagnose(0x%x) returned error %q", tc.cbor, err) + t.Errorf("Diagnose(0x%x) returned error %q", tc.data, err) } - if str != tc.diag { - t.Errorf("Diagnose(0x%x) returned `%s`, want %s", tc.cbor, str, tc.diag) + if str != tc.wantDiag { + t.Errorf("Diagnose(0x%x) returned `%s`, want %s", tc.data, str, tc.wantDiag) } }) } @@ -917,72 +917,72 @@ func TestDiagnoseCBORSequences(t *testing.T) { func TestDiagnoseTag(t *testing.T) { testCases := []struct { - title string - cbor []byte - diag string + name string + data []byte + wantDiag string opts *DiagOptions returnError bool }{ { - title: "CBOR tag number 2 with not well-formed encoded CBOR data item", - cbor: mustHexDecode("c201"), - diag: ``, + name: "CBOR tag number 2 with not well-formed encoded CBOR data item", + data: mustHexDecode("c201"), + wantDiag: ``, opts: &DiagOptions{}, returnError: true, }, { - title: "CBOR tag number 3 with not well-formed encoded CBOR data item", - cbor: mustHexDecode("c301"), - diag: ``, + name: "CBOR tag number 3 with not well-formed encoded CBOR data item", + data: mustHexDecode("c301"), + wantDiag: ``, opts: &DiagOptions{}, returnError: true, }, { - title: "CBOR tag number 2 with well-formed encoded CBOR data item", - cbor: mustHexDecode("c240"), - diag: `0`, + name: "CBOR tag number 2 with well-formed encoded CBOR data item", + data: mustHexDecode("c240"), + wantDiag: `0`, opts: &DiagOptions{}, returnError: false, }, { - title: "CBOR tag number 3 with well-formed encoded CBOR data item", - cbor: mustHexDecode("c340"), - diag: `-1`, // -1 - n + name: "CBOR tag number 3 with well-formed encoded CBOR data item", + data: mustHexDecode("c340"), + wantDiag: `-1`, // -1 - n opts: &DiagOptions{}, returnError: false, }, { - title: "CBOR tag number 2 with well-formed encoded CBOR data item", - cbor: mustHexDecode("c249010000000000000000"), - diag: `18446744073709551616`, + name: "CBOR tag number 2 with well-formed encoded CBOR data item", + data: mustHexDecode("c249010000000000000000"), + wantDiag: `18446744073709551616`, opts: &DiagOptions{}, returnError: false, }, { - title: "CBOR tag number 3 with well-formed encoded CBOR data item", - cbor: mustHexDecode("c349010000000000000000"), - diag: `-18446744073709551617`, // -1 - n + name: "CBOR tag number 3 with well-formed encoded CBOR data item", + data: mustHexDecode("c349010000000000000000"), + wantDiag: `-18446744073709551617`, // -1 - n opts: &DiagOptions{}, returnError: false, }, } for _, tc := range testCases { - t.Run(tc.title, func(t *testing.T) { + t.Run(tc.name, func(t *testing.T) { dm, err := tc.opts.DiagMode() if err != nil { - t.Errorf("DiagMode() for 0x%x returned error %q", tc.cbor, err) + t.Errorf("DiagMode() for 0x%x returned error %q", tc.data, err) } - str, err := dm.Diagnose(tc.cbor) + str, err := dm.Diagnose(tc.data) if tc.returnError && err == nil { - t.Errorf("Diagnose(0x%x) returned error %q", tc.cbor, err) + t.Errorf("Diagnose(0x%x) returned error %q", tc.data, err) } else if !tc.returnError && err != nil { - t.Errorf("Diagnose(0x%x) returned error %q", tc.cbor, err) + t.Errorf("Diagnose(0x%x) returned error %q", tc.data, err) } - if str != tc.diag { - t.Errorf("Diagnose(0x%x) returned `%s`, want %s", tc.cbor, str, tc.diag) + if str != tc.wantDiag { + t.Errorf("Diagnose(0x%x) returned `%s`, want %s", tc.data, str, tc.wantDiag) } }) } @@ -1036,7 +1036,7 @@ func TestInvalidDiagnoseOptions(t *testing.T) { } _, err := opts.DiagMode() if err == nil { - t.Errorf("DiagMode() with invalid ByteStringEncoding option didn't return error") + t.Errorf("DiagMode() with invalid ByteStringEncoding option didn't return an error") } } @@ -1044,7 +1044,7 @@ func TestDiagnoseExtraneousData(t *testing.T) { data := mustHexDecode("63666F6FF6") _, err := Diagnose(data) if err == nil { - t.Errorf("Diagnose(0x%x) didn't return error", data) + t.Errorf("Diagnose(0x%x) didn't return an error", data) } else if !strings.Contains(err.Error(), `extraneous data`) { t.Errorf("Diagnose(0x%x) returned error %q", data, err) } @@ -1059,7 +1059,7 @@ func TestDiagnoseNotwellformedData(t *testing.T) { data := mustHexDecode("5f4060ff") _, err := Diagnose(data) if err == nil { - t.Errorf("Diagnose(0x%x) didn't return error", data) + t.Errorf("Diagnose(0x%x) didn't return an error", data) } else if !strings.Contains(err.Error(), `wrong element type`) { t.Errorf("Diagnose(0x%x) returned error %q", data, err) } @@ -1103,8 +1103,20 @@ func TestDiagnoseEmptyData(t *testing.T) { } } +func TestDiagnoseInvalidByteStringEncoding(t *testing.T) { + _, err := DiagOptions{ + ByteStringEncoding: maxByteStringEncoding, + }.DiagMode() + if err == nil { + t.Fatal("DiagMode() expected error for invalid ByteStringEncoding, got nil") + } + if !strings.Contains(err.Error(), "invalid ByteStringEncoding") { + t.Errorf("DiagMode() error = %q, want error containing \"invalid ByteStringEncoding\"", err.Error()) + } +} + func BenchmarkDiagnose(b *testing.B) { - for _, tc := range []struct { + testCases := []struct { name string opts DiagOptions input []byte @@ -1134,7 +1146,8 @@ func BenchmarkDiagnose(b *testing.B) { opts: DiagOptions{ByteStringEncoding: ByteStringBase64Encoding}, input: []byte("\x45hello"), }, - } { + } + for _, tc := range testCases { b.Run(tc.name, func(b *testing.B) { dm, err := tc.opts.DiagMode() if err != nil { diff --git a/encode.go b/encode.go index 880b8516..ab317aa2 100644 --- a/encode.go +++ b/encode.go @@ -30,7 +30,7 @@ import ( // If value implements the Marshaler interface, Marshal calls its // MarshalCBOR method. // -// If value implements encoding.BinaryMarshaler, Marhsal calls its +// If value implements encoding.BinaryMarshaler, Marshal calls its // MarshalBinary method and encode it as CBOR byte string. // // Boolean values encode as CBOR booleans (type 7). @@ -440,7 +440,7 @@ const ( // FieldNameToTextString encodes struct fields to CBOR text string (major type 3). FieldNameToTextString FieldNameMode = iota - // FieldNameToTextString encodes struct fields to CBOR byte string (major type 2). + // FieldNameToByteString encodes struct fields to CBOR byte string (major type 2). FieldNameToByteString maxFieldNameMode @@ -571,7 +571,7 @@ type EncOptions struct { // RFC3339 format gets tag number 0, and numeric epoch time tag number 1. TimeTag EncTagMode - // IndefLength specifies whether to allow indefinite length CBOR items. + // IndefLength specifies whether to allow indefinite-length CBOR items. IndefLength IndefLengthMode // NilContainers specifies how to encode nil slices and maps. @@ -1539,8 +1539,8 @@ func encodeStruct(e *bytes.Buffer, em *encMode, v reflect.Value) (err error) { // Head is rewritten later if actual encoded field count is different from struct field count. encodedHeadLen := encodeHead(e, byte(cborTypeMap), uint64(len(flds))) - kvbegin := e.Len() - kvcount := 0 + kvBeginOffset := e.Len() + kvCount := 0 for offset := 0; offset < len(flds); offset++ { f := flds[(start+offset)%len(flds)] @@ -1586,10 +1586,10 @@ func encodeStruct(e *bytes.Buffer, em *encMode, v reflect.Value) (err error) { return err } - kvcount++ + kvCount++ } - if len(flds) == kvcount { + if len(flds) == kvCount { // Encoded element count in head is the same as actual element count. return nil } @@ -1597,8 +1597,8 @@ func encodeStruct(e *bytes.Buffer, em *encMode, v reflect.Value) (err error) { // Overwrite the bytes that were reserved for the head before encoding the map entries. var actualHeadLen int { - headbuf := *bytes.NewBuffer(e.Bytes()[kvbegin-encodedHeadLen : kvbegin-encodedHeadLen : kvbegin]) - actualHeadLen = encodeHead(&headbuf, byte(cborTypeMap), uint64(kvcount)) + headbuf := *bytes.NewBuffer(e.Bytes()[kvBeginOffset-encodedHeadLen : kvBeginOffset-encodedHeadLen : kvBeginOffset]) + actualHeadLen = encodeHead(&headbuf, byte(cborTypeMap), uint64(kvCount)) } if actualHeadLen == encodedHeadLen { @@ -1611,8 +1611,8 @@ func encodeStruct(e *bytes.Buffer, em *encMode, v reflect.Value) (err error) { // encoded. The encoded entries are offset to the right by the number of excess reserved // bytes. Shift the entries left to remove the gap. excessReservedBytes := encodedHeadLen - actualHeadLen - dst := e.Bytes()[kvbegin-excessReservedBytes : e.Len()-excessReservedBytes] - src := e.Bytes()[kvbegin:e.Len()] + dst := e.Bytes()[kvBeginOffset-excessReservedBytes : e.Len()-excessReservedBytes] + src := e.Bytes()[kvBeginOffset:e.Len()] copy(dst, src) // After shifting, the excess bytes are at the end of the output buffer and they are diff --git a/encode_test.go b/encode_test.go index f8cc7ea4..2f71a351 100644 --- a/encode_test.go +++ b/encode_test.go @@ -18,19 +18,19 @@ import ( "time" ) -type marshalTest struct { +type marshalTestCase struct { wantData []byte values []any } -type marshalErrorTest struct { +type marshalErrorTestCase struct { name string value any wantErrorMsg string } // CBOR test data are from https://tools.ietf.org/html/rfc7049#appendix-A. -var marshalTests = []marshalTest{ +var marshalTestCases = []marshalTestCase{ // unsigned integer { wantData: mustHexDecode("00"), @@ -459,7 +459,7 @@ var marshalTests = []marshalTest{ } func TestMarshal(t *testing.T) { - testMarshal(t, marshalTests) + testMarshal(t, marshalTestCases) } func TestInvalidTypeMarshal(t *testing.T) { @@ -470,7 +470,7 @@ func TestInvalidTypeMarshal(t *testing.T) { _ struct{} `cbor:",toarray"` Chan chan bool } - var marshalErrorTests = []marshalErrorTest{ + var marshalErrorTestCases = []marshalErrorTestCase{ { name: "channel cannot be marshaled", value: make(chan bool), @@ -516,7 +516,7 @@ func TestInvalidTypeMarshal(t *testing.T) { if err != nil { t.Errorf("EncMode() returned an error %v", err) } - for _, tc := range marshalErrorTests { + for _, tc := range marshalErrorTestCases { t.Run(tc.name, func(t *testing.T) { v := tc.value b, err := Marshal(&v) @@ -548,7 +548,7 @@ func TestInvalidTypeMarshal(t *testing.T) { func TestMarshalLargeByteString(t *testing.T) { // []byte{100, 100, 100, ...} lengths := []int{0, 1, 2, 22, 23, 24, 254, 255, 256, 65534, 65535, 65536, 10000000} - tests := make([]marshalTest, len(lengths)) + testCases := make([]marshalTestCase, len(lengths)) for i, length := range lengths { data := bytes.NewBuffer(encodeCborHeader(cborTypeByteString, uint64(length))) value := make([]byte, length) @@ -556,16 +556,16 @@ func TestMarshalLargeByteString(t *testing.T) { data.WriteByte(100) value[j] = 100 } - tests[i] = marshalTest{data.Bytes(), []any{value}} + testCases[i] = marshalTestCase{data.Bytes(), []any{value}} } - testMarshal(t, tests) + testMarshal(t, testCases) } func TestMarshalLargeTextString(t *testing.T) { // "ddd..." lengths := []int{0, 1, 2, 22, 23, 24, 254, 255, 256, 65534, 65535, 65536, 10000000} - tests := make([]marshalTest, len(lengths)) + testCases := make([]marshalTestCase, len(lengths)) for i, length := range lengths { data := bytes.NewBuffer(encodeCborHeader(cborTypeTextString, uint64(length))) value := make([]byte, length) @@ -573,16 +573,16 @@ func TestMarshalLargeTextString(t *testing.T) { data.WriteByte(100) value[j] = 100 } - tests[i] = marshalTest{data.Bytes(), []any{string(value)}} + testCases[i] = marshalTestCase{data.Bytes(), []any{string(value)}} } - testMarshal(t, tests) + testMarshal(t, testCases) } func TestMarshalLargeArray(t *testing.T) { // []string{"水", "水", "水", ...} lengths := []int{0, 1, 2, 22, 23, 24, 254, 255, 256, 65534, 65535, 65536, 131072} - tests := make([]marshalTest, len(lengths)) + testCases := make([]marshalTestCase, len(lengths)) for i, length := range lengths { data := bytes.NewBuffer(encodeCborHeader(cborTypeArray, uint64(length))) value := make([]string, length) @@ -590,16 +590,16 @@ func TestMarshalLargeArray(t *testing.T) { data.Write([]byte{0x63, 0xe6, 0xb0, 0xb4}) value[j] = "水" } - tests[i] = marshalTest{data.Bytes(), []any{value}} + testCases[i] = marshalTestCase{data.Bytes(), []any{value}} } - testMarshal(t, tests) + testMarshal(t, testCases) } func TestMarshalLargeMapCanonical(t *testing.T) { // map[int]int {0:0, 1:1, 2:2, ...} lengths := []int{0, 1, 2, 22, 23, 24, 254, 255, 256, 65534, 65535, 65536, 131072} - tests := make([]marshalTest, len(lengths)) + testCases := make([]marshalTestCase, len(lengths)) for i, length := range lengths { data := bytes.NewBuffer(encodeCborHeader(cborTypeMap, uint64(length))) value := make(map[int]int, length) @@ -609,10 +609,10 @@ func TestMarshalLargeMapCanonical(t *testing.T) { data.Write(d) value[j] = j } - tests[i] = marshalTest{data.Bytes(), []any{value}} + testCases[i] = marshalTestCase{data.Bytes(), []any{value}} } - testMarshal(t, tests) + testMarshal(t, testCases) } func TestMarshalLargeMap(t *testing.T) { @@ -683,7 +683,7 @@ func encodeCborHeader(t cborType, n uint64) []byte { return b[:] } -func testMarshal(t *testing.T, testCases []marshalTest) { +func testMarshal(t *testing.T, testCases []marshalTestCase) { em, err := EncOptions{Sort: SortCanonical}.EncMode() if err != nil { t.Errorf("EncMode() returned an error %v", err) @@ -828,7 +828,7 @@ func TestMarshalStructVariableLength(t *testing.T) { t.Fatal(err) } if !bytes.Equal(tc.want, got) { - t.Errorf("want 0x%x but got 0x%x", tc.want, got) + t.Errorf("Marshal(%v) = 0x%x, want 0x%x", tc.in, got, tc.want) } }) } @@ -1301,10 +1301,10 @@ func TestOmitAndRenameStructField(t *testing.T) { em, _ := EncOptions{}.EncMode() dm, _ := DecOptions{}.DecMode() - tests := []roundTripTest{ + testCases := []roundTripTestCase{ {"default values", v1, want1}, {"non-default values", v2, want2}} - testRoundTrip(t, tests, em, dm) + testRoundTrip(t, testCases, em, dm) } func TestOmitEmptyForBuiltinType(t *testing.T) { @@ -1345,7 +1345,7 @@ func TestOmitEmptyForBuiltinType(t *testing.T) { em, _ := EncOptions{}.EncMode() dm, _ := DecOptions{}.DecMode() - testRoundTrip(t, []roundTripTest{{"default values", v, want}}, em, dm) + testRoundTrip(t, []roundTripTestCase{{"default values", v, want}}, em, dm) } func TestOmitEmptyForAnonymousStruct(t *testing.T) { @@ -1359,7 +1359,7 @@ func TestOmitEmptyForAnonymousStruct(t *testing.T) { em, _ := EncOptions{}.EncMode() dm, _ := DecOptions{}.DecMode() - testRoundTrip(t, []roundTripTest{{"default values", v, want}}, em, dm) + testRoundTrip(t, []roundTripTestCase{{"default values", v, want}}, em, dm) } func TestOmitEmptyForStruct1(t *testing.T) { @@ -1384,7 +1384,7 @@ func TestOmitEmptyForStruct1(t *testing.T) { em, _ := EncOptions{}.EncMode() dm, _ := DecOptions{}.DecMode() - testRoundTrip(t, []roundTripTest{{"default values", v, want}}, em, dm) + testRoundTrip(t, []roundTripTestCase{{"default values", v, want}}, em, dm) } func TestOmitEmptyForStruct2(t *testing.T) { @@ -1408,7 +1408,7 @@ func TestOmitEmptyForStruct2(t *testing.T) { em, _ := EncOptions{}.EncMode() dm, _ := DecOptions{}.DecMode() - testRoundTrip(t, []roundTripTest{{"non-default values", v, want}}, em, dm) + testRoundTrip(t, []roundTripTestCase{{"non-default values", v, want}}, em, dm) } func TestInvalidOmitEmptyMode(t *testing.T) { @@ -1500,8 +1500,8 @@ func TestOmitEmptyMode(t *testing.T) { emOmitEmptyGoValue, _ := EncOptions{OmitEmpty: OmitEmptyGoValue}.EncMode() emOmitEmptyCBORValue, _ := EncOptions{OmitEmpty: OmitEmptyCBORValue}.EncMode() dm, _ := DecOptions{}.DecMode() - testRoundTrip(t, []roundTripTest{{"OmitEmptyGoValue (default) ", v, wantDataWithOmitEmptyGoValue}}, emOmitEmptyGoValue, dm) - testRoundTrip(t, []roundTripTest{{"OmitEmptyCBORValue", v, wantDataWithOmitEmptyCBORValue}}, emOmitEmptyCBORValue, dm) + testRoundTrip(t, []roundTripTestCase{{"OmitEmptyGoValue (default)", v, wantDataWithOmitEmptyGoValue}}, emOmitEmptyGoValue, dm) + testRoundTrip(t, []roundTripTestCase{{"OmitEmptyCBORValue", v, wantDataWithOmitEmptyCBORValue}}, emOmitEmptyCBORValue, dm) } func TestOmitEmptyForNestedStruct(t *testing.T) { @@ -1529,7 +1529,7 @@ func TestOmitEmptyForNestedStruct(t *testing.T) { em, _ := EncOptions{}.EncMode() dm, _ := DecOptions{}.DecMode() - testRoundTrip(t, []roundTripTest{{"default values", v, want}}, em, dm) + testRoundTrip(t, []roundTripTestCase{{"default values", v, want}}, em, dm) } func TestOmitEmptyForToArrayStruct1(t *testing.T) { @@ -1558,7 +1558,7 @@ func TestOmitEmptyForToArrayStruct1(t *testing.T) { em, _ := EncOptions{}.EncMode() dm, _ := DecOptions{}.DecMode() - testRoundTrip(t, []roundTripTest{{"no exportable fields", v, want}}, em, dm) + testRoundTrip(t, []roundTripTestCase{{"no exportable fields", v, want}}, em, dm) } func TestOmitEmptyForToArrayStruct2(t *testing.T) { @@ -1584,7 +1584,7 @@ func TestOmitEmptyForToArrayStruct2(t *testing.T) { em, _ := EncOptions{}.EncMode() dm, _ := DecOptions{}.DecMode() - testRoundTrip(t, []roundTripTest{{"has exportable fields", v, want}}, em, dm) + testRoundTrip(t, []roundTripTestCase{{"has exportable fields", v, want}}, em, dm) } func TestOmitEmptyForStructWithPtrToAnonymousField(t *testing.T) { @@ -1714,7 +1714,7 @@ func TestOmitEmptyForBinaryMarshaler1(t *testing.T) { Stro T1 `cbor:"stro,omitempty"` } - testCases := []roundTripTest{ + testCases := []roundTripTestCase{ { "empty BinaryMarshaler", T1{}, @@ -1741,7 +1741,7 @@ func TestOmitEmptyForBinaryMarshaler2(t *testing.T) { Stro T1 `cbor:"stro,omitempty"` } - testCases := []roundTripTest{ + testCases := []roundTripTestCase{ { "empty BinaryMarshaler", T1{}, @@ -1770,7 +1770,7 @@ func TestOmitEmptyForTime(t *testing.T) { em, _ := EncOptions{}.EncMode() dm, _ := DecOptions{}.DecMode() - testRoundTrip(t, []roundTripTest{{"default values", v, want}}, em, dm) + testRoundTrip(t, []roundTripTestCase{{"default values", v, want}}, em, dm) } // omitempty is a no-op for big.Int. @@ -1784,7 +1784,7 @@ func TestOmitEmptyForBigInt(t *testing.T) { em, _ := EncOptions{BigIntConvert: BigIntConvertNone}.EncMode() dm, _ := DecOptions{}.DecMode() - testRoundTrip(t, []roundTripTest{{"default values", v, want}}, em, dm) + testRoundTrip(t, []roundTripTestCase{{"default values", v, want}}, em, dm) } func TestOmitZeroForBuiltinType(t *testing.T) { @@ -1825,7 +1825,7 @@ func TestOmitZeroForBuiltinType(t *testing.T) { em, _ := EncOptions{}.EncMode() dm, _ := DecOptions{}.DecMode() - testRoundTrip(t, []roundTripTest{{"default values", v, want}}, em, dm) + testRoundTrip(t, []roundTripTestCase{{"default values", v, want}}, em, dm) } func TestOmitZeroForAnonymousStruct(t *testing.T) { @@ -1839,7 +1839,7 @@ func TestOmitZeroForAnonymousStruct(t *testing.T) { em, _ := EncOptions{}.EncMode() dm, _ := DecOptions{}.DecMode() - testRoundTrip(t, []roundTripTest{{"default values", v, want}}, em, dm) + testRoundTrip(t, []roundTripTestCase{{"default values", v, want}}, em, dm) } func TestOmitZeroForStruct1(t *testing.T) { @@ -1864,7 +1864,7 @@ func TestOmitZeroForStruct1(t *testing.T) { em, _ := EncOptions{}.EncMode() dm, _ := DecOptions{}.DecMode() - testRoundTrip(t, []roundTripTest{{"default values", v, want}}, em, dm) + testRoundTrip(t, []roundTripTestCase{{"default values", v, want}}, em, dm) } func TestOmitZeroForStruct2(t *testing.T) { @@ -1888,7 +1888,7 @@ func TestOmitZeroForStruct2(t *testing.T) { em, _ := EncOptions{}.EncMode() dm, _ := DecOptions{}.DecMode() - testRoundTrip(t, []roundTripTest{{"non-default values", v, want}}, em, dm) + testRoundTrip(t, []roundTripTestCase{{"non-default values", v, want}}, em, dm) } func TestOmitZeroForNestedStruct(t *testing.T) { @@ -1916,7 +1916,7 @@ func TestOmitZeroForNestedStruct(t *testing.T) { em, _ := EncOptions{}.EncMode() dm, _ := DecOptions{}.DecMode() - testRoundTrip(t, []roundTripTest{{"default values", v, want}}, em, dm) + testRoundTrip(t, []roundTripTestCase{{"default values", v, want}}, em, dm) } func TestOmitZeroForToArrayStruct1(t *testing.T) { @@ -1945,7 +1945,7 @@ func TestOmitZeroForToArrayStruct1(t *testing.T) { em, _ := EncOptions{}.EncMode() dm, _ := DecOptions{}.DecMode() - testRoundTrip(t, []roundTripTest{{"no exportable fields", v, want}}, em, dm) + testRoundTrip(t, []roundTripTestCase{{"no exportable fields", v, want}}, em, dm) } func TestOmitZeroForToArrayStruct2(t *testing.T) { @@ -1971,7 +1971,7 @@ func TestOmitZeroForToArrayStruct2(t *testing.T) { em, _ := EncOptions{}.EncMode() dm, _ := DecOptions{}.DecMode() - testRoundTrip(t, []roundTripTest{{"has exportable fields", v, want}}, em, dm) + testRoundTrip(t, []roundTripTestCase{{"has exportable fields", v, want}}, em, dm) } func TestOmitZeroForStructWithPtrToAnonymousField(t *testing.T) { @@ -2101,7 +2101,7 @@ func TestOmitZeroForBinaryMarshaler1(t *testing.T) { Stro T1 `cbor:"stro,omitzero"` } - testCases := []roundTripTest{ + testCases := []roundTripTestCase{ { "empty BinaryMarshaler", T1{}, @@ -2128,7 +2128,7 @@ func TestOmitZeroForBinaryMarshaler2(t *testing.T) { Stro T1 `cbor:"stro,omitzero"` } - testCases := []roundTripTest{ + testCases := []roundTripTestCase{ { "empty BinaryMarshaler", T1{}, @@ -2156,7 +2156,7 @@ func TestOmitZeroForTime(t *testing.T) { em, _ := EncOptions{}.EncMode() dm, _ := DecOptions{}.DecMode() - testRoundTrip(t, []roundTripTest{{"default values", v, want}}, em, dm) + testRoundTrip(t, []roundTripTestCase{{"default values", v, want}}, em, dm) } func TestOmitZeroForBigInt(t *testing.T) { @@ -2169,257 +2169,257 @@ func TestOmitZeroForBigInt(t *testing.T) { em, _ := EncOptions{BigIntConvert: BigIntConvertNone}.EncMode() dm, _ := DecOptions{}.DecMode() - testRoundTrip(t, []roundTripTest{{"default values", v, want}}, em, dm) + testRoundTrip(t, []roundTripTestCase{{"default values", v, want}}, em, dm) } func TestIsZero(t *testing.T) { var zeroStructZeroer isZeroer = zeroTestTypeCustom{value: 42} - testcases := []struct { + testCases := []struct { name string t reflect.Type v reflect.Value - expect bool - expectErr bool + want bool + wantHasErr bool }{ { - name: "nil", - t: reflect.TypeOf(nil), - v: reflect.ValueOf(nil), - expect: true, + name: "nil", + t: reflect.TypeOf(nil), + v: reflect.ValueOf(nil), + want: true, }, { - name: "string-zero", - t: reflect.TypeOf(""), - v: reflect.ValueOf(""), - expect: true, + name: "string-zero", + t: reflect.TypeOf(""), + v: reflect.ValueOf(""), + want: true, }, { - name: "string-nonzero", - t: reflect.TypeOf(""), - v: reflect.ValueOf("a"), - expect: false, + name: "string-nonzero", + t: reflect.TypeOf(""), + v: reflect.ValueOf("a"), + want: false, }, { - name: "int-zero", - t: reflect.TypeOf(0), - v: reflect.ValueOf(0), - expect: true, + name: "int-zero", + t: reflect.TypeOf(0), + v: reflect.ValueOf(0), + want: true, }, { - name: "int-nonzero", - t: reflect.TypeOf(0), - v: reflect.ValueOf(1), - expect: false, + name: "int-nonzero", + t: reflect.TypeOf(0), + v: reflect.ValueOf(1), + want: false, }, { - name: "bool-zero", - t: reflect.TypeOf(false), - v: reflect.ValueOf(false), - expect: true, + name: "bool-zero", + t: reflect.TypeOf(false), + v: reflect.ValueOf(false), + want: true, }, { - name: "bool-nonzero", - t: reflect.TypeOf(false), - v: reflect.ValueOf(true), - expect: false, + name: "bool-nonzero", + t: reflect.TypeOf(false), + v: reflect.ValueOf(true), + want: false, }, { - name: "slice-zero", - t: reflect.TypeOf([]string(nil)), - v: reflect.ValueOf([]string(nil)), - expect: true, + name: "slice-zero", + t: reflect.TypeOf([]string(nil)), + v: reflect.ValueOf([]string(nil)), + want: true, }, { - name: "slice-nonzero", - t: reflect.TypeOf([]string(nil)), - v: reflect.ValueOf([]string{}), - expect: false, + name: "slice-nonzero", + t: reflect.TypeOf([]string(nil)), + v: reflect.ValueOf([]string{}), + want: false, }, { - name: "map-zero", - t: reflect.TypeOf(map[string]string(nil)), - v: reflect.ValueOf(map[string]string(nil)), - expect: true, + name: "map-zero", + t: reflect.TypeOf(map[string]string(nil)), + v: reflect.ValueOf(map[string]string(nil)), + want: true, }, { - name: "map-nonzero", - t: reflect.TypeOf(map[string]string(nil)), - v: reflect.ValueOf(map[string]string{}), - expect: false, + name: "map-nonzero", + t: reflect.TypeOf(map[string]string(nil)), + v: reflect.ValueOf(map[string]string{}), + want: false, }, { - name: "struct-zero", - t: reflect.TypeOf(zeroTestType{}), - v: reflect.ValueOf(zeroTestType{}), - expect: true, + name: "struct-zero", + t: reflect.TypeOf(zeroTestType{}), + v: reflect.ValueOf(zeroTestType{}), + want: true, }, { - name: "struct-nonzero", - t: reflect.TypeOf(zeroTestType{}), - v: reflect.ValueOf(zeroTestType{value: 42}), - expect: false, + name: "struct-nonzero", + t: reflect.TypeOf(zeroTestType{}), + v: reflect.ValueOf(zeroTestType{value: 42}), + want: false, }, { - name: "pointer-zero", - t: reflect.TypeOf((*zeroTestType)(nil)), - v: reflect.ValueOf((*zeroTestType)(nil)), - expect: true, + name: "pointer-zero", + t: reflect.TypeOf((*zeroTestType)(nil)), + v: reflect.ValueOf((*zeroTestType)(nil)), + want: true, }, { - name: "pointer-nonzero", - t: reflect.TypeOf((*zeroTestType)(nil)), - v: reflect.ValueOf(&zeroTestType{}), - expect: false, + name: "pointer-nonzero", + t: reflect.TypeOf((*zeroTestType)(nil)), + v: reflect.ValueOf(&zeroTestType{}), + want: false, }, { - name: "any-struct-zero", - t: reflect.TypeOf(any(nil)), - v: reflect.ValueOf(zeroTestType{}), - expect: true, + name: "any-struct-zero", + t: reflect.TypeOf(any(nil)), + v: reflect.ValueOf(zeroTestType{}), + want: true, }, { - name: "any-struct-nonzero", - t: reflect.TypeOf(any(nil)), - v: reflect.ValueOf(zeroTestType{value: 42}), - expect: false, + name: "any-struct-nonzero", + t: reflect.TypeOf(any(nil)), + v: reflect.ValueOf(zeroTestType{value: 42}), + want: false, }, { - name: "any-pointer-zero", - t: reflect.TypeOf(any(nil)), - v: reflect.ValueOf((*zeroTestType)(nil)), - expect: true, + name: "any-pointer-zero", + t: reflect.TypeOf(any(nil)), + v: reflect.ValueOf((*zeroTestType)(nil)), + want: true, }, { - name: "any-pointer-nonzero", - t: reflect.TypeOf(any(nil)), - v: reflect.ValueOf(&zeroTestType{}), - expect: false, + name: "any-pointer-nonzero", + t: reflect.TypeOf(any(nil)), + v: reflect.ValueOf(&zeroTestType{}), + want: false, }, { - name: "custom-structreceiver-zero-structvalue", - t: reflect.TypeOf(zeroTestTypeCustom{}), - v: reflect.ValueOf(zeroTestTypeCustom{value: 42}), - expect: true, + name: "custom-structreceiver-zero-structvalue", + t: reflect.TypeOf(zeroTestTypeCustom{}), + v: reflect.ValueOf(zeroTestTypeCustom{value: 42}), + want: true, }, { - name: "custom-structreceiver-nonzero-structvalue", - t: reflect.TypeOf(zeroTestTypeCustom{}), - v: reflect.ValueOf(zeroTestTypeCustom{value: 1}), - expect: false, + name: "custom-structreceiver-nonzero-structvalue", + t: reflect.TypeOf(zeroTestTypeCustom{}), + v: reflect.ValueOf(zeroTestTypeCustom{value: 1}), + want: false, }, { - name: "custom-structreceiver-zero-pointervalue", - t: reflect.TypeOf(zeroTestTypeCustom{}), - v: reflect.ValueOf(&zeroTestTypeCustom{value: 42}), - expect: true, + name: "custom-structreceiver-zero-pointervalue", + t: reflect.TypeOf(zeroTestTypeCustom{}), + v: reflect.ValueOf(&zeroTestTypeCustom{value: 42}), + want: true, }, { - name: "custom-structreceiver-nonzero-pointervalue", - t: reflect.TypeOf(zeroTestTypeCustom{}), - v: reflect.ValueOf(&zeroTestTypeCustom{value: 1}), - expect: false, + name: "custom-structreceiver-nonzero-pointervalue", + t: reflect.TypeOf(zeroTestTypeCustom{}), + v: reflect.ValueOf(&zeroTestTypeCustom{value: 1}), + want: false, }, { - name: "custom-structreceiver-zero-pointervalue", - t: reflect.TypeOf(&zeroTestTypeCustom{}), - v: reflect.ValueOf(&zeroTestTypeCustom{value: 42}), - expect: true, + name: "custom-structreceiver-zero-pointervalue", + t: reflect.TypeOf(&zeroTestTypeCustom{}), + v: reflect.ValueOf(&zeroTestTypeCustom{value: 42}), + want: true, }, { - name: "custom-structreceiver-nonzero-pointervalue", - t: reflect.TypeOf(&zeroTestTypeCustom{}), - v: reflect.ValueOf(&zeroTestTypeCustom{value: 1}), - expect: false, + name: "custom-structreceiver-nonzero-pointervalue", + t: reflect.TypeOf(&zeroTestTypeCustom{}), + v: reflect.ValueOf(&zeroTestTypeCustom{value: 1}), + want: false, }, { - name: "custom-structreceiver-zero-nil-pointervalue", - t: reflect.TypeOf(&zeroTestTypeCustom{}), - v: reflect.ValueOf((*zeroTestTypeCustom)(nil)), - expect: true, + name: "custom-structreceiver-zero-nil-pointervalue", + t: reflect.TypeOf(&zeroTestTypeCustom{}), + v: reflect.ValueOf((*zeroTestTypeCustom)(nil)), + want: true, }, { - name: "custom-pointerreceiver-zero-structvalue", - t: reflect.TypeOf(zeroTestTypeCustomPointer{}), - v: reflect.ValueOf(zeroTestTypeCustomPointer{value: 42}), - expect: true, + name: "custom-pointerreceiver-zero-structvalue", + t: reflect.TypeOf(zeroTestTypeCustomPointer{}), + v: reflect.ValueOf(zeroTestTypeCustomPointer{value: 42}), + want: true, }, { - name: "custom-pointerreceiver-nonzero-structvalue", - t: reflect.TypeOf(zeroTestTypeCustomPointer{}), - v: reflect.ValueOf(zeroTestTypeCustomPointer{value: 1}), - expect: false, + name: "custom-pointerreceiver-nonzero-structvalue", + t: reflect.TypeOf(zeroTestTypeCustomPointer{}), + v: reflect.ValueOf(zeroTestTypeCustomPointer{value: 1}), + want: false, }, { - name: "custom-pointerreceiver-zero-pointervalue", - t: reflect.TypeOf(&zeroTestTypeCustomPointer{}), - v: reflect.ValueOf(&zeroTestTypeCustomPointer{value: 42}), - expect: true, + name: "custom-pointerreceiver-zero-pointervalue", + t: reflect.TypeOf(&zeroTestTypeCustomPointer{}), + v: reflect.ValueOf(&zeroTestTypeCustomPointer{value: 42}), + want: true, }, { - name: "custom-pointerreceiver-nonzero-pointervalue", - t: reflect.TypeOf(&zeroTestTypeCustomPointer{}), - v: reflect.ValueOf(&zeroTestTypeCustomPointer{value: 1}), - expect: false, + name: "custom-pointerreceiver-nonzero-pointervalue", + t: reflect.TypeOf(&zeroTestTypeCustomPointer{}), + v: reflect.ValueOf(&zeroTestTypeCustomPointer{value: 1}), + want: false, }, { - name: "custom-interface-nil-pointer", - t: isZeroerType, - v: reflect.ValueOf((*zeroTestTypeCustom)(nil)), - expect: true, + name: "custom-interface-nil-pointer", + t: isZeroerType, + v: reflect.ValueOf((*zeroTestTypeCustom)(nil)), + want: true, }, { - name: "custom-interface-zero-structreceiver-pointer", - t: isZeroerType, - v: reflect.ValueOf(&zeroTestTypeCustom{value: 42}), - expect: true, + name: "custom-interface-zero-structreceiver-pointer", + t: isZeroerType, + v: reflect.ValueOf(&zeroTestTypeCustom{value: 42}), + want: true, }, { - name: "custom-interface-zero-structreceiver", - t: isZeroerType, - v: reflect.ValueOf(zeroStructZeroer), - expect: true, + name: "custom-interface-zero-structreceiver", + t: isZeroerType, + v: reflect.ValueOf(zeroStructZeroer), + want: true, }, { - name: "custom-interface-nonzero-struct", - t: isZeroerType, - v: reflect.ValueOf(&zeroTestTypeCustom{value: 1}), - expect: false, + name: "custom-interface-nonzero-struct", + t: isZeroerType, + v: reflect.ValueOf(&zeroTestTypeCustom{value: 1}), + want: false, }, { - name: "custom-interface-nil-pointerreceiver", - t: isZeroerType, - v: reflect.ValueOf((*zeroTestTypeCustomPointer)(nil)), - expect: true, + name: "custom-interface-nil-pointerreceiver", + t: isZeroerType, + v: reflect.ValueOf((*zeroTestTypeCustomPointer)(nil)), + want: true, }, { - name: "custom-interface-zero-pointerreceiver", - t: isZeroerType, - v: reflect.ValueOf(&zeroTestTypeCustomPointer{value: 42}), - expect: true, + name: "custom-interface-zero-pointerreceiver", + t: isZeroerType, + v: reflect.ValueOf(&zeroTestTypeCustomPointer{value: 42}), + want: true, }, { - name: "custom-interface-nonzero-pointerreceiver", - t: isZeroerType, - v: reflect.ValueOf(&zeroTestTypeCustomPointer{value: 1}), - expect: false, + name: "custom-interface-nonzero-pointerreceiver", + t: isZeroerType, + v: reflect.ValueOf(&zeroTestTypeCustomPointer{value: 1}), + want: false, }, } - for _, tc := range testcases { + for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { defer func() { if err := recover(); err != nil { @@ -2428,11 +2428,11 @@ func TestIsZero(t *testing.T) { } }() got, err := getIsZeroFunc(tc.t)(tc.v) - if tc.expectErr != (err != nil) { - t.Errorf("got err=%v, expected %v", err, tc.expectErr) + if tc.wantHasErr != (err != nil) { + t.Errorf("getIsZeroFunc() returned err=%v, wantErr=%v", err, tc.wantHasErr) } - if tc.expect != got { - t.Errorf("got %v, expected %v", got, tc.expect) + if tc.want != got { + t.Errorf("getIsZeroFunc() returned %v, want %v", got, tc.want) } }) } @@ -2466,7 +2466,7 @@ func TestJSONStdlibOmitZero(t *testing.T) { S string `json:"s,omitzero"` } - testcases := []struct { + testCases := []struct { name string stdlib bool obj any @@ -2513,7 +2513,7 @@ func TestJSONStdlibOmitZero(t *testing.T) { }) } - for _, tc := range testcases { + for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { reset() jsonStdlibSupportsOmitzero = tc.stdlib @@ -2521,7 +2521,7 @@ func TestJSONStdlibOmitZero(t *testing.T) { em, _ := EncOptions{}.EncMode() dm, _ := DecOptions{}.DecMode() - testRoundTrip(t, []roundTripTest{{tc.name, tc.obj, tc.want}}, em, dm) + testRoundTrip(t, []roundTripTestCase{{tc.name, tc.obj, tc.want}}, em, dm) }) } } @@ -3413,7 +3413,7 @@ func TestMarshalRawMessageValue(t *testing.T) { raw = RawMessage([]byte{0x01}) ) - tests := []struct { + testCases := []struct { obj any want []byte }{ @@ -3640,7 +3640,7 @@ func TestMarshalRawMessageValue(t *testing.T) { }, } - for _, tc := range tests { + for _, tc := range testCases { b, err := Marshal(tc.obj) if err != nil { t.Errorf("Marshal(%+v) returned error %v", tc.obj, err) @@ -3686,12 +3686,12 @@ func TestMarshalUnmarshalStructKeyAsInt(t *testing.T) { wantCborData []byte }{ { - name: "Zero value struct", + name: "zero value struct", obj: T{}, wantCborData: mustHexDecode("a0"), // {} }, { - name: "Initialized value struct", + name: "initialized value struct", obj: T{F1: 1, F2: 2, F3: 3}, wantCborData: mustHexDecode("a301012203613202"), // {1: 1, -3: 3, "2": 2} }, @@ -3728,6 +3728,9 @@ func TestMarshalStructKeyAsIntNumError(t *testing.T) { type T2 struct { F1 int `cbor:"-18446744073709551616,keyasint"` } + type T3 struct { + F1 int `cbor:"99999999999999999999,keyasint"` + } testCases := []struct { name string obj any @@ -3739,10 +3742,15 @@ func TestMarshalStructKeyAsIntNumError(t *testing.T) { wantErrorMsg: "cbor: failed to parse field name \"2.0\" to int", }, { - name: "out of range int as key", + name: "int key < math.MinInt", obj: T2{}, wantErrorMsg: "cbor: failed to parse field name \"-18446744073709551616\" to int", }, + { + name: "int key > math.MaxInt", + obj: T3{}, + wantErrorMsg: "cbor: failed to parse field name \"99999999999999999999\" to int", + }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { @@ -3779,17 +3787,17 @@ func TestMarshalUnmarshalStructToArray(t *testing.T) { wantCborData []byte }{ { - name: "Zero value struct (test omitempty)", + name: "zero value struct (test omitempty)", obj: T{}, wantCborData: mustHexDecode("8500a000f6f6"), // [0, {}, 0, nil, nil] }, { - name: "Initialized struct", + name: "initialized struct", obj: T{A: 24, B: T1{M: 1}, T1: T1{M: 2}, T2: &T2{N: 3, O: 4}}, wantCborData: mustHexDecode("851818a1614d01020304"), // [24, {M: 1}, 2, 3, 4] }, { - name: "Null pointer to embedded struct", + name: "null pointer to embedded struct", obj: T{A: 24, B: T1{M: 1}, T1: T1{M: 2}}, wantCborData: mustHexDecode("851818a1614d0102f6f6"), // [24, {M: 1}, 2, nil, nil] }, @@ -3854,12 +3862,12 @@ func TestMapSort(t *testing.T) { wantCborData []byte }{ { - name: "Length first sort", + name: "length first sort", opts: EncOptions{Sort: SortLengthFirst}, wantCborData: lenFirstSortedCborData, }, { - name: "Bytewise sort", + name: "bytewise sort", opts: EncOptions{Sort: SortBytewiseLexical}, wantCborData: bytewiseSortedCborData, }, @@ -3874,7 +3882,7 @@ func TestMapSort(t *testing.T) { wantCborData: bytewiseSortedCborData, }, { - name: "Core deterministic sort", + name: "core deterministic sort", opts: EncOptions{Sort: SortCoreDeterministic}, wantCborData: bytewiseSortedCborData, }, @@ -3916,22 +3924,22 @@ func TestStructSort(t *testing.T) { wantCborData []byte }{ { - name: "No sort", + name: "no sort", opts: EncOptions{}, wantCborData: unsortedCborData, }, { - name: "No sort", + name: "no sort", opts: EncOptions{Sort: SortNone}, wantCborData: unsortedCborData, }, { - name: "Length first sort", + name: "length first sort", opts: EncOptions{Sort: SortLengthFirst}, wantCborData: lenFirstSortedCborData, }, { - name: "Bytewise sort", + name: "bytewise sort", opts: EncOptions{Sort: SortBytewiseLexical}, wantCborData: bytewiseSortedCborData, }, @@ -3946,7 +3954,7 @@ func TestStructSort(t *testing.T) { wantCborData: bytewiseSortedCborData, }, { - name: "Core deterministic sort", + name: "core deterministic sort", opts: EncOptions{Sort: SortCoreDeterministic}, wantCborData: bytewiseSortedCborData, }, @@ -4016,7 +4024,7 @@ func TestTypeAlias(t *testing.T) { //nolint:dupl,unconvert type myIntArray = [4]int type myMapIntInt = map[int]int - testCases := []roundTripTest{ + testCases := []roundTripTestCase{ { name: "bool alias", obj: myBool(true), @@ -4139,7 +4147,7 @@ func TestNewTypeWithBuiltinUnderlyingType(t *testing.T) { //nolint:dupl type myIntArray [4]int type myMapIntInt map[int]int - testCases := []roundTripTest{ + testCases := []roundTripTestCase{ { name: "bool alias", obj: myBool(true), @@ -4250,77 +4258,77 @@ func TestShortestFloat16(t *testing.T) { }{ // Data from RFC 7049 appendix A { - name: "Shrink to float16", + name: "shrink to float16", f64: 0.0, wantCborData: mustHexDecode("f90000"), }, { - name: "Shrink to float16", + name: "shrink to float16", f64: 1.0, wantCborData: mustHexDecode("f93c00"), }, { - name: "Shrink to float16", + name: "shrink to float16", f64: 1.5, wantCborData: mustHexDecode("f93e00"), }, { - name: "Shrink to float16", + name: "shrink to float16", f64: 65504.0, wantCborData: mustHexDecode("f97bff"), }, { - name: "Shrink to float16", + name: "shrink to float16", f64: 5.960464477539063e-08, wantCborData: mustHexDecode("f90001"), }, { - name: "Shrink to float16", + name: "shrink to float16", f64: 6.103515625e-05, wantCborData: mustHexDecode("f90400"), }, { - name: "Shrink to float16", + name: "shrink to float16", f64: -4.0, wantCborData: mustHexDecode("f9c400"), }, // Data from https://en.wikipedia.org/wiki/Half-precision_floating-point_format { - name: "Shrink to float16", + name: "shrink to float16", f64: 0.333251953125, wantCborData: mustHexDecode("f93555"), }, // Data from 7049bis 4.2.1 and 5.5 { - name: "Shrink to float16", + name: "shrink to float16", f64: 5.5, wantCborData: mustHexDecode("f94580"), }, // Data from RFC 7049 appendix A { - name: "Shrink to float32", + name: "shrink to float32", f64: 100000.0, wantCborData: mustHexDecode("fa47c35000"), }, { - name: "Shrink to float32", + name: "shrink to float32", f64: 3.4028234663852886e+38, wantCborData: mustHexDecode("fa7f7fffff"), }, // Data from 7049bis 4.2.1 and 5.5 { - name: "Shrink to float32", + name: "shrink to float32", f64: 5555.5, wantCborData: mustHexDecode("fa45ad9c00"), }, { - name: "Shrink to float32", + name: "shrink to float32", f64: 1000000.5, wantCborData: mustHexDecode("fa49742408"), }, // Data from RFC 7049 appendix A { - name: "Shrink to float64", + name: "shrink to float64", f64: 1.0e+300, wantCborData: mustHexDecode("fb7e37e43c8800759c"), }, @@ -4638,7 +4646,7 @@ func TestInfConvert(t *testing.T) { } want := &UnsupportedValueError{msg: "floating-point infinity"} if _, got := em.Marshal(tc.v); !reflect.DeepEqual(want, got) { - t.Errorf("expected Marshal(%v) to return error: %v, got: %v", tc.v, want, got) + t.Errorf("Marshal(%v) returned error %v, want %v", tc.v, got, want) } }) } @@ -5315,7 +5323,7 @@ func TestNaNConvert(t *testing.T) { } want := &UnsupportedValueError{msg: "floating-point NaN"} if _, got := em.Marshal(tc.v); !reflect.DeepEqual(want, got) { - t.Errorf("expected Marshal(%v) to return error: %v, got: %v", tc.v, want, got) + t.Errorf("Marshal(%v) returned error %v, want %v", tc.v, got, want) } }) } @@ -5745,7 +5753,7 @@ func TestEncModeInvalidFieldNameMode(t *testing.T) { } func TestEncIndefiniteLengthOption(t *testing.T) { - // Default option allows indefinite length items + // Default option allows indefinite-length items var buf bytes.Buffer enc := NewEncoder(&buf) if err := enc.StartIndefiniteByteString(); err != nil { @@ -6024,10 +6032,10 @@ func TestStructWithSimpleValueFields(t *testing.T) { em, _ := EncOptions{}.EncMode() dm, _ := DecOptions{}.DecMode() - tests := []roundTripTest{ + testCases := []roundTripTestCase{ {"default values", v1, want1}, {"non-default values", v2, want2}} - testRoundTrip(t, tests, em, dm) + testRoundTrip(t, testCases, em, dm) } func TestMapWithSimpleValueKey(t *testing.T) { @@ -6277,13 +6285,13 @@ func TestMarshalerReturnsDisallowedCBORData(t *testing.T) { wantErrorMsg string }{ { - name: "enc mode forbids indefinite length, data has indefinite length", + name: "enc mode forbids indefinite-length, data has indefinite-length", encOpts: EncOptions{IndefLength: IndefLengthForbidden}, value: marshaler{data: mustHexDecode("5f42010243030405ff")}, wantErrorMsg: "cbor: error calling MarshalCBOR for type cbor.marshaler: cbor: indefinite-length byte string isn't allowed", }, { - name: "enc mode allows indefinite length, data has indefinite length", + name: "enc mode allows indefinite-length, data has indefinite-length", encOpts: EncOptions{IndefLength: IndefLengthAllowed}, value: marshaler{data: mustHexDecode("5f42010243030405ff")}, }, @@ -6451,28 +6459,28 @@ func TestInvalidByteArray(t *testing.T) { func TestMarshalByteArrayMode(t *testing.T) { for _, tc := range []struct { - name string - opts EncOptions - in any - expected []byte + name string + opts EncOptions + in any + want []byte }{ { - name: "byte array treated as byte slice by default", - opts: EncOptions{}, - in: [1]byte{}, - expected: []byte{0x41, 0x00}, + name: "byte array treated as byte slice by default", + opts: EncOptions{}, + in: [1]byte{}, + want: []byte{0x41, 0x00}, }, { - name: "byte array treated as byte slice with ByteArrayAsByteSlice", - opts: EncOptions{ByteArray: ByteArrayToByteSlice}, - in: [1]byte{}, - expected: []byte{0x41, 0x00}, + name: "byte array treated as byte slice with ByteArrayAsByteSlice", + opts: EncOptions{ByteArray: ByteArrayToByteSlice}, + in: [1]byte{}, + want: []byte{0x41, 0x00}, }, { - name: "byte array treated as array of integers with ByteArrayToArray", - opts: EncOptions{ByteArray: ByteArrayToArray}, - in: [1]byte{}, - expected: []byte{0x81, 0x00}, + name: "byte array treated as array of integers with ByteArrayToArray", + opts: EncOptions{ByteArray: ByteArrayToArray}, + in: [1]byte{}, + want: []byte{0x81, 0x00}, }, } { t.Run(tc.name, func(t *testing.T) { @@ -6486,8 +6494,8 @@ func TestMarshalByteArrayMode(t *testing.T) { t.Fatal(err) } - if !bytes.Equal(out, tc.expected) { - t.Errorf("unexpected output, got 0x%x want 0x%x", out, tc.expected) + if !bytes.Equal(out, tc.want) { + t.Errorf("unexpected output, got 0x%x want 0x%x", out, tc.want) } }) } @@ -6501,69 +6509,69 @@ func TestMarshalByteSliceMode(t *testing.T) { } for _, tc := range []struct { - name string - tags TagSet - opts EncOptions - in any - expected []byte + name string + tags TagSet + opts EncOptions + in any + want []byte }{ { - name: "byte slice marshals to byte string by default", - opts: EncOptions{}, - in: []byte{0xbb}, - expected: []byte{0x41, 0xbb}, + name: "byte slice marshals to byte string by default", + opts: EncOptions{}, + in: []byte{0xbb}, + want: []byte{0x41, 0xbb}, }, { - name: "byte slice marshals to byte string by with ByteSliceToByteString", - opts: EncOptions{ByteSliceLaterFormat: ByteSliceLaterFormatNone}, - in: []byte{0xbb}, - expected: []byte{0x41, 0xbb}, + name: "byte slice marshals to byte string by with ByteSliceToByteString", + opts: EncOptions{ByteSliceLaterFormat: ByteSliceLaterFormatNone}, + in: []byte{0xbb}, + want: []byte{0x41, 0xbb}, }, { - name: "byte slice marshaled to byte string enclosed in base64url expected encoding tag", - opts: EncOptions{ByteSliceLaterFormat: ByteSliceLaterFormatBase64URL}, - in: []byte{0xbb}, - expected: []byte{0xd5, 0x41, 0xbb}, + name: "byte slice marshaled to byte string enclosed in base64url expected encoding tag", + opts: EncOptions{ByteSliceLaterFormat: ByteSliceLaterFormatBase64URL}, + in: []byte{0xbb}, + want: []byte{0xd5, 0x41, 0xbb}, }, { - name: "byte slice marshaled to byte string enclosed in base64 expected encoding tag", - opts: EncOptions{ByteSliceLaterFormat: ByteSliceLaterFormatBase64}, - in: []byte{0xbb}, - expected: []byte{0xd6, 0x41, 0xbb}, + name: "byte slice marshaled to byte string enclosed in base64 expected encoding tag", + opts: EncOptions{ByteSliceLaterFormat: ByteSliceLaterFormatBase64}, + in: []byte{0xbb}, + want: []byte{0xd6, 0x41, 0xbb}, }, { - name: "byte slice marshaled to byte string enclosed in base16 expected encoding tag", - opts: EncOptions{ByteSliceLaterFormat: ByteSliceLaterFormatBase16}, - in: []byte{0xbb}, - expected: []byte{0xd7, 0x41, 0xbb}, + name: "byte slice marshaled to byte string enclosed in base16 expected encoding tag", + opts: EncOptions{ByteSliceLaterFormat: ByteSliceLaterFormatBase16}, + in: []byte{0xbb}, + want: []byte{0xd7, 0x41, 0xbb}, }, { - name: "user-registered tag numbers are encoded with no expected encoding tag", - tags: ts, - opts: EncOptions{ByteSliceLaterFormat: ByteSliceLaterFormatNone}, - in: namedByteSlice{0xbb}, - expected: []byte{0xd8, 0xcc, 0x41, 0xbb}, + name: "user-registered tag numbers are encoded with no expected encoding tag", + tags: ts, + opts: EncOptions{ByteSliceLaterFormat: ByteSliceLaterFormatNone}, + in: namedByteSlice{0xbb}, + want: []byte{0xd8, 0xcc, 0x41, 0xbb}, }, { - name: "user-registered tag numbers are encoded after base64url expected encoding tag", - tags: ts, - opts: EncOptions{ByteSliceLaterFormat: ByteSliceLaterFormatBase64URL}, - in: namedByteSlice{0xbb}, - expected: []byte{0xd5, 0xd8, 0xcc, 0x41, 0xbb}, + name: "user-registered tag numbers are encoded after base64url expected encoding tag", + tags: ts, + opts: EncOptions{ByteSliceLaterFormat: ByteSliceLaterFormatBase64URL}, + in: namedByteSlice{0xbb}, + want: []byte{0xd5, 0xd8, 0xcc, 0x41, 0xbb}, }, { - name: "user-registered tag numbers are encoded after base64 expected encoding tag", - tags: ts, - opts: EncOptions{ByteSliceLaterFormat: ByteSliceLaterFormatBase64}, - in: namedByteSlice{0xbb}, - expected: []byte{0xd6, 0xd8, 0xcc, 0x41, 0xbb}, + name: "user-registered tag numbers are encoded after base64 expected encoding tag", + tags: ts, + opts: EncOptions{ByteSliceLaterFormat: ByteSliceLaterFormatBase64}, + in: namedByteSlice{0xbb}, + want: []byte{0xd6, 0xd8, 0xcc, 0x41, 0xbb}, }, { - name: "user-registered tag numbers are encoded after base16 expected encoding tag", - tags: ts, - opts: EncOptions{ByteSliceLaterFormat: ByteSliceLaterFormatBase16}, - in: namedByteSlice{0xbb}, - expected: []byte{0xd7, 0xd8, 0xcc, 0x41, 0xbb}, + name: "user-registered tag numbers are encoded after base16 expected encoding tag", + tags: ts, + opts: EncOptions{ByteSliceLaterFormat: ByteSliceLaterFormatBase16}, + in: namedByteSlice{0xbb}, + want: []byte{0xd7, 0xd8, 0xcc, 0x41, 0xbb}, }, } { t.Run(tc.name, func(t *testing.T) { @@ -6585,8 +6593,8 @@ func TestMarshalByteSliceMode(t *testing.T) { t.Fatal(err) } - if !bytes.Equal(out, tc.expected) { - t.Errorf("unexpected output, got 0x%x want 0x%x", out, tc.expected) + if !bytes.Equal(out, tc.want) { + t.Errorf("unexpected output, got 0x%x want 0x%x", out, tc.want) } }) } @@ -7084,6 +7092,59 @@ func TestJSONMarshalerTranscoder(t *testing.T) { } } +func TestMarshalerErrorUnwrap(t *testing.T) { + innerErr := errors.New("MarshalCBOR: error") + v := marshalCBORError(innerErr.Error()) + _, err := Marshal(v) + if err == nil { + t.Fatal("Marshal() didn't return an error") + } + var me *MarshalerError + if errors.As(err, &me) { + if unwrapped := me.Unwrap(); unwrapped == nil || unwrapped.Error() != innerErr.Error() { + t.Errorf("MarshalerError.Unwrap() = %v, want error with message %q", unwrapped, innerErr.Error()) + } + } + // The marshalCBORError type returns the raw error, not a MarshalerError, + // so also test Unwrap directly by constructing a MarshalerError. + me2 := &MarshalerError{typ: reflect.TypeOf(0), err: innerErr} + if unwrapped := me2.Unwrap(); unwrapped != innerErr { + t.Errorf("MarshalerError.Unwrap() = %v, want %v", unwrapped, innerErr) + } +} + +func TestTranscodeErrorUnwrap(t *testing.T) { + innerErr := errors.New("transcode failed") + te := TranscodeError{err: innerErr, rtype: reflect.TypeOf(0), sourceFormat: "json", targetFormat: "cbor"} + if unwrapped := te.Unwrap(); unwrapped != innerErr { + t.Errorf("TranscodeError.Unwrap() = %v, want %v", unwrapped, innerErr) + } +} + +func TestUnsupportedValueErrorMessage(t *testing.T) { + err := &UnsupportedValueError{msg: "floating-point infinity"} + want := "cbor: unsupported value: floating-point infinity" + if got := err.Error(); got != want { + t.Errorf("UnsupportedValueError.Error() = %q, want %q", got, want) + } +} + +func TestMarshalToBufferNilBuffer(t *testing.T) { + // Test package-level function + if err := MarshalToBuffer(42, nil); err == nil { + t.Error("MarshalToBuffer(42, nil) didn't return an error") + } + + // Test UserBufferEncMode method + bem, err := EncOptions{}.UserBufferEncMode() + if err != nil { + t.Fatal(err) + } + if err := bem.MarshalToBuffer(42, nil); err == nil { + t.Error("UserBufferEncMode.MarshalToBuffer(42, nil) didn't return an error") + } +} + func mustParseTime(layout string, value string) time.Time { tm, err := time.Parse(layout, value) if err != nil { diff --git a/example_test.go b/example_test.go index 2176f955..f9c4139b 100644 --- a/example_test.go +++ b/example_test.go @@ -184,11 +184,11 @@ func ExampleEncoder() { } // ExampleEncoder_indefiniteLengthByteString encodes a stream of definite -// length byte string ("chunks") as an indefinite length byte string. +// length byte string ("chunks") as an indefinite-length byte string. func ExampleEncoder_indefiniteLengthByteString() { var buf bytes.Buffer encoder := cbor.NewEncoder(&buf) - // Start indefinite length byte string encoding. + // Start indefinite-length byte string encoding. if err := encoder.StartIndefiniteByteString(); err != nil { fmt.Println("error:", err) } @@ -200,7 +200,7 @@ func ExampleEncoder_indefiniteLengthByteString() { if err := encoder.Encode([3]byte{3, 4, 5}); err != nil { fmt.Println("error:", err) } - // Close indefinite length byte string. + // Close indefinite-length byte string. if err := encoder.EndIndefinite(); err != nil { fmt.Println("error:", err) } @@ -210,11 +210,11 @@ func ExampleEncoder_indefiniteLengthByteString() { } // ExampleEncoder_indefiniteLengthTextString encodes a stream of definite -// length text string ("chunks") as an indefinite length text string. +// length text string ("chunks") as an indefinite-length text string. func ExampleEncoder_indefiniteLengthTextString() { var buf bytes.Buffer encoder := cbor.NewEncoder(&buf) - // Start indefinite length text string encoding. + // Start indefinite-length text string encoding. if err := encoder.StartIndefiniteTextString(); err != nil { fmt.Println("error:", err) } @@ -226,7 +226,7 @@ func ExampleEncoder_indefiniteLengthTextString() { if err := encoder.Encode("ming"); err != nil { fmt.Println("error:", err) } - // Close indefinite length text string. + // Close indefinite-length text string. if err := encoder.EndIndefinite(); err != nil { fmt.Println("error:", err) } @@ -236,11 +236,11 @@ func ExampleEncoder_indefiniteLengthTextString() { } // ExampleEncoder_indefiniteLengthArray encodes a stream of elements as an -// indefinite length array. Encoder supports nested indefinite length values. +// indefinite-length array. Encoder supports nested indefinite-length values. func ExampleEncoder_indefiniteLengthArray() { var buf bytes.Buffer enc := cbor.NewEncoder(&buf) - // Start indefinite length array encoding. + // Start indefinite-length array encoding. if err := enc.StartIndefiniteArray(); err != nil { fmt.Println("error:", err) } @@ -252,7 +252,7 @@ func ExampleEncoder_indefiniteLengthArray() { if err := enc.Encode([]int{2, 3}); err != nil { fmt.Println("error:", err) } - // Start a nested indefinite length array as array element. + // Start a nested indefinite-length array as array element. if err := enc.StartIndefiniteArray(); err != nil { fmt.Println("error:", err) } @@ -264,11 +264,11 @@ func ExampleEncoder_indefiniteLengthArray() { if err := enc.Encode(5); err != nil { fmt.Println("error:", err) } - // Close nested indefinite length array. + // Close nested indefinite-length array. if err := enc.EndIndefinite(); err != nil { fmt.Println("error:", err) } - // Close outer indefinite length array. + // Close outer indefinite-length array. if err := enc.EndIndefinite(); err != nil { fmt.Println("error:", err) } @@ -278,7 +278,7 @@ func ExampleEncoder_indefiniteLengthArray() { } // ExampleEncoder_indefiniteLengthMap encodes a stream of elements as an -// indefinite length map. Encoder supports nested indefinite length values. +// indefinite-length map. Encoder supports nested indefinite-length values. func ExampleEncoder_indefiniteLengthMap() { var buf bytes.Buffer em, err := cbor.EncOptions{Sort: cbor.SortCanonical}.EncMode() @@ -286,7 +286,7 @@ func ExampleEncoder_indefiniteLengthMap() { fmt.Println("error:", err) } enc := em.NewEncoder(&buf) - // Start indefinite length map encoding. + // Start indefinite-length map encoding. if err := enc.StartIndefiniteMap(); err != nil { fmt.Println("error:", err) } @@ -302,7 +302,7 @@ func ExampleEncoder_indefiniteLengthMap() { if err := enc.Encode("b"); err != nil { fmt.Println("error:", err) } - // Start an indefinite length array as map value. + // Start an indefinite-length array as map value. if err := enc.StartIndefiniteArray(); err != nil { fmt.Println("error:", err) } @@ -314,11 +314,11 @@ func ExampleEncoder_indefiniteLengthMap() { if err := enc.Encode(3); err != nil { fmt.Println("error:", err) } - // Close indefinite length array. + // Close indefinite-length array. if err := enc.EndIndefinite(); err != nil { fmt.Println("error:", err) } - // Close indefinite length map. + // Close indefinite-length map. if err := enc.EndIndefinite(); err != nil { fmt.Println("error:", err) } diff --git a/json_test.go b/json_test.go index 67352eca..59dfc959 100644 --- a/json_test.go +++ b/json_test.go @@ -35,7 +35,7 @@ func TestStdlibJSONCompatibility(t *testing.T) { t.Fatal(err) } - for _, tc := range []struct { + testCases := []struct { name string original any ifaceEqual bool // require equal intermediate interface{} values from both protocols @@ -50,7 +50,8 @@ func TestStdlibJSONCompatibility(t *testing.T) { original: [11]byte{'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd'}, ifaceEqual: false, // encoding/json decodes the array elements to float64 }, - } { + } + for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { t.Logf("original: %#v", tc.original) diff --git a/simplevalue_test.go b/simplevalue_test.go index 02ac7a4a..c0935d6b 100644 --- a/simplevalue_test.go +++ b/simplevalue_test.go @@ -55,90 +55,90 @@ func TestUnmarshalSimpleValue(t *testing.T) { func TestUnmarshalSimpleValueOnBadData(t *testing.T) { testCases := []struct { - name string - data []byte - errMsg string + name string + data []byte + wantErrorMsg string }{ // Empty data { - name: "nil data", - data: nil, - errMsg: io.EOF.Error(), + name: "nil data", + data: nil, + wantErrorMsg: io.EOF.Error(), }, { - name: "empty data", - data: []byte{}, - errMsg: io.EOF.Error(), + name: "empty data", + data: []byte{}, + wantErrorMsg: io.EOF.Error(), }, // Wrong CBOR types { - name: "uint type", - data: mustHexDecode("01"), - errMsg: "cbor: cannot unmarshal positive integer into Go value of type SimpleValue", + name: "uint type", + data: mustHexDecode("01"), + wantErrorMsg: "cbor: cannot unmarshal positive integer into Go value of type SimpleValue", }, { - name: "int type", - data: mustHexDecode("20"), - errMsg: "cbor: cannot unmarshal negative integer into Go value of type SimpleValue", + name: "int type", + data: mustHexDecode("20"), + wantErrorMsg: "cbor: cannot unmarshal negative integer into Go value of type SimpleValue", }, { - name: "byte string type", - data: mustHexDecode("40"), - errMsg: "cbor: cannot unmarshal byte string into Go value of type SimpleValue", + name: "byte string type", + data: mustHexDecode("40"), + wantErrorMsg: "cbor: cannot unmarshal byte string into Go value of type SimpleValue", }, { - name: "string type", - data: mustHexDecode("60"), - errMsg: "cbor: cannot unmarshal UTF-8 text string into Go value of type SimpleValue", + name: "string type", + data: mustHexDecode("60"), + wantErrorMsg: "cbor: cannot unmarshal UTF-8 text string into Go value of type SimpleValue", }, { - name: "array type", - data: mustHexDecode("80"), - errMsg: "cbor: cannot unmarshal array into Go value of type SimpleValue", + name: "array type", + data: mustHexDecode("80"), + wantErrorMsg: "cbor: cannot unmarshal array into Go value of type SimpleValue", }, { - name: "map type", - data: mustHexDecode("a0"), - errMsg: "cbor: cannot unmarshal map into Go value of type SimpleValue", + name: "map type", + data: mustHexDecode("a0"), + wantErrorMsg: "cbor: cannot unmarshal map into Go value of type SimpleValue", }, { - name: "tag type", - data: mustHexDecode("c074323031332d30332d32315432303a30343a30305a"), - errMsg: "cbor: cannot unmarshal tag into Go value of type SimpleValue", + name: "tag type", + data: mustHexDecode("c074323031332d30332d32315432303a30343a30305a"), + wantErrorMsg: "cbor: cannot unmarshal tag into Go value of type SimpleValue", }, { - name: "float type", - data: mustHexDecode("f90000"), - errMsg: "cbor: cannot unmarshal primitives into Go value of type SimpleValue", + name: "float type", + data: mustHexDecode("f90000"), + wantErrorMsg: "cbor: cannot unmarshal primitives into Go value of type SimpleValue", }, // Truncated CBOR data { - name: "truncated head", - data: mustHexDecode("18"), - errMsg: io.ErrUnexpectedEOF.Error(), + name: "truncated head", + data: mustHexDecode("18"), + wantErrorMsg: io.ErrUnexpectedEOF.Error(), }, // Truncated CBOR simple value { - name: "truncated simple value", - data: mustHexDecode("f8"), - errMsg: io.ErrUnexpectedEOF.Error(), + name: "truncated simple value", + data: mustHexDecode("f8"), + wantErrorMsg: io.ErrUnexpectedEOF.Error(), }, // Invalid simple value { - name: "invalid simple value", - data: mustHexDecode("f800"), - errMsg: "cbor: invalid simple value 0 for type primitives", + name: "invalid simple value", + data: mustHexDecode("f800"), + wantErrorMsg: "cbor: invalid simple value 0 for type primitives", }, // Extraneous CBOR data { - name: "extraneous data", - data: mustHexDecode("f4f5"), - errMsg: "cbor: 1 bytes of extraneous data starting at index 1", + name: "extraneous data", + data: mustHexDecode("f4f5"), + wantErrorMsg: "cbor: 1 bytes of extraneous data starting at index 1", }, } @@ -152,8 +152,8 @@ func TestUnmarshalSimpleValueOnBadData(t *testing.T) { if err == nil { t.Errorf("UnmarshalCBOR(%x) didn't return error", tc.data) } - if !strings.HasPrefix(err.Error(), tc.errMsg) { - t.Errorf("UnmarshalCBOR(%x) returned error %q, want %q", tc.data, err.Error(), tc.errMsg) + if !strings.HasPrefix(err.Error(), tc.wantErrorMsg) { + t.Errorf("UnmarshalCBOR(%x) returned error %q, want %q", tc.data, err.Error(), tc.wantErrorMsg) } } // Test Unmarshal(data, *SimpleValue), which calls SimpleValue.unmarshalCBOR() under the hood @@ -164,8 +164,8 @@ func TestUnmarshalSimpleValueOnBadData(t *testing.T) { if err == nil { t.Errorf("Unmarshal(%x) didn't return error", tc.data) } - if !strings.HasPrefix(err.Error(), tc.errMsg) { - t.Errorf("Unmarshal(%x) returned error %q, want %q", tc.data, err.Error(), tc.errMsg) + if !strings.HasPrefix(err.Error(), tc.wantErrorMsg) { + t.Errorf("Unmarshal(%x) returned error %q, want %q", tc.data, err.Error(), tc.wantErrorMsg) } } }) diff --git a/stream.go b/stream.go index 39768029..8d726df9 100644 --- a/stream.go +++ b/stream.go @@ -204,35 +204,35 @@ func (enc *Encoder) Encode(v any) error { return err } -// StartIndefiniteByteString starts byte string encoding of indefinite length. +// StartIndefiniteByteString starts indefinite-length byte string encoding. // Subsequent calls of (*Encoder).Encode() encodes definite length byte strings // ("chunks") as one contiguous string until EndIndefinite is called. func (enc *Encoder) StartIndefiniteByteString() error { return enc.startIndefinite(cborTypeByteString) } -// StartIndefiniteTextString starts text string encoding of indefinite length. +// StartIndefiniteTextString starts indefinite-length text string encoding. // Subsequent calls of (*Encoder).Encode() encodes definite length text strings // ("chunks") as one contiguous string until EndIndefinite is called. func (enc *Encoder) StartIndefiniteTextString() error { return enc.startIndefinite(cborTypeTextString) } -// StartIndefiniteArray starts array encoding of indefinite length. +// StartIndefiniteArray starts indefinite-length array encoding. // Subsequent calls of (*Encoder).Encode() encodes elements of the array // until EndIndefinite is called. func (enc *Encoder) StartIndefiniteArray() error { return enc.startIndefinite(cborTypeArray) } -// StartIndefiniteMap starts map encoding of indefinite length. +// StartIndefiniteMap starts indefinite-length map encoding. // Subsequent calls of (*Encoder).Encode() encodes elements of the map // until EndIndefinite is called. func (enc *Encoder) StartIndefiniteMap() error { return enc.startIndefinite(cborTypeMap) } -// EndIndefinite closes last opened indefinite length value. +// EndIndefinite closes last opened indefinite-length value. func (enc *Encoder) EndIndefinite() error { if len(enc.indefTypes) == 0 { return errors.New("cbor: cannot encode \"break\" code outside indefinite length values") @@ -244,18 +244,22 @@ func (enc *Encoder) EndIndefinite() error { return err } -var cborIndefHeader = map[cborType][]byte{ - cborTypeByteString: {cborByteStringWithIndefiniteLengthHead}, - cborTypeTextString: {cborTextStringWithIndefiniteLengthHead}, - cborTypeArray: {cborArrayWithIndefiniteLengthHead}, - cborTypeMap: {cborMapWithIndefiniteLengthHead}, -} - func (enc *Encoder) startIndefinite(typ cborType) error { if enc.em.indefLength == IndefLengthForbidden { return &IndefiniteLengthError{typ} } - _, err := enc.w.Write(cborIndefHeader[typ]) + var head byte + switch typ { + case cborTypeByteString: + head = cborByteStringWithIndefiniteLengthHead + case cborTypeTextString: + head = cborTextStringWithIndefiniteLengthHead + case cborTypeArray: + head = cborArrayWithIndefiniteLengthHead + case cborTypeMap: + head = cborMapWithIndefiniteLengthHead + } + _, err := enc.w.Write([]byte{head}) if err == nil { enc.indefTypes = append(enc.indefTypes, typ) } diff --git a/stream_test.go b/stream_test.go index ddfc5fcb..f6827ca5 100644 --- a/stream_test.go +++ b/stream_test.go @@ -17,7 +17,7 @@ import ( func TestDecoder(t *testing.T) { var buf bytes.Buffer for i := 0; i < 5; i++ { - for _, tc := range unmarshalTests { + for _, tc := range unmarshalTestCases { buf.Write(tc.data) } } @@ -45,7 +45,7 @@ func TestDecoder(t *testing.T) { decoder := NewDecoder(tc.reader) bytesRead := 0 for i := 0; i < 5; i++ { - for _, tc := range unmarshalTests { + for _, tc := range unmarshalTestCases { var v any if err := decoder.Decode(&v); err != nil { t.Fatalf("Decode() returned error %v", err) @@ -81,7 +81,7 @@ func TestDecoder(t *testing.T) { func TestDecoderUnmarshalTypeError(t *testing.T) { var buf bytes.Buffer for i := 0; i < 5; i++ { - for _, tc := range unmarshalTests { + for _, tc := range unmarshalTestCases { for j := 0; j < len(tc.wrongTypes)*2; j++ { buf.Write(tc.data) } @@ -111,7 +111,7 @@ func TestDecoderUnmarshalTypeError(t *testing.T) { decoder := NewDecoder(tc.reader) bytesRead := 0 for i := 0; i < 5; i++ { - for _, tc := range unmarshalTests { + for _, tc := range unmarshalTestCases { for _, typ := range tc.wrongTypes { v := reflect.New(typ) if err := decoder.Decode(v.Interface()); err == nil { @@ -159,7 +159,7 @@ func TestDecoderUnmarshalTypeError(t *testing.T) { func TestDecoderUnexpectedEOFError(t *testing.T) { var buf bytes.Buffer - for _, tc := range unmarshalTests { + for _, tc := range unmarshalTestCases { buf.Write(tc.data) } buf.Truncate(buf.Len() - 1) @@ -187,8 +187,8 @@ func TestDecoderUnexpectedEOFError(t *testing.T) { decoder := NewDecoder(tc.reader) bytesRead := 0 - for i := 0; i < len(unmarshalTests)-1; i++ { - tc := unmarshalTests[i] + for i := 0; i < len(unmarshalTestCases)-1; i++ { + tc := unmarshalTestCases[i] var v any if err := decoder.Decode(&v); err != nil { t.Fatalf("Decode() returned error %v", err) @@ -222,7 +222,7 @@ func TestDecoderUnexpectedEOFError(t *testing.T) { func TestDecoderReadError(t *testing.T) { var buf bytes.Buffer - for _, tc := range unmarshalTests { + for _, tc := range unmarshalTestCases { buf.Write(tc.data) } buf.Truncate(buf.Len() - 1) @@ -251,8 +251,8 @@ func TestDecoderReadError(t *testing.T) { t.Run(tc.name, func(t *testing.T) { decoder := NewDecoder(tc.reader) bytesRead := 0 - for i := 0; i < len(unmarshalTests)-1; i++ { - tc := unmarshalTests[i] + for i := 0; i < len(unmarshalTestCases)-1; i++ { + tc := unmarshalTestCases[i] var v any if err := decoder.Decode(&v); err != nil { t.Fatalf("Decode() returned error %v", err) @@ -293,7 +293,7 @@ func TestDecoderNoData(t *testing.T) { wantErr error }{ { - name: "byte.Buffer", + name: "bytes.Buffer", reader: new(bytes.Buffer), wantErr: io.EOF, }, @@ -383,7 +383,7 @@ func TestDecoderInvalidData(t *testing.T) { func TestDecoderSkip(t *testing.T) { var buf bytes.Buffer for i := 0; i < 5; i++ { - for _, tc := range unmarshalTests { + for _, tc := range unmarshalTestCases { buf.Write(tc.data) } } @@ -411,7 +411,7 @@ func TestDecoderSkip(t *testing.T) { decoder := NewDecoder(tc.reader) bytesRead := 0 for i := 0; i < 5; i++ { - for _, tc := range unmarshalTests { + for _, tc := range unmarshalTestCases { if err := decoder.Skip(); err != nil { t.Fatalf("Skip() returned error %v", err) } @@ -434,7 +434,7 @@ func TestDecoderSkip(t *testing.T) { func TestDecoderSkipInvalidDataError(t *testing.T) { var buf bytes.Buffer - for _, tc := range unmarshalTests { + for _, tc := range unmarshalTestCases { buf.Write(tc.data) } buf.WriteByte(0x3e) @@ -461,8 +461,8 @@ func TestDecoderSkipInvalidDataError(t *testing.T) { t.Run(tc.name, func(t *testing.T) { decoder := NewDecoder(tc.reader) bytesRead := 0 - for i := 0; i < len(unmarshalTests); i++ { - tc := unmarshalTests[i] + for i := 0; i < len(unmarshalTestCases); i++ { + tc := unmarshalTestCases[i] if err := decoder.Skip(); err != nil { t.Fatalf("Skip() returned error %v", err) } @@ -486,7 +486,7 @@ func TestDecoderSkipInvalidDataError(t *testing.T) { func TestDecoderSkipUnexpectedEOFError(t *testing.T) { var buf bytes.Buffer - for _, tc := range unmarshalTests { + for _, tc := range unmarshalTestCases { buf.Write(tc.data) } buf.Truncate(buf.Len() - 1) @@ -513,8 +513,8 @@ func TestDecoderSkipUnexpectedEOFError(t *testing.T) { t.Run(tc.name, func(t *testing.T) { decoder := NewDecoder(tc.reader) bytesRead := 0 - for i := 0; i < len(unmarshalTests)-1; i++ { - tc := unmarshalTests[i] + for i := 0; i < len(unmarshalTestCases)-1; i++ { + tc := unmarshalTestCases[i] if err := decoder.Skip(); err != nil { t.Fatalf("Skip() returned error %v", err) } @@ -536,7 +536,7 @@ func TestDecoderSkipUnexpectedEOFError(t *testing.T) { func TestDecoderSkipReadError(t *testing.T) { var buf bytes.Buffer - for _, tc := range unmarshalTests { + for _, tc := range unmarshalTestCases { buf.Write(tc.data) } buf.Truncate(buf.Len() - 1) @@ -565,8 +565,8 @@ func TestDecoderSkipReadError(t *testing.T) { t.Run(tc.name, func(t *testing.T) { decoder := NewDecoder(tc.reader) bytesRead := 0 - for i := 0; i < len(unmarshalTests)-1; i++ { - tc := unmarshalTests[i] + for i := 0; i < len(unmarshalTestCases)-1; i++ { + tc := unmarshalTestCases[i] if err := decoder.Skip(); err != nil { t.Fatalf("Skip() returned error %v", err) } @@ -595,7 +595,7 @@ func TestDecoderSkipNoData(t *testing.T) { wantErr error }{ { - name: "byte.Buffer", + name: "bytes.Buffer", reader: new(bytes.Buffer), wantErr: io.EOF, }, @@ -767,7 +767,7 @@ func TestEncoder(t *testing.T) { t.Errorf("EncMode() returned an error %v", err) } encoder := em.NewEncoder(&w) - for _, tc := range marshalTests { + for _, tc := range marshalTestCases { for _, value := range tc.values { want.Write(tc.wantData) @@ -782,7 +782,7 @@ func TestEncoder(t *testing.T) { } func TestEncoderError(t *testing.T) { - testcases := []struct { + testCases := []struct { name string value any wantErrorMsg string @@ -805,7 +805,7 @@ func TestEncoderError(t *testing.T) { } var w bytes.Buffer encoder := NewEncoder(&w) - for _, tc := range testcases { + for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { v := tc.value err := encoder.Encode(&v) diff --git a/tag_test.go b/tag_test.go index 86c670f2..a958b72c 100644 --- a/tag_test.go +++ b/tag_test.go @@ -66,7 +66,7 @@ func TestTagNewTypeWithBuiltinUnderlyingType(t *testing.T) { em, _ := EncOptions{Sort: SortCanonical}.EncModeWithTags(tags) dm, _ := DecOptions{}.DecModeWithTags(tags) - testCases := []roundTripTest{ + testCases := []roundTripTestCase{ { name: "bool", obj: myBool(true), @@ -177,7 +177,7 @@ func TestTagBinaryMarshalerUnmarshaler(t *testing.T) { em, _ := EncOptions{}.EncModeWithTags(tags) dm, _ := DecOptions{}.DecModeWithTags(tags) - testCases := []roundTripTest{ + testCases := []roundTripTestCase{ { name: "primitive obj", obj: number(1234567890), @@ -743,7 +743,7 @@ func TestDecodeTagData(t *testing.T) { {"EncTagRequired_DecTagIgnored", tagsDecIgnored}, } - testCases := []roundTripTest{ + testCases := []roundTripTestCase{ { name: "BinaryMarshaler non-struct", obj: number(1234567890), @@ -813,7 +813,7 @@ func TestDecodeNoTagData(t *testing.T) { {"EncTagIgnored_DecTagOptional", tagsDecOptional}, } - testCases := []roundTripTest{ + testCases := []roundTripTestCase{ { name: "BinaryMarshaler non-struct", obj: number(1234567890), @@ -1497,7 +1497,7 @@ func TestMarshalRawTagContainingMalformedCBORData(t *testing.T) { // TestEncodeBuiltinTag tests that marshaling a value of type Tag "does the right thing" when // marshaling the enclosed data item of a built-in tag number. func TestEncodeBuiltinTag(t *testing.T) { - for _, tc := range []struct { + testCases := []struct { name string tag Tag opts EncOptions @@ -1521,7 +1521,8 @@ func TestEncodeBuiltinTag(t *testing.T) { opts: EncOptions{String: StringToByteString}, want: mustHexDecode("c074323031332d30332d32315432303a30343a30305a"), }, - } { + } + for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { em, err := tc.opts.EncMode() if err != nil { @@ -1542,93 +1543,93 @@ func TestEncodeBuiltinTag(t *testing.T) { func TestUnmarshalRawTagOnBadData(t *testing.T) { testCases := []struct { - name string - data []byte - errMsg string + name string + data []byte + wantErrorMsg string }{ // Empty data { - name: "nil data", - data: nil, - errMsg: io.EOF.Error(), + name: "nil data", + data: nil, + wantErrorMsg: io.EOF.Error(), }, { - name: "empty data", - data: []byte{}, - errMsg: io.EOF.Error(), + name: "empty data", + data: []byte{}, + wantErrorMsg: io.EOF.Error(), }, // Wrong CBOR types { - name: "uint type", - data: mustHexDecode("01"), - errMsg: "cbor: cannot unmarshal positive integer into Go value of type cbor.RawTag", + name: "uint type", + data: mustHexDecode("01"), + wantErrorMsg: "cbor: cannot unmarshal positive integer into Go value of type cbor.RawTag", }, { - name: "int type", - data: mustHexDecode("20"), - errMsg: "cbor: cannot unmarshal negative integer into Go value of type cbor.RawTag", + name: "int type", + data: mustHexDecode("20"), + wantErrorMsg: "cbor: cannot unmarshal negative integer into Go value of type cbor.RawTag", }, { - name: "byte string type", - data: mustHexDecode("40"), - errMsg: "cbor: cannot unmarshal byte string into Go value of type cbor.RawTag", + name: "byte string type", + data: mustHexDecode("40"), + wantErrorMsg: "cbor: cannot unmarshal byte string into Go value of type cbor.RawTag", }, { - name: "string type", - data: mustHexDecode("60"), - errMsg: "cbor: cannot unmarshal UTF-8 text string into Go value of type cbor.RawTag", + name: "string type", + data: mustHexDecode("60"), + wantErrorMsg: "cbor: cannot unmarshal UTF-8 text string into Go value of type cbor.RawTag", }, { - name: "array type", - data: mustHexDecode("80"), - errMsg: "cbor: cannot unmarshal array into Go value of type cbor.RawTag", + name: "array type", + data: mustHexDecode("80"), + wantErrorMsg: "cbor: cannot unmarshal array into Go value of type cbor.RawTag", }, { - name: "map type", - data: mustHexDecode("a0"), - errMsg: "cbor: cannot unmarshal map into Go value of type cbor.RawTag", + name: "map type", + data: mustHexDecode("a0"), + wantErrorMsg: "cbor: cannot unmarshal map into Go value of type cbor.RawTag", }, { - name: "primitive type", - data: mustHexDecode("f4"), - errMsg: "cbor: cannot unmarshal primitives into Go value of type cbor.RawTag", + name: "primitive type", + data: mustHexDecode("f4"), + wantErrorMsg: "cbor: cannot unmarshal primitives into Go value of type cbor.RawTag", }, { - name: "float type", - data: mustHexDecode("f90000"), - errMsg: "cbor: cannot unmarshal primitives into Go value of type cbor.RawTag", + name: "float type", + data: mustHexDecode("f90000"), + wantErrorMsg: "cbor: cannot unmarshal primitives into Go value of type cbor.RawTag", }, // Truncated CBOR data { - name: "truncated head", - data: mustHexDecode("18"), - errMsg: io.ErrUnexpectedEOF.Error(), + name: "truncated head", + data: mustHexDecode("18"), + wantErrorMsg: io.ErrUnexpectedEOF.Error(), }, // Truncated CBOR tag data { - name: "truncated tag number", - data: mustHexDecode("d8"), - errMsg: io.ErrUnexpectedEOF.Error(), + name: "truncated tag number", + data: mustHexDecode("d8"), + wantErrorMsg: io.ErrUnexpectedEOF.Error(), }, { - name: "tag number not followed by tag content", - data: mustHexDecode("da"), - errMsg: io.ErrUnexpectedEOF.Error(), + name: "tag number not followed by tag content", + data: mustHexDecode("da"), + wantErrorMsg: io.ErrUnexpectedEOF.Error(), }, { - name: "truncated tag content", - data: mustHexDecode("c074323031332d30332d32315432303a30343a3030"), - errMsg: io.ErrUnexpectedEOF.Error(), + name: "truncated tag content", + data: mustHexDecode("c074323031332d30332d32315432303a30343a3030"), + wantErrorMsg: io.ErrUnexpectedEOF.Error(), }, // Extraneous CBOR data { - name: "extraneous data", - data: mustHexDecode("c074323031332d30332d32315432303a30343a30305a00"), - errMsg: "cbor: 1 bytes of extraneous data starting at index 22", + name: "extraneous data", + data: mustHexDecode("c074323031332d30332d32315432303a30343a30305a00"), + wantErrorMsg: "cbor: 1 bytes of extraneous data starting at index 22", }, } @@ -1642,8 +1643,8 @@ func TestUnmarshalRawTagOnBadData(t *testing.T) { if err == nil { t.Errorf("UnmarshalCBOR(%x) didn't return error", tc.data) } - if !strings.HasPrefix(err.Error(), tc.errMsg) { - t.Errorf("UnmarshalCBOR(%x) returned error %q, want %q", tc.data, err.Error(), tc.errMsg) + if !strings.HasPrefix(err.Error(), tc.wantErrorMsg) { + t.Errorf("UnmarshalCBOR(%x) returned error %q, want %q", tc.data, err.Error(), tc.wantErrorMsg) } } // Test Unmarshal(data, *RawTag), which calls RawTag.unmarshalCBOR() under the hood @@ -1654,8 +1655,8 @@ func TestUnmarshalRawTagOnBadData(t *testing.T) { if err == nil { t.Errorf("Unmarshal(%x) didn't return error", tc.data) } - if !strings.HasPrefix(err.Error(), tc.errMsg) { - t.Errorf("Unmarshal(%x) returned error %q, want %q", tc.data, err.Error(), tc.errMsg) + if !strings.HasPrefix(err.Error(), tc.wantErrorMsg) { + t.Errorf("Unmarshal(%x) returned error %q, want %q", tc.data, err.Error(), tc.wantErrorMsg) } } }) diff --git a/valid.go b/valid.go index b40793b9..b9166367 100644 --- a/valid.go +++ b/valid.go @@ -54,7 +54,7 @@ func (e *MaxMapPairsError) Error() string { return "cbor: exceeded max number of key-value pairs " + strconv.Itoa(e.maxMapPairs) + " for CBOR map" } -// IndefiniteLengthError indicates found disallowed indefinite length items. +// IndefiniteLengthError indicates found disallowed indefinite-length items. type IndefiniteLengthError struct { t cborType } @@ -212,7 +212,7 @@ func (d *decoder) wellformedInternal(depth int, checkBuiltinTags bool) (int, err return depth, nil } -// wellformedIndefiniteString checks indefinite length byte/text string's well-formedness and returns max depth and error. +// wellformedIndefiniteString checks indefinite-length byte/text string's well-formedness and returns max depth and error. func (d *decoder) wellformedIndefiniteString(t cborType, depth int, checkBuiltinTags bool) (int, error) { var err error for { @@ -223,7 +223,7 @@ func (d *decoder) wellformedIndefiniteString(t cborType, depth int, checkBuiltin d.off++ break } - // Peek ahead to get next type and indefinite length status. + // Peek ahead to get next type and indefinite-length status. nt, ai := parseInitialByte(d.data[d.off]) if t != nt { return 0, &SyntaxError{"cbor: wrong element type " + nt.String() + " for indefinite-length " + t.String()} @@ -238,7 +238,7 @@ func (d *decoder) wellformedIndefiniteString(t cborType, depth int, checkBuiltin return depth, nil } -// wellformedIndefiniteArrayOrMap checks indefinite length array/map's well-formedness and returns max depth and error. +// wellformedIndefiniteArrayOrMap checks indefinite-length array/map's well-formedness and returns max depth and error. func (d *decoder) wellformedIndefiniteArrayOrMap(t cborType, depth int, checkBuiltinTags bool) (int, error) { var err error maxDepth := depth @@ -379,12 +379,12 @@ func (d *decoder) wellformedHead() (t cborType, ai byte, val uint64, err error) func (d *decoder) acceptableFloat(f float64) error { switch { - case d.dm.nanDec == NaNDecodeForbidden && math.IsNaN(f): + case d.dm.nan == NaNDecodeForbidden && math.IsNaN(f): return &UnacceptableDataItemError{ CBORType: cborTypePrimitives.String(), Message: "floating-point NaN", } - case d.dm.infDec == InfDecodeForbidden && math.IsInf(f, 0): + case d.dm.inf == InfDecodeForbidden && math.IsInf(f, 0): return &UnacceptableDataItemError{ CBORType: cborTypePrimitives.String(), Message: "floating-point infinity", diff --git a/valid_test.go b/valid_test.go index 181fbea3..5c2dba17 100644 --- a/valid_test.go +++ b/valid_test.go @@ -9,17 +9,17 @@ import ( ) func TestValid1(t *testing.T) { - for _, mt := range marshalTests { - if err := Wellformed(mt.wantData); err != nil { + for _, tc := range marshalTestCases { + if err := Wellformed(tc.wantData); err != nil { t.Errorf("Wellformed() returned error %v", err) } } } func TestValid2(t *testing.T) { - for _, mt := range marshalTests { + for _, tc := range marshalTestCases { dm, _ := DecOptions{DupMapKey: DupMapKeyEnforcedAPF}.DecMode() - if err := dm.Wellformed(mt.wantData); err != nil { + if err := dm.Wellformed(tc.wantData); err != nil { t.Errorf("Wellformed() returned error %v", err) } } @@ -73,11 +73,11 @@ func TestValidExtraneousData(t *testing.T) { func TestValidOnStreamingData(t *testing.T) { var buf bytes.Buffer - for _, t := range marshalTests { - buf.Write(t.wantData) + for _, tc := range marshalTestCases { + buf.Write(tc.wantData) } d := decoder{data: buf.Bytes(), dm: defaultDecMode} - for i := 0; i < len(marshalTests); i++ { + for i := 0; i < len(marshalTestCases); i++ { if err := d.wellformed(true, false); err != nil { t.Errorf("wellformed() returned error %v", err) } @@ -121,7 +121,7 @@ func TestDepth(t *testing.T) { wantDepth: 0, }, // []byte{} { - name: "indefinite length byte string", + name: "indefinite-length byte string", data: mustHexDecode("5f42010243030405ff"), wantDepth: 0, }, // []byte{1, 2, 3, 4, 5} @@ -131,7 +131,7 @@ func TestDepth(t *testing.T) { wantDepth: 0, }, // "" { - name: "indefinite length text string", + name: "indefinite-length text string", data: mustHexDecode("7f657374726561646d696e67ff"), wantDepth: 0, }, // "streaming" @@ -141,7 +141,7 @@ func TestDepth(t *testing.T) { wantDepth: 1, }, // [] { - name: "indefinite length empty array", + name: "indefinite-length empty array", data: mustHexDecode("9fff"), wantDepth: 1, }, // [] @@ -151,7 +151,7 @@ func TestDepth(t *testing.T) { wantDepth: 1, }, // [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] { - name: "indefinite length array", + name: "indefinite-length array", data: mustHexDecode("9f0102030405060708090a0b0c0d0e0f101112131415161718181819ff"), wantDepth: 1, }, // [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] @@ -161,7 +161,7 @@ func TestDepth(t *testing.T) { wantDepth: 2, }, // [1,[2,3],[4,5]] { - name: "indefinite length nested array", + name: "indefinite-length nested array", data: mustHexDecode("83018202039f0405ff"), wantDepth: 2, }, // [1,[2,3],[4,5]] @@ -171,7 +171,7 @@ func TestDepth(t *testing.T) { wantDepth: 2, }, // [a", {"b": "c"}] { - name: "indefinite length array and map", + name: "indefinite-length array and map", data: mustHexDecode("826161bf61626163ff"), wantDepth: 2, }, // [a", {"b": "c"}] @@ -181,7 +181,7 @@ func TestDepth(t *testing.T) { wantDepth: 1, }, // {} { - name: "indefinite length empty map", + name: "indefinite-length empty map", data: mustHexDecode("bfff"), wantDepth: 1, }, // {} @@ -196,7 +196,7 @@ func TestDepth(t *testing.T) { wantDepth: 2, }, // {"a": 1, "b": [2, 3]} { - name: "indefinite length nested map", + name: "indefinite-length nested map", data: mustHexDecode("bf61610161629f0203ffff"), wantDepth: 2, }, // {"a": 1, "b": [2, 3]} @@ -231,7 +231,7 @@ func TestDepth(t *testing.T) { wantDepth: 32, }, { - name: "32-level indefinite length array", + name: "32-level indefinite-length array", data: mustHexDecode("9f018181818181818181818181818181818181818181818181818181818181818101ff"), wantDepth: 32, }, @@ -241,7 +241,7 @@ func TestDepth(t *testing.T) { wantDepth: 32, }, { - name: "32-level indefinite length map", + name: "32-level indefinite-length map", data: mustHexDecode("bf018181818181818181818181818181818181818181818181818181818181818101ff"), wantDepth: 32, }, @@ -291,7 +291,7 @@ func TestDepthError(t *testing.T) { wantErrorMsg: "cbor: exceeded max nested level 32", }, { - name: "33-level indefinite length array", + name: "33-level indefinite-length array", data: mustHexDecode("9f01818181818181818181818181818181818181818181818181818181818181818101ff"), opts: DecOptions{}, wantErrorMsg: "cbor: exceeded max nested level 32", @@ -303,7 +303,7 @@ func TestDepthError(t *testing.T) { wantErrorMsg: "cbor: exceeded max nested level 32", }, { - name: "33-level indefinite length map", + name: "33-level indefinite-length map", data: mustHexDecode("bf01818181818181818181818181818181818181818181818181818181818181818101ff"), opts: DecOptions{}, wantErrorMsg: "cbor: exceeded max nested level 32",