@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,500 @@
1
+ /**
2
+ * CBOR Advanced Tag Tests - Semantic Interpretation & Validation
3
+ * Tests for Tag 258 (Set), Tag 4 (Decimal Fraction), Tag 5 (Bigfloat)
4
+ * Following TDD principles with real-world CBOR examples
5
+ */
6
+
7
+ import { describe, it, expect } from 'vitest'
8
+ import { useCborTag } from '../composables/useCborTag'
9
+
10
+ describe('useCborTag - Advanced Semantic Tags', () => {
11
+ describe('Tag 258: Mathematical Finite Set (with uniqueness validation)', () => {
12
+ describe('Valid sets (no duplicates)', () => {
13
+ it('should parse set of unique integers', () => {
14
+ const { parseTag } = useCborTag()
15
+
16
+ // 258([1, 2, 3]) - unique integers
17
+ // d9 0102 = tag 258 (2-byte), 83 = array(3)
18
+ const result = parseTag('d9010283010203')
19
+
20
+ expect(result.value.tag).toBe(258)
21
+ expect(result.value.value).toEqual([1, 2, 3])
22
+ expect(result.bytesRead).toBe(7)
23
+ })
24
+
25
+ it('should parse set of unique strings', () => {
26
+ const { parseTag } = useCborTag()
27
+
28
+ // 258(["a", "b", "c"]) - unique strings
29
+ const result = parseTag('d9010283616161626163')
30
+
31
+ expect(result.value.tag).toBe(258)
32
+ expect(result.value.value).toEqual(['a', 'b', 'c'])
33
+ })
34
+
35
+ it('should parse empty set', () => {
36
+ const { parseTag } = useCborTag()
37
+
38
+ // 258([]) - empty set (always valid)
39
+ const result = parseTag('d9010280')
40
+
41
+ expect(result.value.tag).toBe(258)
42
+ expect(result.value.value).toEqual([])
43
+ })
44
+
45
+ it('should parse single-element set', () => {
46
+ const { parseTag } = useCborTag()
47
+
48
+ // 258([42]) - single element
49
+ // d9 0102 = tag 258, 81 = array(1), 18 2a = value 42
50
+ const result = parseTag('d901028118 2a'.replace(/\s/g, ''))
51
+
52
+ expect(result.value.tag).toBe(258)
53
+ expect(result.value.value).toEqual([42])
54
+ })
55
+
56
+ it('should parse set with mixed types (valid if unique)', () => {
57
+ const { parseTag } = useCborTag()
58
+
59
+ // 258([1, "a", true]) - mixed types, all unique
60
+ // d9 0102 = tag 258, 83 = array(3)
61
+ // 01 = 1, 6161 = "a", f5 = true
62
+ const result = parseTag('d9010283016161f5')
63
+
64
+ expect(result.value.tag).toBe(258)
65
+ expect(result.value.value).toEqual([1, 'a', true])
66
+ })
67
+ })
68
+
69
+ describe('Invalid sets (with duplicates) - strict mode', () => {
70
+ it('should reject set with duplicate integers in strict mode', () => {
71
+ const { parseTag } = useCborTag()
72
+
73
+ // 258([1, 2, 1]) - duplicate value 1
74
+ const maliciousHex = 'd9010283010201'
75
+
76
+ expect(() => parseTag(maliciousHex, { strict: true }))
77
+ .toThrow(/duplicate.*set/i)
78
+ })
79
+
80
+ it('should reject set with duplicate strings in strict mode', () => {
81
+ const { parseTag } = useCborTag()
82
+
83
+ // 258(["a", "b", "a"]) - duplicate "a"
84
+ const maliciousHex = 'd901028361616162616161'
85
+
86
+ expect(() => parseTag(maliciousHex, { strict: true }))
87
+ .toThrow(/duplicate.*set/i)
88
+ })
89
+
90
+ it('should reject set with all identical elements in strict mode', () => {
91
+ const { parseTag } = useCborTag()
92
+
93
+ // 258([5, 5, 5, 5]) - all duplicates
94
+ const maliciousHex = 'd901028405050505'
95
+
96
+ expect(() => parseTag(maliciousHex, { strict: true }))
97
+ .toThrow(/duplicate.*set/i)
98
+ })
99
+
100
+ it('should reject set with duplicate boolean values in strict mode', () => {
101
+ const { parseTag } = useCborTag()
102
+
103
+ // 258([true, false, true]) - duplicate true
104
+ const maliciousHex = 'd9010283f5f4f5'
105
+
106
+ expect(() => parseTag(maliciousHex, { strict: true }))
107
+ .toThrow(/duplicate.*set/i)
108
+ })
109
+
110
+ it('should reject set with duplicate byte strings in strict mode', () => {
111
+ const { parseTag } = useCborTag()
112
+
113
+ // 258([h'0102', h'0304', h'0102']) - duplicate h'0102'
114
+ const maliciousHex = 'd901028342010242030442 0102'.replace(/\s/g, '')
115
+
116
+ expect(() => parseTag(maliciousHex, { strict: true }))
117
+ .toThrow(/duplicate.*set/i)
118
+ })
119
+ })
120
+
121
+ describe('Duplicate detection (non-strict mode)', () => {
122
+ it('should allow duplicates in non-strict mode but still parse', () => {
123
+ const { parseTag } = useCborTag()
124
+
125
+ // 258([1, 2, 1]) - with duplicates
126
+ const result = parseTag('d9010283010201')
127
+
128
+ // Should parse successfully (not throw)
129
+ expect(result.value.tag).toBe(258)
130
+ expect(result.value.value).toEqual([1, 2, 1])
131
+ })
132
+
133
+ it('should allow duplicates when validateSetUniqueness is explicitly false', () => {
134
+ const { parseTag } = useCborTag()
135
+
136
+ // 258(["x", "x"]) - duplicates allowed
137
+ const result = parseTag('d901028261786178', {
138
+ validateSetUniqueness: false
139
+ })
140
+
141
+ expect(result.value.tag).toBe(258)
142
+ expect(result.value.value).toEqual(['x', 'x'])
143
+ })
144
+ })
145
+
146
+ describe('Edge cases', () => {
147
+ it('should handle set with nested arrays (compare by serialization)', () => {
148
+ const { parseTag } = useCborTag()
149
+
150
+ // 258([[1,2], [3,4]]) - nested arrays should be unique
151
+ const result = parseTag('d901028282010282 0304'.replace(/\s/g, ''))
152
+
153
+ expect(result.value.tag).toBe(258)
154
+ expect(result.value.value).toEqual([[1, 2], [3, 4]])
155
+ })
156
+
157
+ it('should detect duplicate nested arrays in strict mode', () => {
158
+ const { parseTag } = useCborTag()
159
+
160
+ // 258([[1,2], [1,2]]) - duplicate arrays
161
+ const maliciousHex = 'd901028282010282 0102'.replace(/\s/g, '')
162
+
163
+ expect(() => parseTag(maliciousHex, { strict: true }))
164
+ .toThrow(/duplicate.*set/i)
165
+ })
166
+
167
+ it('should handle large sets efficiently', () => {
168
+ const { parseTag } = useCborTag()
169
+
170
+ // 258([0, 1, 2, ..., 9]) - 10 unique integers (simpler test)
171
+ // d9 0102 = tag 258, 8a = array(10), then 00-09
172
+ const hex = 'd901028a00010203040506070809'
173
+
174
+ const result = parseTag(hex)
175
+
176
+ expect(result.value.tag).toBe(258)
177
+ expect(Array.isArray(result.value.value)).toBe(true)
178
+ expect(result.value.value).toHaveLength(10)
179
+ expect(result.value.value[0]).toBe(0)
180
+ expect(result.value.value[9]).toBe(9)
181
+ })
182
+ })
183
+
184
+ describe('Cardano-specific set usage', () => {
185
+ it('should parse Cardano Plutus set of datums', () => {
186
+ const { parseTag } = useCborTag()
187
+
188
+ // 258([datum1, datum2]) - Set of Plutus datums
189
+ // Using simple integers as placeholder datums
190
+ const result = parseTag('d901028218641865')
191
+
192
+ expect(result.value.tag).toBe(258)
193
+ expect(result.value.value).toEqual([100, 101])
194
+ })
195
+
196
+ it('should validate uniqueness for Cardano asset names in set', () => {
197
+ const { parseTag } = useCborTag()
198
+
199
+ // 258(["TokenA", "TokenB", "TokenC"]) - unique asset names
200
+ const result = parseTag('d901028366546f6b656e4166546f6b656e4266546f6b656e43', {
201
+ strict: true
202
+ })
203
+
204
+ expect(result.value.tag).toBe(258)
205
+ expect(result.value.value).toEqual(['TokenA', 'TokenB', 'TokenC'])
206
+ })
207
+ })
208
+ })
209
+
210
+ describe('Tag 4: Decimal Fraction [exponent, mantissa]', () => {
211
+ describe('Basic decimal fraction parsing', () => {
212
+ it('should parse decimal fraction 273.15 as [exponent: -2, mantissa: 27315]', () => {
213
+ const { parseTag } = useCborTag()
214
+
215
+ // 4([-2, 27315]) represents 27315 * 10^(-2) = 273.15
216
+ // c4 = tag 4, 82 = array(2), 21 = -2, 196ab3 = 27315
217
+ const result = parseTag('c48221196ab3')
218
+
219
+ expect(result.value.tag).toBe(4)
220
+ expect(result.value.value).toEqual([-2, 27315])
221
+
222
+ // Semantic interpretation: mantissa * 10^exponent
223
+ const [exponent, mantissa] = result.value.value as [number, number]
224
+ const decimalValue = mantissa * Math.pow(10, exponent)
225
+ expect(decimalValue).toBeCloseTo(273.15, 10)
226
+ })
227
+
228
+ it('should parse decimal fraction 1.1 (not exactly representable in binary)', () => {
229
+ const { parseTag } = useCborTag()
230
+
231
+ // 4([-1, 11]) represents 11 * 10^(-1) = 1.1
232
+ // c4 = tag 4, 82 = array(2), 20 = -1, 0b = 11
233
+ const result = parseTag('c482200b')
234
+
235
+ expect(result.value.tag).toBe(4)
236
+ const [exponent, mantissa] = result.value.value as [number, number]
237
+ const decimalValue = mantissa * Math.pow(10, exponent)
238
+ expect(decimalValue).toBeCloseTo(1.1, 10)
239
+ })
240
+
241
+ it('should parse positive exponent decimal', () => {
242
+ const { parseTag } = useCborTag()
243
+
244
+ // 4([2, 5]) represents 5 * 10^2 = 500
245
+ const result = parseTag('c4820205')
246
+
247
+ expect(result.value.tag).toBe(4)
248
+ const [exponent, mantissa] = result.value.value as [number, number]
249
+ expect(mantissa * Math.pow(10, exponent)).toBe(500)
250
+ })
251
+
252
+ it('should parse zero exponent decimal', () => {
253
+ const { parseTag } = useCborTag()
254
+
255
+ // 4([0, 123]) represents 123 * 10^0 = 123
256
+ const result = parseTag('c48200187b')
257
+
258
+ expect(result.value.tag).toBe(4)
259
+ const [exponent, mantissa] = result.value.value as [number, number]
260
+ expect(mantissa * Math.pow(10, exponent)).toBe(123)
261
+ })
262
+
263
+ it('should parse negative mantissa decimal', () => {
264
+ const { parseTag } = useCborTag()
265
+
266
+ // 4([-2, -273]) represents -273 * 10^(-2) = -2.73
267
+ // c4 = tag 4, 82 = array(2), 21 = -2, 39 0110 = -273
268
+ const result = parseTag('c4822139 0110'.replace(/\s/g, ''))
269
+
270
+ expect(result.value.tag).toBe(4)
271
+ const [exponent, mantissa] = result.value.value as [number, number]
272
+ expect(mantissa * Math.pow(10, exponent)).toBeCloseTo(-2.73, 10)
273
+ })
274
+ })
275
+
276
+ describe('Financial/monetary use cases', () => {
277
+ it('should parse price $19.99 as decimal fraction', () => {
278
+ const { parseTag } = useCborTag()
279
+
280
+ // 4([-2, 1999]) = 1999 * 10^(-2) = $19.99
281
+ const result = parseTag('c48221190 7cf'.replace(/\s/g, ''))
282
+
283
+ expect(result.value.tag).toBe(4)
284
+ const [exponent, mantissa] = result.value.value as [number, number]
285
+ expect(mantissa * Math.pow(10, exponent)).toBeCloseTo(19.99, 10)
286
+ })
287
+
288
+ it('should parse Cardano ADA amount 1000.50 as decimal fraction', () => {
289
+ const { parseTag } = useCborTag()
290
+
291
+ // 4([-2, 100050]) = 100050 * 10^(-2) = 1000.50 ADA
292
+ const result = parseTag('c482211a000186d2')
293
+
294
+ expect(result.value.tag).toBe(4)
295
+ const [exponent, mantissa] = result.value.value as [number, number]
296
+ expect(mantissa * Math.pow(10, exponent)).toBeCloseTo(1000.50, 10)
297
+ })
298
+ })
299
+
300
+ describe('Error cases', () => {
301
+ it('should reject decimal fraction with non-array value', () => {
302
+ const { parseTag } = useCborTag()
303
+
304
+ // 4(42) - invalid, must be array
305
+ expect(() => parseTag('c4182a', { validateTagSemantics: true }))
306
+ .toThrow(/decimal fraction.*array/i)
307
+ })
308
+
309
+ it('should reject decimal fraction with wrong array length', () => {
310
+ const { parseTag } = useCborTag()
311
+
312
+ // 4([1, 2, 3]) - invalid, must be exactly 2 elements
313
+ expect(() => parseTag('c483010203', { validateTagSemantics: true }))
314
+ .toThrow(/decimal fraction.*exactly.*2/i)
315
+ })
316
+
317
+ it('should reject decimal fraction with non-integer exponent', () => {
318
+ const { parseTag } = useCborTag()
319
+
320
+ // 4(["x", 100]) - invalid, exponent must be integer
321
+ expect(() => parseTag('c4826178186 4'.replace(/\s/g, ''), { validateTagSemantics: true }))
322
+ .toThrow(/exponent.*integer/i)
323
+ })
324
+
325
+ it('should reject decimal fraction with non-integer mantissa', () => {
326
+ const { parseTag } = useCborTag()
327
+
328
+ // 4([-2, "hello"]) - invalid, mantissa must be integer
329
+ expect(() => parseTag('c482216568656c6c6f', { validateTagSemantics: true }))
330
+ .toThrow(/mantissa.*integer/i)
331
+ })
332
+ })
333
+ })
334
+
335
+ describe('Tag 5: Bigfloat [exponent, mantissa]', () => {
336
+ describe('Basic bigfloat parsing', () => {
337
+ it('should parse bigfloat [exponent: -2, mantissa: 3]', () => {
338
+ const { parseTag } = useCborTag()
339
+
340
+ // 5([-2, 3]) represents 3 * 2^(-2) = 3 * 0.25 = 0.75
341
+ // c5 = tag 5, 82 = array(2), 21 = -2, 03 = 3
342
+ const result = parseTag('c5822103')
343
+
344
+ expect(result.value.tag).toBe(5)
345
+ expect(result.value.value).toEqual([-2, 3])
346
+
347
+ // Semantic interpretation: mantissa * 2^exponent
348
+ const [exponent, mantissa] = result.value.value as [number, number]
349
+ const floatValue = mantissa * Math.pow(2, exponent)
350
+ expect(floatValue).toBe(0.75)
351
+ })
352
+
353
+ it('should parse bigfloat with positive exponent', () => {
354
+ const { parseTag } = useCborTag()
355
+
356
+ // 5([10, 1000000]) represents 1000000 * 2^10 = 1024000000
357
+ // c5 = tag 5, 82 = array(2), 0a = 10, 1a000f4240 = 1000000
358
+ const result = parseTag('c5820a1a000f4240')
359
+
360
+ expect(result.value.tag).toBe(5)
361
+ const [exponent, mantissa] = result.value.value as [number, number]
362
+ expect(mantissa * Math.pow(2, exponent)).toBe(1024000000)
363
+ })
364
+
365
+ it('should parse bigfloat with zero exponent', () => {
366
+ const { parseTag } = useCborTag()
367
+
368
+ // 5([0, 42]) represents 42 * 2^0 = 42
369
+ const result = parseTag('c5820018 2a'.replace(/\s/g, ''))
370
+
371
+ expect(result.value.tag).toBe(5)
372
+ const [exponent, mantissa] = result.value.value as [number, number]
373
+ expect(mantissa * Math.pow(2, exponent)).toBe(42)
374
+ })
375
+
376
+ it('should parse bigfloat with negative mantissa', () => {
377
+ const { parseTag } = useCborTag()
378
+
379
+ // 5([-1, -8]) represents -8 * 2^(-1) = -4
380
+ const result = parseTag('c5822027')
381
+
382
+ expect(result.value.tag).toBe(5)
383
+ const [exponent, mantissa] = result.value.value as [number, number]
384
+ expect(mantissa * Math.pow(2, exponent)).toBe(-4)
385
+ })
386
+
387
+ it('should parse bigfloat with bigint mantissa (beyond Number.MAX_SAFE_INTEGER)', () => {
388
+ const { parseTag } = useCborTag()
389
+
390
+ // 5([0, 2^63]) - large mantissa
391
+ // c5 = tag 5, 82 = array(2), 00 = 0, 1b8000000000000000 = 2^63
392
+ const result = parseTag('c582001b8000000000000000')
393
+
394
+ expect(result.value.tag).toBe(5)
395
+ expect(result.value.value[0]).toBe(0)
396
+ expect(result.value.value[1]).toBe(BigInt('9223372036854775808'))
397
+ })
398
+ })
399
+
400
+ describe('High-precision scientific computing', () => {
401
+ it('should represent fractional values precisely', () => {
402
+ const { parseTag } = useCborTag()
403
+
404
+ // 5([-10, 1025]) = 1025 * 2^(-10) = 1025 / 1024 ≈ 1.0009765625
405
+ const result = parseTag('c5822919040 1'.replace(/\s/g, ''))
406
+
407
+ expect(result.value.tag).toBe(5)
408
+ const [exponent, mantissa] = result.value.value as [number, number]
409
+ expect(mantissa * Math.pow(2, exponent)).toBeCloseTo(1.0009765625, 15)
410
+ })
411
+
412
+ it('should handle very large exponents', () => {
413
+ const { parseTag } = useCborTag()
414
+
415
+ // 5([1000, 1]) = 1 * 2^1000 (astronomically large)
416
+ const result = parseTag('c58219 03e801'.replace(/\s/g, ''))
417
+
418
+ expect(result.value.tag).toBe(5)
419
+ expect(result.value.value).toEqual([1000, 1])
420
+ // Don't compute the value - it's too large!
421
+ })
422
+
423
+ it('should handle very negative exponents (tiny values)', () => {
424
+ const { parseTag } = useCborTag()
425
+
426
+ // 5([-1000, 1]) = 1 * 2^(-1000) (infinitesimally small)
427
+ const result = parseTag('c5823903e701')
428
+
429
+ expect(result.value.tag).toBe(5)
430
+ expect(result.value.value).toEqual([-1000, 1])
431
+ // Don't compute - underflows to 0 in JavaScript
432
+ })
433
+ })
434
+
435
+ describe('Error cases', () => {
436
+ it('should reject bigfloat with non-array value', () => {
437
+ const { parseTag } = useCborTag()
438
+
439
+ // 5(100) - invalid, must be array
440
+ expect(() => parseTag('c51864', { validateTagSemantics: true }))
441
+ .toThrow(/bigfloat.*array/i)
442
+ })
443
+
444
+ it('should reject bigfloat with wrong array length', () => {
445
+ const { parseTag } = useCborTag()
446
+
447
+ // 5([1]) - invalid, must be exactly 2 elements
448
+ expect(() => parseTag('c58101', { validateTagSemantics: true }))
449
+ .toThrow(/bigfloat.*exactly.*2/i)
450
+ })
451
+
452
+ it('should reject bigfloat with non-integer exponent', () => {
453
+ const { parseTag } = useCborTag()
454
+
455
+ // 5(["text", 100]) - invalid, exponent must be integer
456
+ expect(() => parseTag('c4826474657874186 4'.replace(/\s/g, ''), { validateTagSemantics: true }))
457
+ .toThrow(/exponent.*integer/i)
458
+ })
459
+
460
+ it('should reject bigfloat with non-integer mantissa', () => {
461
+ const { parseTag } = useCborTag()
462
+
463
+ // 5([0, true]) - invalid, mantissa must be integer
464
+ expect(() => parseTag('c58200f5', { validateTagSemantics: true }))
465
+ .toThrow(/mantissa.*integer/i)
466
+ })
467
+ })
468
+ })
469
+
470
+ describe('Integration: Complex nested structures with advanced tags', () => {
471
+ it('should parse set containing decimal fractions', () => {
472
+ const { parseTag } = useCborTag()
473
+
474
+ // 258([4([-2, 1000]), 4([-2, 2000]), 4([-2, 3000])])
475
+ // Set of prices: {$10.00, $20.00, $30.00}
476
+ const result = parseTag('d9010283c482211903e8c482211907d0c482211 90bb8'.replace(/\s/g, ''))
477
+
478
+ expect(result.value.tag).toBe(258)
479
+ expect(result.value.value).toHaveLength(3)
480
+
481
+ // Each element should be a tagged decimal fraction
482
+ const prices = result.value.value as Array<{ tag: number, value: [number, number] }>
483
+ prices.forEach(item => {
484
+ expect(item.tag).toBe(4)
485
+ expect(item.value).toHaveLength(2)
486
+ })
487
+ })
488
+
489
+ it('should parse set containing bigfloats', () => {
490
+ const { parseTag } = useCborTag()
491
+
492
+ // 258([5([-2, 1]), 5([-2, 3])])
493
+ // Set of binary fractions: {0.25, 0.75}
494
+ const result = parseTag('d9010282c5822101c5822103')
495
+
496
+ expect(result.value.tag).toBe(258)
497
+ expect(result.value.value).toHaveLength(2)
498
+ })
499
+ })
500
+ })