@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.
- package/CHANGELOG.md +64 -0
- package/LICENSE +674 -0
- package/README.md +345 -0
- package/dist/chunk-2FUTHZQQ.cjs +755 -0
- package/dist/chunk-2FUTHZQQ.cjs.map +1 -0
- package/dist/chunk-2HBCILJS.cjs +2034 -0
- package/dist/chunk-2HBCILJS.cjs.map +1 -0
- package/dist/chunk-7CFYWHS6.js +742 -0
- package/dist/chunk-7CFYWHS6.js.map +1 -0
- package/dist/chunk-PD72MVTX.cjs +160 -0
- package/dist/chunk-PD72MVTX.cjs.map +1 -0
- package/dist/chunk-ZDZ2B5PE.js +149 -0
- package/dist/chunk-ZDZ2B5PE.js.map +1 -0
- package/dist/chunk-ZRPJUEIZ.js +2020 -0
- package/dist/chunk-ZRPJUEIZ.js.map +1 -0
- package/dist/encoder/index.cjs +57 -0
- package/dist/encoder/index.cjs.map +1 -0
- package/dist/encoder/index.d.cts +72 -0
- package/dist/encoder/index.d.ts +72 -0
- package/dist/encoder/index.js +4 -0
- package/dist/encoder/index.js.map +1 -0
- package/dist/index.cjs +606 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +494 -0
- package/dist/index.d.ts +494 -0
- package/dist/index.js +523 -0
- package/dist/index.js.map +1 -0
- package/dist/metafile-cjs.json +1 -0
- package/dist/metafile-esm.json +1 -0
- package/dist/parser/index.cjs +85 -0
- package/dist/parser/index.cjs.map +1 -0
- package/dist/parser/index.d.cts +72 -0
- package/dist/parser/index.d.ts +72 -0
- package/dist/parser/index.js +4 -0
- package/dist/parser/index.js.map +1 -0
- package/dist/types-DvNlfbKB.d.cts +301 -0
- package/dist/types-DvNlfbKB.d.ts +301 -0
- package/dist/useCborSimpleEncoder-ButVU988.d.cts +268 -0
- package/dist/useCborSimpleEncoder-TVxzNJ_9.d.ts +268 -0
- package/dist/useCborTag-B_iaShG6.d.ts +142 -0
- package/dist/useCborTag-BfTIV8HM.d.cts +142 -0
- package/package.json +102 -0
- package/src/__tests__/public-api.test.ts +326 -0
- package/src/encoder/__tests__/cbor-collection-encoder.test.ts +331 -0
- package/src/encoder/__tests__/cbor-integer-encoder.test.ts +283 -0
- package/src/encoder/__tests__/cbor-simple-encoder.test.ts +224 -0
- package/src/encoder/__tests__/cbor-string-encoder.test.ts +345 -0
- package/src/encoder/__tests__/cbor-tag-encoder.test.ts +565 -0
- package/src/encoder/composables/#useCborTagEncoder.ts# +158 -0
- package/src/encoder/composables/useCborCollectionEncoder.ts +424 -0
- package/src/encoder/composables/useCborEncoder.ts +203 -0
- package/src/encoder/composables/useCborIntegerEncoder.ts +188 -0
- package/src/encoder/composables/useCborSimpleEncoder.ts +266 -0
- package/src/encoder/composables/useCborStringEncoder.ts +266 -0
- package/src/encoder/composables/useCborTagEncoder.ts +158 -0
- package/src/encoder/index.ts +35 -0
- package/src/encoder/types.ts +88 -0
- package/src/encoder/utils.ts +80 -0
- package/src/index.ts +434 -0
- package/src/parser/__tests__/ast-tree-structure.test.ts +311 -0
- package/src/parser/__tests__/cbor-collection-errors.test.ts +296 -0
- package/src/parser/__tests__/cbor-collection.test.ts +369 -0
- package/src/parser/__tests__/cbor-deterministic-encoding.test.ts +432 -0
- package/src/parser/__tests__/cbor-diagnostic.test.ts +333 -0
- package/src/parser/__tests__/cbor-duplicate-keys.test.ts +235 -0
- package/src/parser/__tests__/cbor-float-errors.test.ts +222 -0
- package/src/parser/__tests__/cbor-float.test.ts +502 -0
- package/src/parser/__tests__/cbor-integer-errors.test.ts +139 -0
- package/src/parser/__tests__/cbor-integer.test.ts +200 -0
- package/src/parser/__tests__/cbor-map-duplicate-keys.test.ts +403 -0
- package/src/parser/__tests__/cbor-parser-errors.test.ts +126 -0
- package/src/parser/__tests__/cbor-security-dos-protection.test.ts +503 -0
- package/src/parser/__tests__/cbor-sequences.test.ts +150 -0
- package/src/parser/__tests__/cbor-source-map.test.ts +321 -0
- package/src/parser/__tests__/cbor-standard-tags.test.ts +340 -0
- package/src/parser/__tests__/cbor-string-errors.test.ts +227 -0
- package/src/parser/__tests__/cbor-string.test.ts +224 -0
- package/src/parser/__tests__/cbor-tag-advanced.test.ts +500 -0
- package/src/parser/__tests__/cbor-tag-errors.test.ts +447 -0
- package/src/parser/__tests__/cbor-tag-source-map.test.ts +360 -0
- package/src/parser/__tests__/cbor-tag.test.ts +684 -0
- package/src/parser/__tests__/extreme-edge-cases.test.ts +146 -0
- package/src/parser/__tests__/pathBuilder.test.ts +256 -0
- package/src/parser/__tests__/rfc-test-vectors.test.ts +607 -0
- package/src/parser/__tests__/security-limits.test.ts +248 -0
- package/src/parser/__tests__/utils-errors.test.ts +127 -0
- package/src/parser/composables/useCborCollection.ts +509 -0
- package/src/parser/composables/useCborDiagnostic.ts +381 -0
- package/src/parser/composables/useCborFloat.ts +256 -0
- package/src/parser/composables/useCborInteger.ts +114 -0
- package/src/parser/composables/useCborParser.ts +951 -0
- package/src/parser/composables/useCborString.ts +330 -0
- package/src/parser/composables/useCborStringTypes.ts +129 -0
- package/src/parser/composables/useCborTag.ts +739 -0
- package/src/parser/index.ts +56 -0
- package/src/parser/types.ts +371 -0
- package/src/parser/utils/pathBuilder.ts +259 -0
- package/src/parser/utils.ts +398 -0
- package/src/utils/__tests__/logger.test.ts +186 -0
- 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
|
+
})
|