@rosen-bridge/config 0.2.1 → 0.4.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.
@@ -40,6 +40,203 @@ describe('ConfigValidator', () => {
40
40
  testData.apiSchemaDefaultValuePairSample.defaultVal
41
41
  );
42
42
  });
43
+
44
+ /**
45
+ * @target generateDefault({ validate: true }) should fail when defaults violate choices
46
+ * @dependencies
47
+ * @scenario
48
+ * - define a primitive with choices and a wrong default
49
+ * - define a nested array object where a field has choices and wrong default
50
+ * - call generateDefault({ validate: true }) and expect failure
51
+ * @expected
52
+ * - generateDefault with validate should throw
53
+ */
54
+ it(`should fail validate=true when defaults violate choices (primitive and nested)`, async () => {
55
+ const cv1 = new ConfigValidator(
56
+ <ConfigSchema>testData.wrongChoiceDefaultSchema.schema
57
+ );
58
+ expect(() => cv1.generateDefault({ validate: true })).toThrow();
59
+
60
+ const cv2 = new ConfigValidator(
61
+ <ConfigSchema>testData.nestedWrongChoiceDefaultSchema.schema
62
+ );
63
+ expect(() => cv2.generateDefault({ validate: true })).toThrow();
64
+ });
65
+
66
+ /**
67
+ * @target generateDefault should return default values for array fields with
68
+ * string and number items
69
+ * @dependencies
70
+ * @scenario
71
+ * - call generateDefault on schema with array fields
72
+ * - check if correct default value object is returned
73
+ * @expected
74
+ * - correct default value object should have been returned including arrays
75
+ */
76
+ it(`should return default values for array fields with string and number items`, async () => {
77
+ const config = new ConfigValidator(
78
+ <ConfigSchema>testData.arraySchemaDefaultValuePairSample.schema
79
+ );
80
+ expect(config.generateDefault()).toEqual(
81
+ testData.arraySchemaDefaultValuePairSample.defaultVal
82
+ );
83
+ });
84
+
85
+ /**
86
+ * @target generateDefault should handle empty array defaults
87
+ * @dependencies
88
+ * @scenario
89
+ * - call generateDefault on schema with empty array default
90
+ * - check if empty array is included in result
91
+ * @expected
92
+ * - empty array should be included in default values
93
+ */
94
+ it(`should handle empty array defaults`, async () => {
95
+ const config = new ConfigValidator(
96
+ <ConfigSchema>testData.emptyArrayDefaultsPair.schema
97
+ );
98
+ const result = config.generateDefault();
99
+ expect(result).toEqual(testData.emptyArrayDefaultsPair.defaultVal);
100
+ });
101
+
102
+ /**
103
+ * @target generateDefault should exclude arrays without default values
104
+ * @dependencies
105
+ * @scenario
106
+ * - call generateDefault on schema with array field without default
107
+ * - check if array field is excluded from result
108
+ * @expected
109
+ * - array field without default should be excluded from result
110
+ */
111
+ it(`should exclude arrays without default values`, async () => {
112
+ const config = new ConfigValidator(
113
+ <ConfigSchema>testData.arrayWithoutDefaultPair.schema
114
+ );
115
+ const result = config.generateDefault();
116
+ expect(result).toEqual(testData.arrayWithoutDefaultPair.defaultVal);
117
+ expect(result).not.toHaveProperty('arrayWithoutDefault');
118
+ });
119
+
120
+ /**
121
+ * @target generateDefault should merge array of object item defaults with provided elements
122
+ * @dependencies
123
+ * @scenario
124
+ * - define an array of object items with item-level defaults
125
+ * - provide array default with elements that override some fields
126
+ * - call generateDefault
127
+ * @expected
128
+ * - each element is merged with object item defaults
129
+ */
130
+ it(`should merge array of object item defaults with provided elements`, async () => {
131
+ const config = new ConfigValidator(
132
+ <ConfigSchema>testData.logsArraySchemaDefaultsPair.schema
133
+ );
134
+ const result = config.generateDefault();
135
+ expect(result).toEqual(testData.logsArraySchemaDefaultsPair.defaultVal);
136
+ });
137
+
138
+ /**
139
+ * @target generateDefault should not validate array item defaults; validateConfig should catch it
140
+ * @dependencies
141
+ * @scenario
142
+ * - define an array of object items with validations (choices/required)
143
+ * - provide an invalid array default (e.g., wrong choice and missing required)
144
+ * - call generateDefault and ensure it returns merged defaults
145
+ * - call validateConfig and ensure it throws
146
+ * @expected
147
+ * - generateDefault should succeed and return merged values
148
+ * - validateConfig should throw due to schema violations in defaults
149
+ */
150
+ it(`should not validate array item defaults; validateConfig should catch it`, async () => {
151
+ const confValidator = new ConfigValidator(
152
+ <ConfigSchema>testData.invalidLogsArrayDefaultsPair.schema
153
+ );
154
+ const generated = confValidator.generateDefault();
155
+ expect(generated).toEqual(
156
+ testData.invalidLogsArrayDefaultsPair.defaultVal
157
+ );
158
+ expect(() => confValidator.validateConfig(generated)).toThrow();
159
+ });
160
+
161
+ /**
162
+ * @target generateDefault with validate option should throw for invalid defaults
163
+ * @dependencies
164
+ * @scenario
165
+ * - define invalid defaults (choices violation and missing required)
166
+ * - call generateDefault({ validate: true })
167
+ * @expected
168
+ * - generation should throw due to validation
169
+ */
170
+ it(`should throw when generateDefault is called with validate option and defaults are invalid`, async () => {
171
+ const confValidator = new ConfigValidator(
172
+ <ConfigSchema>testData.invalidDefaultsValidateOptionSchema.schema
173
+ );
174
+ expect(() => confValidator.generateDefault({ validate: true })).toThrow();
175
+ });
176
+
177
+ /**
178
+ * @target generateDefault should carry unknown keys in array item defaults; schema ignores them
179
+ * @dependencies
180
+ * @scenario
181
+ * - define an array of object items with known keys (path, level)
182
+ * - provide defaults containing an unknown key (pathsskddkfjd)
183
+ * - call generateDefault and ensure unknown key is preserved alongside item defaults
184
+ * - call validateConfig and ensure no error is thrown (unknown keys are ignored by schema)
185
+ * @expected
186
+ * - generateDefault returns merged defaults plus unknown key
187
+ * - validateConfig does not throw
188
+ */
189
+ it(`should reject schema defaults with unknown keys at schema validation time`, async () => {
190
+ expect(
191
+ () =>
192
+ new ConfigValidator(
193
+ <ConfigSchema>testData.unknownKeyLogsArrayDefaultsPair.schema
194
+ )
195
+ ).toThrow('key is not found in the schema');
196
+ });
197
+
198
+ /**
199
+ * @target generateDefault should handle nested array fields inside array item objects
200
+ * @dependencies
201
+ * @scenario
202
+ * - define an array of objects; each object has a nested array field
203
+ * - provide array default with and without the nested array specified
204
+ * - call generateDefault
205
+ * @expected
206
+ * - item-level non-array defaults are merged
207
+ * - nested array schema default is not merged by current implementation
208
+ * - nested array provided in defaults is preserved
209
+ */
210
+ it(`should handle nested array field inside array item objects`, async () => {
211
+ const confValidator = new ConfigValidator(
212
+ <ConfigSchema>testData.nestedArrayInArrayDefaultsPair.schema
213
+ );
214
+ const result = confValidator.generateDefault();
215
+ expect(result).toEqual(
216
+ testData.nestedArrayInArrayDefaultsPair.defaultVal
217
+ );
218
+ });
219
+
220
+ /**
221
+ * @target generateDefault should omit required fields without defaults and validation should fail
222
+ * @dependencies
223
+ * @scenario
224
+ * - define a required field without default
225
+ * - call generateDefault and ensure the field is not present
226
+ * - call validateConfig and ensure it throws due to missing required value
227
+ * @expected
228
+ * - defaults omit the field
229
+ * - validation throws
230
+ */
231
+ it(`should omit required fields without defaults and fail validation`, async () => {
232
+ const confValidator = new ConfigValidator(
233
+ <ConfigSchema>testData.requiredWithoutDefaultSchema.schema
234
+ );
235
+ const defaults = confValidator.generateDefault();
236
+ expect(defaults).toEqual({});
237
+ expect(() => confValidator.validateConfig(defaults)).toThrow();
238
+ expect(() => confValidator.generateDefault({ validate: true })).toThrow();
239
+ });
43
240
  });
