1
16
17 package modes_test
18
19 import (
20 "encoding/hex"
21 "fmt"
22 "reflect"
23 "testing"
24
25 "k8s.io/apimachinery/pkg/runtime/serializer/cbor/internal/modes"
26
27 "github.com/fxamacker/cbor/v2"
28 "github.com/google/go-cmp/cmp"
29 )
30
31 func TestDecode(t *testing.T) {
32 hex := func(h string) []byte {
33 b, err := hex.DecodeString(h)
34 if err != nil {
35 t.Fatal(err)
36 }
37 return b
38 }
39
40 for _, tc := range []struct {
41 name string
42 modes []cbor.DecMode
43 in []byte
44 into interface{}
45 want interface{}
46 assertOnError func(t *testing.T, e error)
47 }{
48 {
49 name: "reject duplicate negative int keys into struct",
50 modes: []cbor.DecMode{modes.DecodeLax},
51 in: hex("a220012002"),
52 into: struct{}{},
53 assertOnError: assertIdenticalError(&cbor.DupMapKeyError{Key: int64(-1), Index: 1}),
54 },
55 {
56 name: "reject duplicate negative int keys into map",
57 in: hex("a220012002"),
58 into: map[int64]interface{}{},
59 assertOnError: assertIdenticalError(&cbor.DupMapKeyError{Key: int64(-1), Index: 1}),
60 },
61 {
62 name: "reject duplicate positive int keys into struct",
63 modes: []cbor.DecMode{modes.DecodeLax},
64 in: hex("a201010102"),
65 into: struct{}{},
66 assertOnError: assertIdenticalError(&cbor.DupMapKeyError{Key: int64(1), Index: 1}),
67 },
68 {
69 name: "reject duplicate positive int keys into map",
70 in: hex("a201010102"),
71 into: map[int64]interface{}{},
72 assertOnError: assertIdenticalError(&cbor.DupMapKeyError{Key: int64(1), Index: 1}),
73 },
74 {
75 name: "reject duplicate text string keys into struct",
76 in: hex("a2614101614102"),
77 into: struct {
78 A int `json:"A"`
79 }{},
80 assertOnError: assertIdenticalError(&cbor.DupMapKeyError{Key: string("A"), Index: 1}),
81 },
82 {
83 name: "reject duplicate text string keys into map",
84 in: hex("a2614101614102"),
85 into: map[string]interface{}{},
86 assertOnError: assertIdenticalError(&cbor.DupMapKeyError{Key: string("A"), Index: 1}),
87 },
88 {
89 name: "reject duplicate byte string keys into map",
90 in: hex("a2414101414102"),
91 into: map[string]interface{}{},
92 assertOnError: assertIdenticalError(&cbor.DupMapKeyError{Key: string("A"), Index: 1}),
93 },
94 {
95 name: "reject duplicate byte string keys into struct",
96 in: hex("a2414101414102"),
97 into: struct {
98 A int `json:"A"`
99 }{},
100 assertOnError: assertIdenticalError(&cbor.DupMapKeyError{Key: string("A"), Index: 1}),
101 },
102 {
103 name: "reject duplicate byte string and text string keys into map",
104 in: hex("a2414101614102"),
105 into: map[string]interface{}{},
106 assertOnError: assertIdenticalError(&cbor.DupMapKeyError{Key: string("A"), Index: 1}),
107 },
108 {
109 name: "reject duplicate byte string and text string keys into struct",
110 in: hex("a2414101614102"),
111 into: struct {
112 A int `json:"A"`
113 }{},
114 assertOnError: assertIdenticalError(&cbor.DupMapKeyError{Key: string("A"), Index: 1}),
115 },
116 {
117 name: "reject two identical indefinite-length byte string keys split into chunks differently into struct",
118 in: hex("a25f426865436c6c6fff015f416844656c6c6fff02"),
119 into: struct {
120 Hello int `json:"hello"`
121 }{},
122 assertOnError: assertIdenticalError(&cbor.DupMapKeyError{Key: string("hello"), Index: 1}),
123 },
124 {
125 name: "reject two identical indefinite-length byte string keys split into chunks differently into map",
126 in: hex("a25f426865436c6c6fff015f416844656c6c6fff02"),
127 into: map[string]interface{}{},
128 assertOnError: assertIdenticalError(&cbor.DupMapKeyError{Key: string("hello"), Index: 1}),
129 },
130 {
131 name: "reject two identical indefinite-length text string keys split into chunks differently into struct",
132 in: hex("a27f626865636c6c6fff017f616864656c6c6fff02"),
133 into: struct {
134 Hello int `json:"hello"`
135 }{},
136 assertOnError: assertIdenticalError(&cbor.DupMapKeyError{Key: string("hello"), Index: 1}),
137 },
138 {
139 name: "reject two identical indefinite-length text string keys split into chunks differently into map",
140 modes: []cbor.DecMode{modes.DecodeLax},
141 in: hex("a27f626865636c6c6fff017f616864656c6c6fff02"),
142 into: map[string]interface{}{},
143 assertOnError: assertIdenticalError(&cbor.DupMapKeyError{Key: string("hello"), Index: 1}),
144 },
145 {
146 name: "case-insensitive match treated as unknown field",
147 modes: []cbor.DecMode{modes.Decode},
148 in: hex("a1614101"),
149 into: struct {
150 A int `json:"a"`
151 }{},
152 assertOnError: assertIdenticalError(&cbor.UnknownFieldError{Index: 0}),
153 },
154 {
155 name: "case-insensitive match ignored in lax mode",
156 modes: []cbor.DecMode{modes.DecodeLax},
157 in: hex("a1614101"),
158 into: struct {
159 A int `json:"a"`
160 }{},
161 want: struct {
162 A int `json:"a"`
163 }{
164 A: 0,
165 },
166 assertOnError: assertNilError,
167 },
168 {
169 name: "case-insensitive match after exact match treated as unknown field",
170 modes: []cbor.DecMode{modes.Decode},
171 in: hex("a2616101614102"),
172 into: struct {
173 A int `json:"a"`
174 }{},
175 want: struct {
176 A int `json:"a"`
177 }{
178 A: 1,
179 },
180 assertOnError: assertIdenticalError(&cbor.UnknownFieldError{Index: 1}),
181 },
182 {
183 name: "case-insensitive match after exact match ignored in lax mode",
184 modes: []cbor.DecMode{modes.DecodeLax},
185 in: hex("a2616101614102"),
186 into: struct {
187 A int `json:"a"`
188 }{},
189 want: struct {
190 A int `json:"a"`
191 }{
192 A: 1,
193 },
194 assertOnError: assertNilError,
195 },
196 {
197 name: "case-insensitive match before exact match treated as unknown field",
198 modes: []cbor.DecMode{modes.Decode},
199 in: hex("a2614101616102"),
200 into: struct {
201 A int `json:"a"`
202 }{},
203 assertOnError: assertIdenticalError(&cbor.UnknownFieldError{Index: 0}),
204 },
205 {
206 name: "case-insensitive match before exact match ignored in lax mode",
207 modes: []cbor.DecMode{modes.DecodeLax},
208 in: hex("a2614101616102"),
209 into: struct {
210 A int `json:"a"`
211 }{},
212 want: struct {
213 A int `json:"a"`
214 }{
215 A: 2,
216 },
217 assertOnError: assertNilError,
218 },
219 {
220 name: "reject text string containing invalid utf-8 sequence",
221 in: hex("6180"),
222 assertOnError: assertOnConcreteError(func(t *testing.T, e *cbor.SemanticError) {
223 const expected = "cbor: invalid UTF-8 string"
224 if msg := e.Error(); msg != expected {
225 t.Errorf("expected %v, got %v", expected, msg)
226 }
227 }),
228 },
229 {
230 name: "unsigned integer decodes to interface{} as int64",
231 in: hex("0a"),
232 want: int64(10),
233 assertOnError: assertNilError,
234 },
235 {
236 name: "unknown field error",
237 modes: []cbor.DecMode{modes.Decode},
238 in: hex("a1616101"),
239 into: struct{}{},
240 assertOnError: assertOnConcreteError(func(t *testing.T, e *cbor.UnknownFieldError) {
241 if e.Index != 0 {
242 t.Errorf("expected %#v, got %#v", &cbor.UnknownFieldError{Index: 0}, e)
243 }
244 }),
245 },
246 {
247 name: "no unknown field error in lax mode",
248 modes: []cbor.DecMode{modes.DecodeLax},
249 in: hex("a1616101"),
250 into: struct{}{},
251 want: struct{}{},
252 assertOnError: assertNilError,
253 },
254 {
255 name: "indefinite-length text string",
256 in: hex("7f616161626163ff"),
257 want: "abc",
258 assertOnError: assertNilError,
259 },
260 {
261 name: "nested indefinite-length array",
262 in: hex("9f9f8080ff9f8080ffff"),
263 want: []interface{}{
264 []interface{}{[]interface{}{}, []interface{}{}},
265 []interface{}{[]interface{}{}, []interface{}{}},
266 },
267 assertOnError: assertNilError,
268 },
269 {
270 name: "nested indefinite-length map",
271 in: hex("bf6141bf616101616202ff6142bf616901616a02ffff"),
272 want: map[string]interface{}{
273 "A": map[string]interface{}{"a": int64(1), "b": int64(2)},
274 "B": map[string]interface{}{"i": int64(1), "j": int64(2)},
275 },
276 assertOnError: assertNilError,
277 },
278 } {
279 decModes := tc.modes
280 if len(decModes) == 0 {
281 decModes = allDecModes
282 }
283
284 for _, decMode := range decModes {
285 modeName, ok := decModeNames[decMode]
286 if !ok {
287 t.Fatal("test case configured to run against unrecognized mode")
288 }
289
290 t.Run(fmt.Sprintf("mode=%s/%s", modeName, tc.name), func(t *testing.T) {
291 var dst reflect.Value
292 if tc.into == nil {
293 var i interface{}
294 dst = reflect.ValueOf(&i)
295 } else {
296 dst = reflect.New(reflect.TypeOf(tc.into))
297 }
298 err := decMode.Unmarshal(tc.in, dst.Interface())
299 tc.assertOnError(t, err)
300 if tc.want != nil {
301 if diff := cmp.Diff(tc.want, dst.Elem().Interface()); diff != "" {
302 t.Errorf("unexpected output:\n%s", diff)
303 }
304 }
305 })
306 }
307 }
308 }
309
View as plain text