@accounter/shaam-uniform-format-generator 0.1.0 → 0.1.1
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/README.md +366 -13
- package/dist/README.md +476 -0
- package/dist/cjs/api/generate-report-legacy.js +6 -0
- package/dist/cjs/api/generate-report.js +328 -0
- package/dist/cjs/constants.js +11 -0
- package/dist/cjs/generator/format/encoder.js +86 -0
- package/dist/cjs/generator/records/a000-sum.js +66 -0
- package/dist/cjs/generator/records/a000.js +349 -0
- package/dist/cjs/generator/records/a100.js +107 -0
- package/dist/cjs/generator/records/b100.js +305 -0
- package/dist/cjs/generator/records/b110.js +255 -0
- package/dist/cjs/generator/records/c100.js +338 -0
- package/dist/cjs/generator/records/d110.js +272 -0
- package/dist/cjs/generator/records/d120.js +278 -0
- package/{cjs → dist/cjs}/generator/records/index.js +1 -0
- package/dist/cjs/generator/records/m100.js +177 -0
- package/dist/cjs/generator/records/z900.js +93 -0
- package/{cjs → dist/cjs}/index.js +3 -0
- package/dist/cjs/records/a100.js +78 -0
- package/dist/cjs/records/index.js +20 -0
- package/dist/cjs/records/z900.js +82 -0
- package/dist/cjs/types/enums.js +457 -0
- package/{cjs → dist/cjs}/types/index.js +6 -1
- package/dist/cjs/utils/file-helpers.js +198 -0
- package/dist/cjs/utils/index.js +8 -0
- package/dist/cjs/utils/key-generator.js +71 -0
- package/dist/esm/api/generate-report-legacy.js +2 -0
- package/dist/esm/api/generate-report.js +325 -0
- package/dist/esm/constants.js +8 -0
- package/dist/esm/generator/format/encoder.js +77 -0
- package/dist/esm/generator/records/a000-sum.js +61 -0
- package/dist/esm/generator/records/a000.js +344 -0
- package/dist/esm/generator/records/a100.js +102 -0
- package/dist/esm/generator/records/b100.js +300 -0
- package/dist/esm/generator/records/b110.js +250 -0
- package/dist/esm/generator/records/c100.js +333 -0
- package/dist/esm/generator/records/d110.js +267 -0
- package/dist/esm/generator/records/d120.js +273 -0
- package/{esm → dist/esm}/generator/records/index.js +1 -0
- package/dist/esm/generator/records/m100.js +172 -0
- package/dist/esm/generator/records/z900.js +88 -0
- package/{esm → dist/esm}/index.js +3 -0
- package/dist/esm/records/a100.js +73 -0
- package/dist/esm/records/index.js +11 -0
- package/dist/esm/records/z900.js +77 -0
- package/dist/esm/types/enums.js +454 -0
- package/{esm → dist/esm}/types/index.js +5 -1
- package/dist/esm/utils/file-helpers.js +188 -0
- package/dist/esm/utils/index.js +5 -0
- package/dist/esm/utils/key-generator.js +65 -0
- package/dist/package.json +54 -0
- package/dist/typings/api/generate-report-legacy.d.cts +1 -0
- package/dist/typings/api/generate-report-legacy.d.ts +1 -0
- package/dist/typings/constants.d.cts +8 -0
- package/dist/typings/constants.d.ts +8 -0
- package/dist/typings/generator/format/encoder.d.cts +57 -0
- package/dist/typings/generator/format/encoder.d.ts +57 -0
- package/dist/typings/generator/records/a000-sum.d.cts +40 -0
- package/dist/typings/generator/records/a000-sum.d.ts +40 -0
- package/dist/typings/generator/records/a000.d.cts +238 -0
- package/dist/typings/generator/records/a000.d.ts +238 -0
- package/dist/typings/generator/records/a100.d.cts +59 -0
- package/dist/typings/generator/records/a100.d.ts +59 -0
- package/dist/typings/generator/records/b100.d.cts +101 -0
- package/dist/typings/generator/records/b100.d.ts +101 -0
- package/dist/typings/generator/records/b110.d.cts +89 -0
- package/dist/typings/generator/records/b110.d.ts +89 -0
- package/dist/typings/generator/records/c100.d.cts +133 -0
- package/dist/typings/generator/records/c100.d.ts +133 -0
- package/dist/typings/generator/records/d110.d.cts +98 -0
- package/dist/typings/generator/records/d110.d.ts +98 -0
- package/dist/typings/generator/records/d120.d.cts +95 -0
- package/dist/typings/generator/records/d120.d.ts +95 -0
- package/{typings → dist/typings}/generator/records/index.d.cts +1 -0
- package/{typings → dist/typings}/generator/records/index.d.ts +1 -0
- package/dist/typings/generator/records/m100.d.cts +69 -0
- package/dist/typings/generator/records/m100.d.ts +69 -0
- package/dist/typings/generator/records/z900.d.cts +61 -0
- package/dist/typings/generator/records/z900.d.ts +61 -0
- package/{typings → dist/typings}/index.d.cts +3 -0
- package/{typings → dist/typings}/index.d.ts +3 -0
- package/dist/typings/records/a100.d.cts +35 -0
- package/dist/typings/records/a100.d.ts +35 -0
- package/dist/typings/records/index.d.cts +2 -0
- package/dist/typings/records/index.d.ts +2 -0
- package/dist/typings/records/z900.d.cts +38 -0
- package/dist/typings/records/z900.d.ts +38 -0
- package/dist/typings/types/enums.d.cts +162 -0
- package/dist/typings/types/enums.d.ts +162 -0
- package/{typings → dist/typings}/types/index.d.cts +17 -14
- package/{typings → dist/typings}/types/index.d.ts +17 -14
- package/dist/typings/utils/file-helpers.d.cts +131 -0
- package/dist/typings/utils/file-helpers.d.ts +131 -0
- package/dist/typings/utils/index.d.cts +5 -0
- package/dist/typings/utils/index.d.ts +5 -0
- package/dist/typings/utils/key-generator.d.cts +41 -0
- package/dist/typings/utils/key-generator.d.ts +41 -0
- package/documentation/IncomeTax_IncomeTaxSoftwareHousesInfo_horaot1.31_2_05.pdf +0 -0
- package/documentation/_4D6963726F736F667420576F7264202D20F8E5E0E9ED20F8E7E5F720F8E5E0E9ED20F9F7E5F32E646F63_.pdf +0 -0
- package/documentation/a000-sum.csv +3 -0
- package/documentation/a000.csv +37 -0
- package/documentation/a100.csv +7 -0
- package/documentation/b100.csv +29 -0
- package/documentation/b110.csv +26 -0
- package/documentation/c100.csv +37 -0
- package/documentation/d110.csv +27 -0
- package/documentation/d120.csv +26 -0
- package/documentation/m100.csv +17 -0
- package/documentation/z900.csv +8 -0
- package/package.json +50 -29
- package/prompt_plan.md +259 -0
- package/spec.md +206 -0
- package/src/api/generate-report.ts +366 -0
- package/src/api/parse-files.ts +33 -0
- package/src/constants.ts +9 -0
- package/src/format/index.ts +6 -0
- package/src/format/newline.ts +8 -0
- package/src/format/padding.ts +39 -0
- package/src/generator/format/decoder.ts +15 -0
- package/src/generator/format/encoder.ts +95 -0
- package/src/generator/format/index.ts +6 -0
- package/src/generator/index.ts +6 -0
- package/src/generator/records/a000-sum.ts +78 -0
- package/src/generator/records/a000.ts +373 -0
- package/src/generator/records/a100.ts +118 -0
- package/src/generator/records/b100.ts +317 -0
- package/src/generator/records/b110.ts +267 -0
- package/src/generator/records/c100.ts +347 -0
- package/src/generator/records/d110.ts +286 -0
- package/src/generator/records/d120.ts +293 -0
- package/src/generator/records/index.ts +14 -0
- package/src/generator/records/m100.ts +185 -0
- package/src/generator/records/z900.ts +104 -0
- package/src/index.ts +18 -0
- package/src/parser/data-parser.ts +14 -0
- package/src/parser/index.ts +6 -0
- package/src/parser/ini-parser.ts +14 -0
- package/src/types/enums.ts +531 -0
- package/src/types/index.ts +110 -0
- package/src/utils/file-helpers.ts +221 -0
- package/src/utils/index.ts +6 -0
- package/src/utils/key-generator.ts +75 -0
- package/src/validation/errors.ts +35 -0
- package/src/validation/index.ts +6 -0
- package/src/validation/validate-input.ts +67 -0
- package/tests/debug-output.test.ts +81 -0
- package/tests/format/crlf-join.test.ts +124 -0
- package/tests/format/encoder.test.ts +80 -0
- package/tests/format/newline.test.ts +19 -0
- package/tests/format/padding.test.ts +74 -0
- package/tests/index.test.ts +29 -0
- package/tests/ini-text.test.ts +122 -0
- package/tests/integration/comprehensive.integration.test.ts +350 -0
- package/tests/integration/roundtrip.integration.test.ts +377 -0
- package/tests/records/a000-sum.test.ts +278 -0
- package/tests/records/a000.test.ts +318 -0
- package/tests/records/a100.test.ts +239 -0
- package/tests/records/b100.test.ts +419 -0
- package/tests/records/b110.test.ts +445 -0
- package/tests/records/c100.test.ts +333 -0
- package/tests/records/d110.test.ts +93 -0
- package/tests/records/d120.test.ts +275 -0
- package/tests/records/m100.test.ts +437 -0
- package/tests/records/z900.test.ts +254 -0
- package/tests/types/enums.test.ts +290 -0
- package/tests/utils/file-helpers.test.ts +276 -0
- package/tests/utils/key-generator.test.ts +121 -0
- package/tests/validation/document-type-validation.test.ts +521 -0
- package/tests/validation/validate-input.test.ts +219 -0
- package/todo.md +203 -0
- package/tsconfig.json +10 -0
- package/vitest.config.ts +11 -0
- package/cjs/api/generate-report.js +0 -53
- package/cjs/generator/format/encoder.js +0 -46
- package/cjs/generator/records/a000.js +0 -8
- package/cjs/generator/records/a100.js +0 -8
- package/cjs/generator/records/b100.js +0 -8
- package/cjs/generator/records/b110.js +0 -8
- package/cjs/generator/records/c100.js +0 -8
- package/cjs/generator/records/d110.js +0 -8
- package/cjs/generator/records/d120.js +0 -8
- package/cjs/generator/records/m100.js +0 -8
- package/cjs/generator/records/z900.js +0 -8
- package/esm/api/generate-report.js +0 -50
- package/esm/generator/format/encoder.js +0 -42
- package/esm/generator/records/a000.js +0 -5
- package/esm/generator/records/a100.js +0 -5
- package/esm/generator/records/b100.js +0 -5
- package/esm/generator/records/b110.js +0 -5
- package/esm/generator/records/c100.js +0 -5
- package/esm/generator/records/d110.js +0 -5
- package/esm/generator/records/d120.js +0 -5
- package/esm/generator/records/m100.js +0 -5
- package/esm/generator/records/z900.js +0 -5
- package/typings/generator/format/encoder.d.cts +0 -33
- package/typings/generator/format/encoder.d.ts +0 -33
- package/typings/generator/records/a000.d.cts +0 -4
- package/typings/generator/records/a000.d.ts +0 -4
- package/typings/generator/records/a100.d.cts +0 -4
- package/typings/generator/records/a100.d.ts +0 -4
- package/typings/generator/records/b100.d.cts +0 -4
- package/typings/generator/records/b100.d.ts +0 -4
- package/typings/generator/records/b110.d.cts +0 -4
- package/typings/generator/records/b110.d.ts +0 -4
- package/typings/generator/records/c100.d.cts +0 -4
- package/typings/generator/records/c100.d.ts +0 -4
- package/typings/generator/records/d110.d.cts +0 -4
- package/typings/generator/records/d110.d.ts +0 -4
- package/typings/generator/records/d120.d.cts +0 -4
- package/typings/generator/records/d120.d.ts +0 -4
- package/typings/generator/records/m100.d.cts +0 -4
- package/typings/generator/records/m100.d.ts +0 -4
- package/typings/generator/records/z900.d.cts +0 -4
- package/typings/generator/records/z900.d.ts +0 -4
- /package/{cjs → dist/cjs}/api/parse-files.js +0 -0
- /package/{cjs → dist/cjs}/format/index.js +0 -0
- /package/{cjs → dist/cjs}/format/newline.js +0 -0
- /package/{cjs → dist/cjs}/format/padding.js +0 -0
- /package/{cjs → dist/cjs}/generator/format/decoder.js +0 -0
- /package/{cjs → dist/cjs}/generator/format/index.js +0 -0
- /package/{cjs → dist/cjs}/generator/index.js +0 -0
- /package/{cjs → dist/cjs}/package.json +0 -0
- /package/{cjs → dist/cjs}/parser/data-parser.js +0 -0
- /package/{cjs → dist/cjs}/parser/index.js +0 -0
- /package/{cjs → dist/cjs}/parser/ini-parser.js +0 -0
- /package/{cjs → dist/cjs}/validation/errors.js +0 -0
- /package/{cjs → dist/cjs}/validation/index.js +0 -0
- /package/{cjs → dist/cjs}/validation/validate-input.js +0 -0
- /package/{esm → dist/esm}/api/parse-files.js +0 -0
- /package/{esm → dist/esm}/format/index.js +0 -0
- /package/{esm → dist/esm}/format/newline.js +0 -0
- /package/{esm → dist/esm}/format/padding.js +0 -0
- /package/{esm → dist/esm}/generator/format/decoder.js +0 -0
- /package/{esm → dist/esm}/generator/format/index.js +0 -0
- /package/{esm → dist/esm}/generator/index.js +0 -0
- /package/{esm → dist/esm}/parser/data-parser.js +0 -0
- /package/{esm → dist/esm}/parser/index.js +0 -0
- /package/{esm → dist/esm}/parser/ini-parser.js +0 -0
- /package/{esm → dist/esm}/validation/errors.js +0 -0
- /package/{esm → dist/esm}/validation/index.js +0 -0
- /package/{esm → dist/esm}/validation/validate-input.js +0 -0
- /package/{typings → dist/typings}/api/generate-report.d.cts +0 -0
- /package/{typings → dist/typings}/api/generate-report.d.ts +0 -0
- /package/{typings → dist/typings}/api/parse-files.d.cts +0 -0
- /package/{typings → dist/typings}/api/parse-files.d.ts +0 -0
- /package/{typings → dist/typings}/format/index.d.cts +0 -0
- /package/{typings → dist/typings}/format/index.d.ts +0 -0
- /package/{typings → dist/typings}/format/newline.d.cts +0 -0
- /package/{typings → dist/typings}/format/newline.d.ts +0 -0
- /package/{typings → dist/typings}/format/padding.d.cts +0 -0
- /package/{typings → dist/typings}/format/padding.d.ts +0 -0
- /package/{typings → dist/typings}/generator/format/decoder.d.cts +0 -0
- /package/{typings → dist/typings}/generator/format/decoder.d.ts +0 -0
- /package/{typings → dist/typings}/generator/format/index.d.cts +0 -0
- /package/{typings → dist/typings}/generator/format/index.d.ts +0 -0
- /package/{typings → dist/typings}/generator/index.d.cts +0 -0
- /package/{typings → dist/typings}/generator/index.d.ts +0 -0
- /package/{typings → dist/typings}/parser/data-parser.d.cts +0 -0
- /package/{typings → dist/typings}/parser/data-parser.d.ts +0 -0
- /package/{typings → dist/typings}/parser/index.d.cts +0 -0
- /package/{typings → dist/typings}/parser/index.d.ts +0 -0
- /package/{typings → dist/typings}/parser/ini-parser.d.cts +0 -0
- /package/{typings → dist/typings}/parser/ini-parser.d.ts +0 -0
- /package/{typings → dist/typings}/validation/errors.d.cts +0 -0
- /package/{typings → dist/typings}/validation/errors.d.ts +0 -0
- /package/{typings → dist/typings}/validation/index.d.cts +0 -0
- /package/{typings → dist/typings}/validation/index.d.ts +0 -0
- /package/{typings → dist/typings}/validation/validate-input.d.cts +0 -0
- /package/{typings → dist/typings}/validation/validate-input.d.ts +0 -0
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration test for round-trip generation and parsing
|
|
3
|
+
* This test ensures that data can be generated to SHAAM format and parsed back correctly
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { describe, expect, it } from 'vitest';
|
|
7
|
+
import { generateUniformFormatReport } from '../../src/api/generate-report';
|
|
8
|
+
import {
|
|
9
|
+
parseA100,
|
|
10
|
+
parseB100,
|
|
11
|
+
parseB110,
|
|
12
|
+
parseC100,
|
|
13
|
+
parseD110,
|
|
14
|
+
parseD120,
|
|
15
|
+
parseM100,
|
|
16
|
+
parseZ900,
|
|
17
|
+
} from '../../src/generator/records/index';
|
|
18
|
+
import type { ReportInput } from '../../src/types/index';
|
|
19
|
+
|
|
20
|
+
describe('SHAAM Format Round-trip Integration Test', () => {
|
|
21
|
+
it('should generate and parse back a complete report', () => {
|
|
22
|
+
// Full ReportInput fixture
|
|
23
|
+
const input: ReportInput = {
|
|
24
|
+
business: {
|
|
25
|
+
businessId: '12345',
|
|
26
|
+
name: 'Test Company Ltd',
|
|
27
|
+
taxId: '123456789',
|
|
28
|
+
reportingPeriod: {
|
|
29
|
+
startDate: '2024-01-01',
|
|
30
|
+
endDate: '2024-12-31',
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
documents: [
|
|
34
|
+
{
|
|
35
|
+
id: 'DOC001',
|
|
36
|
+
type: '320', // Invoice
|
|
37
|
+
date: '2024-03-15',
|
|
38
|
+
amount: 1000.5,
|
|
39
|
+
description: 'Consulting services',
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
id: 'DOC002',
|
|
43
|
+
type: '330', // Credit memo
|
|
44
|
+
date: '2024-03-20',
|
|
45
|
+
amount: 250.75,
|
|
46
|
+
description: 'Product return',
|
|
47
|
+
},
|
|
48
|
+
],
|
|
49
|
+
journalEntries: [
|
|
50
|
+
{
|
|
51
|
+
id: 'JE001',
|
|
52
|
+
date: '2024-03-15',
|
|
53
|
+
amount: 1000.5,
|
|
54
|
+
accountId: '1100',
|
|
55
|
+
description: 'Sales revenue',
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
id: 'JE002',
|
|
59
|
+
date: '2024-03-20',
|
|
60
|
+
amount: -250.75,
|
|
61
|
+
accountId: '1200',
|
|
62
|
+
description: 'Returns and allowances',
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
accounts: [
|
|
66
|
+
{
|
|
67
|
+
id: '1100',
|
|
68
|
+
name: 'Cash',
|
|
69
|
+
type: 'Asset',
|
|
70
|
+
balance: 5000.0,
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
id: '1200',
|
|
74
|
+
name: 'Accounts Receivable',
|
|
75
|
+
type: 'Asset',
|
|
76
|
+
balance: 3000.0,
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
id: '4000',
|
|
80
|
+
name: 'Sales Revenue',
|
|
81
|
+
type: 'Revenue',
|
|
82
|
+
balance: 8000.0,
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
inventory: [
|
|
86
|
+
{
|
|
87
|
+
id: 'ITEM001',
|
|
88
|
+
name: 'Product A',
|
|
89
|
+
quantity: 100,
|
|
90
|
+
unitPrice: 25.0,
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
id: 'ITEM002',
|
|
94
|
+
name: 'Product B',
|
|
95
|
+
quantity: 50,
|
|
96
|
+
unitPrice: 45.0,
|
|
97
|
+
},
|
|
98
|
+
],
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
// Generate the report
|
|
102
|
+
const result = generateUniformFormatReport(input);
|
|
103
|
+
|
|
104
|
+
expect(result).toBeDefined();
|
|
105
|
+
expect(result.dataText).toBeDefined();
|
|
106
|
+
expect(result.iniText).toBeDefined();
|
|
107
|
+
expect(result.summary.totalRecords).toBeGreaterThan(0);
|
|
108
|
+
|
|
109
|
+
// Split dataText into lines and parse each record
|
|
110
|
+
const lines = result.dataText.split('\r\n').filter(line => line.trim().length > 0);
|
|
111
|
+
|
|
112
|
+
interface ParsedData {
|
|
113
|
+
businessMetadata: ReturnType<typeof parseA100> | null;
|
|
114
|
+
documents: ReturnType<typeof parseC100>[];
|
|
115
|
+
documentLines: ReturnType<typeof parseD110>[];
|
|
116
|
+
payments: ReturnType<typeof parseD120>[];
|
|
117
|
+
journalEntries: ReturnType<typeof parseB100>[];
|
|
118
|
+
accounts: ReturnType<typeof parseB110>[];
|
|
119
|
+
inventory: ReturnType<typeof parseM100>[];
|
|
120
|
+
closingRecord: ReturnType<typeof parseZ900> | null;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const parsedData: ParsedData = {
|
|
124
|
+
businessMetadata: null,
|
|
125
|
+
documents: [],
|
|
126
|
+
documentLines: [],
|
|
127
|
+
payments: [],
|
|
128
|
+
journalEntries: [],
|
|
129
|
+
accounts: [],
|
|
130
|
+
inventory: [],
|
|
131
|
+
closingRecord: null,
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
// Parse each line based on record type
|
|
135
|
+
for (const line of lines) {
|
|
136
|
+
const recordType = line.substring(0, 4);
|
|
137
|
+
|
|
138
|
+
switch (recordType) {
|
|
139
|
+
case 'A100':
|
|
140
|
+
parsedData.businessMetadata = parseA100(line);
|
|
141
|
+
break;
|
|
142
|
+
case 'C100':
|
|
143
|
+
parsedData.documents.push(parseC100(line));
|
|
144
|
+
break;
|
|
145
|
+
case 'D110':
|
|
146
|
+
parsedData.documentLines.push(parseD110(line));
|
|
147
|
+
break;
|
|
148
|
+
case 'D120':
|
|
149
|
+
parsedData.payments.push(parseD120(line));
|
|
150
|
+
break;
|
|
151
|
+
case 'B100':
|
|
152
|
+
parsedData.journalEntries.push(parseB100(line));
|
|
153
|
+
break;
|
|
154
|
+
case 'B110':
|
|
155
|
+
parsedData.accounts.push(parseB110(line));
|
|
156
|
+
break;
|
|
157
|
+
case 'M100':
|
|
158
|
+
parsedData.inventory.push(parseM100(line));
|
|
159
|
+
break;
|
|
160
|
+
case 'Z900':
|
|
161
|
+
parsedData.closingRecord = parseZ900(line);
|
|
162
|
+
break;
|
|
163
|
+
default:
|
|
164
|
+
// Unknown record type, skip silently for test purposes
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Verify business metadata
|
|
170
|
+
expect(parsedData.businessMetadata).toBeDefined();
|
|
171
|
+
expect(parsedData.businessMetadata?.vatId).toBe(input.business.taxId);
|
|
172
|
+
// primaryIdentifier is now auto-generated, so just verify it's a valid 15-digit string
|
|
173
|
+
expect(parsedData.businessMetadata?.primaryIdentifier).toMatch(/^\d{15}$/);
|
|
174
|
+
|
|
175
|
+
// Verify documents
|
|
176
|
+
expect(parsedData.documents).toHaveLength(input.documents.length);
|
|
177
|
+
for (let i = 0; i < input.documents.length; i++) {
|
|
178
|
+
const original = input.documents[i];
|
|
179
|
+
const parsed = parsedData.documents[i];
|
|
180
|
+
expect(parsed.documentId).toBe(original.id);
|
|
181
|
+
expect(parsed.documentType).toBe(original.type);
|
|
182
|
+
expect(parsed.documentIssueDate).toBe(original.date.replace(/-/g, ''));
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Verify document lines
|
|
186
|
+
expect(parsedData.documentLines).toHaveLength(input.documents.length);
|
|
187
|
+
for (let i = 0; i < input.documents.length; i++) {
|
|
188
|
+
const original = input.documents[i];
|
|
189
|
+
const parsed = parsedData.documentLines[i];
|
|
190
|
+
expect(parsed.documentNumber).toBe(original.id);
|
|
191
|
+
expect(parsed.documentType).toBe(original.type);
|
|
192
|
+
expect(parsed.goodsServiceDescription).toBe(original.description || 'Item');
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Verify payments
|
|
196
|
+
expect(parsedData.payments).toHaveLength(input.documents.length);
|
|
197
|
+
for (let i = 0; i < input.documents.length; i++) {
|
|
198
|
+
const original = input.documents[i];
|
|
199
|
+
const parsed = parsedData.payments[i];
|
|
200
|
+
expect(parsed.documentNumber).toBe(original.id);
|
|
201
|
+
expect(parsed.documentType).toBe(original.type);
|
|
202
|
+
expect(parsed.lineAmount).toBe(original.amount.toFixed(2));
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Verify journal entries
|
|
206
|
+
expect(parsedData.journalEntries).toHaveLength(input.journalEntries.length);
|
|
207
|
+
for (let i = 0; i < input.journalEntries.length; i++) {
|
|
208
|
+
const original = input.journalEntries[i];
|
|
209
|
+
const parsed = parsedData.journalEntries[i];
|
|
210
|
+
const expectedTransactionNumber =
|
|
211
|
+
(original.id.replace(/\D/g, '') || '1').replace(/^0+/, '') || '0';
|
|
212
|
+
expect(parsed.transactionNumber).toBe(expectedTransactionNumber); // Numeric part with leading zeros stripped
|
|
213
|
+
expect(parsed.accountKey).toBe(original.accountId);
|
|
214
|
+
expect(parsed.transactionAmount).toBe(Math.abs(original.amount).toFixed(2));
|
|
215
|
+
expect(parsed.debitCreditIndicator).toBe(original.amount >= 0 ? '1' : '2');
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Verify accounts
|
|
219
|
+
expect(parsedData.accounts).toHaveLength(input.accounts.length);
|
|
220
|
+
for (let i = 0; i < input.accounts.length; i++) {
|
|
221
|
+
const original = input.accounts[i];
|
|
222
|
+
const parsed = parsedData.accounts[i];
|
|
223
|
+
expect(parsed.accountKey).toBe(original.id);
|
|
224
|
+
expect(parsed.accountName).toBe(original.name);
|
|
225
|
+
expect(parsed.trialBalanceCode).toBe(original.type);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Verify inventory
|
|
229
|
+
expect(parsedData.inventory).toHaveLength(input.inventory.length);
|
|
230
|
+
for (let i = 0; i < input.inventory.length; i++) {
|
|
231
|
+
const original = input.inventory[i];
|
|
232
|
+
const parsed = parsedData.inventory[i];
|
|
233
|
+
expect(parsed.internalItemCode).toBe(original.id);
|
|
234
|
+
expect(parsed.itemName).toBe(original.name);
|
|
235
|
+
expect(parsed.totalStockOut).toBe(original.quantity.toString());
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Verify closing record
|
|
239
|
+
expect(parsedData.closingRecord).toBeDefined();
|
|
240
|
+
expect(parsedData.closingRecord?.vatId).toBe(input.business.taxId);
|
|
241
|
+
// uniqueId is now auto-generated and should match the primaryIdentifier
|
|
242
|
+
expect(parsedData.closingRecord?.uniqueId).toMatch(/^\d{15}$/);
|
|
243
|
+
expect(parsedData.closingRecord?.uniqueId).toBe(parsedData.businessMetadata?.primaryIdentifier);
|
|
244
|
+
expect(parseInt(parsedData.closingRecord?.totalRecords || '0')).toBeGreaterThan(0);
|
|
245
|
+
|
|
246
|
+
// Verify summary record counts match parsed data
|
|
247
|
+
const expectedTotalRecords =
|
|
248
|
+
1 + // A000 (INI file)
|
|
249
|
+
8 + // A000Sum records (one for each record type: A100, C100, D110, D120, B100, B110, M100, Z900)
|
|
250
|
+
1 + // A100
|
|
251
|
+
input.documents.length + // C100 records
|
|
252
|
+
input.documents.length + // D110 records
|
|
253
|
+
input.documents.length + // D120 records
|
|
254
|
+
input.journalEntries.length + // B100 records
|
|
255
|
+
input.accounts.length + // B110 records
|
|
256
|
+
input.inventory.length + // M100 records
|
|
257
|
+
1; // Z900
|
|
258
|
+
|
|
259
|
+
expect(result.summary.totalRecords).toBe(expectedTotalRecords);
|
|
260
|
+
expect(parseInt(parsedData.closingRecord?.totalRecords || '0')).toBe(expectedTotalRecords - 10); // Z900 counts data records only (excludes A000, A000Sum records, and Z900 itself)
|
|
261
|
+
|
|
262
|
+
// Verify record type counts in summary
|
|
263
|
+
expect(result.summary.perType.A000).toBe(1);
|
|
264
|
+
expect(result.summary.perType.A100).toBe(1);
|
|
265
|
+
expect(result.summary.perType.C100).toBe(input.documents.length);
|
|
266
|
+
expect(result.summary.perType.D110).toBe(input.documents.length);
|
|
267
|
+
expect(result.summary.perType.D120).toBe(input.documents.length);
|
|
268
|
+
expect(result.summary.perType.B100).toBe(input.journalEntries.length);
|
|
269
|
+
expect(result.summary.perType.B110).toBe(input.accounts.length);
|
|
270
|
+
expect(result.summary.perType.M100).toBe(input.inventory.length);
|
|
271
|
+
expect(result.summary.perType.Z900).toBe(1);
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
it('should handle empty data sections correctly', () => {
|
|
275
|
+
const minimalInput: ReportInput = {
|
|
276
|
+
business: {
|
|
277
|
+
businessId: '54321',
|
|
278
|
+
name: 'Minimal Company',
|
|
279
|
+
taxId: '987654321',
|
|
280
|
+
reportingPeriod: {
|
|
281
|
+
startDate: '2024-01-01',
|
|
282
|
+
endDate: '2024-12-31',
|
|
283
|
+
},
|
|
284
|
+
},
|
|
285
|
+
documents: [],
|
|
286
|
+
journalEntries: [],
|
|
287
|
+
accounts: [],
|
|
288
|
+
inventory: [],
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
const result = generateUniformFormatReport(minimalInput);
|
|
292
|
+
|
|
293
|
+
expect(result).toBeDefined();
|
|
294
|
+
expect(result.dataText).toBeDefined();
|
|
295
|
+
expect(result.summary.totalRecords).toBe(5); // A000 + 2 A000Sum (A100, Z900) + A100 + Z900
|
|
296
|
+
|
|
297
|
+
const lines = result.dataText.split('\r\n').filter(line => line.trim().length > 0);
|
|
298
|
+
expect(lines).toHaveLength(2);
|
|
299
|
+
|
|
300
|
+
// Should have A100 and Z900 records only
|
|
301
|
+
expect(lines[0].startsWith('A100')).toBe(true);
|
|
302
|
+
expect(lines[1].startsWith('Z900')).toBe(true);
|
|
303
|
+
|
|
304
|
+
// Parse and verify
|
|
305
|
+
const businessRecord = parseA100(lines[0]);
|
|
306
|
+
const closingRecord = parseZ900(lines[1]);
|
|
307
|
+
|
|
308
|
+
expect(businessRecord.vatId).toBe(minimalInput.business.taxId);
|
|
309
|
+
expect(closingRecord.vatId).toBe(minimalInput.business.taxId);
|
|
310
|
+
expect(closingRecord.totalRecords).toBe('1'); // Only A100 counted
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
it('should maintain data integrity for monetary values', () => {
|
|
314
|
+
const input: ReportInput = {
|
|
315
|
+
business: {
|
|
316
|
+
businessId: '99999',
|
|
317
|
+
name: 'Financial Test Co',
|
|
318
|
+
taxId: '111111111',
|
|
319
|
+
reportingPeriod: {
|
|
320
|
+
startDate: '2024-01-01',
|
|
321
|
+
endDate: '2024-12-31',
|
|
322
|
+
},
|
|
323
|
+
},
|
|
324
|
+
documents: [
|
|
325
|
+
{
|
|
326
|
+
id: 'HIGH-VAL',
|
|
327
|
+
type: '320',
|
|
328
|
+
date: '2024-06-15',
|
|
329
|
+
amount: 999_999.99,
|
|
330
|
+
description: 'High value transaction',
|
|
331
|
+
},
|
|
332
|
+
],
|
|
333
|
+
journalEntries: [
|
|
334
|
+
{
|
|
335
|
+
id: 'PRECISION-TEST',
|
|
336
|
+
date: '2024-06-15',
|
|
337
|
+
amount: 123.45,
|
|
338
|
+
accountId: '2000',
|
|
339
|
+
description: 'Precision test',
|
|
340
|
+
},
|
|
341
|
+
],
|
|
342
|
+
accounts: [
|
|
343
|
+
{
|
|
344
|
+
id: '2000',
|
|
345
|
+
name: 'Test Account',
|
|
346
|
+
type: 'Liability',
|
|
347
|
+
balance: 123_456.78,
|
|
348
|
+
},
|
|
349
|
+
],
|
|
350
|
+
inventory: [
|
|
351
|
+
{
|
|
352
|
+
id: 'EXPENSIVE-ITEM',
|
|
353
|
+
name: 'Expensive Product',
|
|
354
|
+
quantity: 1,
|
|
355
|
+
unitPrice: 999.99,
|
|
356
|
+
},
|
|
357
|
+
],
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
const result = generateUniformFormatReport(input);
|
|
361
|
+
const lines = result.dataText.split('\r\n').filter(line => line.trim().length > 0);
|
|
362
|
+
|
|
363
|
+
// Find and parse the payment record for the high-value document
|
|
364
|
+
const paymentLine = lines.find(line => line.startsWith('D120'));
|
|
365
|
+
expect(paymentLine).toBeDefined();
|
|
366
|
+
|
|
367
|
+
const paymentRecord = parseD120(paymentLine!);
|
|
368
|
+
expect(paymentRecord.lineAmount).toBe('999999.99');
|
|
369
|
+
|
|
370
|
+
// Find and parse the journal entry
|
|
371
|
+
const journalLine = lines.find(line => line.startsWith('B100'));
|
|
372
|
+
expect(journalLine).toBeDefined();
|
|
373
|
+
|
|
374
|
+
const journalRecord = parseB100(journalLine!);
|
|
375
|
+
expect(journalRecord.transactionAmount).toBe('123.45');
|
|
376
|
+
});
|
|
377
|
+
});
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import {
|
|
3
|
+
A000SumSchema,
|
|
4
|
+
encodeA000Sum,
|
|
5
|
+
parseA000Sum,
|
|
6
|
+
type A000Sum,
|
|
7
|
+
type A000SumInput,
|
|
8
|
+
} from '../../src/generator/records/a000-sum';
|
|
9
|
+
|
|
10
|
+
describe('A000Sum Record', () => {
|
|
11
|
+
const validA000Sum: A000Sum = {
|
|
12
|
+
code: 'A100',
|
|
13
|
+
recordCount: '12345',
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const validA000SumInput: A000SumInput = {
|
|
17
|
+
code: 'B100',
|
|
18
|
+
recordCount: '67890',
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
describe('Schema Validation', () => {
|
|
22
|
+
it('should validate a valid A000Sum record', () => {
|
|
23
|
+
expect(() => A000SumSchema.parse(validA000Sum)).not.toThrow();
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('should reject empty code', () => {
|
|
27
|
+
const invalidRecord = { ...validA000Sum, code: '' };
|
|
28
|
+
expect(() => A000SumSchema.parse(invalidRecord)).toThrow();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('should reject code longer than 4 characters', () => {
|
|
32
|
+
const invalidRecord = { ...validA000Sum, code: 'TOOLONG' };
|
|
33
|
+
expect(() => A000SumSchema.parse(invalidRecord)).toThrow();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('should reject empty record count', () => {
|
|
37
|
+
const invalidRecord = { ...validA000Sum, recordCount: '' };
|
|
38
|
+
expect(() => A000SumSchema.parse(invalidRecord)).toThrow();
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('should reject record count longer than 15 characters', () => {
|
|
42
|
+
const invalidRecord = { ...validA000Sum, recordCount: '1234567890123456' };
|
|
43
|
+
expect(() => A000SumSchema.parse(invalidRecord)).toThrow();
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('should reject non-numeric record count', () => {
|
|
47
|
+
const invalidRecord = { ...validA000Sum, recordCount: 'abc123' };
|
|
48
|
+
expect(() => A000SumSchema.parse(invalidRecord)).toThrow();
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('should accept valid record codes', () => {
|
|
52
|
+
const validCodes = ['A100', 'B100', 'C100', 'D110', 'M100', 'Z900'];
|
|
53
|
+
for (const code of validCodes) {
|
|
54
|
+
const record = { ...validA000Sum, code };
|
|
55
|
+
expect(() => A000SumSchema.parse(record)).not.toThrow();
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('should accept record count with leading zeros when parsed as string', () => {
|
|
60
|
+
const record = { ...validA000Sum, recordCount: '000123' };
|
|
61
|
+
expect(() => A000SumSchema.parse(record)).not.toThrow();
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
describe('encodeA000Sum', () => {
|
|
66
|
+
it('should encode a valid A000Sum record to fixed-width string', () => {
|
|
67
|
+
const encoded = encodeA000Sum(validA000SumInput);
|
|
68
|
+
|
|
69
|
+
// Should end with CRLF
|
|
70
|
+
expect(encoded).toMatch(/\r\n$/);
|
|
71
|
+
|
|
72
|
+
// Should have correct length (19 + 2 for CRLF)
|
|
73
|
+
expect(encoded.length).toBe(21);
|
|
74
|
+
|
|
75
|
+
// Should start with the record code
|
|
76
|
+
expect(encoded.slice(0, 4)).toBe('B100');
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('should pad numeric fields with leading zeros', () => {
|
|
80
|
+
const shortCountInput: A000SumInput = {
|
|
81
|
+
code: 'A100',
|
|
82
|
+
recordCount: '123',
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const encoded = encodeA000Sum(shortCountInput);
|
|
86
|
+
|
|
87
|
+
// Record count should be zero-padded to 15 digits (position 4-18)
|
|
88
|
+
const recordCountField = encoded.slice(4, 19);
|
|
89
|
+
expect(recordCountField).toBe('000000000000123');
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('should handle maximum length fields', () => {
|
|
93
|
+
const maxLengthInput: A000SumInput = {
|
|
94
|
+
code: 'ABCD',
|
|
95
|
+
recordCount: '123456789012345',
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
const encoded = encodeA000Sum(maxLengthInput);
|
|
99
|
+
expect(encoded.length).toBe(21); // Should still have correct total length
|
|
100
|
+
|
|
101
|
+
// Check that fields are not truncated
|
|
102
|
+
expect(encoded.slice(0, 4)).toBe('ABCD');
|
|
103
|
+
expect(encoded.slice(4, 19)).toBe('123456789012345');
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('should handle single digit record count', () => {
|
|
107
|
+
const singleDigitInput: A000SumInput = {
|
|
108
|
+
code: 'Z900',
|
|
109
|
+
recordCount: '1',
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
const encoded = encodeA000Sum(singleDigitInput);
|
|
113
|
+
const recordCountField = encoded.slice(4, 19);
|
|
114
|
+
expect(recordCountField).toBe('000000000000001');
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
describe('parseA000Sum', () => {
|
|
119
|
+
it('should parse a valid fixed-width A000Sum record string', () => {
|
|
120
|
+
const encoded = encodeA000Sum(validA000SumInput);
|
|
121
|
+
const parsed = parseA000Sum(encoded);
|
|
122
|
+
|
|
123
|
+
expect(parsed.code).toBe('B100');
|
|
124
|
+
expect(parsed.recordCount).toBe('67890');
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it('should handle lines with and without CRLF', () => {
|
|
128
|
+
const encoded = encodeA000Sum(validA000SumInput);
|
|
129
|
+
const withoutCRLF = encoded.replace(/\r\n$/, '');
|
|
130
|
+
|
|
131
|
+
expect(() => parseA000Sum(encoded)).not.toThrow();
|
|
132
|
+
expect(() => parseA000Sum(withoutCRLF)).not.toThrow();
|
|
133
|
+
|
|
134
|
+
const parsedWithCRLF = parseA000Sum(encoded);
|
|
135
|
+
const parsedWithoutCRLF = parseA000Sum(withoutCRLF);
|
|
136
|
+
|
|
137
|
+
expect(parsedWithCRLF).toEqual(parsedWithoutCRLF);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('should throw error for invalid record length', () => {
|
|
141
|
+
const shortLine = 'A100' + ' '.repeat(10);
|
|
142
|
+
const longLine = 'A100' + ' '.repeat(50);
|
|
143
|
+
|
|
144
|
+
expect(() => parseA000Sum(shortLine)).toThrow(
|
|
145
|
+
'Invalid A000Sum record length: expected 19 characters, got 14',
|
|
146
|
+
);
|
|
147
|
+
expect(() => parseA000Sum(longLine)).toThrow(
|
|
148
|
+
'Invalid A000Sum record length: expected 19 characters, got 54',
|
|
149
|
+
);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it('should properly strip leading zeros from numeric fields', () => {
|
|
153
|
+
const paddedInput: A000SumInput = {
|
|
154
|
+
code: 'M100',
|
|
155
|
+
recordCount: '00000000000042',
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
const encoded = encodeA000Sum(paddedInput);
|
|
159
|
+
const parsed = parseA000Sum(encoded);
|
|
160
|
+
|
|
161
|
+
// Should strip leading zeros
|
|
162
|
+
expect(parsed.recordCount).toBe('42');
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it('should handle zero record count correctly', () => {
|
|
166
|
+
const zeroInput: A000SumInput = {
|
|
167
|
+
code: 'C100',
|
|
168
|
+
recordCount: '0',
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
const encoded = encodeA000Sum(zeroInput);
|
|
172
|
+
const parsed = parseA000Sum(encoded);
|
|
173
|
+
|
|
174
|
+
expect(parsed.recordCount).toBe('0');
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it('should preserve code field correctly', () => {
|
|
178
|
+
const testCodes = ['A100', 'B100', 'C100', 'D110', 'M100', 'Z900'];
|
|
179
|
+
|
|
180
|
+
for (const code of testCodes) {
|
|
181
|
+
const input: A000SumInput = { code, recordCount: '100' };
|
|
182
|
+
const encoded = encodeA000Sum(input);
|
|
183
|
+
const parsed = parseA000Sum(encoded);
|
|
184
|
+
|
|
185
|
+
expect(parsed.code).toBe(code);
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
describe('Round-trip Tests', () => {
|
|
191
|
+
it('should maintain data integrity through encode-parse round trip', () => {
|
|
192
|
+
const encoded = encodeA000Sum(validA000SumInput);
|
|
193
|
+
const parsed = parseA000Sum(encoded);
|
|
194
|
+
const reEncoded = encodeA000Sum(parsed);
|
|
195
|
+
|
|
196
|
+
expect(reEncoded).toBe(encoded);
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it('should preserve all field values in round trip', () => {
|
|
200
|
+
const encoded = encodeA000Sum(validA000SumInput);
|
|
201
|
+
const parsed = parseA000Sum(encoded);
|
|
202
|
+
|
|
203
|
+
expect(parsed.code).toBe(validA000SumInput.code);
|
|
204
|
+
expect(parsed.recordCount).toBe(validA000SumInput.recordCount);
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it('should handle edge cases in round trip', () => {
|
|
208
|
+
const edgeCases: A000SumInput[] = [
|
|
209
|
+
{ code: 'A', recordCount: '1' }, // Minimum lengths
|
|
210
|
+
{ code: 'ABCD', recordCount: '123456789012345' }, // Maximum lengths
|
|
211
|
+
{ code: 'Z900', recordCount: '0' }, // Zero count
|
|
212
|
+
{ code: 'TEST', recordCount: '999999999999999' }, // Large number
|
|
213
|
+
];
|
|
214
|
+
|
|
215
|
+
for (const testCase of edgeCases) {
|
|
216
|
+
const encoded = encodeA000Sum(testCase);
|
|
217
|
+
const parsed = parseA000Sum(encoded);
|
|
218
|
+
const reEncoded = encodeA000Sum(parsed);
|
|
219
|
+
|
|
220
|
+
expect(reEncoded).toBe(encoded);
|
|
221
|
+
expect(parsed.code).toBe(testCase.code);
|
|
222
|
+
expect(parsed.recordCount).toBe(testCase.recordCount);
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
it('should handle record count with various leading zero patterns', () => {
|
|
227
|
+
const testCases = [
|
|
228
|
+
{ input: '1', expected: '1' },
|
|
229
|
+
{ input: '01', expected: '1' },
|
|
230
|
+
{ input: '001', expected: '1' },
|
|
231
|
+
{ input: '0001234', expected: '1234' },
|
|
232
|
+
{ input: '000000000000001', expected: '1' },
|
|
233
|
+
];
|
|
234
|
+
|
|
235
|
+
for (const { input, expected } of testCases) {
|
|
236
|
+
const testInput: A000SumInput = { code: 'TEST', recordCount: input };
|
|
237
|
+
const encoded = encodeA000Sum(testInput);
|
|
238
|
+
const parsed = parseA000Sum(encoded);
|
|
239
|
+
|
|
240
|
+
expect(parsed.recordCount).toBe(expected);
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
describe('Error Handling', () => {
|
|
246
|
+
it('should throw error when feeding invalid line to parseA000Sum', () => {
|
|
247
|
+
const invalidLines = [
|
|
248
|
+
'', // Empty line
|
|
249
|
+
'A100', // Too short
|
|
250
|
+
'A100' + ' '.repeat(100), // Too long
|
|
251
|
+
'XY', // Way too short
|
|
252
|
+
];
|
|
253
|
+
|
|
254
|
+
for (const line of invalidLines) {
|
|
255
|
+
expect(() => parseA000Sum(line)).toThrow();
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
it('should validate schema after parsing', () => {
|
|
260
|
+
// Create a line with valid length but invalid content that should fail schema validation
|
|
261
|
+
const validEncoded = encodeA000Sum(validA000SumInput);
|
|
262
|
+
|
|
263
|
+
// This should pass since the content is valid
|
|
264
|
+
expect(() => parseA000Sum(validEncoded)).not.toThrow();
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
it('should handle malformed input gracefully', () => {
|
|
268
|
+
// Test with various malformed inputs that should fail schema validation
|
|
269
|
+
|
|
270
|
+
// Test first input separately to debug - all spaces should fail because code becomes empty
|
|
271
|
+
expect(() => parseA000Sum(' '.repeat(19)), 'All spaces input should fail').toThrow();
|
|
272
|
+
|
|
273
|
+
// Test second input - this creates "A" + 18 spaces = "A " which is valid
|
|
274
|
+
// Let's use something that should actually fail
|
|
275
|
+
expect(() => parseA000Sum('ABCDE' + ' '.repeat(14)), 'Code too long should fail').toThrow();
|
|
276
|
+
});
|
|
277
|
+
});
|
|
278
|
+
});
|