assertie 0.3.2 → 1.0.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/CHANGELOG.md +24 -1
- package/MIGRATION-GUIDE.md +13 -0
- package/README.md +18 -6
- package/lib/assert-helpers.d.ts +20 -0
- package/lib/assert-helpers.js +66 -0
- package/lib/index.d.ts +49 -56
- package/lib/index.js +56 -117
- package/lib/types.d.ts +29 -0
- package/lib/types.js +1 -0
- package/package.json +9 -4
- package/src/assert-helpers.ts +63 -0
- package/src/index.ts +146 -143
- package/src/types.ts +39 -0
- package/test/runtime/assert-helpers.test.ts +583 -0
- package/test/runtime/asserts.test.ts +641 -0
- package/test/runtime/main.ts +6 -0
- package/test/runtime/testing.ts +168 -0
- package/test/runtime/tsconfig.json +18 -0
- package/test/types/readonly.5+.test.ts +44 -0
- package/test/types/readonly.test.ts +238 -0
- package/test/types/run.ts +29 -0
- package/test/types/tsconfig.4.x.json +7 -0
- package/test/types/tsconfig.json +18 -0
- package/test/types/type-narrowing.5+.test.ts +32 -0
- package/test/types/type-narrowing.test.ts +654 -0
- package/tsconfig.json +1 -0
|
@@ -0,0 +1,641 @@
|
|
|
1
|
+
import { group, test, mustThrow, mustNotThrow } from "./testing";
|
|
2
|
+
import {
|
|
3
|
+
assert,
|
|
4
|
+
assertType,
|
|
5
|
+
assertArrayType,
|
|
6
|
+
assertTupleTypes,
|
|
7
|
+
assertTypeOfString,
|
|
8
|
+
assertTypeOfNumber,
|
|
9
|
+
assertTypeOfBoolean,
|
|
10
|
+
assertTypeOfBigint,
|
|
11
|
+
assertTypeOfUndefined,
|
|
12
|
+
assertTypeOfFunction,
|
|
13
|
+
assertTypeOfObject,
|
|
14
|
+
assertTypeOfSymbol,
|
|
15
|
+
assertNull,
|
|
16
|
+
assertInstanceOf,
|
|
17
|
+
assertIsTuple,
|
|
18
|
+
assertUnreachable,
|
|
19
|
+
assertNonNullable,
|
|
20
|
+
assertPropsNonNullable,
|
|
21
|
+
assertArrayNonNullable,
|
|
22
|
+
assertTupleNonNullable,
|
|
23
|
+
assertFiniteNumber,
|
|
24
|
+
} from "../../src/index";
|
|
25
|
+
|
|
26
|
+
group("assert", () => {
|
|
27
|
+
group("should not throw", () => {
|
|
28
|
+
test("when condition is true", () => {
|
|
29
|
+
mustNotThrow(() => assert(true));
|
|
30
|
+
mustNotThrow(() => assert(1 === 1));
|
|
31
|
+
mustNotThrow(() => assert(Boolean(1)));
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
group("should throw", () => {
|
|
36
|
+
test("when condition is false", () => {
|
|
37
|
+
mustThrow(() => assert(false));
|
|
38
|
+
// @ts-expect-error: TypeScript would not allow 1 === 2
|
|
39
|
+
mustThrow(() => assert(1 === 2));
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test("with custom message", () => {
|
|
43
|
+
mustThrow(() => assert(false, "custom message"), /custom message/);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
group("assertType", () => {
|
|
49
|
+
group("with primitive type strings", () => {
|
|
50
|
+
group("should not throw", () => {
|
|
51
|
+
test('for "string" with string value', () => {
|
|
52
|
+
mustNotThrow(() => assertType("hello", "string"));
|
|
53
|
+
mustNotThrow(() => assertType("", "string"));
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test('for "number" with number value', () => {
|
|
57
|
+
mustNotThrow(() => assertType(42, "number"));
|
|
58
|
+
mustNotThrow(() => assertType(0, "number"));
|
|
59
|
+
mustNotThrow(() => assertType(-1, "number"));
|
|
60
|
+
mustNotThrow(() => assertType(NaN, "number"));
|
|
61
|
+
mustNotThrow(() => assertType(Infinity, "number"));
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test('for "boolean" with boolean value', () => {
|
|
65
|
+
mustNotThrow(() => assertType(true, "boolean"));
|
|
66
|
+
mustNotThrow(() => assertType(false, "boolean"));
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test('for "bigint" with bigint value', () => {
|
|
70
|
+
mustNotThrow(() => assertType(123n, "bigint"));
|
|
71
|
+
mustNotThrow(() => assertType(0n, "bigint"));
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test('for "undefined" with undefined value', () => {
|
|
75
|
+
mustNotThrow(() => assertType(undefined, "undefined"));
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test('for "function" with function value', () => {
|
|
79
|
+
mustNotThrow(() => assertType(() => {}, "function"));
|
|
80
|
+
mustNotThrow(() => assertType(function () {}, "function"));
|
|
81
|
+
mustNotThrow(() => assertType(Date, "function"));
|
|
82
|
+
mustNotThrow(() => assertType(class {}, "function"));
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test('for "object" with object value', () => {
|
|
86
|
+
mustNotThrow(() => assertType({}, "object"));
|
|
87
|
+
mustNotThrow(() => assertType([], "object"));
|
|
88
|
+
mustNotThrow(() => assertType(new Date(), "object"));
|
|
89
|
+
mustNotThrow(() => assertType(null, "object"));
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
test('for "symbol" with symbol value', () => {
|
|
93
|
+
mustNotThrow(() => assertType(Symbol("test"), "symbol"));
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
group("should throw", () => {
|
|
98
|
+
test('for "string" with non-string value', () => {
|
|
99
|
+
mustThrow(() => assertType(new String("test"), "string"));
|
|
100
|
+
mustThrow(() => assertType(42, "string"));
|
|
101
|
+
mustThrow(() => assertType(null, "string"));
|
|
102
|
+
mustThrow(() => assertType(undefined, "string"));
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test('for "number" with non-number value', () => {
|
|
106
|
+
mustThrow(() => assertType(new Number(42), "number"));
|
|
107
|
+
mustThrow(() => assertType("42", "number"));
|
|
108
|
+
mustThrow(() => assertType(42n, "number"));
|
|
109
|
+
mustThrow(() => assertType(undefined, "number"));
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test('for "boolean" with non-boolean value', () => {
|
|
113
|
+
mustThrow(() => assertType(new Boolean(true), "boolean"));
|
|
114
|
+
mustThrow(() => assertType(1, "boolean"));
|
|
115
|
+
mustThrow(() => assertType("true", "boolean"));
|
|
116
|
+
mustThrow(() => assertType(undefined, "boolean"));
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
test('for "bigint" with non-bigint value', () => {
|
|
120
|
+
mustThrow(() => assertType(123, "bigint"));
|
|
121
|
+
mustThrow(() => assertType(undefined, "bigint"));
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
test('for "function" with non-function value', () => {
|
|
125
|
+
mustThrow(() => assertType({}, "function"));
|
|
126
|
+
mustThrow(() => assertType(undefined, "function"));
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
group("with null and undefined", () => {
|
|
132
|
+
test("should not throw for null with null", () => {
|
|
133
|
+
mustNotThrow(() => assertType(null, null));
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
test("should throw for non-null with null", () => {
|
|
137
|
+
mustThrow(() => assertType("null", null));
|
|
138
|
+
mustThrow(() => assertType(NaN, null));
|
|
139
|
+
mustThrow(() => assertType(undefined, null));
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
test("should not throw for undefined with undefined", () => {
|
|
143
|
+
mustNotThrow(() => assertType(undefined, undefined));
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
test("should throw for non-undefined with undefined", () => {
|
|
147
|
+
mustThrow(() => assertType(null, undefined));
|
|
148
|
+
mustThrow(() => assertType(NaN, undefined));
|
|
149
|
+
mustThrow(() => assertType("undefined", undefined));
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
group("with constructors", () => {
|
|
154
|
+
test("should not throw for instance of class", () => {
|
|
155
|
+
mustNotThrow(() => assertType(new Date(), Date));
|
|
156
|
+
mustNotThrow(() => assertType(new Error(), Error));
|
|
157
|
+
mustNotThrow(() => assertType([], Array));
|
|
158
|
+
mustNotThrow(() => assertType({}, Object));
|
|
159
|
+
mustNotThrow(() => assertType(/test/, RegExp));
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
test("should throw for non-instance", () => {
|
|
163
|
+
mustThrow(() => assertType({}, Date));
|
|
164
|
+
mustThrow(() => assertType("2026-01-01", Date));
|
|
165
|
+
mustThrow(() => assertType(null, Object));
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
test("should work with custom classes", () => {
|
|
169
|
+
class CustomClass {}
|
|
170
|
+
mustNotThrow(() => assertType(new CustomClass(), CustomClass));
|
|
171
|
+
mustThrow(() => assertType({}, CustomClass));
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
test("should handle inheritance", () => {
|
|
175
|
+
class Parent {}
|
|
176
|
+
class Child extends Parent {}
|
|
177
|
+
const child = new Child();
|
|
178
|
+
mustNotThrow(() => assertType(child, Parent));
|
|
179
|
+
mustNotThrow(() => assertType(child, Child));
|
|
180
|
+
const parent = new Parent();
|
|
181
|
+
mustNotThrow(() => assertType(parent, Parent));
|
|
182
|
+
mustThrow(() => assertType(parent, Child));
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
group("assertArrayType", () => {
|
|
188
|
+
group("should not throw", () => {
|
|
189
|
+
test("for array of strings", () => {
|
|
190
|
+
mustNotThrow(() => assertArrayType([""], "string"));
|
|
191
|
+
mustNotThrow(() => assertArrayType(["a", "b", "c"], "string"));
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
test("for array of numbers", () => {
|
|
195
|
+
mustNotThrow(() => assertArrayType([1, 2, 3], "number"));
|
|
196
|
+
mustNotThrow(() => assertArrayType([0, -1, NaN, Infinity], "number"));
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
test("for empty array", () => {
|
|
200
|
+
mustNotThrow(() => assertArrayType([], "string"));
|
|
201
|
+
mustNotThrow(() => assertArrayType([], "number"));
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
test("for array of class instances", () => {
|
|
205
|
+
mustNotThrow(() => assertArrayType([new Date(), new Date()], Date));
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
test("for array of null", () => {
|
|
209
|
+
mustNotThrow(() => assertArrayType([null, null], null));
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
test("for array of undefined", () => {
|
|
213
|
+
mustNotThrow(() => assertArrayType([undefined, undefined], undefined));
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
group("should throw", () => {
|
|
218
|
+
test("for mixed type array", () => {
|
|
219
|
+
const stringsAndNumbers = [1, "a", 2];
|
|
220
|
+
mustThrow(() => assertArrayType(stringsAndNumbers, "number"));
|
|
221
|
+
mustThrow(() => assertArrayType(stringsAndNumbers, "string"));
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
test("for sparse array", () => {
|
|
225
|
+
const sparse = [1, 2, 3];
|
|
226
|
+
delete sparse[1]; // [1, empty, 3]
|
|
227
|
+
mustThrow(() => assertArrayType(sparse, "number"), /sparse/);
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
test("with an error message specifying the first wrong index", () => {
|
|
231
|
+
mustThrow(() => assertArrayType([1, 2, "oops", 4, "oh"], "number"), /index 2/);
|
|
232
|
+
const sparse = [1, 2, 3];
|
|
233
|
+
delete sparse[1]; // [1, empty, 3]
|
|
234
|
+
mustThrow(() => assertArrayType(sparse, "number"), /index 1/);
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
group("assertTupleTypes", () => {
|
|
240
|
+
group("should not throw", () => {
|
|
241
|
+
test("for matching tuple types", () => {
|
|
242
|
+
mustNotThrow(() => assertTupleTypes(
|
|
243
|
+
[1, 1n, "a", undefined, null, new Date()],
|
|
244
|
+
["number", "bigint", "string", undefined, null, Date]
|
|
245
|
+
));
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
test("for empty tuple", () => {
|
|
249
|
+
mustNotThrow(() => assertTupleTypes([], []));
|
|
250
|
+
});
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
group("should throw", () => {
|
|
254
|
+
test("for length mismatch", () => {
|
|
255
|
+
const oneTuple = [1];
|
|
256
|
+
mustThrow(() => assertTupleTypes(oneTuple, ["number", "number"]), /length mismatch.*?expected 2.*?got 1/);
|
|
257
|
+
const threeTuple = [1, 2, 3];
|
|
258
|
+
mustThrow(() => assertTupleTypes(threeTuple, ["number", "number"]), /length mismatch.*?expected 2.*?got 3/);
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
test("for type mismatch at specific index", () => {
|
|
262
|
+
mustThrow(() => assertTupleTypes([1, 2], ["number", "string"]), /index 1/);
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
test("for sparse tuple", () => {
|
|
266
|
+
const sparseTuple = [1, 2, 3];
|
|
267
|
+
delete sparseTuple[1]; // [1, empty, 3]
|
|
268
|
+
mustThrow(() => assertTupleTypes(sparseTuple, ["number", "number", "number"]), /index 1/);
|
|
269
|
+
// [1, empty, 3] != [1, 3]
|
|
270
|
+
mustThrow(() => assertTupleTypes(sparseTuple, ["number", "number"]), /length mismatch/);
|
|
271
|
+
});
|
|
272
|
+
});
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
group("assertTypeOfString", () => {
|
|
276
|
+
test("should not throw for string", () => {
|
|
277
|
+
mustNotThrow(() => assertTypeOfString("hello"));
|
|
278
|
+
mustNotThrow(() => assertTypeOfString(""));
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
test("should throw for non-string", () => {
|
|
282
|
+
mustThrow(() => assertTypeOfString(new String("hello")));
|
|
283
|
+
mustThrow(() => assertTypeOfString(42));
|
|
284
|
+
mustThrow(() => assertTypeOfString(null));
|
|
285
|
+
mustThrow(() => assertTypeOfString(undefined));
|
|
286
|
+
});
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
group("assertTypeOfNumber", () => {
|
|
290
|
+
test("should not throw for number", () => {
|
|
291
|
+
mustNotThrow(() => assertTypeOfNumber(42));
|
|
292
|
+
mustNotThrow(() => assertTypeOfNumber(0));
|
|
293
|
+
mustNotThrow(() => assertTypeOfNumber(NaN));
|
|
294
|
+
mustNotThrow(() => assertTypeOfNumber(Infinity));
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
test("should throw for non-number", () => {
|
|
298
|
+
mustThrow(() => assertTypeOfNumber(new Number(42)));
|
|
299
|
+
mustThrow(() => assertTypeOfNumber(42n));
|
|
300
|
+
mustThrow(() => assertTypeOfNumber("42"));
|
|
301
|
+
mustThrow(() => assertTypeOfNumber(undefined));
|
|
302
|
+
});
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
group("assertTypeOfBoolean", () => {
|
|
306
|
+
test("should not throw for boolean", () => {
|
|
307
|
+
mustNotThrow(() => assertTypeOfBoolean(true));
|
|
308
|
+
mustNotThrow(() => assertTypeOfBoolean(false));
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
test("should throw for non-boolean", () => {
|
|
312
|
+
mustThrow(() => assertTypeOfBoolean(new Boolean(true)));
|
|
313
|
+
mustThrow(() => assertTypeOfBoolean(1));
|
|
314
|
+
mustThrow(() => assertTypeOfBoolean("true"));
|
|
315
|
+
mustThrow(() => assertTypeOfBoolean(undefined));
|
|
316
|
+
});
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
group("assertTypeOfBigint", () => {
|
|
320
|
+
test("should not throw for bigint", () => {
|
|
321
|
+
mustNotThrow(() => assertTypeOfBigint(123n));
|
|
322
|
+
mustNotThrow(() => assertTypeOfBigint(0n));
|
|
323
|
+
mustNotThrow(() => assertTypeOfBigint(-1n));
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
test("should throw for non-bigint", () => {
|
|
327
|
+
mustThrow(() => assertTypeOfBigint(123));
|
|
328
|
+
mustThrow(() => assertTypeOfBigint("123"));
|
|
329
|
+
mustThrow(() => assertTypeOfBigint(undefined));
|
|
330
|
+
});
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
group("assertTypeOfUndefined", () => {
|
|
334
|
+
test("should not throw for undefined", () => {
|
|
335
|
+
mustNotThrow(() => assertTypeOfUndefined(undefined));
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
test("should throw for non-undefined", () => {
|
|
339
|
+
mustThrow(() => assertTypeOfUndefined(null));
|
|
340
|
+
mustThrow(() => assertTypeOfUndefined("undefined"));
|
|
341
|
+
mustThrow(() => assertTypeOfUndefined(0));
|
|
342
|
+
mustThrow(() => assertTypeOfUndefined(false));
|
|
343
|
+
mustThrow(() => assertTypeOfUndefined(Symbol(undefined)));
|
|
344
|
+
});
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
group("assertTypeOfFunction", () => {
|
|
348
|
+
test("should not throw for function", () => {
|
|
349
|
+
mustNotThrow(() => assertTypeOfFunction(() => {}));
|
|
350
|
+
mustNotThrow(() => assertTypeOfFunction(function () {}));
|
|
351
|
+
mustNotThrow(() => assertTypeOfFunction(class {}));
|
|
352
|
+
mustNotThrow(() => assertTypeOfFunction(Date));
|
|
353
|
+
mustNotThrow(() => assertTypeOfFunction(new Function("return 42")));
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
test("should throw for non-function", () => {
|
|
357
|
+
mustThrow(() => assertTypeOfFunction({}));
|
|
358
|
+
mustThrow(() => assertTypeOfFunction("function"));
|
|
359
|
+
mustThrow(() => assertTypeOfFunction(undefined));
|
|
360
|
+
});
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
group("assertTypeOfObject", () => {
|
|
364
|
+
test("should not throw for object", () => {
|
|
365
|
+
mustNotThrow(() => assertTypeOfObject({}));
|
|
366
|
+
mustNotThrow(() => assertTypeOfObject([]));
|
|
367
|
+
mustNotThrow(() => assertTypeOfObject(new Object()));
|
|
368
|
+
mustNotThrow(() => assertTypeOfObject(new Date()));
|
|
369
|
+
mustNotThrow(() => assertTypeOfObject(null));
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
test("should throw for non-object", () => {
|
|
373
|
+
mustThrow(() => assertTypeOfObject("object"));
|
|
374
|
+
mustThrow(() => assertTypeOfObject(42));
|
|
375
|
+
mustThrow(() => assertTypeOfObject(() => {}));
|
|
376
|
+
mustThrow(() => assertTypeOfObject(new Function("return 42")));
|
|
377
|
+
mustThrow(() => assertTypeOfObject(undefined));
|
|
378
|
+
});
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
group("assertTypeOfSymbol", () => {
|
|
382
|
+
test("should not throw for symbol", () => {
|
|
383
|
+
mustNotThrow(() => assertTypeOfSymbol(Symbol("test")));
|
|
384
|
+
mustNotThrow(() => assertTypeOfSymbol(Symbol.iterator));
|
|
385
|
+
mustNotThrow(() => assertTypeOfSymbol(Symbol(undefined)));
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
test("should throw for non-symbol", () => {
|
|
389
|
+
mustThrow(() => assertTypeOfSymbol(() => Symbol("test")));
|
|
390
|
+
mustThrow(() => assertTypeOfSymbol("symbol"));
|
|
391
|
+
mustThrow(() => assertTypeOfSymbol({}));
|
|
392
|
+
mustThrow(() => assertTypeOfSymbol(undefined));
|
|
393
|
+
});
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
group("assertNull", () => {
|
|
397
|
+
test("should not throw for null", () => {
|
|
398
|
+
mustNotThrow(() => assertNull(null));
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
test("should throw for non-null", () => {
|
|
402
|
+
mustThrow(() => assertNull(undefined));
|
|
403
|
+
mustThrow(() => assertNull(""));
|
|
404
|
+
mustThrow(() => assertNull("null"));
|
|
405
|
+
mustThrow(() => assertNull(0));
|
|
406
|
+
mustThrow(() => assertNull(NaN));
|
|
407
|
+
mustThrow(() => assertNull(0n));
|
|
408
|
+
mustThrow(() => assertNull(false));
|
|
409
|
+
mustThrow(() => assertNull({}));
|
|
410
|
+
});
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
group("assertInstanceOf", () => {
|
|
414
|
+
test("should not throw for valid instance", () => {
|
|
415
|
+
mustNotThrow(() => assertInstanceOf({}, Object));
|
|
416
|
+
mustNotThrow(() => assertInstanceOf(new Date(), Date));
|
|
417
|
+
mustNotThrow(() => assertInstanceOf(new Error(), Error));
|
|
418
|
+
mustNotThrow(() => assertInstanceOf([], Array));
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
test("should handle inheritance", () => {
|
|
422
|
+
class Parent {}
|
|
423
|
+
class Child extends Parent {}
|
|
424
|
+
const child = new Child();
|
|
425
|
+
mustNotThrow(() => assertInstanceOf(child, Parent));
|
|
426
|
+
mustNotThrow(() => assertInstanceOf(child, Child));
|
|
427
|
+
const parent = new Parent();
|
|
428
|
+
mustNotThrow(() => assertInstanceOf(parent, Parent));
|
|
429
|
+
mustThrow(() => assertInstanceOf(parent, Child));
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
test("should throw for non-instance", () => {
|
|
433
|
+
mustThrow(() => assertInstanceOf({}, Date));
|
|
434
|
+
mustThrow(() => assertInstanceOf("2026-01-01", Date));
|
|
435
|
+
mustThrow(() => assertInstanceOf(null, Object));
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
test("should throw with descriptive error", () => {
|
|
439
|
+
mustThrow(() => assertInstanceOf({}, Date), /Date/);
|
|
440
|
+
mustThrow(() => assertInstanceOf("", Object), /Object/);
|
|
441
|
+
class CustomClass {}
|
|
442
|
+
mustThrow(() => assertInstanceOf(new Date(), CustomClass), /CustomClass/);
|
|
443
|
+
});
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
group("assertIsTuple", () => {
|
|
447
|
+
group("should not throw", () => {
|
|
448
|
+
test("for array matching expected length", () => {
|
|
449
|
+
// casting because otherwise TypeScript doesn't allow a tuple of known length to be passed
|
|
450
|
+
mustNotThrow(() => assertIsTuple([1, 2] as number[], 2));
|
|
451
|
+
mustNotThrow(() => assertIsTuple(["a"] as string[], 1));
|
|
452
|
+
mustNotThrow(() => assertIsTuple([1, 2, 3, 4, 5] as number[], 5));
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
test("for empty array with length 0", () => {
|
|
456
|
+
mustNotThrow(() => assertIsTuple([] as unknown[], 0));
|
|
457
|
+
});
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
group("should throw", () => {
|
|
461
|
+
test("for array shorter than expected", () => {
|
|
462
|
+
mustThrow(() => assertIsTuple([1] as number[], 2), /expected length 2.*?has length 1/i);
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
test("for array longer than expected", () => {
|
|
466
|
+
mustThrow(() => assertIsTuple([1, 2, 3] as number[], 2), /expected length 2.*?has length 3/i);
|
|
467
|
+
});
|
|
468
|
+
|
|
469
|
+
test("for sparse array", () => {
|
|
470
|
+
const sparse = [1, 2, 3];
|
|
471
|
+
delete sparse[1];
|
|
472
|
+
mustThrow(() => assertIsTuple(sparse, 3), /sparse.*?index 1/i);
|
|
473
|
+
});
|
|
474
|
+
});
|
|
475
|
+
});
|
|
476
|
+
|
|
477
|
+
group("assertUnreachable", () => {
|
|
478
|
+
test("should throw when called", () => {
|
|
479
|
+
// This function should only be called if there's a type error somewhere
|
|
480
|
+
// So it should always throw at runtime
|
|
481
|
+
mustThrow(() => assertUnreachable("unreachable" as never));
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
test("should include value and type info in error", () => {
|
|
485
|
+
mustThrow(() => assertUnreachable("myValue" as never), /string.*?myValue/);
|
|
486
|
+
mustThrow(() => assertUnreachable(new Date() as never), /Date/);
|
|
487
|
+
mustThrow(() => assertUnreachable((() => {}) as never), /Function/);
|
|
488
|
+
mustThrow(() => assertUnreachable(null as never), /null/);
|
|
489
|
+
mustThrow(() => assertUnreachable(undefined as never), /undefined/);
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
test("should include custom message", () => {
|
|
493
|
+
mustThrow(() => assertUnreachable("myValue" as never, "Custom error message"), /Custom error message/);
|
|
494
|
+
});
|
|
495
|
+
});
|
|
496
|
+
|
|
497
|
+
group("assertNonNullable", () => {
|
|
498
|
+
group("should not throw", () => {
|
|
499
|
+
test("for non-null values", () => {
|
|
500
|
+
mustNotThrow(() => assertNonNullable(""));
|
|
501
|
+
mustNotThrow(() => assertNonNullable(0));
|
|
502
|
+
mustNotThrow(() => assertNonNullable(false));
|
|
503
|
+
mustNotThrow(() => assertNonNullable({}));
|
|
504
|
+
mustNotThrow(() => assertNonNullable([]));
|
|
505
|
+
});
|
|
506
|
+
});
|
|
507
|
+
|
|
508
|
+
group("should throw", () => {
|
|
509
|
+
test("for null", () => {
|
|
510
|
+
mustThrow(() => assertNonNullable(null), /null/);
|
|
511
|
+
});
|
|
512
|
+
|
|
513
|
+
test("for undefined", () => {
|
|
514
|
+
mustThrow(() => assertNonNullable(undefined), /undefined/);
|
|
515
|
+
});
|
|
516
|
+
});
|
|
517
|
+
});
|
|
518
|
+
|
|
519
|
+
group("assertPropsNonNullable", () => {
|
|
520
|
+
type TestObject = { a: string | undefined | null, b?: number };
|
|
521
|
+
|
|
522
|
+
group("should not throw", () => {
|
|
523
|
+
test("for object with non-null checked props", () => {
|
|
524
|
+
const obj: TestObject = { a: "hello"};
|
|
525
|
+
mustNotThrow(() => assertPropsNonNullable(obj, ["a"]));
|
|
526
|
+
});
|
|
527
|
+
|
|
528
|
+
test("for empty propKeys array", () => {
|
|
529
|
+
const obj: TestObject = { a: undefined };
|
|
530
|
+
mustNotThrow(() => assertPropsNonNullable(obj, []));
|
|
531
|
+
});
|
|
532
|
+
});
|
|
533
|
+
|
|
534
|
+
group("should throw", () => {
|
|
535
|
+
test("for null property value", () => {
|
|
536
|
+
const obj: TestObject = { a: null, b: 42 };
|
|
537
|
+
mustThrow(() => assertPropsNonNullable(obj, ["a"]), /a/);
|
|
538
|
+
});
|
|
539
|
+
|
|
540
|
+
test("for undefined property value", () => {
|
|
541
|
+
const obj: TestObject = { a: undefined };
|
|
542
|
+
mustThrow(() => assertPropsNonNullable(obj, ["a"]), /a/);
|
|
543
|
+
});
|
|
544
|
+
|
|
545
|
+
test("for missing property", () => {
|
|
546
|
+
const obj: TestObject = { a: "" };
|
|
547
|
+
mustThrow(() => assertPropsNonNullable(obj, ["b"]), /b.*?not present/);
|
|
548
|
+
});
|
|
549
|
+
});
|
|
550
|
+
});
|
|
551
|
+
|
|
552
|
+
group("assertArrayNonNullable", () => {
|
|
553
|
+
group("should not throw", () => {
|
|
554
|
+
test("for array without null or undefined", () => {
|
|
555
|
+
mustNotThrow(() => assertArrayNonNullable([1, 2, 3]));
|
|
556
|
+
mustNotThrow(() => assertArrayNonNullable(["a", "b"]));
|
|
557
|
+
mustNotThrow(() => assertArrayNonNullable([0, "", false, Date, new Date(), {}, []]));
|
|
558
|
+
});
|
|
559
|
+
|
|
560
|
+
test("for empty array", () => {
|
|
561
|
+
mustNotThrow(() => assertArrayNonNullable([]));
|
|
562
|
+
});
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
group("should throw", () => {
|
|
566
|
+
test("for array containing null", () => {
|
|
567
|
+
mustThrow(() => assertArrayNonNullable([1, null, 3]), /null.*?index 1/i);
|
|
568
|
+
});
|
|
569
|
+
|
|
570
|
+
test("for array containing undefined", () => {
|
|
571
|
+
mustThrow(() => assertArrayNonNullable([1, undefined, 3]), /undefined.*?index 1/i);
|
|
572
|
+
});
|
|
573
|
+
|
|
574
|
+
test("for sparse array", () => {
|
|
575
|
+
const sparse = [1, 2, 3];
|
|
576
|
+
delete sparse[1];
|
|
577
|
+
mustThrow(() => assertArrayNonNullable(sparse), /sparse.*?index 1/i);
|
|
578
|
+
});
|
|
579
|
+
});
|
|
580
|
+
});
|
|
581
|
+
|
|
582
|
+
group("assertTupleNonNullable", () => {
|
|
583
|
+
group("should not throw", () => {
|
|
584
|
+
test("for tuple without null or undefined", () => {
|
|
585
|
+
const tuple: [number, string, boolean, Date, object, unknown[]]
|
|
586
|
+
= [0, "", false, new Date(), {}, []];
|
|
587
|
+
mustNotThrow(() => assertTupleNonNullable(tuple));
|
|
588
|
+
});
|
|
589
|
+
});
|
|
590
|
+
|
|
591
|
+
group("should throw", () => {
|
|
592
|
+
test("for tuple containing null", () => {
|
|
593
|
+
const tuple: [number, null] = [1, null];
|
|
594
|
+
mustThrow(() => assertTupleNonNullable(tuple), /null.*?index 1/i);
|
|
595
|
+
});
|
|
596
|
+
|
|
597
|
+
test("for tuple containing undefined", () => {
|
|
598
|
+
const tuple: [number, undefined] = [1, undefined];
|
|
599
|
+
mustThrow(() => assertTupleNonNullable(tuple), /undefined.*?index 1/i);
|
|
600
|
+
});
|
|
601
|
+
|
|
602
|
+
test("for sparse tuple", () => {
|
|
603
|
+
const tuple: [number, number, number] = [1, 2, 3];
|
|
604
|
+
// @ts-expect-error - TypeScript is trying to protect us from invalidating the tuple type
|
|
605
|
+
delete tuple[1];
|
|
606
|
+
mustThrow(() => assertTupleNonNullable(tuple), /sparse.*?index 1/i);
|
|
607
|
+
});
|
|
608
|
+
});
|
|
609
|
+
});
|
|
610
|
+
|
|
611
|
+
group("assertFiniteNumber", () => {
|
|
612
|
+
group("should not throw", () => {
|
|
613
|
+
test("for finite numbers", () => {
|
|
614
|
+
mustNotThrow(() => assertFiniteNumber(42));
|
|
615
|
+
mustNotThrow(() => assertFiniteNumber(0));
|
|
616
|
+
mustNotThrow(() => assertFiniteNumber(-1));
|
|
617
|
+
mustNotThrow(() => assertFiniteNumber(3.14));
|
|
618
|
+
mustNotThrow(() => assertFiniteNumber(Number.MAX_VALUE));
|
|
619
|
+
mustNotThrow(() => assertFiniteNumber(Number.MIN_VALUE));
|
|
620
|
+
});
|
|
621
|
+
});
|
|
622
|
+
|
|
623
|
+
group("should throw", () => {
|
|
624
|
+
test("for NaN", () => {
|
|
625
|
+
mustThrow(() => assertFiniteNumber(NaN), /NaN/);
|
|
626
|
+
});
|
|
627
|
+
|
|
628
|
+
test("for Infinity", () => {
|
|
629
|
+
mustThrow(() => assertFiniteNumber(Infinity), /Infinity/);
|
|
630
|
+
mustThrow(() => assertFiniteNumber(-Infinity), /-Infinity/);
|
|
631
|
+
});
|
|
632
|
+
|
|
633
|
+
test("for non-number types", () => {
|
|
634
|
+
mustThrow(() => assertFiniteNumber("42"), /string/);
|
|
635
|
+
mustThrow(() => assertFiniteNumber(42n), /bigint/);
|
|
636
|
+
mustThrow(() => assertFiniteNumber(new Number(42)), /Number/);
|
|
637
|
+
mustThrow(() => assertFiniteNumber(null), /null/);
|
|
638
|
+
mustThrow(() => assertFiniteNumber(undefined), /undefined/);
|
|
639
|
+
});
|
|
640
|
+
});
|
|
641
|
+
});
|