Skip to content

Commit afc0e9b

Browse files
committed
ut increase
Signed-off-by: xil <fridalu66@gmail.com>
1 parent 2ffa4c7 commit afc0e9b

2 files changed

Lines changed: 632 additions & 1 deletion

File tree

tools/proto-convert/test/SchemaModifier.test.ts

Lines changed: 269 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -648,7 +648,7 @@ describe('SchemaModifier', () => {
648648
expect(schema.$ref).toBe('#/components/schemas/SortOrderSingleMap');
649649
expect(schema.type).toBeUndefined();
650650
expect(schema.properties).toBeUndefined();
651-
651+
652652
// New SortOrderSingleMap schema should be created
653653
expect(doc.components!.schemas!.SortOrderSingleMap).toBeDefined();
654654
const mapSchema = doc.components!.schemas!.SortOrderSingleMap as OpenAPIV3.SchemaObject;
@@ -737,6 +737,71 @@ describe('SchemaModifier', () => {
737737

738738
expect(schema.additionalProperties).toBeDefined();
739739
});
740+
741+
it('should use inline modification for QueryContainer properties', () => {
742+
const doc = createDocument();
743+
doc.components!.schemas!.BoolQuery = {
744+
type: 'object',
745+
properties: {
746+
must: {
747+
type: 'array',
748+
items: { type: 'string' }
749+
}
750+
}
751+
};
752+
753+
const modifier = new SchemaModifier(doc);
754+
const visit = new Set();
755+
756+
const schema: any = {
757+
type: 'object',
758+
additionalProperties: {
759+
$ref: '#/components/schemas/BoolQuery'
760+
},
761+
minProperties: 1,
762+
maxProperties: 1
763+
};
764+
765+
// Pass 'QueryContainer' as parent schema name
766+
modifier.simplifySingleMapSchema(schema, visit, 'QueryContainer');
767+
768+
// Should use old inline behavior - becomes a $ref directly (no SingleMap wrapper)
769+
expect(schema.$ref).toBe('#/components/schemas/BoolQuery');
770+
expect(doc.components!.schemas!.BoolQuerySingleMap).toBeUndefined();
771+
772+
// Properties should be deleted
773+
expect(schema.type).toBeUndefined();
774+
expect(schema.additionalProperties).toBeUndefined();
775+
expect(schema.minProperties).toBeUndefined();
776+
expect(schema.maxProperties).toBeUndefined();
777+
});
778+
779+
it('should create SingleMap for non-QueryContainer properties', () => {
780+
const doc = createDocument();
781+
doc.components!.schemas!.SortOrder = {
782+
type: 'string',
783+
enum: ['asc', 'desc']
784+
};
785+
786+
const modifier = new SchemaModifier(doc);
787+
const visit = new Set();
788+
789+
const schema: any = {
790+
type: 'object',
791+
additionalProperties: {
792+
$ref: '#/components/schemas/SortOrder'
793+
},
794+
minProperties: 1,
795+
maxProperties: 1
796+
};
797+
798+
// Pass a different parent schema name (not QueryContainer)
799+
modifier.simplifySingleMapSchema(schema, visit, 'AggregateOrder');
800+
801+
// Should use new SingleMap behavior
802+
expect(schema.$ref).toBe('#/components/schemas/SortOrderSingleMap');
803+
expect(doc.components!.schemas!.SortOrderSingleMap).toBeDefined();
804+
});
740805
});
741806

