v / vlib / encoding / cbor / tests / rfc8949_appendix_a_test.v
781 lines · 697 sloc · 20.74 KB · 468855eef1db0ff73c62be2d1bf176ffa0e1478e
Raw
1// RFC 8949 Appendix A conformance tests. Each entry is taken verbatim
2// from the published `cbor/test-vectors` list. Roundtrip-true entries
3// are exercised in both directions (encode-and-compare-bytes plus
4// decode-and-compare-value); roundtrip-false entries are decode-only,
5// which matches the test-vector flag.
6//
7// Hex bytes are kept as string literals so the diffs against the RFC
8// are obvious when reading the file.
9module main
10
11import encoding.cbor
12import encoding.hex
13import math
14
15fn h(s string) []u8 {
16 return hex.decode(s) or { panic('invalid hex: ${s}') }
17}
18
19fn bytes_eq(a []u8, b []u8) bool {
20 if a.len != b.len {
21 return false
22 }
23 for i in 0 .. a.len {
24 if a[i] != b[i] {
25 return false
26 }
27 }
28 return true
29}
30
31fn assert_encode_uint(v u64, hex_expected string) {
32 got := cbor.encode[u64](v, cbor.EncodeOpts{}) or { panic(err) }
33 expected := h(hex_expected)
34 if !bytes_eq(got, expected) {
35 panic('encode u64 ${v}: got ${hex.encode(got)}, want ${hex_expected}')
36 }
37}
38
39fn assert_encode_int(v i64, hex_expected string) {
40 got := cbor.encode[i64](v, cbor.EncodeOpts{}) or { panic(err) }
41 expected := h(hex_expected)
42 if !bytes_eq(got, expected) {
43 panic('encode i64 ${v}: got ${hex.encode(got)}, want ${hex_expected}')
44 }
45}
46
47// ---------------------------------------------------------------------
48// Unsigned integers (major type 0)
49// ---------------------------------------------------------------------
50
51fn test_unsigned_zero() {
52 assert_encode_uint(0, '00')
53}
54
55fn test_unsigned_small() {
56 assert_encode_uint(1, '01')
57 assert_encode_uint(10, '0a')
58 assert_encode_uint(23, '17')
59}
60
61fn test_unsigned_one_byte() {
62 assert_encode_uint(24, '1818')
63 assert_encode_uint(25, '1819')
64 assert_encode_uint(100, '1864')
65 assert_encode_uint(0xff, '18ff')
66}
67
68fn test_unsigned_two_bytes() {
69 assert_encode_uint(1000, '1903e8')
70 assert_encode_uint(0xffff, '19ffff')
71}
72
73fn test_unsigned_four_bytes() {
74 assert_encode_uint(1_000_000, '1a000f4240')
75 assert_encode_uint(0xffffffff, '1affffffff')
76}
77
78fn test_unsigned_eight_bytes() {
79 assert_encode_uint(1_000_000_000_000, '1b000000e8d4a51000')
80 assert_encode_uint(u64(0xffffffffffffffff), '1bffffffffffffffff')
81}
82
83// ---------------------------------------------------------------------
84// Negative integers (major type 1)
85// ---------------------------------------------------------------------
86
87fn test_negative_small() {
88 assert_encode_int(-1, '20')
89 assert_encode_int(-10, '29')
90}
91
92fn test_negative_one_byte() {
93 assert_encode_int(-100, '3863')
94}
95
96fn test_negative_two_bytes() {
97 assert_encode_int(-1000, '3903e7')
98}
99
100fn test_negative_extreme() {
101 // -2^63 still fits i64.
102 assert_encode_int(-9_223_372_036_854_775_808, '3b7fffffffffffffff')
103}
104
105fn test_negative_lower_bound_via_packer() {
106 // -2^64 (lower bound of CBOR negative ints) requires the full u64
107 // argument and can't be represented as an i64.
108 mut p := cbor.new_packer(cbor.EncodeOpts{})
109 p.pack_negative_arg(u64(0xffffffffffffffff))
110 assert bytes_eq(p.bytes(), h('3bffffffffffffffff'))
111}
112
113// ---------------------------------------------------------------------
114// Floats — preferred serialisation (RFC 8949 §4.2.2)
115// ---------------------------------------------------------------------
116
117fn assert_encode_float(v f64, hex_expected string) {
118 got := cbor.encode[f64](v, cbor.EncodeOpts{}) or { panic(err) }
119 expected := h(hex_expected)
120 if !bytes_eq(got, expected) {
121 panic('encode f64 ${v}: got ${hex.encode(got)}, want ${hex_expected}')
122 }
123}
124
125fn test_float_zero() {
126 assert_encode_float(0.0, 'f90000')
127 // -0.0 — distinct bit pattern from +0.0.
128 neg_zero := math.f64_from_bits(u64(0x8000000000000000))
129 assert_encode_float(neg_zero, 'f98000')
130}
131
132fn test_float_simple_values() {
133 assert_encode_float(1.0, 'f93c00')
134 assert_encode_float(1.5, 'f93e00')
135 assert_encode_float(65504.0, 'f97bff')
136 assert_encode_float(-4.0, 'f9c400')
137}
138
139fn test_float_subnormal_half() {
140 // 2^-24 — smallest positive half subnormal (preserved exactly in f32/f64).
141 assert_encode_float(5.960464477539063e-08, 'f90001')
142 // 2^-14 — smallest positive normal half.
143 assert_encode_float(6.103515625e-05, 'f90400')
144}
145
146fn test_float_single() {
147 assert_encode_float(100000.0, 'fa47c35000')
148 assert_encode_float(3.4028234663852886e+38, 'fa7f7fffff')
149}
150
151fn test_float_double() {
152 assert_encode_float(1.1, 'fb3ff199999999999a')
153 assert_encode_float(1.0e+300, 'fb7e37e43c8800759c')
154 assert_encode_float(-4.1, 'fbc010666666666666')
155}
156
157fn test_float_special_values() {
158 assert_encode_float(math.inf(1), 'f97c00')
159 assert_encode_float(math.inf(-1), 'f9fc00')
160 // NaN — encoder collapses to the canonical quiet NaN.
161 got := cbor.encode[f64](math.nan(), cbor.EncodeOpts{}) or { panic(err) }
162 assert bytes_eq(got, h('f97e00')), 'NaN encoded as ${hex.encode(got)}, want f97e00'
163}
164
165// ---------------------------------------------------------------------
166// Booleans, null, undefined
167// ---------------------------------------------------------------------
168
169fn test_bool_false() {
170 got := cbor.encode[bool](false, cbor.EncodeOpts{}) or { panic(err) }
171 assert bytes_eq(got, [u8(0xf4)])
172}
173
174fn test_bool_true() {
175 got := cbor.encode[bool](true, cbor.EncodeOpts{}) or { panic(err) }
176 assert bytes_eq(got, [u8(0xf5)])
177}
178
179fn test_null_via_packer() {
180 mut p := cbor.new_packer(cbor.EncodeOpts{})
181 p.pack_null()
182 assert bytes_eq(p.bytes(), [u8(0xf6)])
183}
184
185fn test_undefined_via_packer() {
186 mut p := cbor.new_packer(cbor.EncodeOpts{})
187 p.pack_undefined()
188 assert bytes_eq(p.bytes(), [u8(0xf7)])
189}
190
191fn test_simple_values() {
192 mut p := cbor.new_packer(cbor.EncodeOpts{})
193 p.pack_simple(16) or { panic(err) }
194 assert bytes_eq(p.bytes(), h('f0'))
195
196 mut p3 := cbor.new_packer(cbor.EncodeOpts{})
197 p3.pack_simple(255) or { panic(err) }
198 assert bytes_eq(p3.bytes(), h('f8ff'))
199}
200
201// RFC 8949 §3.3: encoder MUST NOT issue two-byte sequences starting
202// with 0xf8 and continuing with a byte < 0x20. We refuse to emit such a
203// value, and the decoder rejects them on input.
204fn test_simple_values_rfc8949_strictness() {
205 // Encoding side: pack_simple(24..31) returns an error.
206 mut p := cbor.new_packer(cbor.EncodeOpts{})
207 if _ := p.pack_simple(24) {
208 assert false, 'expected pack_simple(24) to fail'
209 }
210 if _ := p.pack_simple(31) {
211 assert false, 'expected pack_simple(31) to fail'
212 }
213 // Decoder side: f818 (simple(24) two-byte form) is malformed.
214 cbor.decode[cbor.Value](h('f818'), cbor.DecodeOpts{}) or {
215 assert err.msg().contains('1-byte form'), 'unexpected: ${err.msg()}'
216 return
217 }
218 assert false, 'expected decoder to reject simple(24) two-byte form'
219}
220
221// ---------------------------------------------------------------------
222// Byte and text strings
223// ---------------------------------------------------------------------
224
225fn test_empty_byte_string() {
226 got := cbor.encode[[]u8]([]u8{}, cbor.EncodeOpts{}) or { panic(err) }
227 assert bytes_eq(got, h('40'))
228}
229
230fn test_byte_string_4() {
231 got := cbor.encode[[]u8]([u8(0x01), 0x02, 0x03, 0x04], cbor.EncodeOpts{}) or { panic(err) }
232 assert bytes_eq(got, h('4401020304'))
233}
234
235fn test_empty_text_string() {
236 got := cbor.encode[string]('', cbor.EncodeOpts{}) or { panic(err) }
237 assert bytes_eq(got, h('60'))
238}
239
240fn test_text_a() {
241 got := cbor.encode[string]('a', cbor.EncodeOpts{}) or { panic(err) }
242 assert bytes_eq(got, h('6161'))
243}
244
245fn test_text_ietf() {
246 got := cbor.encode[string]('IETF', cbor.EncodeOpts{}) or { panic(err) }
247 assert bytes_eq(got, h('6449455446'))
248}
249
250fn test_text_escaped() {
251 got := cbor.encode[string]('"\\', cbor.EncodeOpts{}) or { panic(err) }
252 assert bytes_eq(got, h('62225c'))
253}
254
255fn test_text_utf8_2byte() {
256 got := cbor.encode[string]('ü', cbor.EncodeOpts{}) or { panic(err) }
257 assert bytes_eq(got, h('62c3bc'))
258}
259
260fn test_text_utf8_3byte() {
261 got := cbor.encode[string]('水', cbor.EncodeOpts{}) or { panic(err) }
262 assert bytes_eq(got, h('63e6b0b4'))
263}
264
265fn test_text_utf8_4byte() {
266 got := cbor.encode[string]('𐅑', cbor.EncodeOpts{}) or { panic(err) }
267 assert bytes_eq(got, h('64f0908591'))
268}
269
270// ---------------------------------------------------------------------
271// Arrays
272// ---------------------------------------------------------------------
273
274fn test_empty_array() {
275 got := cbor.encode[[]int]([]int{}, cbor.EncodeOpts{}) or { panic(err) }
276 assert bytes_eq(got, h('80'))
277}
278
279fn test_array_3() {
280 got := cbor.encode[[]int]([1, 2, 3], cbor.EncodeOpts{}) or { panic(err) }
281 assert bytes_eq(got, h('83010203'))
282}
283
284fn test_array_nested_via_value() {
285 v := cbor.Value(cbor.Array{
286 elements: [
287 cbor.Value(cbor.new_uint(1)),
288 cbor.Value(cbor.Array{
289 elements: [cbor.Value(cbor.new_uint(2)), cbor.Value(cbor.new_uint(3))]
290 }),
291 cbor.Value(cbor.Array{
292 elements: [cbor.Value(cbor.new_uint(4)), cbor.Value(cbor.new_uint(5))]
293 }),
294 ]
295 })
296 got := cbor.encode_value(v, cbor.EncodeOpts{})!
297 assert bytes_eq(got, h('8301820203820405'))
298}
299
300fn test_array_25_items() {
301 mut elements := []u64{cap: 25}
302 for i in 0 .. 25 {
303 elements << u64(i + 1)
304 }
305 got := cbor.encode[[]u64](elements, cbor.EncodeOpts{}) or { panic(err) }
306 want := '98190102030405060708090a0b0c0d0e0f101112131415161718181819'
307 assert bytes_eq(got, h(want))
308}
309
310// ---------------------------------------------------------------------
311// Maps
312// ---------------------------------------------------------------------
313
314fn test_empty_map() {
315 got := cbor.encode[map[string]int](map[string]int{}, cbor.EncodeOpts{}) or { panic(err) }
316 assert bytes_eq(got, h('a0'))
317}
318
319fn test_int_key_map_via_packer() {
320 mut p := cbor.new_packer(cbor.EncodeOpts{})
321 p.pack_map_header(2)
322 p.pack_int(1)
323 p.pack_int(2)
324 p.pack_int(3)
325 p.pack_int(4)
326 assert bytes_eq(p.bytes(), h('a201020304'))
327}
328
329fn test_string_key_map_with_array_value() {
330 v := cbor.Value(cbor.Map{
331 pairs: [
332 cbor.MapPair{
333 key: cbor.Value(cbor.Text{
334 value: 'a'
335 })
336 value: cbor.Value(cbor.new_uint(1))
337 },
338 cbor.MapPair{
339 key: cbor.Value(cbor.Text{
340 value: 'b'
341 })
342 value: cbor.Value(cbor.Array{
343 elements: [cbor.Value(cbor.new_uint(2)), cbor.Value(cbor.new_uint(3))]
344 })
345 },
346 ]
347 })
348 got := cbor.encode_value(v, cbor.EncodeOpts{})!
349 assert bytes_eq(got, h('a26161016162820203'))
350}
351
352fn test_array_with_map_inside() {
353 v := cbor.Value(cbor.Array{
354 elements: [
355 cbor.Value(cbor.Text{
356 value: 'a'
357 }),
358 cbor.Value(cbor.Map{
359 pairs: [
360 cbor.MapPair{
361 key: cbor.Value(cbor.Text{
362 value: 'b'
363 })
364 value: cbor.Value(cbor.Text{
365 value: 'c'
366 })
367 },
368 ]
369 }),
370 ]
371 })
372 got := cbor.encode_value(v, cbor.EncodeOpts{})!
373 assert bytes_eq(got, h('826161a161626163'))
374}
375
376// ---------------------------------------------------------------------
377// Tags
378// ---------------------------------------------------------------------
379
380fn test_tag_date_time() {
381 mut p := cbor.new_packer(cbor.EncodeOpts{})
382 p.pack_tag(0)
383 p.pack_text('2013-03-21T20:04:00Z')
384 assert bytes_eq(p.bytes(), h('c074323031332d30332d32315432303a30343a30305a'))
385}
386
387fn test_tag_epoch_int() {
388 mut p := cbor.new_packer(cbor.EncodeOpts{})
389 p.pack_tag(1)
390 p.pack_int(1363896240)
391 assert bytes_eq(p.bytes(), h('c11a514b67b0'))
392}
393
394fn test_tag_epoch_float() {
395 mut p := cbor.new_packer(cbor.EncodeOpts{})
396 p.pack_tag(1)
397 p.pack_float64(1363896240.5)
398 assert bytes_eq(p.bytes(), h('c1fb41d452d9ec200000'))
399}
400
401fn test_tag_uri() {
402 mut p := cbor.new_packer(cbor.EncodeOpts{})
403 p.pack_tag(32)
404 p.pack_text('http://www.example.com')
405 assert bytes_eq(p.bytes(), h('d82076687474703a2f2f7777772e6578616d706c652e636f6d'))
406}
407
408fn test_tag_unsigned_bignum() {
409 // Tag 2 + 9-byte big-endian magnitude for 18446744073709551616 = 2^64.
410 mut p := cbor.new_packer(cbor.EncodeOpts{})
411 p.pack_tag(2)
412 p.pack_bytes([u8(0x01), 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
413 assert bytes_eq(p.bytes(), h('c249010000000000000000'))
414}
415
416// ---------------------------------------------------------------------
417// Indefinite-length items
418// ---------------------------------------------------------------------
419
420fn test_indefinite_byte_string() {
421 mut p := cbor.new_packer(cbor.EncodeOpts{})
422 p.pack_bytes_indef()!
423 p.pack_bytes([u8(0x01), 0x02])
424 p.pack_bytes([u8(0x03), 0x04, 0x05])
425 p.pack_break()!
426 assert bytes_eq(p.bytes(), h('5f42010243030405ff'))
427}
428
429fn test_indefinite_text_string() {
430 mut p := cbor.new_packer(cbor.EncodeOpts{})
431 p.pack_text_indef()!
432 p.pack_text('strea')
433 p.pack_text('ming')
434 p.pack_break()!
435 assert bytes_eq(p.bytes(), h('7f657374726561646d696e67ff'))
436}
437
438fn test_indefinite_array() {
439 mut p := cbor.new_packer(cbor.EncodeOpts{})
440 p.pack_array_indef()!
441 p.pack_break()!
442 assert bytes_eq(p.bytes(), h('9fff'))
443}
444
445fn test_indefinite_array_with_definite_inside() {
446 // [_ 1, [2, 3], [_ 4, 5]]
447 mut p := cbor.new_packer(cbor.EncodeOpts{})
448 p.pack_array_indef()!
449 p.pack_int(1)
450 p.pack_array_header(2)
451 p.pack_int(2)
452 p.pack_int(3)
453 p.pack_array_indef()!
454 p.pack_int(4)
455 p.pack_int(5)
456 p.pack_break()!
457 p.pack_break()!
458 assert bytes_eq(p.bytes(), h('9f018202039f0405ffff'))
459}
460
461fn test_indefinite_map() {
462 // {_ "a": 1, "b": [_ 2, 3]}
463 mut p := cbor.new_packer(cbor.EncodeOpts{})
464 p.pack_map_indef()!
465 p.pack_text('a')
466 p.pack_int(1)
467 p.pack_text('b')
468 p.pack_array_indef()!
469 p.pack_int(2)
470 p.pack_int(3)
471 p.pack_break()!
472 p.pack_break()!
473 assert bytes_eq(p.bytes(), h('bf61610161629f0203ffff'))
474}
475
476// ---------------------------------------------------------------------
477// Decode side: every Appendix A vector decodes to the right value
478// ---------------------------------------------------------------------
479
480struct UintCase {
481 hex string
482 val u64
483}
484
485struct IntCase {
486 hex string
487 val i64
488}
489
490fn test_decode_unsigned() {
491 for pair in [
492 UintCase{
493 hex: '00'
494 val: 0
495 },
496 UintCase{
497 hex: '17'
498 val: 23
499 },
500 UintCase{
501 hex: '1818'
502 val: 24
503 },
504 UintCase{
505 hex: '1864'
506 val: 100
507 },
508 UintCase{
509 hex: '1903e8'
510 val: 1000
511 },
512 UintCase{
513 hex: '1a000f4240'
514 val: 1_000_000
515 },
516 UintCase{
517 hex: '1b000000e8d4a51000'
518 val: 1_000_000_000_000
519 },
520 UintCase{
521 hex: '1bffffffffffffffff'
522 val: u64(0xffffffffffffffff)
523 },
524 ] {
525 v := cbor.decode[u64](h(pair.hex), cbor.DecodeOpts{}) or {
526 panic('decode ${pair.hex}: ${err}')
527 }
528 assert v == pair.val, 'decoded ${pair.hex}: got ${v}, want ${pair.val}'
529 }
530}
531
532fn test_decode_negative() {
533 for pair in [
534 IntCase{
535 hex: '20'
536 val: -1
537 },
538 IntCase{
539 hex: '29'
540 val: -10
541 },
542 IntCase{
543 hex: '3863'
544 val: -100
545 },
546 IntCase{
547 hex: '3903e7'
548 val: -1000
549 },
550 IntCase{
551 hex: '3b7fffffffffffffff'
552 val: i64(-9_223_372_036_854_775_808)
553 },
554 ] {
555 v := cbor.decode[i64](h(pair.hex), cbor.DecodeOpts{}) or {
556 panic('decode ${pair.hex}: ${err}')
557 }
558 assert v == pair.val, 'decoded ${pair.hex}: got ${v}, want ${pair.val}'
559 }
560}
561
562fn test_decode_floats() {
563 // Half precision.
564 v := cbor.decode[f64](h('f93c00'), cbor.DecodeOpts{}) or { panic(err) }
565 assert v == 1.0
566 v2 := cbor.decode[f64](h('f93e00'), cbor.DecodeOpts{}) or { panic(err) }
567 assert v2 == 1.5
568 v3 := cbor.decode[f64](h('f97bff'), cbor.DecodeOpts{}) or { panic(err) }
569 assert v3 == 65504.0
570 // Subnormal half.
571 v4 := cbor.decode[f64](h('f90001'), cbor.DecodeOpts{}) or { panic(err) }
572 assert v4 == 5.960464477539063e-08, 'subnormal half: ${v4}'
573 // f32 / f64.
574 v5 := cbor.decode[f64](h('fa47c35000'), cbor.DecodeOpts{}) or { panic(err) }
575 assert v5 == 100000.0
576 v6 := cbor.decode[f64](h('fb3ff199999999999a'), cbor.DecodeOpts{}) or { panic(err) }
577 assert v6 == 1.1
578 // Inf / -Inf.
579 v7 := cbor.decode[f64](h('f97c00'), cbor.DecodeOpts{}) or { panic(err) }
580 assert math.is_inf(v7, 1)
581 v8 := cbor.decode[f64](h('f9fc00'), cbor.DecodeOpts{}) or { panic(err) }
582 assert math.is_inf(v8, -1)
583 // NaN.
584 v9 := cbor.decode[f64](h('f97e00'), cbor.DecodeOpts{}) or { panic(err) }
585 assert math.is_nan(v9)
586 // Alternate non-canonical encodings (roundtrip=false but must decode).
587 for hex_str in ['fa7f800000', 'fb7ff0000000000000'] {
588 val := cbor.decode[f64](h(hex_str), cbor.DecodeOpts{}) or { panic(err) }
589 assert math.is_inf(val, 1), '${hex_str} → ${val}'
590 }
591 for hex_str in ['faff800000', 'fbfff0000000000000'] {
592 val := cbor.decode[f64](h(hex_str), cbor.DecodeOpts{}) or { panic(err) }
593 assert math.is_inf(val, -1), '${hex_str} → ${val}'
594 }
595 for hex_str in ['fa7fc00000', 'fb7ff8000000000000'] {
596 val := cbor.decode[f64](h(hex_str), cbor.DecodeOpts{}) or { panic(err) }
597 assert math.is_nan(val), '${hex_str} → ${val}'
598 }
599}
600
601fn test_decode_bool_null() {
602 bf := cbor.decode[bool](h('f4'), cbor.DecodeOpts{}) or { panic(err) }
603 assert bf == false
604 bt := cbor.decode[bool](h('f5'), cbor.DecodeOpts{}) or { panic(err) }
605 assert bt == true
606 v := cbor.decode[cbor.Value](h('f6'), cbor.DecodeOpts{}) or { panic(err) }
607 assert v.is_nil()
608 u := cbor.decode[cbor.Value](h('f7'), cbor.DecodeOpts{}) or { panic(err) }
609 assert u.is_undefined()
610}
611
612fn test_decode_simple_extended() {
613 // Inline form for simple(16).
614 v0 := cbor.decode[cbor.Value](h('f0'), cbor.DecodeOpts{}) or { panic(err) }
615 assert v0 is cbor.Simple
616 if v0 is cbor.Simple {
617 assert v0.value == 16
618 }
619 // 1-byte form for simple(32) — first valid two-byte simple value.
620 mut p := cbor.new_packer(cbor.EncodeOpts{})
621 p.pack_simple(32) or { panic(err) }
622 v32 := cbor.decode[cbor.Value](p.bytes(), cbor.DecodeOpts{}) or { panic(err) }
623 assert v32 is cbor.Simple
624 if v32 is cbor.Simple {
625 assert v32.value == 32
626 }
627 // Top of the range.
628 v2 := cbor.decode[cbor.Value](h('f8ff'), cbor.DecodeOpts{}) or { panic(err) }
629 if v2 is cbor.Simple {
630 assert v2.value == 255
631 }
632}
633
634fn test_decode_strings() {
635 a := cbor.decode[string](h('60'), cbor.DecodeOpts{}) or { panic(err) }
636 assert a == ''
637 b := cbor.decode[string](h('6161'), cbor.DecodeOpts{}) or { panic(err) }
638 assert b == 'a'
639 c := cbor.decode[string](h('6449455446'), cbor.DecodeOpts{}) or { panic(err) }
640 assert c == 'IETF'
641 d := cbor.decode[string](h('62c3bc'), cbor.DecodeOpts{}) or { panic(err) }
642 assert d == 'ü'
643 e := cbor.decode[string](h('63e6b0b4'), cbor.DecodeOpts{}) or { panic(err) }
644 assert e == '水'
645 f := cbor.decode[string](h('64f0908591'), cbor.DecodeOpts{}) or { panic(err) }
646 assert f == '𐅑'
647}
648
649fn test_decode_array() {
650 v := cbor.decode[[]int](h('83010203'), cbor.DecodeOpts{}) or { panic(err) }
651 assert v == [1, 2, 3]
652}
653
654fn test_decode_map() {
655 v := cbor.decode[map[string]int](h('a26161016162820203'), cbor.DecodeOpts{}) or {
656 // This vector has b → [2,3], not int — so this decode should fail.
657 assert err.msg().contains('mismatch') || err.msg().contains('overflow')
658 return
659 }
660 _ = v
661 assert false, 'expected type mismatch on map[string]int decode of array value'
662}
663
664fn test_decode_indefinite_text() {
665 // "stream"+"ing"
666 v := cbor.decode[string](h('7f657374726561646d696e67ff'), cbor.DecodeOpts{}) or { panic(err) }
667 assert v == 'streaming'
668}
669
670fn test_decode_indefinite_array() {
671 v := cbor.decode[[]int](h('9fff'), cbor.DecodeOpts{}) or { panic(err) }
672 assert v == []int{}
673 v2 := cbor.decode[[]int](h('9f0102030405060708090a0b0c0d0e0f101112131415161718181819ff'), cbor.DecodeOpts{}) or {
674 panic(err)
675 }
676 mut want := []int{cap: 25}
677 for i in 0 .. 25 {
678 want << i + 1
679 }
680 assert v2 == want
681}
682
683fn test_decode_indefinite_bytes() {
684 v := cbor.decode[[]u8](h('5f42010243030405ff'), cbor.DecodeOpts{}) or { panic(err) }
685 assert bytes_eq(v, [u8(0x01), 0x02, 0x03, 0x04, 0x05])
686}
687
688// ---------------------------------------------------------------------
689// Round-trip for every roundtrip=true vector via the Value tree
690// ---------------------------------------------------------------------
691
692const roundtrip_vectors = [
693 '00',
694 '01',
695 '0a',
696 '17',
697 '1818',
698 '1819',
699 '1864',
700 '1903e8',
701 '1a000f4240',
702 '1b000000e8d4a51000',
703 '1bffffffffffffffff',
704 '3bffffffffffffffff',
705 '20',
706 '29',
707 '3863',
708 '3903e7',
709 'f90000',
710 'f98000',
711 'f93c00',
712 'fb3ff199999999999a',
713 'f93e00',
714 'f97bff',
715 'fa47c35000',
716 'fa7f7fffff',
717 'fb7e37e43c8800759c',
718 'f90001',
719 'f90400',
720 'f9c400',
721 'fbc010666666666666',
722 'f97c00',
723 'f97e00',
724 'f9fc00',
725 'f4',
726 'f5',
727 'f6',
728 'f7',
729 'f0',
730 'f8ff',
731 '40',
732 '4401020304',
733 '60',
734 '6161',
735 '6449455446',
736 '62225c',
737 '62c3bc',
738 '63e6b0b4',
739 '64f0908591',
740 '80',
741 '83010203',
742 '8301820203820405',
743 '98190102030405060708090a0b0c0d0e0f101112131415161718181819',
744 'a0',
745 'a201020304',
746 'a26161016162820203',
747 '826161a161626163',
748 'a56161614161626142616361436164614461656145',
749]
750
751fn test_value_roundtrip_all_canonical_vectors() {
752 for hex_str in roundtrip_vectors {
753 input := h(hex_str)
754 decoded := cbor.decode[cbor.Value](input, cbor.DecodeOpts{}) or {
755 panic('decode ${hex_str}: ${err}')
756 }
757 got := cbor.encode_value(decoded, cbor.EncodeOpts{})!
758 assert bytes_eq(got, input), 'roundtrip ${hex_str}: got ${hex.encode(got)}'
759 }
760}
761
762// Tag-bearing vectors round-trip via the Value tree as well.
763fn test_value_roundtrip_tag_vectors() {
764 for hex_str in [
765 'c074323031332d30332d32315432303a30343a30305a',
766 'c11a514b67b0',
767 'c1fb41d452d9ec200000',
768 'd74401020304',
769 'd818456449455446',
770 'd82076687474703a2f2f7777772e6578616d706c652e636f6d',
771 'c249010000000000000000',
772 'c349010000000000000000',
773 ] {
774 input := h(hex_str)
775 decoded := cbor.decode[cbor.Value](input, cbor.DecodeOpts{}) or {
776 panic('decode ${hex_str}: ${err}')
777 }
778 got := cbor.encode_value(decoded, cbor.EncodeOpts{})!
779 assert bytes_eq(got, input), 'tag roundtrip ${hex_str}: got ${hex.encode(got)}'
780 }
781}
782