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.
- package/.gitignore +9 -4
- package/README.md +681 -176
- package/build/Vortez.d.ts +1 -0
- package/build/Vortez.js +1 -0
- package/build/Vortez.js.map +1 -1
- package/build/server/Response.d.ts +1 -1
- package/build/server/Response.js +1 -1
- package/build/server/Response.js.map +1 -1
- package/build/server/Server.d.ts +4 -4
- package/build/server/Server.js +5 -5
- package/build/server/Server.js.map +1 -1
- package/build/server/ServerDebug.d.ts +10 -1
- package/build/server/ServerDebug.js +85 -17
- package/build/server/ServerDebug.js.map +1 -1
- package/build/server/config/Config.d.ts +274 -47
- package/build/server/config/Config.js +68 -47
- package/build/server/config/Config.js.map +1 -1
- package/build/server/config/{ConfigLoader.d.ts → Loader.d.ts} +4 -5
- package/build/server/config/{ConfigLoader.js → Loader.js} +7 -10
- package/build/server/config/Loader.js.map +1 -0
- package/build/server/router/Router.d.ts +87 -30
- package/build/server/router/Router.js +110 -48
- package/build/server/router/Router.js.map +1 -1
- package/build/server/router/algorithm/Algorithm.d.ts +39 -0
- package/build/server/router/algorithm/Algorithm.js +20 -0
- package/build/server/router/algorithm/Algorithm.js.map +1 -0
- package/build/server/router/algorithm/FIFO.d.ts +15 -0
- package/build/server/router/algorithm/FIFO.js +24 -0
- package/build/server/router/algorithm/FIFO.js.map +1 -0
- package/build/server/router/algorithm/Tree.d.ts +38 -0
- package/build/server/router/algorithm/Tree.js +126 -0
- package/build/server/router/algorithm/Tree.js.map +1 -0
- package/build/server/router/middleware/WsMiddleware.js +1 -1
- package/build/server/router/middleware/WsMiddleware.js.map +1 -1
- package/build/utilities/Flatten.d.ts +56 -0
- package/build/utilities/Flatten.js +59 -0
- package/build/utilities/Flatten.js.map +1 -0
- package/build/utilities/Utilities.d.ts +7 -58
- package/build/utilities/Utilities.js +8 -33
- package/build/utilities/Utilities.js.map +1 -1
- package/build/utilities/schema/Introspection.d.ts +24 -0
- package/build/utilities/schema/Introspection.js +87 -0
- package/build/utilities/schema/Introspection.js.map +1 -0
- package/build/utilities/schema/JSONSchema.d.ts +68 -0
- package/build/utilities/schema/JSONSchema.js +13 -0
- package/build/utilities/schema/JSONSchema.js.map +1 -0
- package/build/utilities/schema/Schema.d.ts +253 -0
- package/build/utilities/schema/Schema.js +241 -0
- package/build/utilities/schema/Schema.js.map +1 -0
- package/build/utilities/schema/SchemaError.d.ts +10 -0
- package/build/utilities/schema/SchemaError.js +13 -0
- package/build/utilities/schema/SchemaError.js.map +1 -0
- package/build/utilities/schema/Validator.d.ts +94 -0
- package/build/utilities/schema/Validator.js +246 -0
- package/build/utilities/schema/Validator.js.map +1 -0
- package/package.json +1 -1
- package/tests/config/config.js +233 -0
- package/tests/router.js +596 -0
- package/tests/schema/schema.js +368 -0
- package/tests/test.env +0 -0
- package/tests/test.js +3 -3
- package/build/server/config/ConfigLoader.js.map +0 -1
- package/build/server/config/ConfigValidator.d.ts +0 -71
- package/build/server/config/ConfigValidator.js +0 -131
- package/build/server/config/ConfigValidator.js.map +0 -1
- package/examples/in-docs.js +0 -96
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @author NetFeez <netfeez.dev@gmail.com>
|
|
3
|
+
* @description Provides utilities for validating the structure of a schema, ensuring that property definitions are consistent and valid according to their types and constraints.
|
|
4
|
+
* @license Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { SchemaError } from './SchemaError.js';
|
|
7
|
+
export class Validator {
|
|
8
|
+
/**
|
|
9
|
+
* Validates the structure of a schema, used for validating the structure of a schema and nested objects.
|
|
10
|
+
* @param schema The schema to validate
|
|
11
|
+
* @param parentKey The parent key of the schema, used for error messages
|
|
12
|
+
*/
|
|
13
|
+
static validateStructure(schema, parentKey) {
|
|
14
|
+
for (const key in schema) {
|
|
15
|
+
const prop = schema[key];
|
|
16
|
+
this.validateProperty(prop, parentKey ? `${parentKey}.${key}` : key);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Validates a property definition, used for validating the structure of a schema and nested objects.
|
|
21
|
+
* @param prop The property definition to validate
|
|
22
|
+
* @param key The key of the property, used for error messages
|
|
23
|
+
*/
|
|
24
|
+
static validateProperty(prop, key) {
|
|
25
|
+
switch (prop.type) {
|
|
26
|
+
case 'string':
|
|
27
|
+
this.validateStringProperty(prop, key);
|
|
28
|
+
break;
|
|
29
|
+
case 'number':
|
|
30
|
+
this.validateNumberProperty(prop, key);
|
|
31
|
+
break;
|
|
32
|
+
case 'boolean': break;
|
|
33
|
+
case 'array':
|
|
34
|
+
this.validateArrayProperty(prop, key);
|
|
35
|
+
break;
|
|
36
|
+
case 'object':
|
|
37
|
+
this.validateObjectProperty(prop, key);
|
|
38
|
+
break;
|
|
39
|
+
default: throw new SchemaError(`Unknown type for property '${key}'`);
|
|
40
|
+
}
|
|
41
|
+
if ('default' in prop)
|
|
42
|
+
this.validateDefaultValue(prop, key);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Validates a default value against a property definition, used for validating default values.
|
|
46
|
+
* @param prop The property definition to validate against
|
|
47
|
+
* @param key The key of the property, used for error messages
|
|
48
|
+
*/
|
|
49
|
+
static validateDefaultValue(prop, key) {
|
|
50
|
+
if (prop.default === undefined) {
|
|
51
|
+
if (!prop.required)
|
|
52
|
+
return;
|
|
53
|
+
throw new SchemaError(`Property '${key}' default value cannot be undefined`);
|
|
54
|
+
}
|
|
55
|
+
if (prop.default === null) {
|
|
56
|
+
if (prop.nullable)
|
|
57
|
+
return;
|
|
58
|
+
throw new SchemaError(`Property '${key}' default value cannot be null`);
|
|
59
|
+
}
|
|
60
|
+
switch (prop.type) {
|
|
61
|
+
case 'string':
|
|
62
|
+
this.validateString(prop.default, prop, key);
|
|
63
|
+
break;
|
|
64
|
+
case 'number':
|
|
65
|
+
this.validateNumber(prop.default, prop, key);
|
|
66
|
+
break;
|
|
67
|
+
case 'boolean':
|
|
68
|
+
this.validateBoolean(prop.default, prop, key);
|
|
69
|
+
break;
|
|
70
|
+
case 'array':
|
|
71
|
+
this.validateArray(prop.default, prop, key);
|
|
72
|
+
break;
|
|
73
|
+
case 'object':
|
|
74
|
+
this.validateObject(prop.default, prop, key);
|
|
75
|
+
break;
|
|
76
|
+
default: throw new SchemaError(`Unknown type for property '${key}'`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Validates a string property definition, used for validating nested objects.
|
|
81
|
+
* @param prop The string property definition to validate
|
|
82
|
+
* @param key The key of the property, used for error messages
|
|
83
|
+
*/
|
|
84
|
+
static validateStringProperty(prop, key) {
|
|
85
|
+
if (prop.enum !== undefined) {
|
|
86
|
+
if (!Array.isArray(prop.enum) || prop.enum.length === 0) {
|
|
87
|
+
throw new SchemaError(`Property '${key}' enum must be a non-empty array`);
|
|
88
|
+
}
|
|
89
|
+
if (prop.enum.some((value) => typeof value !== 'string')) {
|
|
90
|
+
throw new SchemaError(`Property '${key}' enum values must be strings`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
if (prop.maxLength !== undefined && prop.minLength !== undefined && prop.maxLength < prop.minLength) {
|
|
94
|
+
throw new SchemaError(`Property '${key}' maxLength must be greater than or equal to minLength`);
|
|
95
|
+
}
|
|
96
|
+
if (prop.pattern !== undefined && !(prop.pattern instanceof RegExp)) {
|
|
97
|
+
throw new SchemaError(`Property '${key}' pattern must be a RegExp`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Validates a number property definition, used for validating nested objects.
|
|
102
|
+
* @param prop The number property definition to validate
|
|
103
|
+
* @param key The key of the property, used for error messages
|
|
104
|
+
*/
|
|
105
|
+
static validateNumberProperty(prop, key) {
|
|
106
|
+
if (prop.maximum !== undefined && prop.minimum !== undefined && prop.maximum < prop.minimum) {
|
|
107
|
+
throw new SchemaError(`Property '${key}' maximum must be greater than or equal to minimum`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Validates an array property definition, used for validating nested arrays.
|
|
112
|
+
* @param prop The array property definition to validate
|
|
113
|
+
* @param key The key of the property, used for error messages
|
|
114
|
+
*/
|
|
115
|
+
static validateArrayProperty(prop, key) {
|
|
116
|
+
if (prop.maximum !== undefined && prop.minimum !== undefined && prop.maximum < prop.minimum) {
|
|
117
|
+
throw new SchemaError(`Property '${key}' maximum must be greater than or equal to minimum`);
|
|
118
|
+
}
|
|
119
|
+
this.validateProperty(prop.property, `${key}[]`);
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Validates an object property definition, used for validating nested objects.
|
|
123
|
+
* @param prop The object property definition to validate
|
|
124
|
+
* @param key The key of the property, used for error messages
|
|
125
|
+
*/
|
|
126
|
+
static validateObjectProperty(prop, key) {
|
|
127
|
+
this.validateStructure(prop.schema, key);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Validates a string value against a string property definition, used for validating default values and nested objects.
|
|
131
|
+
* @param value The value to validate
|
|
132
|
+
* @param prop The string property definition to validate against
|
|
133
|
+
* @param key The key of the property, used for error messages
|
|
134
|
+
*/
|
|
135
|
+
static validateString(value, prop, key) {
|
|
136
|
+
if (value == null && prop.nullable === true)
|
|
137
|
+
return;
|
|
138
|
+
if (typeof value !== 'string')
|
|
139
|
+
throw new SchemaError(`Property ${key} must be a string`);
|
|
140
|
+
if (prop.enum !== undefined && !prop.enum.includes(value)) {
|
|
141
|
+
throw new SchemaError(`Property ${key} must be one of: ${prop.enum.join(', ')}`);
|
|
142
|
+
}
|
|
143
|
+
if (prop.minLength !== undefined && value.length < prop.minLength) {
|
|
144
|
+
throw new SchemaError(`Property ${key} must have a minimum length of ${prop.minLength}`);
|
|
145
|
+
}
|
|
146
|
+
if (prop.maxLength !== undefined && value.length > prop.maxLength) {
|
|
147
|
+
throw new SchemaError(`Property ${key} must have a maximum length of ${prop.maxLength}`);
|
|
148
|
+
}
|
|
149
|
+
if (prop.pattern && !prop.pattern.test(value)) {
|
|
150
|
+
throw new SchemaError(`Property ${key} must match the pattern ${prop.pattern}`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Validates a number value against a number property definition, used for validating default values.
|
|
155
|
+
* @param value The value to validate
|
|
156
|
+
* @param prop The number property definition to validate against
|
|
157
|
+
* @param key The key of the property, used for error messages
|
|
158
|
+
*/
|
|
159
|
+
static validateNumber(value, prop, key) {
|
|
160
|
+
if (value == null && prop.nullable === true)
|
|
161
|
+
return;
|
|
162
|
+
if (typeof value !== 'number')
|
|
163
|
+
throw new SchemaError(`Property ${key} must be a number`);
|
|
164
|
+
if (prop.minimum !== undefined && value < prop.minimum) {
|
|
165
|
+
throw new SchemaError(`Property ${key} must be greater than or equal to ${prop.minimum}`);
|
|
166
|
+
}
|
|
167
|
+
if (prop.maximum !== undefined && value > prop.maximum) {
|
|
168
|
+
throw new SchemaError(`Property ${key} must be less than or equal to ${prop.maximum}`);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Validates a boolean value against a boolean property definition, used for validating default values.
|
|
173
|
+
* @param value The value to validate
|
|
174
|
+
* @param prop The boolean property definition to validate against
|
|
175
|
+
* @param key The key of the property, used for error messages
|
|
176
|
+
*/
|
|
177
|
+
static validateBoolean(value, prop, key) {
|
|
178
|
+
if (value == null && prop.nullable === true)
|
|
179
|
+
return;
|
|
180
|
+
if (typeof value !== 'boolean')
|
|
181
|
+
throw new SchemaError(`Property ${key} must be a boolean`);
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Validates an object value against an object property definition, used for validating default values and nested objects.
|
|
185
|
+
* @param value The value to validate
|
|
186
|
+
* @param prop The object property definition to validate against
|
|
187
|
+
* @param key The key of the property, used for error messages
|
|
188
|
+
*/
|
|
189
|
+
static validateObject(value, prop, key) {
|
|
190
|
+
if (value == null && prop.nullable === true)
|
|
191
|
+
return;
|
|
192
|
+
if (typeof value !== 'object' || Array.isArray(value)) {
|
|
193
|
+
throw new SchemaError(`Property ${key} must be an object`);
|
|
194
|
+
}
|
|
195
|
+
this.validateStructure(prop.schema, key);
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Validates an array value against an array property definition, used for validating default values and array items.
|
|
199
|
+
* @param value The value to validate
|
|
200
|
+
* @param prop The array property definition to validate against
|
|
201
|
+
* @param key The key of the property, used for error messages
|
|
202
|
+
*/
|
|
203
|
+
static validateArray(value, prop, key) {
|
|
204
|
+
if (value == null && prop.nullable === true)
|
|
205
|
+
return;
|
|
206
|
+
if (!Array.isArray(value))
|
|
207
|
+
throw new SchemaError(`Property ${key} must be an array`);
|
|
208
|
+
if (prop.minimum !== undefined && value.length < prop.minimum) {
|
|
209
|
+
throw new SchemaError(`Property ${key} must have at least ${prop.minimum} items`);
|
|
210
|
+
}
|
|
211
|
+
if (prop.maximum !== undefined && value.length > prop.maximum) {
|
|
212
|
+
throw new SchemaError(`Property ${key} must have at most ${prop.maximum} items`);
|
|
213
|
+
}
|
|
214
|
+
value.forEach((item, index) => {
|
|
215
|
+
this.validateValue(item, prop.property, `${key}[${index}]`);
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Validates a value against a property definition, used for validating default values and array items.
|
|
220
|
+
* @param value The value to validate
|
|
221
|
+
* @param prop The property definition to validate against
|
|
222
|
+
* @param key The key of the property, used for error messages
|
|
223
|
+
*/
|
|
224
|
+
static validateValue(value, prop, key) {
|
|
225
|
+
switch (prop.type) {
|
|
226
|
+
case 'string':
|
|
227
|
+
this.validateString(value, prop, key);
|
|
228
|
+
break;
|
|
229
|
+
case 'number':
|
|
230
|
+
this.validateNumber(value, prop, key);
|
|
231
|
+
break;
|
|
232
|
+
case 'boolean':
|
|
233
|
+
this.validateBoolean(value, prop, key);
|
|
234
|
+
break;
|
|
235
|
+
case 'array':
|
|
236
|
+
this.validateArray(value, prop, key);
|
|
237
|
+
break;
|
|
238
|
+
case 'object':
|
|
239
|
+
this.validateObject(value, prop, key);
|
|
240
|
+
break;
|
|
241
|
+
default: throw new SchemaError(`Unknown type for property '${key}'`);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
export default Validator;
|
|
246
|
+
//# sourceMappingURL=Validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Validator.js","sourceRoot":"","sources":["../../../src/utilities/schema/Validator.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
import { strict as assert } from 'assert';
|
|
3
|
+
import { promises as FSP } from 'fs';
|
|
4
|
+
|
|
5
|
+
import { Logger } from '../../build/Vortez.js';
|
|
6
|
+
import { Config } from '../../build/server/config/Config.js';
|
|
7
|
+
import { Loader } from '../../build/server/config/Loader.js';
|
|
8
|
+
import { SchemaError } from '../../build/utilities/schema/SchemaError.js';
|
|
9
|
+
|
|
10
|
+
const logger = new Logger({ prefix: 'CONFIG' });
|
|
11
|
+
|
|
12
|
+
let testsPassed = 0;
|
|
13
|
+
let testsFailed = 0;
|
|
14
|
+
|
|
15
|
+
const TMP_DIR = 'tests/.tmp/config-suite';
|
|
16
|
+
const CONFIG_PATH = `${TMP_DIR}/config.json`;
|
|
17
|
+
const BAD_CONFIG_PATH = `${TMP_DIR}/bad.json`;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Logs test results.
|
|
21
|
+
* @param { string } testName The test name.
|
|
22
|
+
* @param { boolean } passed Whether the test passed.
|
|
23
|
+
* @param { unknown | null } error Optional error object for failures.
|
|
24
|
+
*/
|
|
25
|
+
function logTestResult(testName, passed, error = null) {
|
|
26
|
+
if (passed) {
|
|
27
|
+
logger.log(`&C2✓ ${testName}`);
|
|
28
|
+
testsPassed++;
|
|
29
|
+
} else {
|
|
30
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
31
|
+
logger.error(`&C1✗ ${testName}${error ? ': ' + message : ''}`);
|
|
32
|
+
testsFailed++;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async function resetTmpDir() {
|
|
37
|
+
await FSP.rm(TMP_DIR, { recursive: true, force: true });
|
|
38
|
+
await FSP.mkdir(TMP_DIR, { recursive: true });
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Ensures constructor applies default values for missing config keys.
|
|
43
|
+
*/
|
|
44
|
+
function testDefaultConfigValues() {
|
|
45
|
+
try {
|
|
46
|
+
const config = new Config({});
|
|
47
|
+
|
|
48
|
+
assert.equal(config.get('host'), 'localhost');
|
|
49
|
+
assert.equal(config.get('port'), 80);
|
|
50
|
+
assert.equal(config.get('ssl'), null);
|
|
51
|
+
assert.equal(config.get('templates.folder'), './global/Template/Folder.vhtml');
|
|
52
|
+
assert.equal(config.get('templates.error'), './global/Template/Error.vhtml');
|
|
53
|
+
assert.equal(config.get('routing.algorithm'), 'FIFO');
|
|
54
|
+
assert.equal(config.get('logger.showAll'), false);
|
|
55
|
+
assert.equal(config.get('logger.server.show'), true);
|
|
56
|
+
assert.equal(config.get('logger.server.save'), true);
|
|
57
|
+
|
|
58
|
+
logTestResult('constructor - Applies defaults', true);
|
|
59
|
+
} catch (error) {
|
|
60
|
+
logTestResult('constructor - Applies defaults', false, error);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Ensures nested object defaults are filled when object is partially provided.
|
|
66
|
+
*/
|
|
67
|
+
function testNestedSslDefaultPort() {
|
|
68
|
+
try {
|
|
69
|
+
const config = new Config({
|
|
70
|
+
ssl: {
|
|
71
|
+
cert: 'cert-path',
|
|
72
|
+
key: 'key-path'
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
assert.equal(config.get('ssl.cert'), 'cert-path');
|
|
77
|
+
assert.equal(config.get('ssl.key'), 'key-path');
|
|
78
|
+
assert.equal(config.get('ssl.port'), 443);
|
|
79
|
+
|
|
80
|
+
logTestResult('constructor - Nested defaults inside ssl', true);
|
|
81
|
+
} catch (error) {
|
|
82
|
+
logTestResult('constructor - Nested defaults inside ssl', false, error);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Ensures enum constraints are validated.
|
|
88
|
+
*/
|
|
89
|
+
function testRoutingEnumValidation() {
|
|
90
|
+
try {
|
|
91
|
+
assert.throws(
|
|
92
|
+
// @ts-expect-error Runtime validation test with invalid enum on purpose.
|
|
93
|
+
() => new Config({ routing: { algorithm: 'BreadthFirst' } }),
|
|
94
|
+
SchemaError
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
logTestResult('validation - Reject invalid routing algorithm', true);
|
|
98
|
+
} catch (error) {
|
|
99
|
+
logTestResult('validation - Reject invalid routing algorithm', false, error);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Ensures get/set use flattened dot-path keys.
|
|
105
|
+
*/
|
|
106
|
+
function testGetSetFlattenedPaths() {
|
|
107
|
+
try {
|
|
108
|
+
const config = new Config({});
|
|
109
|
+
|
|
110
|
+
config.set('host', '127.0.0.1');
|
|
111
|
+
config.set('routing.algorithm', 'Tree');
|
|
112
|
+
config.set('logger.server.show', false);
|
|
113
|
+
|
|
114
|
+
assert.equal(config.get('host'), '127.0.0.1');
|
|
115
|
+
assert.equal(config.get('routing.algorithm'), 'Tree');
|
|
116
|
+
assert.equal(config.get('logger.server.show'), false);
|
|
117
|
+
|
|
118
|
+
logTestResult('api - Get/Set flattened paths', true);
|
|
119
|
+
} catch (error) {
|
|
120
|
+
logTestResult('api - Get/Set flattened paths', false, error);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Ensures save writes nested JSON and creates missing folders.
|
|
126
|
+
*/
|
|
127
|
+
async function testSaveCreatesFileAndNestedData() {
|
|
128
|
+
try {
|
|
129
|
+
await resetTmpDir();
|
|
130
|
+
|
|
131
|
+
const config = new Config({});
|
|
132
|
+
config.set('host', '0.0.0.0');
|
|
133
|
+
config.set('logger.request.save', false);
|
|
134
|
+
await config.save(CONFIG_PATH);
|
|
135
|
+
|
|
136
|
+
const content = await FSP.readFile(CONFIG_PATH, 'utf8');
|
|
137
|
+
const data = JSON.parse(content);
|
|
138
|
+
|
|
139
|
+
assert.equal(data.host, '0.0.0.0');
|
|
140
|
+
assert.equal(data.logger.request.save, false);
|
|
141
|
+
|
|
142
|
+
logTestResult('save - Writes file and nested json', true);
|
|
143
|
+
} catch (error) {
|
|
144
|
+
logTestResult('save - Writes file and nested json', false, error);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Ensures Loader creates a new file when it does not exist.
|
|
150
|
+
*/
|
|
151
|
+
async function testLoaderCreatesMissingFile() {
|
|
152
|
+
try {
|
|
153
|
+
await resetTmpDir();
|
|
154
|
+
|
|
155
|
+
const loaded = await Loader.load(CONFIG_PATH);
|
|
156
|
+
|
|
157
|
+
assert.ok(loaded instanceof Config);
|
|
158
|
+
assert.equal(loaded.get('host'), 'localhost');
|
|
159
|
+
|
|
160
|
+
const content = await FSP.readFile(CONFIG_PATH, 'utf8');
|
|
161
|
+
const data = JSON.parse(content);
|
|
162
|
+
assert.equal(data.port, 80);
|
|
163
|
+
|
|
164
|
+
logTestResult('loader - Creates missing file with defaults', true);
|
|
165
|
+
} catch (error) {
|
|
166
|
+
logTestResult('loader - Creates missing file with defaults', false, error);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Ensures Loader reads and validates existing config files.
|
|
172
|
+
*/
|
|
173
|
+
async function testLoaderReadsExistingFile() {
|
|
174
|
+
try {
|
|
175
|
+
await resetTmpDir();
|
|
176
|
+
|
|
177
|
+
await FSP.writeFile(
|
|
178
|
+
CONFIG_PATH,
|
|
179
|
+
JSON.stringify({ host: 'example.com', routing: { algorithm: 'Tree' } }, null, 4),
|
|
180
|
+
'utf8'
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
const loaded = await Loader.load(CONFIG_PATH);
|
|
184
|
+
|
|
185
|
+
assert.equal(loaded.get('host'), 'example.com');
|
|
186
|
+
assert.equal(loaded.get('routing.algorithm'), 'Tree');
|
|
187
|
+
|
|
188
|
+
logTestResult('loader - Loads existing file', true);
|
|
189
|
+
} catch (error) {
|
|
190
|
+
logTestResult('loader - Loads existing file', false, error);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Ensures Loader throws when the file contains invalid JSON.
|
|
196
|
+
*/
|
|
197
|
+
async function testLoaderRejectsInvalidJson() {
|
|
198
|
+
try {
|
|
199
|
+
await resetTmpDir();
|
|
200
|
+
await FSP.writeFile(BAD_CONFIG_PATH, '{ "host": "localhost", ', 'utf8');
|
|
201
|
+
|
|
202
|
+
await assert.rejects(() => Loader.load(BAD_CONFIG_PATH));
|
|
203
|
+
|
|
204
|
+
logTestResult('loader - Rejects invalid json file', true);
|
|
205
|
+
} catch (error) {
|
|
206
|
+
logTestResult('loader - Rejects invalid json file', false, error);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
async function runTests() {
|
|
211
|
+
logger.log('\n&C6=== Config Test Suite ===\n');
|
|
212
|
+
|
|
213
|
+
testDefaultConfigValues();
|
|
214
|
+
testNestedSslDefaultPort();
|
|
215
|
+
testRoutingEnumValidation();
|
|
216
|
+
testGetSetFlattenedPaths();
|
|
217
|
+
|
|
218
|
+
await testSaveCreatesFileAndNestedData();
|
|
219
|
+
await testLoaderCreatesMissingFile();
|
|
220
|
+
await testLoaderReadsExistingFile();
|
|
221
|
+
await testLoaderRejectsInvalidJson();
|
|
222
|
+
|
|
223
|
+
await FSP.rm(TMP_DIR, { recursive: true, force: true });
|
|
224
|
+
|
|
225
|
+
logger.log('\n&C6=== Results ===');
|
|
226
|
+
logger.log(`&C2✓ Passed: ${testsPassed}`);
|
|
227
|
+
logger.log(`&C1✗ Failed: ${testsFailed}`);
|
|
228
|
+
logger.log(`&C3Total: ${testsPassed + testsFailed}\n`);
|
|
229
|
+
|
|
230
|
+
process.exit(testsFailed > 0 ? 1 : 0);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
runTests();
|