@simplysm/core-common 13.0.74 → 13.0.76

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.
@@ -193,123 +193,8 @@ describe("Time", () => {
193
193
 
194
194
  //#endregion
195
195
 
196
- //#region Getters
197
-
198
- describe("Getters", () => {
199
- it("Returns hour", () => {
200
- const time = new Time(15, 30, 45, 123);
201
- expect(time.hour).toBe(15);
202
- });
203
-
204
- it("Returns minute", () => {
205
- const time = new Time(15, 30, 45, 123);
206
- expect(time.minute).toBe(30);
207
- });
208
-
209
- it("Returns second", () => {
210
- const time = new Time(15, 30, 45, 123);
211
- expect(time.second).toBe(45);
212
- });
213
-
214
- it("Returns millisecond", () => {
215
- const time = new Time(15, 30, 45, 123);
216
- expect(time.millisecond).toBe(123);
217
- });
218
-
219
- it("Returns tick", () => {
220
- const time = new Time(15, 30, 45, 123);
221
- const expectedTick = (15 * 60 * 60 + 30 * 60 + 45) * 1000 + 123;
222
- expect(time.tick).toBe(expectedTick);
223
- });
224
- });
225
-
226
- //#endregion
227
-
228
- //#region tick comparison
229
-
230
- describe("tick comparison", () => {
231
- it("Same times have same tick", () => {
232
- const t1 = new Time(10, 30, 45, 123);
233
- const t2 = new Time(10, 30, 45, 123);
234
-
235
- expect(t1.tick).toBe(t2.tick);
236
- });
237
-
238
- it("Different times have different ticks", () => {
239
- const t1 = new Time(10, 30, 45, 123);
240
- const t2 = new Time(10, 30, 45, 124);
241
-
242
- expect(t1.tick).not.toBe(t2.tick);
243
- });
244
-
245
- it("Can compare time order by tick", () => {
246
- const t1 = new Time(0, 0, 0);
247
- const t2 = new Time(12, 30, 0);
248
- const t3 = new Time(23, 59, 59);
249
-
250
- expect(t1.tick).toBeLessThan(t2.tick);
251
- expect(t2.tick).toBeLessThan(t3.tick);
252
- });
253
-
254
- it("Millisecond precision comparison is possible", () => {
255
- const t1 = new Time(10, 30, 45, 0);
256
- const t2 = new Time(10, 30, 45, 1);
257
-
258
- expect(t2.tick - t1.tick).toBe(1);
259
- });
260
-
261
- it("Can calculate time difference by tick", () => {
262
- const t1 = new Time(10, 0, 0);
263
- const t2 = new Time(11, 0, 0);
264
-
265
- // 1 hour = 3600000ms
266
- expect(t2.tick - t1.tick).toBe(3600000);
267
- });
268
- });
269
-
270
- //#endregion
271
-
272
196
  //#region setX methods (immutable)
273
197
 
274
- describe("setHour()", () => {
275
- it("Returns new instance with hour changed", () => {
276
- const time = new Time(15, 30, 45, 123);
277
- const newTime = time.setHour(20);
278
-
279
- expect(newTime.hour).toBe(20);
280
- expect(newTime.minute).toBe(30);
281
- expect(newTime.second).toBe(45);
282
- expect(newTime.millisecond).toBe(123);
283
- expect(time.hour).toBe(15); // original immutable
284
- });
285
- });
286
-
287
- describe("setMinute()", () => {
288
- it("Returns new instance with minute changed", () => {
289
- const time = new Time(15, 30, 45, 123);
290
- const newTime = time.setMinute(50);
291
-
292
- expect(newTime.hour).toBe(15);
293
- expect(newTime.minute).toBe(50);
294
- expect(newTime.second).toBe(45);
295
- expect(newTime.millisecond).toBe(123);
296
- expect(time.minute).toBe(30); // original immutable
297
- });
298
- });
299
-
300
- describe("setSecond()", () => {
301
- it("Returns new instance with second changed", () => {
302
- const time = new Time(15, 30, 45, 123);
303
- const newTime = time.setSecond(55);
304
-
305
- expect(newTime.hour).toBe(15);
306
- expect(newTime.minute).toBe(30);
307
- expect(newTime.second).toBe(55);
308
- expect(newTime.millisecond).toBe(123);
309
- expect(time.second).toBe(45); // original immutable
310
- });
311
- });
312
-
313
198
  describe("setMillisecond()", () => {
314
199
  it("Returns new instance with millisecond changed", () => {
315
200
  const time = new Time(15, 30, 45, 123);
@@ -495,22 +380,6 @@ describe("Time", () => {
495
380
  //#region isValid
496
381
 
497
382
  describe("isValid", () => {
498
- it("Valid time returns true", () => {
499
- const time = new Time(15, 30, 45);
500
- expect(time.isValid).toBe(true);
501
- });
502
-
503
- it("Default constructor is valid time", () => {
504
- const time = new Time();
505
- expect(time.isValid).toBe(true);
506
- });
507
-
508
- it("Time created with tick is valid", () => {
509
- const tick = (15 * 60 * 60 + 30 * 60 + 45) * 1000;
510
- const time = new Time(tick);
511
- expect(time.isValid).toBe(true);
512
- });
513
-
514
383
  it("Time created with NaN tick has isValid false", () => {
515
384
  const time = new Time(NaN);
516
385
  expect(time.isValid).toBe(false);
@@ -29,14 +29,6 @@ describe("BytesUtils", () => {
29
29
  expect(result.length).toBe(0);
30
30
  });
31
31
 
32
- it("Handles single array", () => {
33
- const arr = new Uint8Array([1, 2, 3]);
34
-
35
- const result = concat([arr]);
36
-
37
- expect(result).toEqual(new Uint8Array([1, 2, 3]));
38
- });
39
-
40
32
  it("Handles empty Uint8Array in array", () => {
41
33
  const arr1 = new Uint8Array([1, 2]);
42
34
  const arr2 = new Uint8Array([]);
@@ -106,15 +98,6 @@ describe("BytesUtils", () => {
106
98
  });
107
99
 
108
100
  describe("toHex/fromHex round-trip conversion", () => {
109
- it("Round-trip conversion matches", () => {
110
- const original = new Uint8Array([0, 127, 128, 255, 1, 2, 3]);
111
-
112
- const hex = toHex(original);
113
- const restored = fromHex(hex);
114
-
115
- expect(restored).toEqual(original);
116
- });
117
-
118
101
  it("Round-trip conversion matches all byte values (0-255)", () => {
119
102
  const original = new Uint8Array(256);
120
103
  for (let i = 0; i < 256; i++) {
@@ -190,15 +173,6 @@ describe("BytesUtils", () => {
190
173
  });
191
174
 
192
175
  describe("toBase64/fromBase64 round-trip conversion", () => {
193
- it("Round-trip conversion matches", () => {
194
- const original = new Uint8Array([0, 127, 128, 255, 1, 2, 3]);
195
-
196
- const base64 = toBase64(original);
197
- const restored = fromBase64(base64);
198
-
199
- expect(restored).toEqual(original);
200
- });
201
-
202
176
  it("Round-trip conversion matches all byte values (0-255)", () => {
203
177
  const original = new Uint8Array(256);
204
178
  for (let i = 0; i < 256; i++) {
@@ -228,14 +228,6 @@ describe("formatDateTime", () => {
228
228
  it("outputs +00:00 with zzz format", () => {
229
229
  expect(formatDate("zzz", { timezoneOffsetMinutes: 0 })).toBe("+00:00");
230
230
  });
231
-
232
- it("outputs +00 with zz format", () => {
233
- expect(formatDate("zz", { timezoneOffsetMinutes: 0 })).toBe("+00");
234
- });
235
-
236
- it("outputs +0 with z format", () => {
237
- expect(formatDate("z", { timezoneOffsetMinutes: 0 })).toBe("+0");
238
- });
239
231
  });
240
232
  });
241
233
 
@@ -308,17 +300,9 @@ describe("normalizeMonth", () => {
308
300
  expect(normalizeMonth(2025, 13, 15)).toEqual({ year: 2026, month: 1, day: 15 });
309
301
  });
310
302
 
311
- it("month 14 becomes February next year", () => {
312
- expect(normalizeMonth(2025, 14, 15)).toEqual({ year: 2026, month: 2, day: 15 });
313
- });
314
-
315
303
  it("month 25 becomes January 2 years later", () => {
316
304
  expect(normalizeMonth(2025, 25, 15)).toEqual({ year: 2027, month: 1, day: 15 });
317
305
  });
318
-
319
- it("month 24 becomes December next year", () => {
320
- expect(normalizeMonth(2025, 24, 15)).toEqual({ year: 2026, month: 12, day: 15 });
321
- });
322
306
  });
323
307
 
324
308
  //#endregion
@@ -334,14 +318,6 @@ describe("normalizeMonth", () => {
334
318
  expect(normalizeMonth(2025, -1, 15)).toEqual({ year: 2024, month: 11, day: 15 });
335
319
  });
336
320
 
337
- it("month -11 becomes January previous year", () => {
338
- expect(normalizeMonth(2025, -11, 15)).toEqual({ year: 2024, month: 1, day: 15 });
339
- });
340
-
341
- it("month -12 becomes December 2 years ago", () => {
342
- expect(normalizeMonth(2025, -12, 15)).toEqual({ year: 2023, month: 12, day: 15 });
343
- });
344
-
345
321
  it("month -13 becomes November 2 years ago", () => {
346
322
  expect(normalizeMonth(2025, -13, 15)).toEqual({ year: 2023, month: 11, day: 15 });
347
323
  });
@@ -204,15 +204,6 @@ describe("DebounceQueue", () => {
204
204
  expect(calls).toEqual([]);
205
205
  });
206
206
 
207
- it("Safe to call multiple times", () => {
208
- const queue = new DebounceQueue(50);
209
-
210
- // Multiple calls without error
211
- queue.dispose();
212
- queue.dispose();
213
- queue.dispose();
214
- });
215
-
216
207
  it("Auto-disposed with using statement", async () => {
217
208
  const calls: number[] = [];
218
209
  {
@@ -230,43 +221,4 @@ describe("DebounceQueue", () => {
230
221
 
231
222
  //#endregion
232
223
 
233
- //#region Synchronous function support
234
-
235
- describe("Synchronous function support", () => {
236
- it("Can execute synchronous function", async () => {
237
- const queue = new DebounceQueue(10);
238
- const calls: number[] = [];
239
-
240
- queue.run(() => {
241
- calls.push(1);
242
- });
243
-
244
- await time(50);
245
-
246
- expect(calls).toEqual([1]);
247
- });
248
-
249
- it("Can mix synchronous and asynchronous functions", async () => {
250
- const queue = new DebounceQueue(10);
251
- const calls: number[] = [];
252
-
253
- queue.run(() => {
254
- calls.push(1);
255
- });
256
- queue.run(async () => {
257
- await time(10);
258
- calls.push(2);
259
- });
260
- queue.run(() => {
261
- calls.push(3);
262
- });
263
-
264
- await time(100);
265
-
266
- // Only last request executed
267
- expect(calls).toEqual([3]);
268
- });
269
- });
270
-
271
- //#endregion
272
224
  });
@@ -12,13 +12,6 @@ describe("JsonConvert", () => {
12
12
  //#region stringify
13
13
 
14
14
  describe("stringify()", () => {
15
- it("Serializes primitive values", () => {
16
- expect(stringify(42)).toBe("42");
17
- expect(stringify("hello")).toBe('"hello"');
18
- expect(stringify(true)).toBe("true");
19
- expect(stringify(null)).toBe("null");
20
- });
21
-
22
15
  it("Serializes Date with __type__", () => {
23
16
  const date = new Date("2024-03-15T10:30:00.000Z");
24
17
  const json = stringify(date);
@@ -122,13 +115,6 @@ describe("JsonConvert", () => {
122
115
  expect(parsed.data.data).toBe("__hidden__");
123
116
  });
124
117
 
125
- it("Indents with space option", () => {
126
- const obj = { a: 1 };
127
- const json = stringify(obj, { space: 2 });
128
-
129
- expect(json).toBe('{\n "a": 1\n}');
130
- });
131
-
132
118
  it("Transforms values with replacer option", () => {
133
119
  const obj = { a: 1, b: 2, c: 3 };
134
120
  const json = stringify(obj, {
@@ -250,65 +236,6 @@ describe("JsonConvert", () => {
250
236
  expect(parsed.converted).toBe(true);
251
237
  expect(parsed.date.__type__).toBe("Date");
252
238
  });
253
-
254
- it("Serializes getter properties", () => {
255
- const obj = {
256
- _value: 10,
257
- get computed() {
258
- return this._value * 2;
259
- },
260
- };
261
-
262
- const json = stringify(obj);
263
- const parsed = JSON.parse(json);
264
-
265
- expect(parsed._value).toBe(10);
266
- expect(parsed.computed).toBe(20);
267
- });
268
-
269
- it("Serializes empty objects and arrays", () => {
270
- expect(stringify({})).toBe("{}");
271
- expect(stringify([])).toBe("[]");
272
- expect(stringify({ arr: [], obj: {} })).toBe('{"arr":[],"obj":{}}');
273
- });
274
-
275
- it("Excludes properties with undefined value", () => {
276
- const obj = { a: 1, b: undefined, c: 3 };
277
- const json = stringify(obj);
278
- const parsed = JSON.parse(json);
279
-
280
- expect(parsed.a).toBe(1);
281
- expect("b" in parsed).toBe(false);
282
- expect(parsed.c).toBe(3);
283
- });
284
-
285
- it("Performance completes in reasonable time", () => {
286
- // Create complex test object
287
- const createTestObject = () => ({
288
- id: 1,
289
- name: "test",
290
- date: new Date(),
291
- nested: {
292
- array: [1, 2, 3, new Date(), { deep: true }],
293
- map: new Map([["a", 1]]),
294
- set: new Set([1, 2, 3]),
295
- },
296
- });
297
-
298
- const iterations = 1000;
299
- const testObj = createTestObject();
300
-
301
- // Measure jsonStringify performance
302
- const startCustom = performance.now();
303
- for (let i = 0; i < iterations; i++) {
304
- stringify(testObj);
305
- }
306
- const customTime = performance.now() - startCustom;
307
-
308
- // 1000 serializations should complete within 100ms
309
- // (includes custom type handling, circular reference detection, etc)
310
- expect(customTime).toBeLessThan(100);
311
- });
312
239
  });
313
240
 
314
241
  //#endregion
@@ -316,12 +243,6 @@ describe("JsonConvert", () => {
316
243
  //#region parse
317
244
 
318
245
  describe("parse()", () => {
319
- it("Deserializes primitive values", () => {
320
- expect(parse("42")).toBe(42);
321
- expect(parse('"hello"')).toBe("hello");
322
- expect(parse("true")).toBe(true);
323
- });
324
-
325
246
  it("Converts null to undefined", () => {
326
247
  expect(parse("null")).toBe(undefined);
327
248
  });
@@ -10,10 +10,6 @@ describe("number utils", () => {
10
10
  //#region numParseInt
11
11
 
12
12
  describe("numParseInt()", () => {
13
- it("Parses numeric string to integer", () => {
14
- expect(parseInt("123")).toBe(123);
15
- });
16
-
17
13
  it("Parses negative string", () => {
18
14
  expect(parseInt("-123")).toBe(-123);
19
15
  });
@@ -62,10 +58,6 @@ describe("number utils", () => {
62
58
  expect(parseRoundedInt("123.4")).toBe(123);
63
59
  });
64
60
 
65
- it("Integer string returned as-is", () => {
66
- expect(parseRoundedInt("123")).toBe(123);
67
- });
68
-
69
61
  it("Rounds number type", () => {
70
62
  expect(parseRoundedInt(123.7)).toBe(124);
71
63
  });
@@ -80,14 +72,6 @@ describe("number utils", () => {
80
72
  //#region numParseFloat
81
73
 
82
74
  describe("numParseFloat()", () => {
83
- it("Parses floating string", () => {
84
- expect(parseFloat("123.45")).toBe(123.45);
85
- });
86
-
87
- it("Parses integer string as float", () => {
88
- expect(parseFloat("123")).toBe(123);
89
- });
90
-
91
75
  it("Parses negative floating string", () => {
92
76
  expect(parseFloat("-123.45")).toBe(-123.45);
93
77
  });
@@ -19,10 +19,6 @@ describe("path utils", () => {
19
19
  expect(pathJoin("a", "", "b")).toBe("a/b");
20
20
  });
21
21
 
22
- it("Returns single segment", () => {
23
- expect(pathJoin("a")).toBe("a");
24
- });
25
-
26
22
  it("Empty input returns empty string", () => {
27
23
  expect(pathJoin()).toBe("");
28
24
  });
@@ -44,10 +40,6 @@ describe("path utils", () => {
44
40
  it("Handles filename without path", () => {
45
41
  expect(pathBasename("file.txt")).toBe("file.txt");
46
42
  });
47
-
48
- it("Empty string returns empty string", () => {
49
- expect(pathBasename("")).toBe("");
50
- });
51
43
  });
52
44
 
53
45
  describe("pathExtname()", () => {
@@ -38,26 +38,6 @@ describe("SdEventEmitter", () => {
38
38
  expect(listener).toHaveBeenNthCalledWith(3, 3);
39
39
  });
40
40
 
41
- it("Passes object data", () => {
42
- const emitter = new EventEmitter<TestEvents>();
43
- const listener = vi.fn();
44
-
45
- emitter.on("data", listener);
46
- emitter.emit("data", { id: 1, name: "test" });
47
-
48
- expect(listener).toHaveBeenCalledWith({ id: 1, name: "test" });
49
- });
50
-
51
- it("Handles void event", () => {
52
- const emitter = new EventEmitter<TestEvents>();
53
- const listener = vi.fn();
54
-
55
- emitter.on("empty", listener);
56
- emitter.emit("empty");
57
-
58
- expect(listener).toHaveBeenCalledTimes(1);
59
- });
60
-
61
41
  it("Can register multiple listeners for same event", () => {
62
42
  const emitter = new EventEmitter<TestEvents>();
63
43
  const listener1 = vi.fn();
@@ -141,13 +121,6 @@ describe("SdEventEmitter", () => {
141
121
  expect(emitter.listenerCount("message")).toBe(0);
142
122
  });
143
123
 
144
- it("Unregistered event type has 0 count", () => {
145
- const emitter = new EventEmitter<TestEvents>();
146
-
147
- expect(emitter.listenerCount("message")).toBe(0);
148
- expect(emitter.listenerCount("count")).toBe(0);
149
- });
150
-
151
124
  it("Different event types have independent counts", () => {
152
125
  const emitter = new EventEmitter<TestEvents>();
153
126
 
@@ -119,41 +119,6 @@ describe("SerialQueue", () => {
119
119
  expect(timestamps[1] - timestamps[0]).toBe(0);
120
120
  });
121
121
 
122
- it("Default gap is 0", async () => {
123
- const queue = new SerialQueue();
124
- const timestamps: number[] = [];
125
-
126
- queue.run(() => {
127
- timestamps.push(Date.now());
128
- });
129
- queue.run(() => {
130
- timestamps.push(Date.now());
131
- });
132
-
133
- await vi.advanceTimersByTimeAsync(50);
134
-
135
- expect(timestamps).toHaveLength(2);
136
- expect(timestamps[1] - timestamps[0]).toBe(0);
137
- });
138
-
139
- it("Does not wait gap after the last task", async () => {
140
- const queue = new SerialQueue(100);
141
- const timestamps: number[] = [];
142
-
143
- queue.run(() => {
144
- timestamps.push(Date.now());
145
- });
146
- queue.run(() => {
147
- timestamps.push(Date.now());
148
- });
149
-
150
- // Wait long enough (task1 + gap100 + task2)
151
- await vi.advanceTimersByTimeAsync(200);
152
-
153
- // Verify gap was applied (exactly 100ms)
154
- expect(timestamps).toHaveLength(2);
155
- expect(timestamps[1] - timestamps[0]).toBe(100);
156
- });
157
122
  });
158
123
 
159
124
  //#endregion
@@ -291,15 +256,6 @@ describe("SerialQueue", () => {
291
256
  expect(calls).toContain(2);
292
257
  });
293
258
 
294
- it("Safe to call multiple times", () => {
295
- const queue = new SerialQueue();
296
-
297
- // Multiple calls without error
298
- queue.dispose();
299
- queue.dispose();
300
- queue.dispose();
301
- });
302
-
303
259
  it("Automatically disposes with using statement", async () => {
304
260
  const calls: number[] = [];
305
261
  {
@@ -324,22 +280,6 @@ describe("SerialQueue", () => {
324
280
  //#region Synchronous function support
325
281
 
326
282
  describe("Synchronous function support", () => {
327
- it("Can execute synchronous functions", async () => {
328
- const queue = new SerialQueue();
329
- const calls: number[] = [];
330
-
331
- queue.run(() => {
332
- calls.push(1);
333
- });
334
- queue.run(() => {
335
- calls.push(2);
336
- });
337
-
338
- await vi.advanceTimersByTimeAsync(50);
339
-
340
- expect(calls).toEqual([1, 2]);
341
- });
342
-
343
283
  it("Can mix synchronous and asynchronous functions", async () => {
344
284
  const queue = new SerialQueue();
345
285
  const calls: number[] = [];
@@ -264,17 +264,9 @@ describe("string utils", () => {
264
264
  expect(strInsert("world", 0, "hello ")).toBe("hello world");
265
265
  });
266
266
 
267
- it("inserts in middle of string", () => {
268
- expect(strInsert("helloworld", 5, " ")).toBe("hello world");
269
- });
270
-
271
267
  it("inserts at end of string", () => {
272
268
  expect(strInsert("hello", 5, " world")).toBe("hello world");
273
269
  });
274
-
275
- it("inserts into empty string", () => {
276
- expect(strInsert("", 0, "hello")).toBe("hello");
277
- });
278
270
  });
279
271
 
280
272
  //#endregion
@@ -39,19 +39,10 @@ describe("template-strings", () => {
39
39
  expect(js`x = ${value}`).toBe("x = ");
40
40
  });
41
41
 
42
- it("Handles number value", () => {
43
- expect(js`x = ${42}`).toBe("x = 42");
44
- });
45
-
46
42
  it("Interpolates multiple values", () => {
47
43
  const a = 1;
48
44
  const b = 2;
49
45
  expect(js`${a} + ${b} = ${a + b}`).toBe("1 + 2 = 3");
50
46
  });
51
-
52
- it("Handles object value", () => {
53
- const obj = { toString: () => "custom" };
54
- expect(js`value = ${obj}`).toBe("value = custom");
55
- });
56
47
  });
57
48
  });