44
241
 
45
242
  describe('validateSchema', () => {
@@ -54,7 +251,9 @@ describe('ConfigValidator', () => {
54
251
  * - no errors should be thrown
55
252
  */
56
253
  it(`should not throw any exceptions when a correct schema is passed`, async () => {
57
- new ConfigValidator(<ConfigSchema>testData.correctApiSchema);
254
+ expect(() => {
255
+ new ConfigValidator(<ConfigSchema>testData.correctApiSchema);
256
+ }).not.toThrow();
58
257
  });
59
258
 
60
259
  /**
@@ -114,6 +313,126 @@ describe('ConfigValidator', () => {
114
313
  )
115
314
  ).toThrow();
116
315
  });
316
+
317
+ /**
318
+ * @target validateSchema should pass when array primitive defaults match items type
319
+ * @dependencies
320
+ * @scenario
321
+ * - construct ConfigValidator with a valid array primitive default
322
+ * @expected
323
+ * - no error thrown
324
+ */
325
+ it(`should pass when array primitive defaults match items type`, async () => {
326
+ expect(() => {
327
+ new ConfigValidator(
328
+ <ConfigSchema>testData.arrayPrimitiveDefaultsValid.schema
329
+ );
330
+ }).not.toThrow();
331
+ });
332
+
333
+ /**
334
+ * @target validateSchema should fail when array primitive defaults mismatch items type
335
+ * @dependencies
336
+ * @scenario
337
+ * - construct ConfigValidator with an invalid array primitive default
338
+ * @expected
339
+ * - error thrown
340
+ */
341
+ it(`should fail when array primitive defaults mismatch items type`, async () => {
342
+ expect(
343
+ () =>
344
+ new ConfigValidator(
345
+ <ConfigSchema>testData.arrayPrimitiveDefaultsInvalid.schema
346
+ )
347
+ ).toThrow();
348
+ });
349
+
350
+ /**
351
+ * @target validateSchema should fail when array object defaults have invalid child types
352
+ * @dependencies
353
+ * @scenario
354
+ * - construct ConfigValidator with an invalid array object default
355
+ * @expected
356
+ * - error thrown
357
+ */
358
+ it(`should fail when array object defaults have invalid child types`, async () => {
359
+ expect(
360
+ () =>
361
+ new ConfigValidator(
362
+ <ConfigSchema>testData.arrayObjectDefaultsInvalidChildType.schema
363
+ )
364
+ ).toThrow();
365
+ });
366
+
367
+ /**
368
+ * @target validateSchema should fail when nested array defaults have invalid element types
369
+ * @dependencies
370
+ * @scenario
371
+ * - construct ConfigValidator with invalid nested array defaults
372
+ * @expected
373
+ * - error thrown
374
+ */
375
+ it(`should fail when nested array defaults have invalid element types`, async () => {
376
+ expect(
377
+ () =>
378
+ new ConfigValidator(
379
+ <ConfigSchema>testData.nestedArrayDefaultsInvalid.schema
380
+ )
381
+ ).toThrow();
382
+ });
383
+
384
+ /**
385
+ * @target validateSchema should pass when nested array defaults are valid
386
+ * @dependencies
387
+ * @scenario
388
+ * - construct ConfigValidator with valid nested array defaults
389
+ * @expected
390
+ * - no error thrown
391
+ */
392
+ it(`should pass when nested array defaults are valid`, async () => {
393
+ expect(() => {
394
+ new ConfigValidator(
395
+ <ConfigSchema>testData.nestedArrayDefaultsValid.schema
396
+ );
397
+ }).not.toThrow();
398
+ });
399
+
400
+ /**
401
+ * @target validateSchema should validate nested array of objects defaults (pass)
402
+ * @dependencies
403
+ * @scenario
404
+ * - array of objects, with a key that is an array of objects with defaults
405
+ * - construct ConfigValidator and then generate defaults to ensure merge works
406
+ * @expected
407
+ * - constructor succeeds
408
+ * - defaults merged as expected
409
+ */
410
+ it(`should pass for nested array of objects defaults`, async () => {
411
+ const cv = new ConfigValidator(
412
+ <ConfigSchema>testData.nestedArrayOfObjectsDefaultsValid.schema
413
+ );
414
+ const defaults = cv.generateDefault();
415
+ expect(defaults).toEqual(
416
+ testData.nestedArrayOfObjectsDefaultsValid.defaultVal
417
+ );
418
+ });
419
+
420
+ /**
421
+ * @target validateSchema should validate nested array of objects defaults (fail)
422
+ * @dependencies
423
+ * @scenario
424
+ * - array of objects, inner array default has invalid element shapes
425
+ * @expected
426
+ * - constructor throws
427
+ */
428
+ it(`should fail for nested array of objects defaults with invalid inner elements`, async () => {
429
+ expect(
430
+ () =>
431
+ new ConfigValidator(
432
+ <ConfigSchema>testData.nestedArrayOfObjectsDefaultsInvalid.schema
433
+ )
434
+ ).toThrow();
435
+ });
117
436
  });
118
437
 
119
438
  describe('validateConfig', () => {
@@ -678,7 +997,7 @@ describe('ConfigValidator', () => {
678
997
 
679
998
  /**
680
999
  * @target validateSchema should not throw exception when "bigint" field is
681
- * passed in string format
1000
+ * passed in string format in config and default field in schema
682
1001
  * @dependencies
683
1002
  * @scenario
684
1003
  * - call validateConfig with the config
@@ -686,15 +1005,16 @@ describe('ConfigValidator', () => {
686
1005
  * @expected
687
1006
  * - exception should not be thrown
688
1007
  */
689
- it(`should not throw exception when "bigint" field is passed in string
690
- format`, async () => {
1008
+ it(`should not throw exception when "bigint" field is passed in string format in config and default field in schema`, async () => {
691
1009
  const confValidator = new ConfigValidator(
692
1010
  <ConfigSchema>testData.apiSchemaConfigPairWithStringBigInt.schema
693
1011
  );
694
1012
 
695
- confValidator.validateConfig(
696
- testData.apiSchemaConfigPairWithStringBigInt.config
697
- );
1013
+ expect(() => {
1014
+ confValidator.validateConfig(
1015
+ testData.apiSchemaConfigPairWithStringBigInt.config
1016
+ );
1017
+ }).not.toThrow();
698
1018
  });
699
1019
 
700
1020
  /**
@@ -826,6 +1146,94 @@ describe('ConfigValidator', () => {
826
1146
  const types = confValidator.generateTSTypes('Infrastructure');
827
1147
  expect(types).toEqual(testData.schemaTypeScriptTypesPair.types);
828
1148
  });
1149
+
1150
+ /**
1151
+ * @target generateTSTypes should generate unique path-based names without numeric suffixes
1152
+ * @dependencies
1153
+ * @scenario
1154
+ * - define a schema with duplicate child keys under different parents
1155
+ * - call generateTSTypes
1156
+ * - check for path-based interface names
1157
+ * @expected
1158
+ * - types should include UserDatabase and ApisExplorer
1159
+ * - types should not include numeric suffixes like Database1/Explorer1
1160
+ */
1161
+ it(`should generate unique path-based names without numeric suffixes`, async () => {
1162
+ const confValidator = new ConfigValidator(
1163
+ <ConfigSchema>testData.duplicateChildKeysSchema.schema
1164
+ );
1165
+ const types = confValidator.generateTSTypes('Infrastructure');
1166
+
1167
+ expect(types).toContain('export interface UserDatabase');
1168
+ expect(types).toContain('export interface ApisExplorer');
1169
+ expect(types).not.toContain('Database1');
1170
+ expect(types).not.toContain('Explorer1');
1171
+ });
1172
+
1173
+ /**
1174
+ * @target generateTSTypes should not emit duplicate interface declarations
1175
+ * @dependencies
1176
+ * @scenario
1177
+ * - define a schema with repeated key names under different parents
1178
+ * - call generateTSTypes
1179
+ * - count interface declarations for each name
1180
+ * @expected
1181
+ * - each interface name should be emitted only once
1182
+ */
1183
+ it(`should not emit duplicate interface declarations`, async () => {
1184
+ const confValidator = new ConfigValidator(
1185
+ <ConfigSchema>testData.duplicateChildKeysSchema.schema
1186
+ );
1187
+ const types = confValidator.generateTSTypes('Infrastructure');
1188
+
1189
+ const countName = (name: string) =>
1190
+ (types.match(new RegExp(`export interface ${name}\\b`, 'g')) || [])
1191
+ .length;
1192
+
1193
+ expect(countName('UserDatabase')).toBe(1);
1194
+ expect(countName('ApisExplorer')).toBe(1);
1195
+ });
1196
+
1197
+ /**
1198
+ * @target generateTSTypes should generate distinct names for identical structures at different paths
1199
+ * @dependencies
1200
+ * @scenario
1201
+ * - define identical object structures under different parents
1202
+ * - call generateTSTypes
1203
+ * - check that interfaces are named by path
1204
+ * @expected
1205
+ * - distinct names should be generated (PrimaryConnection, BackupConnection)
1206
+ */
1207
+ it(`should generate distinct names for identical structures at different paths`, async () => {
1208
+ const confValidator = new ConfigValidator(
1209
+ <ConfigSchema>testData.identicalStructurePathsSchema.schema
1210
+ );
1211
+ const types = confValidator.generateTSTypes('Infrastructure');
1212
+
1213
+ expect(types).toContain('export interface PrimaryConnection');
1214
+ expect(types).toContain('export interface BackupConnection');
1215
+ });
1216
+
1217
+ /**
1218
+ * @target generateTSTypes should name array item object types based on path
1219
+ * @dependencies
1220
+ * @scenario
1221
+ * - define an array of objects at root level
1222
+ * - call generateTSTypes
1223
+ * - check that array item type is generated and referenced correctly
1224
+ * @expected
1225
+ * - Logs array should reference Logs item interface and it should be emitted once
1226
+ */
1227
+ it(`should name array item object types based on path`, async () => {
1228
+ const confValidator = new ConfigValidator(
1229
+ <ConfigSchema>testData.arrayItemsAtRootSchema.schema
1230
+ );
1231
+ const types = confValidator.generateTSTypes('Infrastructure');
1232
+
1233
+ expect(types).toContain('export interface Logs');
1234
+ expect((types.match(/export interface Logs\b/g) || []).length).toBe(1);
1235
+ expect(types).toContain('logs: Logs[]');
1236
+ });
829
1237
  });
830
1238
 
831
1239
  describe('getConfigForLevel', () => {