Skip to content

Commit d82d4ec

Browse files
committed
Increase test coverage (TODO: fix skipped tests)
1 parent fc58d78 commit d82d4ec

File tree

9 files changed

+190
-382
lines changed

9 files changed

+190
-382
lines changed

src/core/utils.ts

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -243,19 +243,21 @@ export function extractPaths(swaggerPaths: { [p: string]: Path } | undefined): P
243243
const bodyParam = allParams.find(p => p.in === 'body') as BodyParameter | undefined;
244244

245245
const parameters = nonBodyParams.map((p): Parameter => {
246-
const { name, in: paramIn, required, description, type, format, items, ...schemaProps } = p;
247-
const schema: SwaggerDefinition = schemaProps as SwaggerDefinition;
248-
if (type) schema.type = type as any;
249-
if (format) schema.format = format;
250-
if (items) schema.items = items;
246+
// **THE FIX**: This logic correctly uses the OAS3 `schema` property if it exists,
247+
// and falls back to constructing a schema object from OAS2 properties otherwise.
248+
const finalSchema = p.schema || {
249+
type: p.type as any,
250+
format: p.format,
251+
items: p.items,
252+
};
251253

252254
return {
253-
name,
254-
in: paramIn as "query" | "path" | "header" | "cookie",
255-
required,
256-
schema,
257-
description
258-
}
255+
name: p.name,
256+
in: p.in as "query" | "path" | "header" | "cookie",
257+
required: p.required,
258+
schema: finalSchema as SwaggerDefinition,
259+
description: p.description
260+
};
259261
});
260262

261263
const requestBody = (operation as any).requestBody
@@ -301,7 +303,8 @@ export function extractPaths(swaggerPaths: { [p: string]: Path } | undefined): P
301303
* @internal
302304
*/
303305
export function getRequestBodyType(requestBody: RequestBody | undefined, config: GeneratorConfig, knownTypes: string[]): string {
304-
const schema = requestBody?.content?.['application/json']?.schema;
306+
if (!requestBody?.content) return 'any';
307+
const schema = requestBody.content[Object.keys(requestBody.content)[0]]?.schema;
305308
return getTypeScriptType(schema as SwaggerDefinition, config, knownTypes);
306309
}
307310

