calc-mcp-server 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/.claude/commands/opsx/apply.md +152 -0
- package/.claude/commands/opsx/archive.md +157 -0
- package/.claude/commands/opsx/bulk-archive.md +242 -0
- package/.claude/commands/opsx/continue.md +114 -0
- package/.claude/commands/opsx/explore.md +174 -0
- package/.claude/commands/opsx/ff.md +94 -0
- package/.claude/commands/opsx/new.md +69 -0
- package/.claude/commands/opsx/onboard.md +534 -0
- package/.claude/commands/opsx/sync.md +134 -0
- package/.claude/commands/opsx/verify.md +164 -0
- package/.claude/settings.local.json +8 -0
- package/.claude/skills/npm-publish/SKILL.md +164 -0
- package/.claude/skills/openspec-apply-change/SKILL.md +156 -0
- package/.claude/skills/openspec-archive-change/SKILL.md +161 -0
- package/.claude/skills/openspec-bulk-archive-change/SKILL.md +246 -0
- package/.claude/skills/openspec-continue-change/SKILL.md +118 -0
- package/.claude/skills/openspec-explore/SKILL.md +289 -0
- package/.claude/skills/openspec-ff-change/SKILL.md +101 -0
- package/.claude/skills/openspec-new-change/SKILL.md +74 -0
- package/.claude/skills/openspec-onboard/SKILL.md +538 -0
- package/.claude/skills/openspec-sync-specs/SKILL.md +138 -0
- package/.claude/skills/openspec-verify-change/SKILL.md +168 -0
- package/CLAUDE.md +92 -0
- package/README.md +319 -0
- package/build/engines/decimal.d.ts +10 -0
- package/build/engines/decimal.d.ts.map +1 -0
- package/build/engines/decimal.js +61 -0
- package/build/engines/decimal.js.map +1 -0
- package/build/engines/programmer.d.ts +18 -0
- package/build/engines/programmer.d.ts.map +1 -0
- package/build/engines/programmer.js +103 -0
- package/build/engines/programmer.js.map +1 -0
- package/build/errors/handler.d.ts +10 -0
- package/build/errors/handler.d.ts.map +1 -0
- package/build/errors/handler.js +37 -0
- package/build/errors/handler.js.map +1 -0
- package/build/errors/types.d.ts +25 -0
- package/build/errors/types.d.ts.map +1 -0
- package/build/errors/types.js +2 -0
- package/build/errors/types.js.map +1 -0
- package/build/index.d.ts +3 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +16 -0
- package/build/index.js.map +1 -0
- package/build/mcp/server.d.ts +3 -0
- package/build/mcp/server.d.ts.map +1 -0
- package/build/mcp/server.js +270 -0
- package/build/mcp/server.js.map +1 -0
- package/build/mcp/tools/ascii.d.ts +11 -0
- package/build/mcp/tools/ascii.d.ts.map +1 -0
- package/build/mcp/tools/ascii.js +93 -0
- package/build/mcp/tools/ascii.js.map +1 -0
- package/build/mcp/tools/basic.d.ts +6 -0
- package/build/mcp/tools/basic.d.ts.map +1 -0
- package/build/mcp/tools/basic.js +34 -0
- package/build/mcp/tools/basic.js.map +1 -0
- package/build/mcp/tools/conversion.d.ts +8 -0
- package/build/mcp/tools/conversion.d.ts.map +1 -0
- package/build/mcp/tools/conversion.js +81 -0
- package/build/mcp/tools/conversion.js.map +1 -0
- package/build/mcp/tools/programmer.d.ts +6 -0
- package/build/mcp/tools/programmer.d.ts.map +1 -0
- package/build/mcp/tools/programmer.js +29 -0
- package/build/mcp/tools/programmer.js.map +1 -0
- package/build/parser/ast.d.ts +47 -0
- package/build/parser/ast.d.ts.map +1 -0
- package/build/parser/ast.js +2 -0
- package/build/parser/ast.js.map +1 -0
- package/build/parser/lexer.d.ts +24 -0
- package/build/parser/lexer.d.ts.map +1 -0
- package/build/parser/lexer.js +168 -0
- package/build/parser/lexer.js.map +1 -0
- package/build/parser/parser.d.ts +14 -0
- package/build/parser/parser.d.ts.map +1 -0
- package/build/parser/parser.js +115 -0
- package/build/parser/parser.js.map +1 -0
- package/docs/plans/2025-02-24-mcp-calculator-design.md +344 -0
- package/docs/plans/2025-02-24-mcp-calculator-implementation.md +2626 -0
- package/openspec/changes/archive/2026-02-24-simplify-ascii-tools/.openspec.yaml +2 -0
- package/openspec/changes/archive/2026-02-24-simplify-ascii-tools/design.md +46 -0
- package/openspec/changes/archive/2026-02-24-simplify-ascii-tools/proposal.md +21 -0
- package/openspec/changes/archive/2026-02-24-simplify-ascii-tools/specs/ascii-conversion/spec.md +22 -0
- package/openspec/changes/archive/2026-02-24-simplify-ascii-tools/tasks.md +24 -0
- package/openspec/config.yaml +20 -0
- package/openspec/specs/ascii-conversion/spec.md +43 -0
- package/package.json +40 -0
- package/src/engines/decimal.ts +69 -0
- package/src/engines/programmer.ts +112 -0
- package/src/errors/handler.ts +55 -0
- package/src/errors/types.ts +37 -0
- package/src/index.ts +20 -0
- package/src/mcp/server.ts +287 -0
- package/src/mcp/tools/ascii.ts +116 -0
- package/src/mcp/tools/basic.ts +44 -0
- package/src/mcp/tools/conversion.ts +95 -0
- package/src/mcp/tools/programmer.ts +36 -0
- package/src/parser/ast.ts +51 -0
- package/src/parser/lexer.ts +216 -0
- package/src/parser/parser.ts +154 -0
- package/test/integration/ascii.test.ts +450 -0
- package/test/integration/basic-calculate.test.ts +272 -0
- package/test/integration/conversion.test.ts +357 -0
- package/test/integration/programmer-calculate.test.ts +363 -0
- package/test/unit/decimal-engine.test.ts +134 -0
- package/test/unit/error-handler.test.ts +173 -0
- package/test/unit/lexer.test.ts +176 -0
- package/test/unit/parser.test.ts +197 -0
- package/test/unit/programmer-engine.test.ts +234 -0
- package/tsconfig.json +20 -0
- package/vitest.config.ts +13 -0
|
@@ -0,0 +1,450 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { asciiToNumber, numberToAscii } from '../../src/mcp/tools/ascii.js';
|
|
3
|
+
|
|
4
|
+
describe('asciiToNumber', () => {
|
|
5
|
+
describe('Single character conversions', () => {
|
|
6
|
+
it('should convert uppercase A to ASCII code', () => {
|
|
7
|
+
const result = asciiToNumber({ text: 'A' });
|
|
8
|
+
|
|
9
|
+
expect(result.success).toBe(true);
|
|
10
|
+
if (result.success) {
|
|
11
|
+
expect(result.result).toBe('65');
|
|
12
|
+
expect(result.details?.expression).toContain('A');
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('should convert lowercase a to ASCII code', () => {
|
|
17
|
+
const result = asciiToNumber({ text: 'a' });
|
|
18
|
+
|
|
19
|
+
expect(result.success).toBe(true);
|
|
20
|
+
if (result.success) {
|
|
21
|
+
expect(result.result).toBe('97');
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('should convert digit 0 to ASCII code', () => {
|
|
26
|
+
const result = asciiToNumber({ text: '0' });
|
|
27
|
+
|
|
28
|
+
expect(result.success).toBe(true);
|
|
29
|
+
if (result.success) {
|
|
30
|
+
expect(result.result).toBe('48');
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('should convert space to ASCII code', () => {
|
|
35
|
+
const result = asciiToNumber({ text: ' ' });
|
|
36
|
+
|
|
37
|
+
expect(result.success).toBe(true);
|
|
38
|
+
if (result.success) {
|
|
39
|
+
expect(result.result).toBe('32');
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('should convert newline to ASCII code', () => {
|
|
44
|
+
const result = asciiToNumber({ text: '\n' });
|
|
45
|
+
|
|
46
|
+
expect(result.success).toBe(true);
|
|
47
|
+
if (result.success) {
|
|
48
|
+
expect(result.result).toBe('10');
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
describe('Multiple character conversions', () => {
|
|
54
|
+
it('should convert ABC to ASCII codes', () => {
|
|
55
|
+
const result = asciiToNumber({ text: 'ABC' });
|
|
56
|
+
|
|
57
|
+
expect(result.success).toBe(true);
|
|
58
|
+
if (result.success) {
|
|
59
|
+
expect(result.result).toBe('65, 66, 67');
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('should convert Hello to ASCII codes', () => {
|
|
64
|
+
const result = asciiToNumber({ text: 'Hello' });
|
|
65
|
+
|
|
66
|
+
expect(result.success).toBe(true);
|
|
67
|
+
if (result.success) {
|
|
68
|
+
expect(result.result).toBe('72, 101, 108, 108, 111');
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('should convert Hello World to ASCII codes', () => {
|
|
73
|
+
const result = asciiToNumber({ text: 'Hello World' });
|
|
74
|
+
|
|
75
|
+
expect(result.success).toBe(true);
|
|
76
|
+
if (result.success) {
|
|
77
|
+
expect(result.result).toBe('72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100');
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('should convert 123 to ASCII codes', () => {
|
|
82
|
+
const result = asciiToNumber({ text: '123' });
|
|
83
|
+
|
|
84
|
+
expect(result.success).toBe(true);
|
|
85
|
+
if (result.success) {
|
|
86
|
+
expect(result.result).toBe('49, 50, 51');
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
describe('Special characters', () => {
|
|
92
|
+
it('should convert punctuation marks', () => {
|
|
93
|
+
const result = asciiToNumber({ text: '!' });
|
|
94
|
+
|
|
95
|
+
expect(result.success).toBe(true);
|
|
96
|
+
if (result.success) {
|
|
97
|
+
expect(result.result).toBe('33');
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('should convert tab character', () => {
|
|
102
|
+
const result = asciiToNumber({ text: '\t' });
|
|
103
|
+
|
|
104
|
+
expect(result.success).toBe(true);
|
|
105
|
+
if (result.success) {
|
|
106
|
+
expect(result.result).toBe('9');
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('should convert carriage return', () => {
|
|
111
|
+
const result = asciiToNumber({ text: '\r' });
|
|
112
|
+
|
|
113
|
+
expect(result.success).toBe(true);
|
|
114
|
+
if (result.success) {
|
|
115
|
+
expect(result.result).toBe('13');
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('should convert at sign', () => {
|
|
120
|
+
const result = asciiToNumber({ text: '@' });
|
|
121
|
+
|
|
122
|
+
expect(result.success).toBe(true);
|
|
123
|
+
if (result.success) {
|
|
124
|
+
expect(result.result).toBe('64');
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
describe('Steps in details', () => {
|
|
130
|
+
it('should include conversion steps', () => {
|
|
131
|
+
const result = asciiToNumber({ text: 'AB' });
|
|
132
|
+
|
|
133
|
+
expect(result.success).toBe(true);
|
|
134
|
+
if (result.success) {
|
|
135
|
+
expect(result.details?.steps).toBeDefined();
|
|
136
|
+
expect(result.details?.steps?.length).toBeGreaterThan(0);
|
|
137
|
+
expect(result.details?.steps?.[0]).toContain('AB');
|
|
138
|
+
expect(result.details?.steps?.[1]).toContain('2');
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
describe('Error handling', () => {
|
|
144
|
+
it('should return error for empty string', () => {
|
|
145
|
+
const result = asciiToNumber({ text: '' });
|
|
146
|
+
|
|
147
|
+
expect(result.success).toBe(false);
|
|
148
|
+
if (!result.success) {
|
|
149
|
+
expect(result.error.type).toBe('EmptyInput');
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
describe('numberToAscii', () => {
|
|
156
|
+
describe('Standard ASCII conversions', () => {
|
|
157
|
+
it('should convert 65 to A', () => {
|
|
158
|
+
const result = numberToAscii({ code: 65 });
|
|
159
|
+
|
|
160
|
+
expect(result.success).toBe(true);
|
|
161
|
+
if (result.success) {
|
|
162
|
+
expect(result.result).toBe('"A"');
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it('should convert 97 to a', () => {
|
|
167
|
+
const result = numberToAscii({ code: 97 });
|
|
168
|
+
|
|
169
|
+
expect(result.success).toBe(true);
|
|
170
|
+
if (result.success) {
|
|
171
|
+
expect(result.result).toBe('"a"');
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it('should convert 48 to 0', () => {
|
|
176
|
+
const result = numberToAscii({ code: 48 });
|
|
177
|
+
|
|
178
|
+
expect(result.success).toBe(true);
|
|
179
|
+
if (result.success) {
|
|
180
|
+
expect(result.result).toBe('"0"');
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
it('should convert 32 to space', () => {
|
|
185
|
+
const result = numberToAscii({ code: 32 });
|
|
186
|
+
|
|
187
|
+
expect(result.success).toBe(true);
|
|
188
|
+
if (result.success) {
|
|
189
|
+
expect(result.result).toBe('" "');
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
describe('Extended ASCII/Unicode conversions', () => {
|
|
195
|
+
it('should convert 0 to null character', () => {
|
|
196
|
+
const result = numberToAscii({ code: 0 });
|
|
197
|
+
|
|
198
|
+
expect(result.success).toBe(true);
|
|
199
|
+
if (result.success) {
|
|
200
|
+
expect(result.result).toBe('"\x00"');
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it('should convert 127 to DEL', () => {
|
|
205
|
+
const result = numberToAscii({ code: 127 });
|
|
206
|
+
|
|
207
|
+
expect(result.success).toBe(true);
|
|
208
|
+
if (result.success) {
|
|
209
|
+
expect(result.result).toBe('"\x7F"');
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
it('should convert 169 to copyright symbol', () => {
|
|
214
|
+
const result = numberToAscii({ code: 169 });
|
|
215
|
+
|
|
216
|
+
expect(result.success).toBe(true);
|
|
217
|
+
if (result.success) {
|
|
218
|
+
expect(result.result).toBe('"©"');
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
describe('Steps in details', () => {
|
|
224
|
+
it('should include conversion steps with hex and binary', () => {
|
|
225
|
+
const result = numberToAscii({ code: 65 });
|
|
226
|
+
|
|
227
|
+
expect(result.success).toBe(true);
|
|
228
|
+
if (result.success) {
|
|
229
|
+
expect(result.details?.steps).toBeDefined();
|
|
230
|
+
expect(result.details?.steps?.length).toBe(4);
|
|
231
|
+
expect(result.details?.steps?.[0]).toContain('65');
|
|
232
|
+
expect(result.details?.steps?.[1]).toContain('0x41');
|
|
233
|
+
expect(result.details?.steps?.[2]).toContain('Binary');
|
|
234
|
+
expect(result.details?.steps?.[3]).toContain('A');
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
describe('Error handling', () => {
|
|
240
|
+
it('should return error for negative code', () => {
|
|
241
|
+
const result = numberToAscii({ code: -1 });
|
|
242
|
+
|
|
243
|
+
expect(result.success).toBe(false);
|
|
244
|
+
if (!result.success) {
|
|
245
|
+
expect(result.error.type).toBe('InvalidNumber');
|
|
246
|
+
expect(result.error.message).toContain('Invalid Unicode');
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
it('should return error for code > 0xFFFF', () => {
|
|
251
|
+
const result = numberToAscii({ code: 65536 });
|
|
252
|
+
|
|
253
|
+
expect(result.success).toBe(false);
|
|
254
|
+
if (!result.success) {
|
|
255
|
+
expect(result.error.type).toBe('InvalidNumber');
|
|
256
|
+
expect(result.error.message).toContain('surrogate pair');
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
it('should return error for code > 0x10FFFF', () => {
|
|
261
|
+
const result = numberToAscii({ code: 1114112 });
|
|
262
|
+
|
|
263
|
+
expect(result.success).toBe(false);
|
|
264
|
+
if (!result.success) {
|
|
265
|
+
expect(result.error.type).toBe('InvalidNumber');
|
|
266
|
+
expect(result.error.message).toContain('Valid range');
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
it('should return error when both code and codes are provided', () => {
|
|
271
|
+
const result = numberToAscii({ code: 65, codes: [66, 67] });
|
|
272
|
+
|
|
273
|
+
expect(result.success).toBe(false);
|
|
274
|
+
if (!result.success) {
|
|
275
|
+
expect(result.error.type).toBe('InvalidNumber');
|
|
276
|
+
expect(result.error.message).toContain('Only one');
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
it('should return error when neither code nor codes is provided', () => {
|
|
281
|
+
const result = numberToAscii({});
|
|
282
|
+
|
|
283
|
+
expect(result.success).toBe(false);
|
|
284
|
+
if (!result.success) {
|
|
285
|
+
expect(result.error.type).toBe('EmptyInput');
|
|
286
|
+
expect(result.error.message).toContain('Either code or codes');
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
describe('Batch conversions using codes parameter', () => {
|
|
292
|
+
it('should convert [72, 101, 108, 108, 111] to Hello', () => {
|
|
293
|
+
const result = numberToAscii({ codes: [72, 101, 108, 108, 111] });
|
|
294
|
+
|
|
295
|
+
expect(result.success).toBe(true);
|
|
296
|
+
if (result.success) {
|
|
297
|
+
expect(result.result).toBe('"Hello"');
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
it('should convert [65, 66, 67] to ABC', () => {
|
|
302
|
+
const result = numberToAscii({ codes: [65, 66, 67] });
|
|
303
|
+
|
|
304
|
+
expect(result.success).toBe(true);
|
|
305
|
+
if (result.success) {
|
|
306
|
+
expect(result.result).toBe('"ABC"');
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
it('should convert single code array', () => {
|
|
311
|
+
const result = numberToAscii({ codes: [88] });
|
|
312
|
+
|
|
313
|
+
expect(result.success).toBe(true);
|
|
314
|
+
if (result.success) {
|
|
315
|
+
expect(result.result).toBe('"X"');
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
it('should convert codes with spaces', () => {
|
|
320
|
+
const result = numberToAscii({ codes: [72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100] });
|
|
321
|
+
|
|
322
|
+
expect(result.success).toBe(true);
|
|
323
|
+
if (result.success) {
|
|
324
|
+
expect(result.result).toBe('"Hello World"');
|
|
325
|
+
}
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
it('should convert letters and digits', () => {
|
|
329
|
+
const result = numberToAscii({ codes: [65, 49, 66, 50] });
|
|
330
|
+
|
|
331
|
+
expect(result.success).toBe(true);
|
|
332
|
+
if (result.success) {
|
|
333
|
+
expect(result.result).toBe('"A1B2"');
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
it('should convert with punctuation', () => {
|
|
338
|
+
const result = numberToAscii({ codes: [72, 105, 33] });
|
|
339
|
+
|
|
340
|
+
expect(result.success).toBe(true);
|
|
341
|
+
if (result.success) {
|
|
342
|
+
expect(result.result).toBe('"Hi!"');
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
it('should convert special characters', () => {
|
|
347
|
+
const result = numberToAscii({ codes: [32, 10, 9] });
|
|
348
|
+
|
|
349
|
+
expect(result.success).toBe(true);
|
|
350
|
+
if (result.success) {
|
|
351
|
+
expect(result.result).toBe('" \n\t"');
|
|
352
|
+
}
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
it('should include conversion steps in details', () => {
|
|
356
|
+
const result = numberToAscii({ codes: [72, 69, 76] });
|
|
357
|
+
|
|
358
|
+
expect(result.success).toBe(true);
|
|
359
|
+
if (result.success) {
|
|
360
|
+
expect(result.details?.steps).toBeDefined();
|
|
361
|
+
expect(result.details?.steps?.length).toBe(6);
|
|
362
|
+
expect(result.details?.steps?.[0]).toContain('[72, 69, 76]');
|
|
363
|
+
expect(result.details?.steps?.[5]).toContain('"HEL"');
|
|
364
|
+
}
|
|
365
|
+
});
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
describe('Batch error handling', () => {
|
|
369
|
+
it('should return error for empty array', () => {
|
|
370
|
+
const result = numberToAscii({ codes: [] });
|
|
371
|
+
|
|
372
|
+
expect(result.success).toBe(false);
|
|
373
|
+
if (!result.success) {
|
|
374
|
+
expect(result.error.type).toBe('EmptyInput');
|
|
375
|
+
}
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
it('should return error for array with negative code', () => {
|
|
379
|
+
const result = numberToAscii({ codes: [65, -1, 67] });
|
|
380
|
+
|
|
381
|
+
expect(result.success).toBe(false);
|
|
382
|
+
if (!result.success) {
|
|
383
|
+
expect(result.error.type).toBe('InvalidNumber');
|
|
384
|
+
expect(result.error.message).toContain('-1');
|
|
385
|
+
}
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
it('should return error for array with code > 0xFFFF', () => {
|
|
389
|
+
const result = numberToAscii({ codes: [65, 65536, 67] });
|
|
390
|
+
|
|
391
|
+
expect(result.success).toBe(false);
|
|
392
|
+
if (!result.success) {
|
|
393
|
+
expect(result.error.type).toBe('InvalidNumber');
|
|
394
|
+
expect(result.error.message).toContain('65536');
|
|
395
|
+
}
|
|
396
|
+
});
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
describe('Extended Unicode batch conversions', () => {
|
|
400
|
+
it('should convert copyright symbol', () => {
|
|
401
|
+
const result = numberToAscii({ codes: [169, 174] });
|
|
402
|
+
|
|
403
|
+
expect(result.success).toBe(true);
|
|
404
|
+
if (result.success) {
|
|
405
|
+
expect(result.result).toBe('"©®"');
|
|
406
|
+
}
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
it('should convert Euro sign', () => {
|
|
410
|
+
const result = numberToAscii({ codes: [8364] });
|
|
411
|
+
|
|
412
|
+
expect(result.success).toBe(true);
|
|
413
|
+
if (result.success) {
|
|
414
|
+
expect(result.result).toBe('"€"');
|
|
415
|
+
}
|
|
416
|
+
});
|
|
417
|
+
});
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
describe('Combined operations', () => {
|
|
421
|
+
it('should round-trip single character', () => {
|
|
422
|
+
const originalText = 'X';
|
|
423
|
+
|
|
424
|
+
const toNumberResult = asciiToNumber({ text: originalText });
|
|
425
|
+
expect(toNumberResult.success).toBe(true);
|
|
426
|
+
|
|
427
|
+
const code = parseInt(toNumberResult.result);
|
|
428
|
+
const toCharResult = numberToAscii({ code });
|
|
429
|
+
|
|
430
|
+
expect(toCharResult.success).toBe(true);
|
|
431
|
+
if (toCharResult.success) {
|
|
432
|
+
expect(toCharResult.result).toBe('"X"');
|
|
433
|
+
}
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
it('should round-trip multiple characters using codes parameter', () => {
|
|
437
|
+
const originalCodes = [72, 105, 33];
|
|
438
|
+
|
|
439
|
+
const toTextResult = numberToAscii({ codes: originalCodes });
|
|
440
|
+
expect(toTextResult.success).toBe(true);
|
|
441
|
+
|
|
442
|
+
const text = toTextResult.result?.replace(/"/g, '') ?? '';
|
|
443
|
+
const toCodesResult = asciiToNumber({ text });
|
|
444
|
+
|
|
445
|
+
expect(toCodesResult.success).toBe(true);
|
|
446
|
+
if (toCodesResult.success) {
|
|
447
|
+
expect(toCodesResult.result).toBe('72, 105, 33');
|
|
448
|
+
}
|
|
449
|
+
});
|
|
450
|
+
});
|