vortez 5.0.0-dev.18 → 5.0.0-dev.19

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.
Files changed (66) hide show
  1. package/.gitignore +9 -4
  2. package/README.md +681 -176
  3. package/build/Vortez.d.ts +1 -0
  4. package/build/Vortez.js +1 -0
  5. package/build/Vortez.js.map +1 -1
  6. package/build/server/Response.d.ts +1 -1
  7. package/build/server/Response.js +1 -1
  8. package/build/server/Response.js.map +1 -1
  9. package/build/server/Server.d.ts +4 -4
  10. package/build/server/Server.js +5 -5
  11. package/build/server/Server.js.map +1 -1
  12. package/build/server/ServerDebug.d.ts +10 -1
  13. package/build/server/ServerDebug.js +85 -17
  14. package/build/server/ServerDebug.js.map +1 -1
  15. package/build/server/config/Config.d.ts +274 -47
  16. package/build/server/config/Config.js +68 -47
  17. package/build/server/config/Config.js.map +1 -1
  18. package/build/server/config/{ConfigLoader.d.ts → Loader.d.ts} +4 -5
  19. package/build/server/config/{ConfigLoader.js → Loader.js} +7 -10
  20. package/build/server/config/Loader.js.map +1 -0
  21. package/build/server/router/Router.d.ts +87 -30
  22. package/build/server/router/Router.js +110 -48
  23. package/build/server/router/Router.js.map +1 -1
  24. package/build/server/router/algorithm/Algorithm.d.ts +39 -0
  25. package/build/server/router/algorithm/Algorithm.js +20 -0
  26. package/build/server/router/algorithm/Algorithm.js.map +1 -0
  27. package/build/server/router/algorithm/FIFO.d.ts +15 -0
  28. package/build/server/router/algorithm/FIFO.js +24 -0
  29. package/build/server/router/algorithm/FIFO.js.map +1 -0
  30. package/build/server/router/algorithm/Tree.d.ts +38 -0
  31. package/build/server/router/algorithm/Tree.js +126 -0
  32. package/build/server/router/algorithm/Tree.js.map +1 -0
  33. package/build/server/router/middleware/WsMiddleware.js +1 -1
  34. package/build/server/router/middleware/WsMiddleware.js.map +1 -1
  35. package/build/utilities/Flatten.d.ts +56 -0
  36. package/build/utilities/Flatten.js +59 -0
  37. package/build/utilities/Flatten.js.map +1 -0
  38. package/build/utilities/Utilities.d.ts +7 -58
  39. package/build/utilities/Utilities.js +8 -33
  40. package/build/utilities/Utilities.js.map +1 -1
  41. package/build/utilities/schema/Introspection.d.ts +24 -0
  42. package/build/utilities/schema/Introspection.js +87 -0
  43. package/build/utilities/schema/Introspection.js.map +1 -0
  44. package/build/utilities/schema/JSONSchema.d.ts +68 -0
  45. package/build/utilities/schema/JSONSchema.js +13 -0
  46. package/build/utilities/schema/JSONSchema.js.map +1 -0
  47. package/build/utilities/schema/Schema.d.ts +253 -0
  48. package/build/utilities/schema/Schema.js +241 -0
  49. package/build/utilities/schema/Schema.js.map +1 -0
  50. package/build/utilities/schema/SchemaError.d.ts +10 -0
  51. package/build/utilities/schema/SchemaError.js +13 -0
  52. package/build/utilities/schema/SchemaError.js.map +1 -0
  53. package/build/utilities/schema/Validator.d.ts +94 -0
  54. package/build/utilities/schema/Validator.js +246 -0
  55. package/build/utilities/schema/Validator.js.map +1 -0
  56. package/package.json +1 -1
  57. package/tests/config/config.js +233 -0
  58. package/tests/router.js +596 -0
  59. package/tests/schema/schema.js +368 -0
  60. package/tests/test.env +0 -0
  61. package/tests/test.js +3 -3
  62. package/build/server/config/ConfigLoader.js.map +0 -1
  63. package/build/server/config/ConfigValidator.d.ts +0 -71
  64. package/build/server/config/ConfigValidator.js +0 -131
  65. package/build/server/config/ConfigValidator.js.map +0 -1
  66. package/examples/in-docs.js +0 -96