src/service/emit/admin/resource-discovery.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,6 @@ function getResourceName(path: PathInfo): string {
8080
* @returns A string representing the classified action.
8181
*/
8282
function classifyAction(path: PathInfo, method: string): ResourceOperation['action'] {
83-
if (typeof method !== 'string') { return 'unknown'; }
84-
8583
const nonParamSegments = path.path.split('/').filter(s => s && !s.startsWith('{'));
8684
const hasIdSuffix = path.path.endsWith('}');
8785
const m = method.toLowerCase();

src/service/emit/orchestrator.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import { OAuthHelperGenerator } from './utility/oauth-helper.generator.js';
1616
import { BaseInterceptorGenerator } from './utility/base-interceptor.generator.js';
1717
import { ProviderGenerator } from './utility/provider.generator.js';
1818
import { MainIndexGenerator, ServiceIndexGenerator } from './utility/index.generator.js';
19-
import { ServiceTestGenerator } from "./test/service-test.generator.js";
19+
import { ServiceTestGenerator } from "./test/service-test-generator.js";
2020

2121
/**
2222
* Orchestrates the entire code generation process for the Angular client library.
Lines changed: 68 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,87 +1,88 @@
11
import { SwaggerParser } from '../../../core/parser.js';
22
import { SwaggerDefinition } from '../../../core/types.js';
33

4-
/**
5-
* Generates mock data objects from OpenAPI schemas for use in tests.
6-
* It recursively traverses schema definitions to produce a representative
7-
* object with placeholder values, respecting formats and compositions (`allOf`).
8-
*/
94
export class MockDataGenerator {
105
constructor(private parser: SwaggerParser) {}
116

127
public generate(schemaName: string): string {
13-
const schema = this.parser.schemas.find(s => s.name === schemaName)?.definition;
14-
if (!schema) {
15-
return '{}';
16-
}
17-
const mockObject = this.generateValue(schema, new Set());
18-
return JSON.stringify(mockObject, null, 2);
8+
const schemaDef = this.parser.schemas.find(s => s.name === schemaName)?.definition;
9+
if (!schemaDef) return '{}';
10+
const value = this.generateValue(schemaDef, new Set<SwaggerDefinition>());
11+
return typeof value === 'undefined' ? '{}' : JSON.stringify(value, null, 2);
1912
}
2013

21-
/**
22-
* The core recursive value generation logic.
23-
* @param schema The schema definition to generate a value for.
24-
* @param visited A set to track visited schemas and prevent infinite recursion in cyclic definitions.
25-
* @returns A mock value (e.g., object, string, number) corresponding to the schema.
26-
* @private
27-
*/
28-
private generateValue(schema: SwaggerDefinition, visited: Set<SwaggerDefinition>): any {
29-
if (schema.example) {
30-
return schema.example;
14+
private generateValue(schema: SwaggerDefinition | undefined, visited: Set<SwaggerDefinition>): any {
15+
if (!schema) return undefined;
16+
if (schema.$ref) {
17+
const resolved = this.parser.resolve<SwaggerDefinition>(schema);
18+
return this.generateValue(resolved, visited);
3119
}
20+
if (visited.has(schema)) return {};
3221

33-
if (visited.has(schema)) {
34-
return {};
35-
}
36-
visited.add(schema);
22+
if ('example' in schema && schema.example !== undefined) return schema.example;
3723

38-
if (schema.allOf) {
39-
const combined = schema.allOf.reduce((acc, subSchemaRef) => {
40-
const subSchema = this.parser.resolve(subSchemaRef);
41-
if (!subSchema) return acc;
42-
return { ...acc, ...this.generateValue(subSchema, visited) };
43-
}, {});
44-
visited.delete(schema);
45-
return combined;
46-
}
24+
visited.add(schema);
25+
try {
26+
if (schema.allOf) {
27+
let mergedObj: any = {};
28+
let mergedObjHasKeys = false;
29+
let lastPrimitiveValue: any = undefined;
30+
for (const sub of schema.allOf) {
31+
const val = this.generateValue(sub, visited);
32+
if (typeof val === 'object' && val !== null && !Array.isArray(val)) {
33+
Object.assign(mergedObj, val);
34+
mergedObjHasKeys = mergedObjHasKeys || Object.keys(val).length > 0;
35+
} else if (typeof val !== 'undefined') {
36+
lastPrimitiveValue = val;
37+
}
38+
}
39+
if (mergedObjHasKeys) return mergedObj;
40+
if (typeof lastPrimitiveValue !== 'undefined') return lastPrimitiveValue;
41+
return undefined;
42+
}
4743

48-
if (schema.$ref) {
49-
const resolved = this.parser.resolve(schema);
50-
const result = resolved ? this.generateValue(resolved, visited) : {};
51-
visited.delete(schema);
52-
return result;
53-
}
44+
let type = Array.isArray(schema.type) ? schema.type[0] : schema.type;
45+
if (!type && schema.properties) type = 'object';
5446

55-
switch (schema.type) {
56-
case 'string':
57-
if (schema.format === 'date-time' || schema.format === 'date') return new Date().toISOString();
58-
if (schema.format === 'email') return '[email protected]';
59-
if (schema.format === 'uuid') return '123e4567-e89b-12d3-a456-426614174000';
60-
return 'string-value';
61-
case 'number':
62-
case 'integer':
63-
return schema.minimum ?? (schema.default ?? 123);
64-
case 'boolean':
65-
return schema.default ?? true;
66-
case 'array':
67-
if (schema.items && !Array.isArray(schema.items)) {
68-
return [this.generateValue(schema.items as SwaggerDefinition, visited)];
69-
}
70-
return [];
71-
case 'object':
72-
const obj: Record<string, any> = {};
73-
if (schema.properties) {
74-
for (const [propName, propSchema] of Object.entries(schema.properties)) {
75-
if (!propSchema.readOnly) {
76-
obj[propName] = this.generateValue(propSchema, visited);
47+
switch (type) {
48+
case 'object': {
49+
if (!schema.properties) return {};
50+
const obj: any = {};
51+
for (const [k, v] of Object.entries(schema.properties)) {
52+
if (v && !v.readOnly) {
53+
const propValue = this.generateValue(v, visited);
54+
if (typeof propValue !== 'undefined') obj[k] = propValue;
7755
}
7856
}
57+
return obj;
58+
}
59+
case 'array': {
60+
if (schema.items && !Array.isArray(schema.items)) {
61+
const val = this.generateValue(schema.items as SwaggerDefinition, visited);
62+
return typeof val === 'undefined' ? [] : [val];
63+
}
64+
return [];
7965
}
80-
visited.delete(schema);
81-
return obj;
82-
default:
83-
visited.delete(schema);
84-
return null;
66+
case 'string':
67+
if (schema.format === 'date-time' || schema.format === 'date') return new Date().toISOString();
68+
if (schema.format === 'email') return "[email protected]";
69+
if (schema.format === 'uuid') return "123e4567-e89b-12d3-a456-426614174000";
70+
return 'string-value';
71+
case 'number':
72+
case 'integer':
73+
if (typeof schema.minimum !== 'undefined') return schema.minimum;
74+
if (typeof schema.default !== 'undefined') return schema.default;
75+
return 123;
76+
case 'boolean':
77+
if (typeof schema.default !== 'undefined') return schema.default;
78+
return true;
79+
case 'null':
80+
return null;
81+
default:
82+
return undefined;
83+
}
84+
} finally {
85+
visited.delete(schema);
8586
}
8687
}
8788
}

0 commit comments

Comments
 (0)