742807
describe('convertAdditionalPropertiesToProperty - edge cases', () => {
@@ -894,5 +959,208 @@ describe('SchemaModifier', () => {
894959
expect(result).toHaveProperty('properties');
895960
expect((result as any).properties).toHaveProperty('customValue');
896961
});
962+
963+
it('should handle oneOf schemas recursively', () => {
964+
const doc = createDocument();
965+
doc.components!.schemas!.OptionA = {
966+
type: 'object',
967+
properties: { a: { type: 'string' } }
968+
};
969+
doc.components!.schemas!.OptionB = {
970+
type: 'object',
971+
properties: { b: { type: 'number' } }
972+
};
973+
doc.components!.schemas!.UnionType = {
974+
oneOf: [
975+
{ $ref: '#/components/schemas/OptionA' },
976+
{ $ref: '#/components/schemas/OptionB' }
977+
]
978+
};
979+
980+
const modifier = new SchemaModifier(doc);
981+
const visit = new Set();
982+
983+
const schema = { $ref: '#/components/schemas/UnionType' };
984+
modifier.reconstructAdditionalPropertySchema(schema, visit);
985+
986+
const optionA = doc.components!.schemas!.OptionA as any;
987+
const optionB = doc.components!.schemas!.OptionB as any;
988+
989+
// Both options should have the field property added
990+
expect(optionA.properties).toHaveProperty('field');
991+
expect(optionB.properties).toHaveProperty('field');
992+
});
993+
994+
it('should handle anyOf schemas recursively', () => {
995+
const doc = createDocument();
996+
doc.components!.schemas!.OptionC = {
997+
type: 'object',
998+
properties: { c: { type: 'string' } }
999+
};
1000+
doc.components!.schemas!.OptionD = {
1001+
type: 'object',
1002+
properties: { d: { type: 'number' } }
1003+
};
1004+
doc.components!.schemas!.FlexibleType = {
1005+
anyOf: [
1006+
{ $ref: '#/components/schemas/OptionC' },
1007+
{ $ref: '#/components/schemas/OptionD' }
1008+
]
1009+
};
1010+
1011+
const modifier = new SchemaModifier(doc);
1012+
const visit = new Set();
1013+
1014+
const schema = { $ref: '#/components/schemas/FlexibleType' };
1015+
modifier.reconstructAdditionalPropertySchema(schema, visit);
1016+
1017+
const optionC = doc.components!.schemas!.OptionC as any;
1018+
const optionD = doc.components!.schemas!.OptionD as any;
1019+
1020+
// Both options should have the field property added
1021+
expect(optionC.properties).toHaveProperty('field');
1022+
expect(optionD.properties).toHaveProperty('field');
1023+
});
1024+
1025+
it('should return original schema if already visited', () => {
1026+
const doc = createDocument();
1027+
doc.components!.schemas!.TestSchema = {
1028+
type: 'object',
1029+
properties: { test: { type: 'string' } }
1030+
};
1031+
1032+
const modifier = new SchemaModifier(doc);
1033+
const visit = new Set();
1034+
1035+
const schema = { $ref: '#/components/schemas/TestSchema' };
1036+
const resolvedSchema = doc.components!.schemas!.TestSchema;
1037+
1038+
visit.add(resolvedSchema);
1039+
1040+
const result = modifier.reconstructAdditionalPropertySchema(schema, visit);
1041+
1042+
// Should return original schema without modification
1043+
expect(result).toBe(schema);
1044+
expect((resolvedSchema as any).properties).not.toHaveProperty('field');
1045+
});
1046+
1047+
it('should handle primitive types without title', () => {
1048+
const doc = createDocument();
1049+
const modifier = new SchemaModifier(doc);
1050+
const visit = new Set();
1051+
1052+
const schema: any = { type: 'number' };
1053+
const result = modifier.reconstructAdditionalPropertySchema(schema, visit);
1054+
1055+
expect(result).toHaveProperty('properties');
1056+
expect((result as any).properties).toHaveProperty('value');
1057+
});
1058+
1059+
it('should log error when field property already exists', () => {
1060+
const doc = createDocument();
1061+
doc.components!.schemas!.ConflictSchema = {
1062+
type: 'object',
1063+
properties: {
1064+
field: { type: 'string' },
1065+
existing: { type: 'number' }
1066+
}
1067+
};
1068+
1069+
const modifier = new SchemaModifier(doc);
1070+
const visit = new Set();
1071+
1072+
const schema = { $ref: '#/components/schemas/ConflictSchema' };
1073+
1074+
const errorSpy = jest.spyOn(console, 'error').mockImplementation();
1075+
1076+
modifier.reconstructAdditionalPropertySchema(schema, visit);
1077+
1078+
expect(errorSpy).toHaveBeenCalled();
1079+
errorSpy.mockRestore();
1080+
});
1081+
});
1082+
1083+
describe('getTypeName', () => {
1084+
it('should extract name from $ref', () => {
1085+
const doc = createDocument();
1086+
const modifier = new SchemaModifier(doc) as any;
1087+
1088+
const schema = { $ref: '#/components/schemas/TestType' };
1089+
const result = modifier.getTypeName(schema);
1090+
1091+
expect(result).toBe('TestType');
1092+
});
1093+
1094+
it('should extract name from title', () => {
1095+
const doc = createDocument();
1096+
const modifier = new SchemaModifier(doc) as any;
1097+
1098+
const schema: OpenAPIV3.SchemaObject = { type: 'object', title: 'CustomTitle' };
1099+
const result = modifier.getTypeName(schema);
1100+
1101+
expect(result).toBe('CustomTitle');
1102+
});
1103+
1104+
it('should return null if no $ref or title', () => {
1105+
const doc = createDocument();
1106+
const modifier = new SchemaModifier(doc) as any;
1107+
1108+
const schema: OpenAPIV3.SchemaObject = { type: 'string' };
1109+
const result = modifier.getTypeName(schema);
1110+
1111+
expect(result).toBeNull();
1112+
});
1113+
});
1114+
1115+
describe('createAdditionalPropertySchema', () => {
1116+
it('should create schema with field property', () => {
1117+
const doc = createDocument();
1118+
const modifier = new SchemaModifier(doc) as any;
1119+
1120+
const result = modifier.createAdditionalPropertySchema();
1121+
1122+
expect(result.type).toBe('object');
1123+
expect(result.properties).toHaveProperty('field');
1124+
expect(result.properties!.field).toEqual({ type: 'string' });
1125+
});
1126+
});
1127+
1128+
describe('isArraySchemaObject', () => {
1129+
it('should return true for array schema with items', () => {
1130+
const doc = createDocument();
1131+
const modifier = new SchemaModifier(doc) as any;
1132+
1133+
const schema: OpenAPIV3.ArraySchemaObject = {
1134+
type: 'array',
1135+
items: { type: 'string' }
1136+
};
1137+
1138+
const result = modifier.isArraySchemaObject(schema);
1139+
expect(result).toBe(true);
1140+
});
1141+
1142+
it('should return false for non-array schema', () => {
1143+
const doc = createDocument();
1144+
const modifier = new SchemaModifier(doc) as any;
1145+
1146+
const schema: OpenAPIV3.SchemaObject = {
1147+
type: 'object'
1148+
};
1149+
1150+
const result = modifier.isArraySchemaObject(schema);
1151+
expect(result).toBe(false);
1152+
});
1153+
1154+
it('should return false for array without items', () => {
1155+
const doc = createDocument();
1156+
const modifier = new SchemaModifier(doc) as any;
1157+
1158+
const schema: any = {
1159+
type: 'array'
1160+
};
1161+
1162+
const result = modifier.isArraySchemaObject(schema);
1163+
expect(result).toBe(false);
1164+
});
8971165
});
8981166
});

0 commit comments

Comments
 (0)