@marcuspuchalla/nachos 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/CHANGELOG.md +64 -0
  2. package/LICENSE +674 -0
  3. package/README.md +345 -0
  4. package/dist/chunk-2FUTHZQQ.cjs +755 -0
  5. package/dist/chunk-2FUTHZQQ.cjs.map +1 -0
  6. package/dist/chunk-2HBCILJS.cjs +2034 -0
  7. package/dist/chunk-2HBCILJS.cjs.map +1 -0
  8. package/dist/chunk-7CFYWHS6.js +742 -0
  9. package/dist/chunk-7CFYWHS6.js.map +1 -0
  10. package/dist/chunk-PD72MVTX.cjs +160 -0
  11. package/dist/chunk-PD72MVTX.cjs.map +1 -0
  12. package/dist/chunk-ZDZ2B5PE.js +149 -0
  13. package/dist/chunk-ZDZ2B5PE.js.map +1 -0
  14. package/dist/chunk-ZRPJUEIZ.js +2020 -0
  15. package/dist/chunk-ZRPJUEIZ.js.map +1 -0
  16. package/dist/encoder/index.cjs +57 -0
  17. package/dist/encoder/index.cjs.map +1 -0
  18. package/dist/encoder/index.d.cts +72 -0
  19. package/dist/encoder/index.d.ts +72 -0
  20. package/dist/encoder/index.js +4 -0
  21. package/dist/encoder/index.js.map +1 -0
  22. package/dist/index.cjs +606 -0
  23. package/dist/index.cjs.map +1 -0
  24. package/dist/index.d.cts +494 -0
  25. package/dist/index.d.ts +494 -0
  26. package/dist/index.js +523 -0
  27. package/dist/index.js.map +1 -0
  28. package/dist/metafile-cjs.json +1 -0
  29. package/dist/metafile-esm.json +1 -0
  30. package/dist/parser/index.cjs +85 -0
  31. package/dist/parser/index.cjs.map +1 -0
  32. package/dist/parser/index.d.cts +72 -0
  33. package/dist/parser/index.d.ts +72 -0
  34. package/dist/parser/index.js +4 -0
  35. package/dist/parser/index.js.map +1 -0
  36. package/dist/types-DvNlfbKB.d.cts +301 -0
  37. package/dist/types-DvNlfbKB.d.ts +301 -0
  38. package/dist/useCborSimpleEncoder-ButVU988.d.cts +268 -0
  39. package/dist/useCborSimpleEncoder-TVxzNJ_9.d.ts +268 -0
  40. package/dist/useCborTag-B_iaShG6.d.ts +142 -0
  41. package/dist/useCborTag-BfTIV8HM.d.cts +142 -0
  42. package/package.json +102 -0
  43. package/src/__tests__/public-api.test.ts +326 -0
  44. package/src/encoder/__tests__/cbor-collection-encoder.test.ts +331 -0
  45. package/src/encoder/__tests__/cbor-integer-encoder.test.ts +283 -0
  46. package/src/encoder/__tests__/cbor-simple-encoder.test.ts +224 -0
  47. package/src/encoder/__tests__/cbor-string-encoder.test.ts +345 -0
  48. package/src/encoder/__tests__/cbor-tag-encoder.test.ts +565 -0
  49. package/src/encoder/composables/#useCborTagEncoder.ts# +158 -0
  50. package/src/encoder/composables/useCborCollectionEncoder.ts +424 -0
  51. package/src/encoder/composables/useCborEncoder.ts +203 -0
  52. package/src/encoder/composables/useCborIntegerEncoder.ts +188 -0
  53. package/src/encoder/composables/useCborSimpleEncoder.ts +266 -0
  54. package/src/encoder/composables/useCborStringEncoder.ts +266 -0
  55. package/src/encoder/composables/useCborTagEncoder.ts +158 -0
  56. package/src/encoder/index.ts +35 -0
  57. package/src/encoder/types.ts +88 -0
  58. package/src/encoder/utils.ts +80 -0
  59. package/src/index.ts +434 -0
  60. package/src/parser/__tests__/ast-tree-structure.test.ts +311 -0
  61. package/src/parser/__tests__/cbor-collection-errors.test.ts +296 -0
  62. package/src/parser/__tests__/cbor-collection.test.ts +369 -0
  63. package/src/parser/__tests__/cbor-deterministic-encoding.test.ts +432 -0
  64. package/src/parser/__tests__/cbor-diagnostic.test.ts +333 -0
  65. package/src/parser/__tests__/cbor-duplicate-keys.test.ts +235 -0
  66. package/src/parser/__tests__/cbor-float-errors.test.ts +222 -0
  67. package/src/parser/__tests__/cbor-float.test.ts +502 -0
  68. package/src/parser/__tests__/cbor-integer-errors.test.ts +139 -0
  69. package/src/parser/__tests__/cbor-integer.test.ts +200 -0
  70. package/src/parser/__tests__/cbor-map-duplicate-keys.test.ts +403 -0
  71. package/src/parser/__tests__/cbor-parser-errors.test.ts +126 -0
  72. package/src/parser/__tests__/cbor-security-dos-protection.test.ts +503 -0
  73. package/src/parser/__tests__/cbor-sequences.test.ts +150 -0
  74. package/src/parser/__tests__/cbor-source-map.test.ts +321 -0
  75. package/src/parser/__tests__/cbor-standard-tags.test.ts +340 -0
  76. package/src/parser/__tests__/cbor-string-errors.test.ts +227 -0
  77. package/src/parser/__tests__/cbor-string.test.ts +224 -0
  78. package/src/parser/__tests__/cbor-tag-advanced.test.ts +500 -0
  79. package/src/parser/__tests__/cbor-tag-errors.test.ts +447 -0
  80. package/src/parser/__tests__/cbor-tag-source-map.test.ts +360 -0
  81. package/src/parser/__tests__/cbor-tag.test.ts +684 -0
  82. package/src/parser/__tests__/extreme-edge-cases.test.ts +146 -0
  83. package/src/parser/__tests__/pathBuilder.test.ts +256 -0
  84. package/src/parser/__tests__/rfc-test-vectors.test.ts +607 -0
  85. package/src/parser/__tests__/security-limits.test.ts +248 -0
  86. package/src/parser/__tests__/utils-errors.test.ts +127 -0
  87. package/src/parser/composables/useCborCollection.ts +509 -0
  88. package/src/parser/composables/useCborDiagnostic.ts +381 -0
  89. package/src/parser/composables/useCborFloat.ts +256 -0
  90. package/src/parser/composables/useCborInteger.ts +114 -0
  91. package/src/parser/composables/useCborParser.ts +951 -0
  92. package/src/parser/composables/useCborString.ts +330 -0
  93. package/src/parser/composables/useCborStringTypes.ts +129 -0
  94. package/src/parser/composables/useCborTag.ts +739 -0
  95. package/src/parser/index.ts +56 -0
  96. package/src/parser/types.ts +371 -0
  97. package/src/parser/utils/pathBuilder.ts +259 -0
  98. package/src/parser/utils.ts +398 -0
  99. package/src/utils/__tests__/logger.test.ts +186 -0
  100. package/src/utils/logger.ts +96 -0