@@ -0,0 +1,596 @@
1
+ // @ts-check
2
+ import { strict as assert } from 'assert';
3
+
4
+ import { Logger } from '../build/Vortez.js';
5
+
6
+ import Request from '../build/server/Request.js';
7
+ import Response from '../build/server/Response.js';
8
+
9
+ import Router from '../build/server/router/router.v2.js';
10
+
11
+ const logger = new Logger({ prefix: 'Router' });
12
+
13
+ let testsPassed = 0;
14
+ let testsFailed = 0;
15
+
16
+ /**
17
+ * Logs test results.
18
+ * @param {string} testName The test name.
19
+ * @param {boolean} passed Whether the test passed.
20
+ * @param {unknown | null} error Optional error object for failures.
21
+ */
22
+ function logTestResult(testName, passed, error = null) {
23
+ if (passed) {
24
+ logger.log(`&C2✓ ${testName}`);
25
+ testsPassed++;
26
+ } else {
27
+ const message = error instanceof Error ? error.message : String(error);
28
+ logger.error(`&C1✗ ${testName}${error ? ': ' + message : ''}`);
29
+ testsFailed++;
30
+ }
31
+ }
32
+
33
+ /**
34
+ * Creates a mock Request object for testing.
35
+ * @param {string} url The URL to test.
36
+ * @param {string} method The HTTP method.
37
+ * @returns {Request} Mock request object.
38
+ */
39
+ function createMockRequest(url, method = 'GET') {
40
+ /** @type {any} */
41
+ const httpRequest = {
42
+ headers: {},
43
+ socket: { remoteAddress: '127.0.0.1' },
44
+ method,
45
+ url: url.endsWith('/') ? url : url + '/',
46
+ };
47
+ return new Request(httpRequest);
48
+ }
49
+
50
+ /**
51
+ * Creates a mock Response object for testing.
52
+ * @param {Request} request The request to bind to the response.
53
+ * @returns {Response & { executed?: boolean; executedWithParams?: Record<string, string | undefined> | null }} Mock response object.
54
+ */
55
+ function createMockResponse(request = createMockRequest('/')) {
56
+ /** @type {any} */
57
+ const serverResponse = {
58
+ setHeader() {},
59
+ writeHead() {},
60
+ end() {},
61
+ writableEnded: false,
62
+ headersSent: false,
63
+ };
64
+ /** @type {any} */
65
+ const response = new Response(request, serverResponse);
66
+ response.executed = false;
67
+ response.executedWithParams = null;
68
+ return response;
69
+ }
70
+
71
+ /**
72
+ * Test basic HTTP routing with FIFO algorithm.
73
+ */
74
+ function testFIFOBasicRouting() {
75
+ try {
76
+ const router = new Router(undefined, [], { algorithm: 'FIFO' });
77
+ const response = createMockResponse();
78
+
79
+ router.addAction('GET', '/hello', (req, res) => {
80
+ response.executed = true;
81
+ });
82
+
83
+ const request = createMockRequest('/hello');
84
+ const routed = router.routeRequest(request, response);
85
+
86
+ assert.equal(routed, true);
87
+ assert.equal(response.executed, true);
88
+ logTestResult('FIFO - Basic HTTP route', true);
89
+ } catch (error) {
90
+ logTestResult('FIFO - Basic HTTP route', false, error);
91
+ }
92
+ }
93
+
94
+ /**
95
+ * Test Tree algorithm basic routing.
96
+ */
97
+ function testTreeBasicRouting() {
98
+ try {
99
+ const router = new Router(undefined, [], { algorithm: 'Tree' });
100
+ const response = createMockResponse();
101
+
102
+ router.addAction('GET', '/api/users', (req, res) => {
103
+ response.executed = true;
104
+ });
105
+
106
+ const request = createMockRequest('/api/users');
107
+ const routed = router.routeRequest(request, response);
108
+
109
+ assert.equal(routed, true);
110
+ assert.equal(response.executed, true);
111
+ logTestResult('Tree - Basic HTTP route', true);
112
+ } catch (error) {
113
+ logTestResult('Tree - Basic HTTP route', false, error);
114
+ }
115
+ }
116
+
117
+ /**
118
+ * Test URL parameters extraction.
119
+ */
120
+ function testURLParameterExtraction() {
121
+ try {
122
+ const router = new Router(undefined, [], { algorithm: 'Tree' });
123
+ const response = createMockResponse();
124
+
125
+ router.addAction('GET', '/users/$id', (req, res) => {
126
+ const params = req.ruleParams;
127
+ if (params && params.id) {
128
+ response.executedWithParams = params;
129
+ }
130
+ });
131
+
132
+ const request = createMockRequest('/users/123');
133
+ const routed = router.routeRequest(request, response);
134
+
135
+ assert.equal(routed, true);
136
+ assert.ok(response.executedWithParams);
137
+ assert.equal(response.executedWithParams.id, '123');
138
+ logTestResult('Tree - URL parameter extraction', true);
139
+ } catch (error) {
140
+ logTestResult('Tree - URL parameter extraction', false, error);
141
+ }
142
+ }
143
+
144
+ /**
145
+ * Test optional URL parameters.
146
+ */
147
+ function testOptionalURLParameters() {
148
+ try {
149
+ const router = new Router(undefined, [], { algorithm: 'Tree' });
150
+ let callCount = 0;
151
+
152
+ router.addAction('GET', '/posts/$?id', (req, res) => {
153
+ callCount++;
154
+ });
155
+
156
+ // Route with param
157
+ const request1 = createMockRequest('/posts/42');
158
+ const routed1 = router.routeRequest(request1, createMockResponse());
159
+
160
+ // Route without param
161
+ const request2 = createMockRequest('/posts');
162
+ const routed2 = router.routeRequest(request2, createMockResponse());
163
+
164
+ assert.equal(routed1, true);
165
+ assert.equal(routed2, true);
166
+ assert.equal(callCount, 2);
167
+ logTestResult('Tree - Optional URL parameters', true);
168
+ } catch (error) {
169
+ logTestResult('Tree - Optional URL parameters', false, error);
170
+ }
171
+ }
172
+
173
+ /**
174
+ * Test wildcard routing.
175
+ */
176
+ function testWildcardRouting() {
177
+ try {
178
+ const router = new Router(undefined, [], { algorithm: 'Tree' });
179
+ let catchAllCalled = false;
180
+
181
+ router.addAction('GET', '/static/*', (req, res) => {
182
+ catchAllCalled = true;
183
+ });
184
+
185
+ const request = createMockRequest('/static/css/style.css');
186
+ const routed = router.routeRequest(request, createMockResponse());
187
+
188
+ assert.equal(routed, true);
189
+ assert.equal(catchAllCalled, true);
190
+ logTestResult('Tree - Wildcard routing', true);
191
+ } catch (error) {
192
+ logTestResult('Tree - Wildcard routing', false, error);
193
+ }
194
+ }
195
+
196
+ /**
197
+ * Test HTTP method filtering.
198
+ */
199
+ function testHTTPMethodFiltering() {
200
+ try {
201
+ const router = new Router();
202
+ let getExecuted = false;
203
+ let postExecuted = false;
204
+
205
+ router.addAction('GET', '/resource', () => { getExecuted = true; });
206
+ router.addAction('POST', '/resource', () => { postExecuted = true; });
207
+
208
+ // Test GET
209
+ const getRequest = createMockRequest('/resource', 'GET');
210
+ router.routeRequest(getRequest, createMockResponse());
211
+
212
+ // Test POST
213
+ const postRequest = createMockRequest('/resource', 'POST');
214
+ router.routeRequest(postRequest, createMockResponse());
215
+
216
+ assert.equal(getExecuted, true);
217
+ assert.equal(postExecuted, true);
218
+ logTestResult('FIFO - HTTP method filtering', true);
219
+ } catch (error) {
220
+ logTestResult('FIFO - HTTP method filtering', false, error);
221
+ }
222
+ }
223
+
224
+ /**
225
+ * Test ALL method matches any HTTP verb.
226
+ */
227
+ function testALLMethod() {
228
+ try {
229
+ const router = new Router();
230
+ let callCount = 0;
231
+
232
+ router.addAction('ALL', '/webhook', () => {
233
+ callCount++;
234
+ });
235
+
236
+ /** @type {string[]} */
237
+ const methods = ['GET', 'POST', 'PUT', 'DELETE'];
238
+ for (const method of methods) {
239
+ const request = createMockRequest('/webhook', method);
240
+ router.routeRequest(request, createMockResponse());
241
+ }
242
+
243
+ assert.equal(callCount, 4);
244
+ logTestResult('FIFO - ALL method matches any verb', true);
245
+ } catch (error) {
246
+ logTestResult('FIFO - ALL method matches any verb', false, error);
247
+ }
248
+ }
249
+
250
+ /**
251
+ * Test no route match returns false.
252
+ */
253
+ function testNoRouteMatch() {
254
+ try {
255
+ const router = new Router();
256
+
257
+ router.addAction('GET', '/api/users', () => {});
258
+
259
+ const request = createMockRequest('/api/posts');
260
+ const routed = router.routeRequest(request, createMockResponse());
261
+
262
+ assert.equal(routed, false);
263
+ logTestResult('FIFO - No route match returns false', true);
264
+ } catch (error) {
265
+ logTestResult('FIFO - No route match returns false', false, error);
266
+ }
267
+ }
268
+
269
+ /**
270
+ * Test router mounting.
271
+ */
272
+ function testRouterMounting() {
273
+ try {
274
+ const mainRouter = new Router();
275
+ const subRouter = new Router();
276
+ let subRouteExecuted = false;
277
+
278
+ subRouter.addAction('GET', '/list', () => {
279
+ subRouteExecuted = true;
280
+ });
281
+
282
+ mainRouter.mount(subRouter, '/api/v1');
283
+
284
+ const request = createMockRequest('/api/v1/list');
285
+ const routed = mainRouter.routeRequest(request, createMockResponse());
286
+
287
+ assert.equal(routed, true);
288
+ assert.equal(subRouteExecuted, true);
289
+ logTestResult('FIFO - Router mounting', true);
290
+ } catch (error) {
291
+ logTestResult('FIFO - Router mounting', false, error);
292
+ }
293
+ }
294
+
295
+ /**
296
+ * Test sub-router creation preserves algorithm.
297
+ */
298
+ function testSubRouterPreservesAlgorithm() {
299
+ try {
300
+ const parentRouter = new Router(undefined, [], { algorithm: 'Tree' });
301
+ const subRouter = parentRouter.createRouter();
302
+
303
+ // Check that sub-router is also using Tree algorithm
304
+ assert.ok(subRouter.algorithm instanceof Router.Tree);
305
+ logTestResult('Tree - Sub-router preserves algorithm', true);
306
+ } catch (error) {
307
+ logTestResult('Tree - Sub-router preserves algorithm', false, error);
308
+ }
309
+ }
310
+
311
+ /**
312
+ * Test multiple rules FIFO evaluation order.
313
+ */
314
+ function testFIFOEvaluationOrder() {
315
+ try {
316
+ const router = new Router(undefined, [], { algorithm: 'FIFO' });
317
+ /** @type {string[]} */
318
+ const executionOrder = [];
319
+
320
+ router.addAction('GET', '/test', () => {
321
+ executionOrder.push('first');
322
+ });
323
+ router.addAction('GET', '/test', () => {
324
+ executionOrder.push('second');
325
+ });
326
+
327
+ const request = createMockRequest('/test');
328
+ router.routeRequest(request, createMockResponse());
329
+
330
+ // FIFO should execute only the first matching rule, then stop
331
+ assert.equal(executionOrder.length, 1);
332
+ assert.equal(executionOrder[0], 'first');
333
+ logTestResult('FIFO - Evaluation order (first match)', true);
334
+ } catch (error) {
335
+ logTestResult('FIFO - Evaluation order (first match)', false, error);
336
+ }
337
+ }
338
+
339
+ /**
340
+ * Test Tree algorithm path precedence.
341
+ */
342
+ function testTreePathPrecedence() {
343
+ try {
344
+ const router = new Router(undefined, [], { algorithm: 'Tree' });
345
+ /** @type {string[]} */
346
+ const results = [];
347
+
348
+ router.addAction('GET', '/api/$id', () => {
349
+ results.push('param');
350
+ });
351
+ router.addAction('GET', '/api/special', () => {
352
+ results.push('static');
353
+ });
354
+
355
+ // Test exact match should take precedence
356
+ const request1 = createMockRequest('/api/special');
357
+ router.routeRequest(request1, createMockResponse());
358
+
359
+ // Test parameter match
360
+ const request2 = createMockRequest('/api/123');
361
+ router.routeRequest(request2, createMockResponse());
362
+
363
+ assert.equal(results[0], 'static');
364
+ assert.equal(results[1], 'param');
365
+ logTestResult('Tree - Static path precedence over parameters', true);
366
+ } catch (error) {
367
+ logTestResult('Tree - Static path precedence over parameters', false, error);
368
+ }
369
+ }
370
+
371
+ /**
372
+ * Test algorithm switching via getAlgorithm.
373
+ */
374
+ function testAlgorithmSwitching() {
375
+ try {
376
+ const fifo = Router.getAlgorithm('FIFO');
377
+ const tree = Router.getAlgorithm('Tree');
378
+ const directTree = Router.getAlgorithm(new Router.Tree());
379
+
380
+ assert.ok(fifo instanceof Router.FIFO);
381
+ assert.ok(tree instanceof Router.Tree);
382
+ assert.ok(directTree instanceof Router.Tree);
383
+ logTestResult('Static - Algorithm switching via getAlgorithm', true);
384
+ } catch (error) {
385
+ logTestResult('Static - Algorithm switching via getAlgorithm', false, error);
386
+ }
387
+ }
388
+
389
+ /**
390
+ * Test invalid algorithm defaults to FIFO.
391
+ */
392
+ function testInvalidAlgorithmDefaultsFIFO() {
393
+ try {
394
+ /** @type {any} */
395
+ const invalidKey = 'InvalidAlgo';
396
+ const invalidAlgorithm = Router.getAlgorithm(invalidKey);
397
+ assert.ok(invalidAlgorithm instanceof Router.FIFO);
398
+ logTestResult('Static - Invalid algorithm defaults to FIFO', true);
399
+ } catch (error) {
400
+ logTestResult('Static - Invalid algorithm defaults to FIFO', false, error);
401
+ }
402
+ }
403
+
404
+ /**
405
+ * Test HTTP rules view filtering.
406
+ */
407
+ function testHTTPRulesView() {
408
+ try {
409
+ const router = new Router();
410
+
411
+ router.addAction('GET', '/api/users', () => {});
412
+ router.addAction('POST', '/api/users', () => {});
413
+ router.addWebSocket('/ws/chat', () => {});
414
+
415
+ const httpRules = router.httpRules;
416
+ const wsRules = router.wsRules;
417
+
418
+ assert.equal(httpRules.length, 2);
419
+ assert.equal(wsRules.length, 1);
420
+ logTestResult('FIFO - HTTP rules view filtering', true);
421
+ } catch (error) {
422
+ logTestResult('FIFO - HTTP rules view filtering', false, error);
423
+ }
424
+ }
425
+
426
+ /**
427
+ * Test WebSocket rules view filtering.
428
+ */
429
+ function testWebSocketRulesView() {
430
+ try {
431
+ const router = new Router();
432
+
433
+ router.addWebSocket('/ws/events', () => {});
434
+ router.addWebSocket('/ws/notifications', () => {});
435
+ router.addAction('GET', '/api/health', () => {});
436
+
437
+ const wsRules = router.wsRules;
438
+ const httpRules = router.httpRules;
439
+
440
+ assert.equal(wsRules.length, 2);
441
+ assert.equal(httpRules.length, 1);
442
+ logTestResult('FIFO - WebSocket rules view filtering', true);
443
+ } catch (error) {
444
+ logTestResult('FIFO - WebSocket rules view filtering', false, error);
445
+ }
446
+ }
447
+
448
+ /**
449
+ * Test method chaining on addRules.
450
+ */
451
+ function testMethodChaining() {
452
+ try {
453
+ const router = new Router();
454
+ let result1 = false;
455
+ let result2 = false;
456
+
457
+ router.addAction('GET', '/a', () => { result1 = true; });
458
+ router.addAction('GET', '/b', () => { result2 = true; });
459
+
460
+ router.routeRequest(createMockRequest('/a'), createMockResponse());
461
+ router.routeRequest(createMockRequest('/b'), createMockResponse());
462
+
463
+ assert.equal(result1, true);
464
+ assert.equal(result2, true);
465
+ logTestResult('FIFO - Method chaining', true);
466
+ } catch (error) {
467
+ logTestResult('FIFO - Method chaining', false, error);
468
+ }
469
+ }
470
+
471
+ /**
472
+ * Test Tree algorithm with nested paths.
473
+ */
474
+ function testTreeNestedPaths() {
475
+ try {
476
+ const router = new Router(undefined, [], { algorithm: 'Tree' });
477
+ /** @type {string[]} */
478
+ const results = [];
479
+
480
+ router.addAction('GET', '/api/v1/users', () => { results.push('v1'); });
481
+ router.addAction('GET', '/api/v2/users', () => { results.push('v2'); });
482
+ router.addAction('GET', '/api/v1/users/$id', () => { results.push('v1-id'); });
483
+
484
+ router.routeRequest(createMockRequest('/api/v1/users'), createMockResponse());
485
+ router.routeRequest(createMockRequest('/api/v2/users'), createMockResponse());
486
+ router.routeRequest(createMockRequest('/api/v1/users/42'), createMockResponse());
487
+
488
+ assert.deepEqual(results, ['v1', 'v2', 'v1-id']);
489
+ logTestResult('Tree - Nested path routing', true);
490
+ } catch (error) {
491
+ logTestResult('Tree - Nested path routing', false, error);
492
+ }
493
+ }
494
+
495
+ /**
496
+ * Test complex router mounting with prefixes.
497
+ */
498
+ function testComplexRouterMounting() {
499
+ try {
500
+ const apiV1 = new Router();
501
+ const apiV2 = new Router();
502
+ const mainRouter = new Router();
503
+
504
+ let v1Called = false;
505
+ let v2Called = false;
506
+
507
+ apiV1.addAction('GET', '/users', () => { v1Called = true; });
508
+ apiV2.addAction('GET', '/users', () => { v2Called = true; });
509
+
510
+ mainRouter.mount(apiV1, '/api/v1');
511
+ mainRouter.mount(apiV2, '/api/v2');
512
+
513
+ mainRouter.routeRequest(createMockRequest('/api/v1/users'), createMockResponse());
514
+ mainRouter.routeRequest(createMockRequest('/api/v2/users'), createMockResponse());
515
+
516
+ assert.equal(v1Called, true);
517
+ assert.equal(v2Called, true);
518
+ logTestResult('FIFO - Complex router mounting', true);
519
+ } catch (error) {
520
+ logTestResult('FIFO - Complex router mounting', false, error);
521
+ }
522
+ }
523
+
524
+ /**
525
+ * Test URL normalization (trailing slashes).
526
+ */
527
+ function testURLNormalization() {
528
+ try {
529
+ const router = new Router();
530
+ let executionCount = 0;
531
+
532
+ router.addAction('GET', '/test', () => {
533
+ executionCount++;
534
+ });
535
+
536
+ // Test with trailing slash (should be normalized)
537
+ const request1 = createMockRequest('/test/');
538
+ const routed1 = router.routeRequest(request1, createMockResponse());
539
+
540
+ // Test without trailing slash
541
+ const request2 = createMockRequest('/test');
542
+ const routed2 = router.routeRequest(request2, createMockResponse());
543
+
544
+ assert.equal(routed1, true);
545
+ assert.equal(routed2, true);
546
+ logTestResult('FIFO - URL normalization', true);
547
+ } catch (error) {
548
+ logTestResult('FIFO - URL normalization', false, error);
549
+ }
550
+ }
551
+
552
+ /**
553
+ * Runs all tests for Router.
554
+ * Logs the results and exits with appropriate code.
555
+ */
556
+ const runTests = () => {
557
+ logger.log('\n&C6=== Router Test Suite ===\n');
558
+
559
+ // FIFO Algorithm Tests
560
+ logger.log('&C6--- FIFO Algorithm ---');
561
+ testFIFOBasicRouting();
562
+ testHTTPMethodFiltering();
563
+ testALLMethod();
564
+ testNoRouteMatch();
565
+ testRouterMounting();
566
+ testFIFOEvaluationOrder();
567
+ testHTTPRulesView();
568
+ testWebSocketRulesView();
569
+ testMethodChaining();
570
+ testComplexRouterMounting();
571
+ testURLNormalization();
572
+
573
+ // Tree Algorithm Tests
574
+ logger.log('\n&C6--- Tree Algorithm ---');
575
+ testTreeBasicRouting();
576
+ testURLParameterExtraction();
577
+ testOptionalURLParameters();
578
+ testWildcardRouting();
579
+ testSubRouterPreservesAlgorithm();
580
+ testTreePathPrecedence();
581
+ testTreeNestedPaths();
582
+
583
+ // Algorithm Management Tests
584
+ logger.log('\n&C6--- Algorithm Management ---');
585
+ testAlgorithmSwitching();
586
+ testInvalidAlgorithmDefaultsFIFO();
587
+
588
+ logger.log(`\n&C6=== Results ===`);
589
+ logger.log(`&C2✓ Passed: ${testsPassed}`);
590
+ logger.log(`&C1✗ Failed: ${testsFailed}`);
591
+ logger.log(`&C3Total: ${testsPassed + testsFailed}\n`);
592
+
593
+ process.exit(testsFailed > 0 ? 1 : 0);
594
+ };
595
+
596
+ runTests();