swagger_generator_flutter/test/simple_generator_test.dart

349 lines
11 KiB
Dart

import 'package:swagger_generator_flutter/core/models.dart';
import 'package:swagger_generator_flutter/generators/model_code_generator.dart';
import 'package:swagger_generator_flutter/generators/retrofit_api_generator.dart';
import 'package:test/test.dart';
void main() {
group('Simple Generator Tests', () {
late SwaggerDocument simpleDocument;
setUp(() {
simpleDocument = SwaggerDocument(
title: 'Simple Test API',
version: '1.0.0',
description: 'A simple test API',
servers: [
const ApiServer(
url: 'https://api.example.com',
description: 'Test server',
),
],
paths: {
const ApiPathKey('/users', HttpMethod.get): const ApiPath(
path: '/users',
method: HttpMethod.get,
summary: 'Get users',
description: 'Get all users',
operationId: 'getUsers',
tags: ['users'],
parameters: [],
responses: {
'200': ApiResponse(
code: '200',
description: 'Success',
content: {
'application/json': ApiMediaType(
schema: {'type': 'array'},
),
},
),
},
),
const ApiPathKey('/users/{id}', HttpMethod.get): const ApiPath(
path: '/users/{id}',
method: HttpMethod.get,
summary: 'Get user by ID',
description: 'Get a specific user',
operationId: 'getUserById',
tags: ['users'],
parameters: [
ApiParameter(
name: 'id',
location: ParameterLocation.path,
required: true,
type: PropertyType.integer,
description: 'User ID',
),
],
responses: {
'200': ApiResponse(
code: '200',
description: 'User found',
content: {
'application/json': ApiMediaType(
schema: {'type': 'object'},
),
},
),
},
),
},
models: {
'User': const ApiModel(
name: 'User',
description: 'User model',
properties: {
'id': ApiProperty(
name: 'id',
type: PropertyType.integer,
description: 'User ID',
required: true,
),
'name': ApiProperty(
name: 'name',
type: PropertyType.string,
description: 'User name',
required: true,
),
},
required: ['id', 'name'],
),
},
controllers: {},
);
});
group('RetrofitApiGenerator Basic Tests', () {
test('generates basic API structure', () {
final generator = RetrofitApiGenerator(
className: 'TestApi',
splitByTags: false,
);
final result = generator.generateFromDocument(simpleDocument);
expect(result, isNotEmpty);
expect(result, contains('TestApi'));
expect(result, contains('@RestApi'));
});
test('generates imports correctly', () {
final generator = RetrofitApiGenerator(splitByTags: false);
final result = generator.generateFromDocument(simpleDocument);
expect(result, contains('import'));
expect(result, contains('Dio'));
expect(result, contains('@RestApi'));
});
test('generates path annotations', () {
final generator = RetrofitApiGenerator(splitByTags: false);
final result = generator.generateFromDocument(simpleDocument);
expect(result, contains('@GET'));
expect(result, contains('/users'));
expect(result, contains('/users/{id}'));
});
test('generates parameter annotations', () {
final generator = RetrofitApiGenerator(splitByTags: false);
final result = generator.generateFromDocument(simpleDocument);
expect(result, contains('@Path'));
expect(result, contains('id'));
});
test('handles split by tags', () {
final generator = RetrofitApiGenerator();
final result = generator.generateFromDocument(simpleDocument);
expect(result, isNotEmpty);
// Should generate modular structure when split by tags
});
});
group('Code Quality Tests', () {
test('generated code has proper structure', () {
final generator = RetrofitApiGenerator(splitByTags: false);
final result = generator.generateFromDocument(simpleDocument);
// Check for basic Dart syntax
expect(result, isNot(contains(';;'))); // No double semicolons
expect(result, isNot(contains(',,'))); // No double commas
// Check for proper class declarations
final classCount = 'class '.allMatches(result).length;
final abstractClassCount = 'abstract class '.allMatches(result).length;
expect(classCount + abstractClassCount, greaterThan(0));
});
test('handles empty paths gracefully', () {
const emptyDocument = SwaggerDocument(
title: 'Empty API',
version: '1.0.0',
description: 'Empty API',
paths: {},
models: {},
controllers: {},
);
final generator = RetrofitApiGenerator(splitByTags: false);
final result = generator.generateFromDocument(emptyDocument);
expect(result, isNotEmpty);
});
test('handles special characters in API names', () {
final specialDocument = SwaggerDocument(
title: 'API-with_Special.Characters',
version: '1.0.0',
description: 'Test',
paths: {
const ApiPathKey('/special-endpoint', HttpMethod.get):
const ApiPath(
path: '/special-endpoint',
method: HttpMethod.get,
summary: 'Special endpoint',
description: 'Test',
operationId: 'getSpecial',
tags: ['special'],
parameters: [],
responses: {
'200': ApiResponse(
code: '200',
description: 'Success',
),
},
),
},
models: {},
controllers: {},
);
final generator = RetrofitApiGenerator(splitByTags: false);
expect(
() => generator.generateFromDocument(specialDocument),
returnsNormally,
);
});
test('handles nullable parameters correctly', () {
final documentWithOptionalParams = SwaggerDocument(
title: 'Test API',
version: '1.0.0',
description: 'Test',
paths: {
const ApiPathKey('/search', HttpMethod.get): const ApiPath(
path: '/search',
method: HttpMethod.get,
summary: 'Search',
description: 'Search endpoint',
operationId: 'search',
tags: ['search'],
parameters: [
ApiParameter(
name: 'query',
location: ParameterLocation.query,
required: true,
type: PropertyType.string,
description: 'Search query',
),
ApiParameter(
name: 'page',
location: ParameterLocation.query,
required: false,
type: PropertyType.integer,
description: 'Page number',
),
],
responses: {
'200': ApiResponse(
code: '200',
description: 'Success',
),
},
),
},
models: {},
controllers: {},
);
final generator = RetrofitApiGenerator(splitByTags: false);
final result =
generator.generateFromDocument(documentWithOptionalParams);
// Required parameters should not be nullable
expect(result, contains('String query'));
// Optional parameters should be nullable
expect(result, contains('int? page'));
});
});
group('Performance Tests', () {
test('handles medium-sized documents efficiently', () {
// Create a document with multiple paths
final paths = <ApiPathKey, ApiPath>{};
for (var i = 0; i < 50; i++) {
final key = ApiPathKey.from('/resource$i', HttpMethod.get);
paths[key] = ApiPath(
path: '/resource$i',
method: HttpMethod.get,
summary: 'Get resource $i',
description: 'Get resource $i',
operationId: 'getResource$i',
tags: ['resources'],
parameters: [],
responses: {
'200': const ApiResponse(
code: '200',
description: 'Success',
),
},
);
}
final largeDocument = SwaggerDocument(
title: 'Large API',
version: '1.0.0',
description: 'Large API',
servers: [],
paths: paths,
models: {},
controllers: {},
security: [],
);
final generator = RetrofitApiGenerator(splitByTags: false);
final stopwatch = Stopwatch()..start();
final result = generator.generateFromDocument(largeDocument);
stopwatch.stop();
expect(result, isNotEmpty);
expect(
stopwatch.elapsedMilliseconds,
lessThan(5000),
); // Should complete within 5 seconds
expect(
result.length,
greaterThan(1000),
); // Should generate substantial code
});
test('memory usage is reasonable', () {
final generator = RetrofitApiGenerator();
final result = generator.generateFromDocument(simpleDocument);
// Basic memory usage check - result should not be excessively large
expect(
result.length,
lessThan(100000),
); // Less than 100KB for simple document
});
});
group('ModelCodeGenerator Tests', () {
test('generates Freezed model structure', () {
final generator = ModelCodeGenerator(simpleDocument);
final result =
generator.generateSingleModelFile(simpleDocument.models['User']!);
expect(result, contains('@freezed'));
expect(result, contains("part 'user.freezed.dart';"));
expect(result, contains("part 'user.g.dart';"));
expect(result, contains('const factory User({'));
expect(
result,
contains('factory User.fromJson(Map<String, dynamic> json)'),
);
});
});
});
}