@@ -0,0 +1,684 @@
1
+ /**
2
+ * CBOR Tag Parser Tests
3
+ * Major Type 6 (Semantic Tags)
4
+ * Following RFC 8949 specification
5
+ */
6
+
7
+ import { describe, it, expect } from 'vitest'
8
+ import { useCborTag } from '../composables/useCborTag'
9
+
10
+ describe('useCborTag', () => {
11
+ describe('Standard Tags (0-5)', () => {
12
+ describe('Tag 0: Standard Date/Time String (RFC 3339)', () => {
13
+ it('should parse tag 0 with ISO 8601 date string', () => {
14
+ const { parseTag } = useCborTag()
15
+
16
+ // RFC 8949 Example: 0("2013-03-21T20:04:00Z")
17
+ // 0xc0 = tag 0, followed by text string
18
+ const result = parseTag('c074323031332d30332d3231543230 3a30343a30305a'.replace(/\s/g, ''))
19
+ expect(result.value).toEqual({
20
+ tag: 0,
21
+ value: '2013-03-21T20:04:00Z'
22
+ })
23
+ expect(result.bytesRead).toBe(22) // 1 (tag) + 1 (string header) + 20 (string data)
24
+ })
25
+
26
+ it('should parse tag 0 with date string including milliseconds', () => {
27
+ const { parseTag } = useCborTag()
28
+
29
+ // "2023-12-25T15:30:45.123Z"
30
+ const result = parseTag('c07818323032332d31322d32355431353a33303a34352e3132335a')
31
+ expect(result.value).toEqual({
32
+ tag: 0,
33
+ value: '2023-12-25T15:30:45.123Z'
34
+ })
35
+ })
36
+
37
+ it('should parse tag 0 with timezone offset', () => {
38
+ const { parseTag } = useCborTag()
39
+
40
+ // "2023-01-01T00:00:00+05:30"
41
+ const result = parseTag('c07819323032332d30312d30315430303a30303a30302b30353a3330')
42
+ expect(result.value.tag).toBe(0)
43
+ expect(result.value.value).toBe('2023-01-01T00:00:00+05:30')
44
+ })
45
+ })
46
+
47
+ describe('Tag 1: Epoch-based Date/Time', () => {
48
+ it('should parse tag 1 with positive integer (epoch timestamp)', () => {
49
+ const { parseTag } = useCborTag()
50
+
51
+ // RFC 8949 Example: 1(1363896240)
52
+ // 0xc1 = tag 1, 0x1a = 4-byte uint
53
+ const result = parseTag('c11a514b67b0')
54
+ expect(result.value).toEqual({
55
+ tag: 1,
56
+ value: 1363896240
57
+ })
58
+ expect(result.bytesRead).toBe(6)
59
+ })
60
+
61
+ it('should parse tag 1 with negative integer (before epoch)', () => {
62
+ const { parseTag } = useCborTag()
63
+
64
+ // 1(-1000000) - before Unix epoch
65
+ const result = parseTag('c13a000f423f')
66
+ expect(result.value).toEqual({
67
+ tag: 1,
68
+ value: -1000000
69
+ })
70
+ })
71
+
72
+ it('should parse tag 1 with float64 (fractional seconds)', () => {
73
+ const { parseTag } = useCborTag()
74
+
75
+ // 1(1363896240.5) - with milliseconds
76
+ const result = parseTag('c1fb41d452d9ec200000')
77
+ expect(result.value.tag).toBe(1)
78
+ expect(result.value.value).toBeCloseTo(1363896240.5, 1)
79
+ })
80
+ })
81
+
82
+ describe('Tag 2: Positive Bignum', () => {
83
+ it('should parse tag 2 with byte string (unsigned bignum)', () => {
84
+ const { parseTag } = useCborTag()
85
+
86
+ // RFC 8949: 2(h'010000000000000000') = 2^64
87
+ // 0xc2 = tag 2, 0x49 = 9-byte byte string
88
+ // Parser converts bignum to BigInt value
89
+ const result = parseTag('c249010000000000000000')
90
+ expect(result.value.tag).toBe(2)
91
+ expect(result.value.value).toBe(18446744073709551616n)
92
+ })
93
+
94
+ it('should parse tag 2 with small bignum', () => {
95
+ const { parseTag } = useCborTag()
96
+
97
+ // 2(h'0100') = 256
98
+ // Parser converts bignum to BigInt value
99
+ const result = parseTag('c2420100')
100
+ expect(result.value.tag).toBe(2)
101
+ expect(result.value.value).toBe(256n)
102
+ })
103
+
104
+ it('should parse tag 2 with empty byte string (value 0)', () => {
105
+ const { parseTag } = useCborTag()
106
+
107
+ // 2(h'') = 0
108
+ // Parser converts bignum to BigInt value
109
+ const result = parseTag('c240')
110
+ expect(result.value.tag).toBe(2)
111
+ expect(result.value.value).toBe(0n)
112
+ })
113
+ })
114
+
115
+ describe('Tag 3: Negative Bignum', () => {
116
+ it('should parse tag 3 with byte string (negative bignum)', () => {
117
+ const { parseTag } = useCborTag()
118
+
119
+ // RFC 8949: 3(h'010000000000000000') = -2^64 - 1
120
+ // Parser converts bignum to BigInt value
121
+ const result = parseTag('c349010000000000000000')
122
+ expect(result.value.tag).toBe(3)
123
+ expect(result.value.value).toBe(-18446744073709551617n)
124
+ })
125
+
126
+ it('should parse tag 3 with small negative bignum', () => {
127
+ const { parseTag } = useCborTag()
128
+
129
+ // 3(h'0100') = -257
130
+ // Parser converts bignum to BigInt value
131
+ const result = parseTag('c3420100')
132
+ expect(result.value.tag).toBe(3)
133
+ expect(result.value.value).toBe(-257n)
134
+ })
135
+ })
136
+
137
+ describe('Tag 4: Decimal Fraction [exponent, mantissa]', () => {
138
+ it('should parse tag 4 with array [exponent, mantissa]', () => {
139
+ const { parseTag } = useCborTag()
140
+
141
+ // RFC 8949: 4([-2, 27315]) = 273.15
142
+ // 0xc4 = tag 4, 0x82 = array(2), 0x21 = -2, 0x196ab3 = 27315
143
+ const result = parseTag('c48221196ab3')
144
+ expect(result.value.tag).toBe(4)
145
+ expect(result.value.value).toEqual([-2, 27315])
146
+ expect(result.bytesRead).toBe(6)
147
+ })
148
+
149
+ it('should parse tag 4 with positive exponent', () => {
150
+ const { parseTag } = useCborTag()
151
+
152
+ // 4([2, 5]) = 500
153
+ const result = parseTag('c4820205')
154
+ expect(result.value.tag).toBe(4)
155
+ expect(result.value.value).toEqual([2, 5])
156
+ })
157
+
158
+ it('should parse tag 4 with zero exponent', () => {
159
+ const { parseTag } = useCborTag()
160
+
161
+ // 4([0, 123]) = 123
162
+ const result = parseTag('c48200187b')
163
+ expect(result.value.tag).toBe(4)
164
+ expect(result.value.value).toEqual([0, 123])
165
+ })
166
+ })
167
+
168
+ describe('Tag 5: Bigfloat [exponent, mantissa]', () => {
169
+ it('should parse tag 5 with array [exponent, mantissa]', () => {
170
+ const { parseTag } = useCborTag()
171
+
172
+ // RFC 8949: 5([-2, 3]) = 3 * 2^-2 = 0.75
173
+ const result = parseTag('c5822103')
174
+ expect(result.value.tag).toBe(5)
175
+ expect(result.value.value).toEqual([-2, 3])
176
+ expect(result.bytesRead).toBe(4)
177
+ })
178
+
179
+ it('should parse tag 5 with large mantissa', () => {
180
+ const { parseTag } = useCborTag()
181
+
182
+ // 5([10, 1000000])
183
+ const result = parseTag('c5820a1a000f4240')
184
+ expect(result.value.tag).toBe(5)
185
+ expect(result.value.value).toEqual([10, 1000000])
186
+ })
187
+ })
188
+ })
189
+
190
+ describe('Encoding Hint Tags (21-36)', () => {
191
+ describe('Tag 21: Base64url Encoding Expected', () => {
192
+ it('should parse tag 21 with byte string', () => {
193
+ const { parseTag } = useCborTag()
194
+
195
+ // 21(h'01020304')
196
+ const result = parseTag('d54401020304')
197
+ expect(result.value.tag).toBe(21)
198
+ expect(result.value.value).toEqual(new Uint8Array([0x01, 0x02, 0x03, 0x04]))
199
+ })
200
+ })
201
+
202
+ describe('Tag 22: Base64 Encoding Expected', () => {
203
+ it('should parse tag 22 with byte string', () => {
204
+ const { parseTag } = useCborTag()
205
+
206
+ // 22(h'48656c6c6f')
207
+ const result = parseTag('d64548656c6c6f')
208
+ expect(result.value.tag).toBe(22)
209
+ expect(result.value.value).toEqual(
210
+ new Uint8Array([0x48, 0x65, 0x6c, 0x6c, 0x6f])
211
+ )
212
+ })
213
+ })
214
+
215
+ describe('Tag 23: Base16 (Hex) Encoding Expected', () => {
216
+ it('should parse tag 23 with byte string', () => {
217
+ const { parseTag } = useCborTag()
218
+
219
+ // 23(h'aabbccdd')
220
+ const result = parseTag('d744aabbccdd')
221
+ expect(result.value.tag).toBe(23)
222
+ expect(result.value.value).toEqual(
223
+ new Uint8Array([0xaa, 0xbb, 0xcc, 0xdd])
224
+ )
225
+ })
226
+ })
227
+
228
+ describe('Tag 24: Embedded CBOR Data Item', () => {
229
+ it('should parse tag 24 with byte string containing CBOR', () => {
230
+ const { parseTag } = useCborTag()
231
+
232
+ // 24(h'8301020 3') - byte string containing CBOR array [1,2,3]
233
+ const result = parseTag('d8184483010203')
234
+ expect(result.value.tag).toBe(24)
235
+ expect(result.value.value).toEqual(new Uint8Array([0x83, 0x01, 0x02, 0x03]))
236
+ })
237
+
238
+ it('should parse tag 24 with nested CBOR map', () => {
239
+ const { parseTag } = useCborTag()
240
+
241
+ // 24(h'a16161 01') - CBOR map {"a": 1}
242
+ const result = parseTag('d81844a1616101')
243
+ expect(result.value.tag).toBe(24)
244
+ expect(result.value.value).toEqual(new Uint8Array([0xa1, 0x61, 0x61, 0x01]))
245
+ })
246
+ })
247
+
248
+ describe('Tag 32: URI', () => {
249
+ it('should parse tag 32 with URI text string', () => {
250
+ const { parseTag } = useCborTag()
251
+
252
+ // 32("http://www.example.com")
253
+ // 0xd8 0x20 = tag 32 (1-byte encoding)
254
+ const result = parseTag('d82076687474703a2f2f7777772e6578616d706c652e636f6d')
255
+ expect(result.value.tag).toBe(32)
256
+ expect(result.value.value).toBe('http://www.example.com')
257
+ })
258
+
259
+ it('should parse tag 32 with HTTPS URI', () => {
260
+ const { parseTag } = useCborTag()
261
+
262
+ // 32("https://github.com")
263
+ const result = parseTag('d82072687474707 33a2f2f6769746875622e636f6d'.replace(/\s/g, ''))
264
+ expect(result.value.tag).toBe(32)
265
+ expect(result.value.value).toBe('https://github.com')
266
+ })
267
+ })
268
+
269
+ describe('Tag 33: Base64url (text string)', () => {
270
+ it('should parse tag 33 with base64url text', () => {
271
+ const { parseTag } = useCborTag()
272
+
273
+ // 33("SGVsbG8")
274
+ const result = parseTag('d82167534756736247 38'.replace(/\s/g, ''))
275
+ expect(result.value.tag).toBe(33)
276
+ expect(result.value.value).toBe('SGVsbG8')
277
+ })
278
+ })
279
+
280
+ describe('Tag 34: Base64 (text string)', () => {
281
+ it('should parse tag 34 with base64 text', () => {
282
+ const { parseTag } = useCborTag()
283
+
284
+ // 34("SGVsbG8=")
285
+ const result = parseTag('d82268534756736247383d')
286
+ expect(result.value.tag).toBe(34)
287
+ expect(result.value.value).toBe('SGVsbG8=')
288
+ })
289
+ })
290
+
291
+ describe('Tag 36: MIME Message', () => {
292
+ it('should parse tag 36 with MIME content', () => {
293
+ const { parseTag } = useCborTag()
294
+
295
+ // 36("Content-Type: text/plain")
296
+ const result = parseTag('d8247818436f6e74656e742d547970653a20746578742f706c61696e')
297
+ expect(result.value.tag).toBe(36)
298
+ expect(result.value.value).toBe('Content-Type: text/plain')
299
+ })
300
+ })
301
+ })
302
+
303
+ describe('Self-Describe CBOR Tag', () => {
304
+ describe('Tag 55799: Self-Describe CBOR', () => {
305
+ it('should parse tag 55799 with magic number', () => {
306
+ const { parseTag } = useCborTag()
307
+
308
+ // RFC 8949: 55799([1, 2])
309
+ // 0xd9d9f7 = tag 55799 (2-byte encoding: 0xd9 + 0xd9f7)
310
+ const result = parseTag('d9d9f7820102')
311
+ expect(result.value.tag).toBe(55799)
312
+ expect(result.value.value).toEqual([1, 2])
313
+ expect(result.bytesRead).toBe(6)
314
+ })
315
+
316
+ it('should parse tag 55799 with complex nested structure', () => {
317
+ const { parseTag } = useCborTag()
318
+
319
+ // 55799({"msg": "Hello"})
320
+ const result = parseTag('d9d9f7a1636d73676548656c6c6f')
321
+ expect(result.value.tag).toBe(55799)
322
+ expect(result.value.value).toEqual(new Map([['msg', 'Hello']]))
323
+ })
324
+
325
+ it('should parse tag 55799 wrapping simple integer', () => {
326
+ const { parseTag } = useCborTag()
327
+
328
+ // 55799(42)
329
+ const result = parseTag('d9d9f7182a')
330
+ expect(result.value.tag).toBe(55799)
331
+ expect(result.value.value).toBe(42)
332
+ })
333
+ })
334
+ })
335
+
336
+ describe('Cardano-Specific Tags', () => {
337
+ describe('Tag 121: Cardano Transaction (placeholder)', () => {
338
+ it('should parse tag 121 with transaction array', () => {
339
+ const { parseTag } = useCborTag()
340
+
341
+ // 121([txBody, witnessSet, metadata])
342
+ // Simplified: 121([1, 2, 3])
343
+ const result = parseTag('d87983010203')
344
+ expect(result.value.tag).toBe(121)
345
+ expect(result.value.value).toEqual([1, 2, 3])
346
+ })
347
+ })
348
+
349
+ describe('Tag 122: Cardano Witness Set (placeholder)', () => {
350
+ it('should parse tag 122 with witness map', () => {
351
+ const { parseTag } = useCborTag()
352
+
353
+ // 122({"vkeys": []})
354
+ // Simplified: 122({})
355
+ const result = parseTag('d87aa0')
356
+ expect(result.value.tag).toBe(122)
357
+ expect(result.value.value).toEqual(new Map())
358
+ })
359
+ })
360
+
361
+ describe('Tag 258: Mathematical Set', () => {
362
+ it('should parse tag 258 with array as set', () => {
363
+ const { parseTag } = useCborTag()
364
+
365
+ // RFC 8949: 258([1, 2, 3]) - represents set {1, 2, 3}
366
+ // 0xd90102 = tag 258 (2-byte encoding: 0xd9 + 0x0102)
367
+ const result = parseTag('d9010283010203')
368
+ expect(result.value.tag).toBe(258)
369
+ expect(result.value.value).toEqual([1, 2, 3])
370
+ })
371
+
372
+ it('should parse tag 258 with empty set', () => {
373
+ const { parseTag } = useCborTag()
374
+
375
+ // 258([]) - empty set
376
+ const result = parseTag('d9010280')
377
+ expect(result.value.tag).toBe(258)
378
+ expect(result.value.value).toEqual([])
379
+ })
380
+
381
+ it('should parse tag 258 with string set', () => {
382
+ const { parseTag } = useCborTag()
383
+
384
+ // 258(["a", "b", "c"])
385
+ const result = parseTag('d9010283616161626163')
386
+ expect(result.value.tag).toBe(258)
387
+ expect(result.value.value).toEqual(['a', 'b', 'c'])
388
+ })
389
+ })
390
+ })
391
+
392
+ describe('Nested Tags', () => {
393
+ it('should parse tag inside tag (double tagging)', () => {
394
+ const { parseTag } = useCborTag()
395
+
396
+ // 0(1(1363896240)) - date as both tag 0 and tag 1
397
+ const result = parseTag('c0c11a514b67b0')
398
+ expect(result.value.tag).toBe(0)
399
+ expect(result.value.value).toEqual({
400
+ tag: 1,
401
+ value: 1363896240
402
+ })
403
+ })
404
+
405
+ it('should parse triple nested tags', () => {
406
+ const { parseTag } = useCborTag()
407
+
408
+ // 258(21(24(h'83010203')))
409
+ // Set containing base64url containing embedded CBOR
410
+ const result = parseTag('d90102d5d8184483010203')
411
+ expect(result.value.tag).toBe(258)
412
+ expect(result.value.value.tag).toBe(21)
413
+ expect(result.value.value.value.tag).toBe(24)
414
+ })
415
+
416
+ it('should parse tag wrapping array of tagged values', () => {
417
+ const { parseTag } = useCborTag()
418
+
419
+ // 258([1(100), 1(200)]) - set of two epoch times
420
+ const result = parseTag('d9010282c11864c118c8')
421
+ expect(result.value.tag).toBe(258)
422
+ expect(result.value.value).toHaveLength(2)
423
+ expect(result.value.value[0]).toEqual({ tag: 1, value: 100 })
424
+ expect(result.value.value[1]).toEqual({ tag: 1, value: 200 })
425
+ })
426
+
427
+ it('should parse tag wrapping map with tagged values', () => {
428
+ const { parseTag } = useCborTag()
429
+
430
+ // 258({"time": 1(1000)})
431
+ const result = parseTag('d90102a16474696d65c11903e8')
432
+ expect(result.value.tag).toBe(258)
433
+ expect(result.value.value).toEqual(new Map([
434
+ ['time', { tag: 1, value: 1000 }]
435
+ ]))
436
+ })
437
+ })
438
+
439
+ describe('Extended Tag Numbers (1-byte, 2-byte, 4-byte, 8-byte)', () => {
440
+ describe('Direct encoding (tags 0-23)', () => {
441
+ it('should parse tag 0 with direct encoding', () => {
442
+ const { parseTag } = useCborTag()
443
+
444
+ // Tag 0: 0xc0
445
+ const result = parseTag('c06474657374')
446
+ expect(result.value.tag).toBe(0)
447
+ expect(result.value.value).toBe('test')
448
+ })
449
+
450
+ it('should parse tag 23 with direct encoding', () => {
451
+ const { parseTag } = useCborTag()
452
+
453
+ // Tag 23: 0xd7
454
+ const result = parseTag('d74401020304')
455
+ expect(result.value.tag).toBe(23)
456
+ })
457
+ })
458
+
459
+ describe('1-byte encoding (tags 24-255)', () => {
460
+ it('should parse tag 24 with 1-byte encoding', () => {
461
+ const { parseTag } = useCborTag()
462
+
463
+ // Tag 24: 0xd8 0x18
464
+ const result = parseTag('d8184401020304')
465
+ expect(result.value.tag).toBe(24)
466
+ expect(result.value.value).toEqual(new Uint8Array([0x01, 0x02, 0x03, 0x04]))
467
+ })
468
+
469
+ it('should parse tag 32 with 1-byte encoding', () => {
470
+ const { parseTag } = useCborTag()
471
+
472
+ // Tag 32: 0xd8 0x20
473
+ const result = parseTag('d8206474657374')
474
+ expect(result.value.tag).toBe(32)
475
+ expect(result.value.value).toBe('test')
476
+ })
477
+
478
+ it('should parse tag 255 with 1-byte encoding', () => {
479
+ const { parseTag } = useCborTag()
480
+
481
+ // Tag 255: 0xd8 0xff
482
+ const result = parseTag('d8ff00')
483
+ expect(result.value.tag).toBe(255)
484
+ expect(result.value.value).toBe(0)
485
+ })
486
+ })
487
+
488
+ describe('2-byte encoding (tags 256-65535)', () => {
489
+ it('should parse tag 256 with 2-byte encoding', () => {
490
+ const { parseTag } = useCborTag()
491
+
492
+ // Tag 256: 0xd9 0x0100
493
+ const result = parseTag('d9010000')
494
+ expect(result.value.tag).toBe(256)
495
+ expect(result.value.value).toBe(0)
496
+ })
497
+
498
+ it('should parse tag 258 (set) with 2-byte encoding', () => {
499
+ const { parseTag } = useCborTag()
500
+
501
+ // Tag 258: 0xd9 0x0102
502
+ const result = parseTag('d9010280')
503
+ expect(result.value.tag).toBe(258)
504
+ })
505
+
506
+ it('should parse tag 55799 (self-describe) with 2-byte encoding', () => {
507
+ const { parseTag } = useCborTag()
508
+
509
+ // Tag 55799: 0xd9 0xd9f7
510
+ const result = parseTag('d9d9f700')
511
+ expect(result.value.tag).toBe(55799)
512
+ expect(result.value.value).toBe(0)
513
+ })
514
+
515
+ it('should parse tag 65535 with 2-byte encoding', () => {
516
+ const { parseTag } = useCborTag()
517
+
518
+ // Tag 65535: 0xd9 0xffff
519
+ const result = parseTag('d9ffff00')
520
+ expect(result.value.tag).toBe(65535)
521
+ expect(result.value.value).toBe(0)
522
+ })
523
+ })
524
+
525
+ describe('4-byte encoding (tags 65536+)', () => {
526
+ it('should parse tag 65536 with 4-byte encoding', () => {
527
+ const { parseTag } = useCborTag()
528
+
529
+ // Tag 65536: 0xda 0x00010000
530
+ const result = parseTag('da0001000000')
531
+ expect(result.value.tag).toBe(65536)
532
+ expect(result.value.value).toBe(0)
533
+ })
534
+
535
+ it('should parse tag 1000000 with 4-byte encoding', () => {
536
+ const { parseTag } = useCborTag()
537
+
538
+ // Tag 1000000: 0xda 0x000f4240
539
+ const result = parseTag('da000f424000')
540
+ expect(result.value.tag).toBe(1000000)
541
+ expect(result.value.value).toBe(0)
542
+ })
543
+
544
+ it('should parse tag 4294967295 (max 4-byte) with 4-byte encoding', () => {
545
+ const { parseTag } = useCborTag()
546
+
547
+ // Tag 2^32-1: 0xda 0xffffffff
548
+ const result = parseTag('daffffffff00')
549
+ expect(result.value.tag).toBe(4294967295)
550
+ expect(result.value.value).toBe(0)
551
+ })
552
+ })
553
+
554
+ describe('8-byte encoding (tags 4294967296+)', () => {
555
+ it('should parse tag with 8-byte encoding', () => {
556
+ const { parseTag } = useCborTag()
557
+
558
+ // Tag 4294967296 (2^32): 0xdb 0x0000000100000000
559
+ const result = parseTag('db000000010000000000')
560
+ expect(result.value.tag).toBe(4294967296)
561
+ expect(result.value.value).toBe(0)
562
+ })
563
+
564
+ it('should parse very large tag number with 8-byte encoding', () => {
565
+ const { parseTag } = useCborTag()
566
+
567
+ // Tag 1000000000000: 0xdb 0x000000e8d4a51000
568
+ const result = parseTag('db000000e8d4a5100000')
569
+ expect(result.value.tag).toBe(1000000000000)
570
+ expect(result.value.value).toBe(0)
571
+ })
572
+ })
573
+ })
574
+
575
+ describe('Error Handling', () => {
576
+ it('should throw error for invalid major type in parseTag', () => {
577
+ const { parseTag } = useCborTag()
578
+
579
+ // 0x00 = integer 0, not tag
580
+ expect(() => parseTag('00')).toThrow('Expected major type 6 (tag)')
581
+ })
582
+
583
+ it('should throw error for truncated tag data', () => {
584
+ const { parseTag } = useCborTag()
585
+
586
+ // 0xc0 = tag 0, but no following data
587
+ expect(() => parseTag('c0')).toThrow()
588
+ })
589
+
590
+ it('should throw error for truncated 1-byte tag number', () => {
591
+ const { parseTag } = useCborTag()
592
+
593
+ // 0xd8 = 1-byte tag, but no tag number
594
+ expect(() => parseTag('d8')).toThrow()
595
+ })
596
+
597
+ it('should throw error for truncated 2-byte tag number', () => {
598
+ const { parseTag } = useCborTag()
599
+
600
+ // 0xd9 = 2-byte tag, incomplete tag number
601
+ expect(() => parseTag('d901')).toThrow()
602
+ })
603
+
604
+ it('should throw error for truncated 4-byte tag number', () => {
605
+ const { parseTag } = useCborTag()
606
+
607
+ // 0xda = 4-byte tag, incomplete tag number
608
+ expect(() => parseTag('da0001')).toThrow()
609
+ })
610
+
611
+ it('should throw error for truncated 8-byte tag number', () => {
612
+ const { parseTag } = useCborTag()
613
+
614
+ // 0xdb = 8-byte tag, incomplete tag number
615
+ expect(() => parseTag('db00000001')).toThrow()
616
+ })
617
+
618
+ it('should throw error for reserved additional info', () => {
619
+ const { parseTag } = useCborTag()
620
+
621
+ // 0xdc = MT 6, AI 28 (reserved)
622
+ expect(() => parseTag('dc')).toThrow('Reserved additional info')
623
+ })
624
+
625
+ it('should throw error for tag with missing value', () => {
626
+ const { parseTag } = useCborTag()
627
+
628
+ // Tag 0 with truncated string
629
+ expect(() => parseTag('c06474')).toThrow()
630
+ })
631
+ })
632
+
633
+ describe('Auto-detect parse function', () => {
634
+ it('should auto-detect and parse tag 0', () => {
635
+ const { parse } = useCborTag()
636
+
637
+ const result = parse('c074323031332d30332d3231543230 3a30343a30305a')
638
+ expect(result.value.tag).toBe(0)
639
+ expect(result.value.value).toBe('2013-03-21T20:04:00Z')
640
+ })
641
+
642
+ it('should auto-detect and parse tag 258', () => {
643
+ const { parse } = useCborTag()
644
+
645
+ const result = parse('d9010283010203')
646
+ expect(result.value.tag).toBe(258)
647
+ expect(result.value.value).toEqual([1, 2, 3])
648
+ })
649
+
650
+ it('should auto-detect and parse nested tags', () => {
651
+ const { parse } = useCborTag()
652
+
653
+ const result = parse('c0c11a514b67b0')
654
+ expect(result.value.tag).toBe(0)
655
+ expect(result.value.value.tag).toBe(1)
656
+ })
657
+ })
658
+
659
+ describe('RFC 8949 Examples', () => {
660
+ it('should parse RFC example: 0("2013-03-21T20:04:00Z")', () => {
661
+ const { parse } = useCborTag()
662
+
663
+ const result = parse('c074323031332d30332d3231543230 3a30343a30305a')
664
+ expect(result.value.tag).toBe(0)
665
+ expect(result.value.value).toBe('2013-03-21T20:04:00Z')
666
+ })
667
+
668
+ it('should parse RFC example: 1(1363896240)', () => {
669
+ const { parse } = useCborTag()
670
+
671
+ const result = parse('c11a514b67b0')
672
+ expect(result.value.tag).toBe(1)
673
+ expect(result.value.value).toBe(1363896240)
674
+ })
675
+
676
+ it('should parse RFC example: 55799(h\'\')', () => {
677
+ const { parse } = useCborTag()
678
+
679
+ const result = parse('d9d9f740')
680
+ expect(result.value.tag).toBe(55799)
681
+ expect(result.value.value).toEqual(new Uint8Array([]))
682
+ })
683
+ })
684
+ })