@simplysm/core-common 13.0.0-beta.2 → 13.0.0-beta.21
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/dist/common.types.js +4 -4
- package/dist/errors/argument-error.js +1 -1
- package/dist/errors/not-implemented-error.js +1 -1
- package/dist/errors/timeout-error.js +1 -1
- package/dist/extensions/arr-ext.helpers.js +4 -4
- package/dist/extensions/arr-ext.js +9 -9
- package/dist/features/debounce-queue.js +2 -2
- package/dist/features/serial-queue.js +3 -3
- package/dist/index.js +30 -30
- package/dist/types/date-only.js +2 -2
- package/dist/types/date-time.js +2 -2
- package/dist/types/time.js +2 -2
- package/dist/types/uuid.js +1 -1
- package/dist/utils/bytes.js +1 -1
- package/dist/utils/json.js +8 -8
- package/dist/utils/obj.js +5 -5
- package/dist/utils/primitive.js +5 -5
- package/dist/utils/transferable.js +4 -4
- package/dist/utils/wait.js +1 -1
- package/package.json +7 -4
- package/.cache/typecheck-browser.tsbuildinfo +0 -1
- package/.cache/typecheck-node.tsbuildinfo +0 -1
- package/.cache/typecheck-tests-browser.tsbuildinfo +0 -1
- package/.cache/typecheck-tests-node.tsbuildinfo +0 -1
- package/src/common.types.ts +0 -91
- package/src/env.ts +0 -11
- package/src/errors/argument-error.ts +0 -40
- package/src/errors/not-implemented-error.ts +0 -32
- package/src/errors/sd-error.ts +0 -53
- package/src/errors/timeout-error.ts +0 -36
- package/src/extensions/arr-ext.helpers.ts +0 -53
- package/src/extensions/arr-ext.ts +0 -777
- package/src/extensions/arr-ext.types.ts +0 -258
- package/src/extensions/map-ext.ts +0 -86
- package/src/extensions/set-ext.ts +0 -68
- package/src/features/debounce-queue.ts +0 -116
- package/src/features/event-emitter.ts +0 -112
- package/src/features/serial-queue.ts +0 -94
- package/src/globals.ts +0 -12
- package/src/index.ts +0 -55
- package/src/types/date-only.ts +0 -329
- package/src/types/date-time.ts +0 -294
- package/src/types/lazy-gc-map.ts +0 -244
- package/src/types/time.ts +0 -210
- package/src/types/uuid.ts +0 -113
- package/src/utils/bytes.ts +0 -160
- package/src/utils/date-format.ts +0 -239
- package/src/utils/json.ts +0 -230
- package/src/utils/num.ts +0 -97
- package/src/utils/obj.ts +0 -956
- package/src/utils/path.ts +0 -40
- package/src/utils/primitive.ts +0 -33
- package/src/utils/str.ts +0 -252
- package/src/utils/template-strings.ts +0 -132
- package/src/utils/transferable.ts +0 -269
- package/src/utils/wait.ts +0 -40
- package/src/utils/xml.ts +0 -105
- package/src/zip/sd-zip.ts +0 -218
- package/tests/errors/errors.spec.ts +0 -196
- package/tests/extensions/array-extension.spec.ts +0 -790
- package/tests/extensions/map-extension.spec.ts +0 -147
- package/tests/extensions/set-extension.spec.ts +0 -74
- package/tests/types/date-only.spec.ts +0 -636
- package/tests/types/date-time.spec.ts +0 -391
- package/tests/types/lazy-gc-map.spec.ts +0 -692
- package/tests/types/time.spec.ts +0 -559
- package/tests/types/types.spec.ts +0 -55
- package/tests/types/uuid.spec.ts +0 -91
- package/tests/utils/bytes-utils.spec.ts +0 -230
- package/tests/utils/date-format.spec.ts +0 -371
- package/tests/utils/debounce-queue.spec.ts +0 -272
- package/tests/utils/json.spec.ts +0 -475
- package/tests/utils/number.spec.ts +0 -184
- package/tests/utils/object.spec.ts +0 -827
- package/tests/utils/path.spec.ts +0 -78
- package/tests/utils/primitive.spec.ts +0 -55
- package/tests/utils/sd-event-emitter.spec.ts +0 -216
- package/tests/utils/serial-queue.spec.ts +0 -365
- package/tests/utils/string.spec.ts +0 -294
- package/tests/utils/template-strings.spec.ts +0 -96
- package/tests/utils/transferable.spec.ts +0 -698
- package/tests/utils/wait.spec.ts +0 -145
- package/tests/utils/xml.spec.ts +0 -146
- package/tests/zip/sd-zip.spec.ts +0 -234
package/tests/utils/json.spec.ts
DELETED
|
@@ -1,475 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from "vitest";
|
|
2
|
-
import { jsonStringify as stringify, jsonParse as parse, DateTime, DateOnly, Time, Uuid } from "@simplysm/core-common";
|
|
3
|
-
|
|
4
|
-
describe("JsonConvert", () => {
|
|
5
|
-
//#region stringify
|
|
6
|
-
|
|
7
|
-
describe("stringify()", () => {
|
|
8
|
-
it("primitive 값을 직렬화한다", () => {
|
|
9
|
-
expect(stringify(42)).toBe("42");
|
|
10
|
-
expect(stringify("hello")).toBe('"hello"');
|
|
11
|
-
expect(stringify(true)).toBe("true");
|
|
12
|
-
expect(stringify(null)).toBe("null");
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
it("Date를 __type__으로 직렬화한다", () => {
|
|
16
|
-
const date = new Date("2024-03-15T10:30:00.000Z");
|
|
17
|
-
const json = stringify(date);
|
|
18
|
-
const parsed = JSON.parse(json);
|
|
19
|
-
|
|
20
|
-
expect(parsed.__type__).toBe("Date");
|
|
21
|
-
expect(parsed.data).toBe("2024-03-15T10:30:00.000Z");
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
it("DateTime을 __type__으로 직렬화한다", () => {
|
|
25
|
-
const dt = new DateTime(2024, 3, 15, 10, 30);
|
|
26
|
-
const json = stringify(dt);
|
|
27
|
-
const parsed = JSON.parse(json);
|
|
28
|
-
|
|
29
|
-
expect(parsed.__type__).toBe("DateTime");
|
|
30
|
-
expect(typeof parsed.data).toBe("string");
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
it("DateOnly를 __type__으로 직렬화한다", () => {
|
|
34
|
-
const d = new DateOnly(2024, 3, 15);
|
|
35
|
-
const json = stringify(d);
|
|
36
|
-
const parsed = JSON.parse(json);
|
|
37
|
-
|
|
38
|
-
expect(parsed.__type__).toBe("DateOnly");
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it("Time을 __type__으로 직렬화한다", () => {
|
|
42
|
-
const t = new Time(10, 30, 45);
|
|
43
|
-
const json = stringify(t);
|
|
44
|
-
const parsed = JSON.parse(json);
|
|
45
|
-
|
|
46
|
-
expect(parsed.__type__).toBe("Time");
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it("Uuid를 __type__으로 직렬화한다", () => {
|
|
50
|
-
const uuid = new Uuid("12345678-9abc-def0-1234-56789abcdef0");
|
|
51
|
-
const json = stringify(uuid);
|
|
52
|
-
const parsed = JSON.parse(json);
|
|
53
|
-
|
|
54
|
-
expect(parsed.__type__).toBe("Uuid");
|
|
55
|
-
expect(parsed.data).toBe("12345678-9abc-def0-1234-56789abcdef0");
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
it("Set을 __type__으로 직렬화한다", () => {
|
|
59
|
-
const set = new Set([1, 2, 3]);
|
|
60
|
-
const json = stringify(set);
|
|
61
|
-
const parsed = JSON.parse(json);
|
|
62
|
-
|
|
63
|
-
expect(parsed.__type__).toBe("Set");
|
|
64
|
-
expect(parsed.data).toEqual([1, 2, 3]);
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
it("Map을 __type__으로 직렬화한다", () => {
|
|
68
|
-
const map = new Map([
|
|
69
|
-
["a", 1],
|
|
70
|
-
["b", 2],
|
|
71
|
-
]);
|
|
72
|
-
const json = stringify(map);
|
|
73
|
-
const parsed = JSON.parse(json);
|
|
74
|
-
|
|
75
|
-
expect(parsed.__type__).toBe("Map");
|
|
76
|
-
expect(parsed.data).toEqual([
|
|
77
|
-
["a", 1],
|
|
78
|
-
["b", 2],
|
|
79
|
-
]);
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
it("Error를 __type__으로 직렬화한다", () => {
|
|
83
|
-
const error = new Error("test error");
|
|
84
|
-
const json = stringify(error);
|
|
85
|
-
const parsed = JSON.parse(json);
|
|
86
|
-
|
|
87
|
-
expect(parsed.__type__).toBe("Error");
|
|
88
|
-
expect(parsed.data.message).toBe("test error");
|
|
89
|
-
expect(parsed.data.name).toBe("Error");
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
it("Error의 확장 속성(code, detail, cause)을 직렬화한다", () => {
|
|
93
|
-
const cause = new Error("원인 에러");
|
|
94
|
-
const error = new Error("test error") as Error & { code: string; detail: object };
|
|
95
|
-
error.code = "ERR_CODE";
|
|
96
|
-
error.detail = { key: "value" };
|
|
97
|
-
(error as Error & { cause: Error }).cause = cause;
|
|
98
|
-
|
|
99
|
-
const json = stringify(error);
|
|
100
|
-
const parsed = JSON.parse(json);
|
|
101
|
-
|
|
102
|
-
expect(parsed.__type__).toBe("Error");
|
|
103
|
-
expect(parsed.data.message).toBe("test error");
|
|
104
|
-
expect(parsed.data.code).toBe("ERR_CODE");
|
|
105
|
-
expect(parsed.data.detail).toEqual({ key: "value" });
|
|
106
|
-
expect(parsed.data.cause.__type__).toBe("Error");
|
|
107
|
-
expect(parsed.data.cause.data.message).toBe("원인 에러");
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
it("redactBytes 옵션으로 Uint8Array를 숨긴다", () => {
|
|
111
|
-
const obj = { data: new TextEncoder().encode("hello") };
|
|
112
|
-
const json = stringify(obj, { redactBytes: true });
|
|
113
|
-
const parsed = JSON.parse(json);
|
|
114
|
-
|
|
115
|
-
expect(parsed.data.data).toBe("__hidden__");
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
it("space 옵션으로 들여쓰기한다", () => {
|
|
119
|
-
const obj = { a: 1 };
|
|
120
|
-
const json = stringify(obj, { space: 2 });
|
|
121
|
-
|
|
122
|
-
expect(json).toBe('{\n "a": 1\n}');
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
it("replacer 옵션으로 값을 변환한다", () => {
|
|
126
|
-
const obj = { a: 1, b: 2, c: 3 };
|
|
127
|
-
const json = stringify(obj, {
|
|
128
|
-
replacer: (key, value) => {
|
|
129
|
-
if (key === "b") return undefined;
|
|
130
|
-
return value;
|
|
131
|
-
},
|
|
132
|
-
});
|
|
133
|
-
const parsed = JSON.parse(json);
|
|
134
|
-
|
|
135
|
-
expect(parsed.a).toBe(1);
|
|
136
|
-
expect(parsed.b).toBeUndefined();
|
|
137
|
-
expect(parsed.c).toBe(3);
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
it("동시 호출 시 경쟁 조건이 발생하지 않는다", async () => {
|
|
141
|
-
// 여러 Date 객체를 포함한 복잡한 객체들을 동시에 직렬화
|
|
142
|
-
const createTestObject = (id: number) => ({
|
|
143
|
-
id,
|
|
144
|
-
date: new Date(`2024-0${(id % 9) + 1}-15T10:30:00.000Z`),
|
|
145
|
-
nested: {
|
|
146
|
-
innerDate: new Date(`2024-0${(id % 9) + 1}-20T15:45:00.000Z`),
|
|
147
|
-
},
|
|
148
|
-
array: [new Date(`2024-0${(id % 9) + 1}-25T08:00:00.000Z`)],
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
// 100개의 동시 호출
|
|
152
|
-
const promises = Array.from({ length: 100 }, (_, i) =>
|
|
153
|
-
Promise.resolve().then(() => {
|
|
154
|
-
const obj = createTestObject(i);
|
|
155
|
-
const json = stringify(obj);
|
|
156
|
-
const parsed = parse<typeof obj>(json);
|
|
157
|
-
|
|
158
|
-
// 모든 Date가 올바르게 복원되었는지 확인
|
|
159
|
-
expect(parsed.date).toBeInstanceOf(Date);
|
|
160
|
-
expect(parsed.nested.innerDate).toBeInstanceOf(Date);
|
|
161
|
-
expect(parsed.array[0]).toBeInstanceOf(Date);
|
|
162
|
-
|
|
163
|
-
return { id: i, success: true };
|
|
164
|
-
}),
|
|
165
|
-
);
|
|
166
|
-
|
|
167
|
-
const results = await Promise.all(promises);
|
|
168
|
-
|
|
169
|
-
// 모든 호출이 성공했는지 확인
|
|
170
|
-
expect(results.every((r) => r.success)).toBe(true);
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
it("중첩된 Date 객체를 올바르게 직렬화한다", () => {
|
|
174
|
-
const obj = {
|
|
175
|
-
level1: {
|
|
176
|
-
level2: {
|
|
177
|
-
level3: {
|
|
178
|
-
date: new Date("2024-06-15T12:00:00.000Z"),
|
|
179
|
-
},
|
|
180
|
-
},
|
|
181
|
-
},
|
|
182
|
-
dates: [new Date("2024-01-01T00:00:00.000Z"), new Date("2024-12-31T23:59:59.000Z")],
|
|
183
|
-
};
|
|
184
|
-
|
|
185
|
-
const json = stringify(obj);
|
|
186
|
-
const parsed = parse<typeof obj>(json);
|
|
187
|
-
|
|
188
|
-
expect(parsed.level1.level2.level3.date).toBeInstanceOf(Date);
|
|
189
|
-
expect(parsed.level1.level2.level3.date.toISOString()).toBe("2024-06-15T12:00:00.000Z");
|
|
190
|
-
expect(parsed.dates[0]).toBeInstanceOf(Date);
|
|
191
|
-
expect(parsed.dates[1]).toBeInstanceOf(Date);
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
it("Date.prototype.toJSON을 수정하지 않는다", () => {
|
|
195
|
-
const originalToJSON = Date.prototype.toJSON;
|
|
196
|
-
|
|
197
|
-
// stringify 호출
|
|
198
|
-
const date = new Date("2024-03-15T10:30:00.000Z");
|
|
199
|
-
stringify({ date });
|
|
200
|
-
|
|
201
|
-
// toJSON이 변경되지 않았는지 확인
|
|
202
|
-
expect(Date.prototype.toJSON).toBe(originalToJSON);
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
it("순환 참조 객체는 TypeError를 던진다", () => {
|
|
206
|
-
const obj: Record<string, unknown> = { name: "test" };
|
|
207
|
-
obj["self"] = obj; // 순환 참조
|
|
208
|
-
|
|
209
|
-
expect(() => stringify(obj)).toThrow(TypeError);
|
|
210
|
-
expect(() => stringify(obj)).toThrow("Converting circular structure to JSON");
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
it("배열 내 순환 참조도 감지한다", () => {
|
|
214
|
-
const arr: unknown[] = [1, 2];
|
|
215
|
-
arr.push(arr); // 배열 순환 참조
|
|
216
|
-
|
|
217
|
-
expect(() => stringify(arr)).toThrow("Converting circular structure to JSON");
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
it("toJSON 메서드를 가진 커스텀 객체를 직렬화한다", () => {
|
|
221
|
-
const obj = {
|
|
222
|
-
amount: 100,
|
|
223
|
-
toJSON() {
|
|
224
|
-
return `$${this.amount}`;
|
|
225
|
-
},
|
|
226
|
-
};
|
|
227
|
-
|
|
228
|
-
const json = stringify(obj);
|
|
229
|
-
expect(json).toBe('"$100"');
|
|
230
|
-
});
|
|
231
|
-
|
|
232
|
-
it("toJSON이 객체를 반환하면 재귀적으로 처리한다", () => {
|
|
233
|
-
const obj = {
|
|
234
|
-
data: "test",
|
|
235
|
-
toJSON() {
|
|
236
|
-
return { converted: true, date: new Date("2024-01-01T00:00:00.000Z") };
|
|
237
|
-
},
|
|
238
|
-
};
|
|
239
|
-
|
|
240
|
-
const json = stringify(obj);
|
|
241
|
-
const parsed = JSON.parse(json);
|
|
242
|
-
|
|
243
|
-
expect(parsed.converted).toBe(true);
|
|
244
|
-
expect(parsed.date.__type__).toBe("Date");
|
|
245
|
-
});
|
|
246
|
-
|
|
247
|
-
it("getter 속성을 직렬화한다", () => {
|
|
248
|
-
const obj = {
|
|
249
|
-
_value: 10,
|
|
250
|
-
get computed() {
|
|
251
|
-
return this._value * 2;
|
|
252
|
-
},
|
|
253
|
-
};
|
|
254
|
-
|
|
255
|
-
const json = stringify(obj);
|
|
256
|
-
const parsed = JSON.parse(json);
|
|
257
|
-
|
|
258
|
-
expect(parsed._value).toBe(10);
|
|
259
|
-
expect(parsed.computed).toBe(20);
|
|
260
|
-
});
|
|
261
|
-
|
|
262
|
-
it("빈 객체와 배열을 직렬화한다", () => {
|
|
263
|
-
expect(stringify({})).toBe("{}");
|
|
264
|
-
expect(stringify([])).toBe("[]");
|
|
265
|
-
expect(stringify({ arr: [], obj: {} })).toBe('{"arr":[],"obj":{}}');
|
|
266
|
-
});
|
|
267
|
-
|
|
268
|
-
it("undefined 값을 가진 속성은 제외된다", () => {
|
|
269
|
-
const obj = { a: 1, b: undefined, c: 3 };
|
|
270
|
-
const json = stringify(obj);
|
|
271
|
-
const parsed = JSON.parse(json);
|
|
272
|
-
|
|
273
|
-
expect(parsed.a).toBe(1);
|
|
274
|
-
expect("b" in parsed).toBe(false);
|
|
275
|
-
expect(parsed.c).toBe(3);
|
|
276
|
-
});
|
|
277
|
-
|
|
278
|
-
it("성능이 합리적인 시간 내에 완료된다", () => {
|
|
279
|
-
// 복잡한 테스트 객체 생성
|
|
280
|
-
const createTestObject = () => ({
|
|
281
|
-
id: 1,
|
|
282
|
-
name: "test",
|
|
283
|
-
date: new Date(),
|
|
284
|
-
nested: {
|
|
285
|
-
array: [1, 2, 3, new Date(), { deep: true }],
|
|
286
|
-
map: new Map([["a", 1]]),
|
|
287
|
-
set: new Set([1, 2, 3]),
|
|
288
|
-
},
|
|
289
|
-
});
|
|
290
|
-
|
|
291
|
-
const iterations = 1000;
|
|
292
|
-
const testObj = createTestObject();
|
|
293
|
-
|
|
294
|
-
// jsonStringify 성능 측정
|
|
295
|
-
const startCustom = performance.now();
|
|
296
|
-
for (let i = 0; i < iterations; i++) {
|
|
297
|
-
stringify(testObj);
|
|
298
|
-
}
|
|
299
|
-
const customTime = performance.now() - startCustom;
|
|
300
|
-
|
|
301
|
-
// 1000회 직렬화가 100ms 이내에 완료되어야 함
|
|
302
|
-
// (커스텀 타입 처리, 순환 참조 감지 등 추가 기능 포함)
|
|
303
|
-
expect(customTime).toBeLessThan(100);
|
|
304
|
-
});
|
|
305
|
-
});
|
|
306
|
-
|
|
307
|
-
//#endregion
|
|
308
|
-
|
|
309
|
-
//#region parse
|
|
310
|
-
|
|
311
|
-
describe("parse()", () => {
|
|
312
|
-
it("primitive 값을 역직렬화한다", () => {
|
|
313
|
-
expect(parse("42")).toBe(42);
|
|
314
|
-
expect(parse('"hello"')).toBe("hello");
|
|
315
|
-
expect(parse("true")).toBe(true);
|
|
316
|
-
});
|
|
317
|
-
|
|
318
|
-
it("null을 undefined로 변환한다", () => {
|
|
319
|
-
expect(parse("null")).toBe(undefined);
|
|
320
|
-
});
|
|
321
|
-
|
|
322
|
-
it("Date를 복원한다", () => {
|
|
323
|
-
const json = '{"__type__":"Date","data":"2024-03-15T10:30:00.000Z"}';
|
|
324
|
-
const result = parse(json);
|
|
325
|
-
|
|
326
|
-
expect(result).toBeInstanceOf(Date);
|
|
327
|
-
expect((result as Date).toISOString()).toBe("2024-03-15T10:30:00.000Z");
|
|
328
|
-
});
|
|
329
|
-
|
|
330
|
-
it("DateTime을 복원한다", () => {
|
|
331
|
-
const dt = new DateTime(2024, 3, 15, 10, 30);
|
|
332
|
-
const json = stringify(dt);
|
|
333
|
-
const result = parse(json);
|
|
334
|
-
|
|
335
|
-
expect(result).toBeInstanceOf(DateTime);
|
|
336
|
-
expect((result as DateTime).year).toBe(2024);
|
|
337
|
-
expect((result as DateTime).month).toBe(3);
|
|
338
|
-
expect((result as DateTime).day).toBe(15);
|
|
339
|
-
});
|
|
340
|
-
|
|
341
|
-
it("DateOnly를 복원한다", () => {
|
|
342
|
-
const d = new DateOnly(2024, 3, 15);
|
|
343
|
-
const json = stringify(d);
|
|
344
|
-
const result = parse(json);
|
|
345
|
-
|
|
346
|
-
expect(result).toBeInstanceOf(DateOnly);
|
|
347
|
-
expect((result as DateOnly).year).toBe(2024);
|
|
348
|
-
});
|
|
349
|
-
|
|
350
|
-
it("Time을 복원한다", () => {
|
|
351
|
-
const t = new Time(10, 30, 45);
|
|
352
|
-
const json = stringify(t);
|
|
353
|
-
const result = parse(json);
|
|
354
|
-
|
|
355
|
-
expect(result).toBeInstanceOf(Time);
|
|
356
|
-
expect((result as Time).hour).toBe(10);
|
|
357
|
-
});
|
|
358
|
-
|
|
359
|
-
it("Uuid를 복원한다", () => {
|
|
360
|
-
const json = '{"__type__":"Uuid","data":"12345678-9abc-def0-1234-56789abcdef0"}';
|
|
361
|
-
const result = parse(json);
|
|
362
|
-
|
|
363
|
-
expect(result).toBeInstanceOf(Uuid);
|
|
364
|
-
expect((result as Uuid).toString()).toBe("12345678-9abc-def0-1234-56789abcdef0");
|
|
365
|
-
});
|
|
366
|
-
|
|
367
|
-
it("Set을 복원한다", () => {
|
|
368
|
-
const json = '{"__type__":"Set","data":[1,2,3]}';
|
|
369
|
-
const result = parse(json);
|
|
370
|
-
|
|
371
|
-
expect(result).toBeInstanceOf(Set);
|
|
372
|
-
expect(Array.from(result as Set<number>)).toEqual([1, 2, 3]);
|
|
373
|
-
});
|
|
374
|
-
|
|
375
|
-
it("Map을 복원한다", () => {
|
|
376
|
-
const json = '{"__type__":"Map","data":[["a",1],["b",2]]}';
|
|
377
|
-
const result = parse(json);
|
|
378
|
-
|
|
379
|
-
expect(result).toBeInstanceOf(Map);
|
|
380
|
-
expect((result as Map<string, number>).get("a")).toBe(1);
|
|
381
|
-
});
|
|
382
|
-
|
|
383
|
-
it("Error를 복원한다 (확장 속성 포함)", () => {
|
|
384
|
-
const cause = new Error("원인 에러");
|
|
385
|
-
const error = new Error("test error") as Error & { code: string; detail: object; cause: Error };
|
|
386
|
-
error.code = "ERR_CODE";
|
|
387
|
-
error.detail = { key: "value" };
|
|
388
|
-
error.cause = cause;
|
|
389
|
-
|
|
390
|
-
const json = stringify(error);
|
|
391
|
-
const result = parse<typeof error>(json);
|
|
392
|
-
|
|
393
|
-
expect(result).toBeInstanceOf(Error);
|
|
394
|
-
expect(result.message).toBe("test error");
|
|
395
|
-
expect(result.code).toBe("ERR_CODE");
|
|
396
|
-
expect(result.detail).toEqual({ key: "value" });
|
|
397
|
-
expect(result.cause).toBeInstanceOf(Error);
|
|
398
|
-
expect(result.cause.message).toBe("원인 에러");
|
|
399
|
-
});
|
|
400
|
-
|
|
401
|
-
it("Uint8Array를 복원한다", () => {
|
|
402
|
-
const json = '{"__type__":"Uint8Array","data":"68656c6c6f"}';
|
|
403
|
-
const result = parse(json);
|
|
404
|
-
|
|
405
|
-
expect(result).toBeInstanceOf(Uint8Array);
|
|
406
|
-
expect(new TextDecoder().decode(result as Uint8Array)).toBe("hello");
|
|
407
|
-
});
|
|
408
|
-
|
|
409
|
-
it("stringify/parse 라운드트립", () => {
|
|
410
|
-
const original = {
|
|
411
|
-
date: new Date("2024-03-15T10:30:00.000Z"),
|
|
412
|
-
dateTime: new DateTime(2024, 3, 15),
|
|
413
|
-
dateOnly: new DateOnly(2024, 3, 15),
|
|
414
|
-
time: new Time(10, 30),
|
|
415
|
-
uuid: new Uuid("12345678-9abc-def0-1234-56789abcdef0"),
|
|
416
|
-
set: new Set([1, 2, 3]),
|
|
417
|
-
map: new Map([["a", 1]]),
|
|
418
|
-
bytes: new TextEncoder().encode("hello"),
|
|
419
|
-
};
|
|
420
|
-
|
|
421
|
-
const json = stringify(original);
|
|
422
|
-
const result = parse<typeof original>(json);
|
|
423
|
-
|
|
424
|
-
expect(result.date).toBeInstanceOf(Date);
|
|
425
|
-
expect(result.dateTime).toBeInstanceOf(DateTime);
|
|
426
|
-
expect(result.dateOnly).toBeInstanceOf(DateOnly);
|
|
427
|
-
expect(result.time).toBeInstanceOf(Time);
|
|
428
|
-
expect(result.uuid).toBeInstanceOf(Uuid);
|
|
429
|
-
expect(result.set).toBeInstanceOf(Set);
|
|
430
|
-
expect(result.map).toBeInstanceOf(Map);
|
|
431
|
-
expect(result.bytes).toBeInstanceOf(Uint8Array);
|
|
432
|
-
});
|
|
433
|
-
|
|
434
|
-
it("redactBytes로 직렬화된 데이터는 parse 시 에러가 발생한다", () => {
|
|
435
|
-
const obj = { data: new TextEncoder().encode("hello") };
|
|
436
|
-
const json = stringify(obj, { redactBytes: true });
|
|
437
|
-
|
|
438
|
-
// "__hidden__"은 redactBytes 옵션으로 직렬화된 데이터이므로 parse 시 에러 발생
|
|
439
|
-
expect(() => parse<typeof obj>(json)).toThrow(
|
|
440
|
-
"redactBytes 옵션으로 직렬화된 Uint8Array는 parse로 복원할 수 없습니다",
|
|
441
|
-
);
|
|
442
|
-
});
|
|
443
|
-
|
|
444
|
-
it("잘못된 JSON은 에러를 던진다", () => {
|
|
445
|
-
expect(() => parse("invalid json")).toThrow("JSON 파싱 에러");
|
|
446
|
-
});
|
|
447
|
-
|
|
448
|
-
it("DEV 모드에서는 전체 JSON이 에러 메시지에 포함된다", () => {
|
|
449
|
-
const longJson = "x".repeat(2000);
|
|
450
|
-
|
|
451
|
-
try {
|
|
452
|
-
parse(longJson);
|
|
453
|
-
expect.fail("에러가 발생해야 합니다");
|
|
454
|
-
} catch (err) {
|
|
455
|
-
const message = (err as Error).message;
|
|
456
|
-
// DEV 모드에서는 전체 JSON이 포함됨
|
|
457
|
-
expect(message).toContain(longJson);
|
|
458
|
-
}
|
|
459
|
-
});
|
|
460
|
-
|
|
461
|
-
it("에러 메시지에 JSON 내용이 포함된다", () => {
|
|
462
|
-
const shortJson = "invalid";
|
|
463
|
-
|
|
464
|
-
try {
|
|
465
|
-
parse(shortJson);
|
|
466
|
-
expect.fail("에러가 발생해야 합니다");
|
|
467
|
-
} catch (err) {
|
|
468
|
-
const message = (err as Error).message;
|
|
469
|
-
expect(message).toContain("invalid");
|
|
470
|
-
}
|
|
471
|
-
});
|
|
472
|
-
});
|
|
473
|
-
|
|
474
|
-
//#endregion
|
|
475
|
-
});
|
|
@@ -1,184 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from "vitest";
|
|
2
|
-
import {
|
|
3
|
-
numParseInt as parseInt,
|
|
4
|
-
numParseRoundedInt as parseRoundedInt,
|
|
5
|
-
numParseFloat as parseFloat,
|
|
6
|
-
numIsNullOrEmpty as isNullOrEmpty,
|
|
7
|
-
numFormat as format,
|
|
8
|
-
} from "@simplysm/core-common";
|
|
9
|
-
|
|
10
|
-
describe("number utils", () => {
|
|
11
|
-
//#region numParseInt
|
|
12
|
-
|
|
13
|
-
describe("numParseInt()", () => {
|
|
14
|
-
it("숫자 문자열을 정수로 파싱한다", () => {
|
|
15
|
-
expect(parseInt("123")).toBe(123);
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
it("음수 문자열을 파싱한다", () => {
|
|
19
|
-
expect(parseInt("-123")).toBe(-123);
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
it("실수 문자열은 정수 부분만 반환한다", () => {
|
|
23
|
-
expect(parseInt("123.45")).toBe(123);
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
it("숫자 타입이면 소수점 이하를 버린다", () => {
|
|
27
|
-
expect(parseInt(123.7)).toBe(123);
|
|
28
|
-
expect(parseInt(123.3)).toBe(123);
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
it("비숫자 문자를 제거 후 파싱한다", () => {
|
|
32
|
-
expect(parseInt("$1,234")).toBe(1234);
|
|
33
|
-
expect(parseInt("가나다123")).toBe(123);
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it("문자 사이의 음수 부호를 처리한다", () => {
|
|
37
|
-
expect(parseInt("가-123나")).toBe(-123);
|
|
38
|
-
expect(parseInt("abc-456def")).toBe(-456);
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it("빈 문자열이면 undefined를 반환한다", () => {
|
|
42
|
-
expect(parseInt("")).toBe(undefined);
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it("숫자가 없는 문자열이면 undefined를 반환한다", () => {
|
|
46
|
-
expect(parseInt("abc")).toBe(undefined);
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it("string이 아닌 타입이면 undefined를 반환한다", () => {
|
|
50
|
-
expect(parseInt(null)).toBe(undefined);
|
|
51
|
-
expect(parseInt(undefined)).toBe(undefined);
|
|
52
|
-
expect(parseInt({})).toBe(undefined);
|
|
53
|
-
});
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
//#endregion
|
|
57
|
-
|
|
58
|
-
//#region numParseRoundedInt
|
|
59
|
-
|
|
60
|
-
describe("numParseRoundedInt()", () => {
|
|
61
|
-
it("실수 문자열을 반올림하여 정수로 반환한다", () => {
|
|
62
|
-
expect(parseRoundedInt("123.5")).toBe(124);
|
|
63
|
-
expect(parseRoundedInt("123.4")).toBe(123);
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
it("정수 문자열은 그대로 반환한다", () => {
|
|
67
|
-
expect(parseRoundedInt("123")).toBe(123);
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
it("숫자 타입을 반올림하여 반환한다", () => {
|
|
71
|
-
expect(parseRoundedInt(123.7)).toBe(124);
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
it("파싱 불가능하면 undefined를 반환한다", () => {
|
|
75
|
-
expect(parseRoundedInt("abc")).toBe(undefined);
|
|
76
|
-
});
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
//#endregion
|
|
80
|
-
|
|
81
|
-
//#region numParseFloat
|
|
82
|
-
|
|
83
|
-
describe("numParseFloat()", () => {
|
|
84
|
-
it("실수 문자열을 파싱한다", () => {
|
|
85
|
-
expect(parseFloat("123.45")).toBe(123.45);
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
it("정수 문자열을 실수로 파싱한다", () => {
|
|
89
|
-
expect(parseFloat("123")).toBe(123);
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
it("음수 실수 문자열을 파싱한다", () => {
|
|
93
|
-
expect(parseFloat("-123.45")).toBe(-123.45);
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
it("숫자 타입이면 그대로 반환한다", () => {
|
|
97
|
-
expect(parseFloat(123.45)).toBe(123.45);
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
it("비숫자 문자를 제거 후 파싱한다", () => {
|
|
101
|
-
expect(parseFloat("$1,234.56")).toBe(1234.56);
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
it("빈 문자열이면 undefined를 반환한다", () => {
|
|
105
|
-
expect(parseFloat("")).toBe(undefined);
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
it("숫자가 없는 문자열이면 undefined를 반환한다", () => {
|
|
109
|
-
expect(parseFloat("abc")).toBe(undefined);
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
it("string이 아닌 타입이면 undefined를 반환한다", () => {
|
|
113
|
-
expect(parseFloat(null)).toBe(undefined);
|
|
114
|
-
expect(parseFloat(undefined)).toBe(undefined);
|
|
115
|
-
});
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
//#endregion
|
|
119
|
-
|
|
120
|
-
//#region numIsNullOrEmpty
|
|
121
|
-
|
|
122
|
-
describe("numIsNullOrEmpty()", () => {
|
|
123
|
-
it("undefined이면 true를 반환한다", () => {
|
|
124
|
-
expect(isNullOrEmpty(undefined)).toBe(true);
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
it("0이면 true를 반환한다", () => {
|
|
128
|
-
expect(isNullOrEmpty(0)).toBe(true);
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
it("양수이면 false를 반환한다", () => {
|
|
132
|
-
expect(isNullOrEmpty(123)).toBe(false);
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
it("음수이면 false를 반환한다", () => {
|
|
136
|
-
expect(isNullOrEmpty(-123)).toBe(false);
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
it("실수이면 false를 반환한다", () => {
|
|
140
|
-
expect(isNullOrEmpty(0.1)).toBe(false);
|
|
141
|
-
});
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
//#endregion
|
|
145
|
-
|
|
146
|
-
//#region numFormat
|
|
147
|
-
|
|
148
|
-
describe("numFormat()", () => {
|
|
149
|
-
it("천단위 구분자를 적용한다", () => {
|
|
150
|
-
expect(format(1234567)).toBe("1,234,567");
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
it("실수에 천단위 구분자를 적용한다", () => {
|
|
154
|
-
const result = format(1234567.89);
|
|
155
|
-
expect(result).toContain("1,234,567");
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
it("최대 소수점 자릿수를 지정한다", () => {
|
|
159
|
-
expect(format(123.456, { max: 2 })).toBe("123.46");
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
it("최소 소수점 자릿수를 지정한다", () => {
|
|
163
|
-
expect(format(123, { min: 2 })).toBe("123.00");
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
it("최대/최소 소수점 자릿수를 함께 지정한다", () => {
|
|
167
|
-
expect(format(123.4, { max: 3, min: 2 })).toBe("123.40");
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
it("undefined이면 undefined를 반환한다", () => {
|
|
171
|
-
expect(format(undefined)).toBe(undefined);
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
it("0을 포맷팅한다", () => {
|
|
175
|
-
expect(format(0)).toBe("0");
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
it("음수를 포맷팅한다", () => {
|
|
179
|
-
expect(format(-1234567)).toBe("-1,234,567");
|
|
180
|
-
});
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
//#endregion
|
|
184
|
-
});
|