import 'dart:convert'; import 'dart:io'; import 'package:swagger_generator_flutter/core/models.dart'; import 'package:swagger_generator_flutter/generators/optimized_retrofit_generator.dart'; import 'package:test/test.dart'; void main() { group('OptimizedRetrofitGenerator', () { late OptimizedRetrofitGenerator generator; late SwaggerDocument testDocument; setUp(() { generator = OptimizedRetrofitGenerator( className: 'TestApiService', generateModularApis: true, generateBaseResult: true, generatePagination: true, generateFileUpload: true, ); // 创建测试文档 testDocument = const SwaggerDocument( title: 'Test API', version: '1.0.0', description: 'Test API for generator', servers: [ ApiServer( url: 'https://api.example.com', description: 'Test server', ), ], components: ApiComponents( schemas: {}, securitySchemes: {}, ), paths: { '/api/v1/users/{id}': const ApiPath( path: '/api/v1/users/{id}', method: HttpMethod.get, summary: 'Get user by ID', description: 'Retrieve user information by ID', operationId: 'getUser', tags: ['users'], parameters: [ ApiParameter( name: 'id', location: ParameterLocation.path, required: true, type: PropertyType.integer, description: 'User ID', ), ], responses: { '200': const ApiResponse( code: '200', description: 'Success', content: { 'application/json': const ApiMediaType( schema: {'type': 'object'}, ), }, ), }, ), '/api/v1/users': const ApiPath( path: '/api/v1/users', method: HttpMethod.post, summary: 'Create user', description: 'Create a new user', operationId: 'createUser', tags: ['users'], parameters: [], requestBody: ApiRequestBody( description: 'User data', required: true, content: { 'application/json': const ApiMediaType( schema: {'type': 'object'}, ), }, ), responses: { '201': const ApiResponse( code: '201', description: 'Created', content: { 'application/json': const ApiMediaType( schema: {'type': 'object'}, ), }, ), }, ), '/api/v1/files/upload': const ApiPath( path: '/api/v1/files/upload', method: HttpMethod.post, summary: 'Upload file', description: 'Upload a file', operationId: 'uploadFile', tags: ['files'], parameters: [], requestBody: ApiRequestBody( description: 'File to upload', required: true, content: { 'multipart/form-data': const ApiMediaType( schema: {'type': 'object'}, ), }, ), responses: { '200': const ApiResponse( code: '200', description: 'Success', content: { 'application/json': const ApiMediaType( schema: {'type': 'object'}, ), }, ), }, ), }, models: {}, controllers: {}, security: [], ); }); test('generates optimized code successfully', () { expect( () => generator.generateFromDocument(testDocument), returnsNormally); final generatedCode = generator.generateFromDocument(testDocument); expect(generatedCode, isNotEmpty); print('Generated code length: ${generatedCode.length} characters'); }); test('includes required imports', () { final generatedCode = generator.generateFromDocument(testDocument); expect(generatedCode, contains('import \'package:dio/dio.dart\';')); expect(generatedCode, contains('import \'package:retrofit/retrofit.dart\';')); expect(generatedCode, contains('import \'package:json_annotation/json_annotation.dart\';')); expect(generatedCode, contains('part \'test_api_service_api.g.dart\';')); }); test('generates BaseResult type', () { final generatedCode = generator.generateFromDocument(testDocument); expect(generatedCode, contains('class BaseResult')); expect(generatedCode, contains('final int code;')); expect(generatedCode, contains('final String message;')); expect(generatedCode, contains('final T? data;')); expect(generatedCode, contains('bool get isSuccess => code == 200;')); }); test('generates pagination types', () { final generatedCode = generator.generateFromDocument(testDocument); expect(generatedCode, contains('class BasePageParameter')); expect(generatedCode, contains('class BasePageResult')); expect(generatedCode, contains('final int page;')); expect(generatedCode, contains('final int size;')); expect(generatedCode, contains('final int total;')); expect(generatedCode, contains('int get totalPages')); expect(generatedCode, contains('bool get hasNext')); expect(generatedCode, contains('bool get hasPrevious')); }); test('generates file upload types', () { final generatedCode = generator.generateFromDocument(testDocument); expect(generatedCode, contains('class FileUploadRequest')); expect(generatedCode, contains('class FileUploadResult')); expect(generatedCode, contains('final MultipartFile file;')); expect(generatedCode, contains('final String url;')); expect(generatedCode, contains('final String filename;')); expect(generatedCode, contains('final int size;')); }); test('generates modular APIs', () { final generatedCode = generator.generateFromDocument(testDocument); expect(generatedCode, contains('class UsersApi')); expect(generatedCode, contains('class FilesApi')); expect(generatedCode, contains('class TestApiService')); expect(generatedCode, contains('late final UsersApi users;')); expect(generatedCode, contains('late final FilesApi files;')); }); test('generates API methods with correct annotations', () { final generatedCode = generator.generateFromDocument(testDocument); // GET 方法 expect(generatedCode, contains('@GET(\'/api/v1/users/{id}\')')); expect(generatedCode, contains('@Path(\'id\') int id')); // POST 方法 expect(generatedCode, contains('@POST(\'/api/v1/users\')')); expect(generatedCode, contains('@Body() Map body')); // 文件上传方法 expect(generatedCode, contains('@POST(\'/api/v1/files/upload\')')); expect(generatedCode, contains('@MultiPart()')); expect(generatedCode, contains('@Part() MultipartFile file')); }); test('generates utility classes', () { final generatedCode = generator.generateFromDocument(testDocument); expect(generatedCode, contains('class ApiUtils')); expect(generatedCode, contains('static Future createFileUpload')); expect( generatedCode, contains('static BasePageParameter createPageParam')); }); test('handles method name generation correctly', () { final generatedCode = generator.generateFromDocument(testDocument); expect(generatedCode, contains('Future> getUsers(')); expect(generatedCode, contains('Future> postUsers(')); expect(generatedCode, contains('Future> postFilesUpload(')); }); test('generates single API when modular is disabled', () { final singleApiGenerator = OptimizedRetrofitGenerator( className: 'SingleApiService', generateModularApis: false, ); final generatedCode = singleApiGenerator.generateFromDocument(testDocument); expect(generatedCode, contains('abstract class SingleApiService')); expect(generatedCode, contains('factory SingleApiService(Dio dio')); expect(generatedCode, isNot(contains('class UsersApi'))); expect(generatedCode, isNot(contains('class FilesApi'))); }); test('handles custom base result type', () { final customGenerator = OptimizedRetrofitGenerator( baseResultType: 'CustomResult', pageResultType: 'CustomPageResult', ); final generatedCode = customGenerator.generateFromDocument(testDocument); expect(generatedCode, contains('class CustomResult')); expect(generatedCode, contains('class CustomPageResult')); expect(generatedCode, contains('Future>')); }); test('extracts module names correctly', () { final generator = OptimizedRetrofitGenerator(); // 使用反射或创建测试方法来测试私有方法 // 这里我们通过生成的代码来验证模块名提取是否正确 final generatedCode = generator.generateFromDocument(testDocument); expect(generatedCode, contains('UsersApi')); // /api/v1/users -> Users expect(generatedCode, contains('FilesApi')); // /api/v1/files -> Files }); test('handles different parameter types', () { // 创建包含不同参数类型的测试文档 const complexDocument = SwaggerDocument( title: 'Complex API', version: '1.0.0', description: 'API with complex parameters', servers: [ApiServer(url: 'https://api.example.com')], components: ApiComponents(schemas: {}, securitySchemes: {}), paths: { '/api/v1/search': const ApiPath( path: '/api/v1/search', method: HttpMethod.get, summary: 'Search', description: 'Search with various parameters', 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', ), ApiParameter( name: 'active', location: ParameterLocation.query, required: false, type: PropertyType.boolean, description: 'Filter active items', ), ], responses: { '200': const ApiResponse( code: '200', description: 'Success', content: { 'application/json': const ApiMediaType(schema: {'type': 'object'}), }, ), }, ), }, models: {}, controllers: {}, security: [], ); final generatedCode = generator.generateFromDocument(complexDocument); expect( generatedCode, contains('@Query(\'query\') required String query')); expect(generatedCode, contains('@Query(\'page\') int? page')); expect(generatedCode, contains('@Query(\'active\') bool? active')); }); test('performance test with complex document', () { final stopwatch = Stopwatch()..start(); final generatedCode = generator.generateFromDocument(testDocument); final elapsedMs = stopwatch.elapsedMilliseconds; stopwatch.stop(); print('Generation time: ${elapsedMs}ms'); print('Generated code size: ${generatedCode.length} characters'); expect(elapsedMs, lessThan(1000)); // 应该在1秒内完成 expect(generatedCode.length, greaterThan(1000)); // 应该生成足够的代码 }); }); group('Real Project Integration', () { test('generates code for real swagger.json', () async { // 读取实际的 swagger.json 文件 final file = File('swagger.json'); if (!file.existsSync()) { print('swagger.json not found, skipping real project test'); return; } final jsonString = await file.readAsString(); final swaggerJson = jsonDecode(jsonString) as Map; final document = SwaggerDocument.fromJson(swaggerJson); final generator = OptimizedRetrofitGenerator( className: 'OAMobileApiService', generateModularApis: true, generateBaseResult: true, generatePagination: true, generateFileUpload: true, ); final stopwatch = Stopwatch()..start(); final generatedCode = generator.generateFromDocument(document); final elapsedMs = stopwatch.elapsedMilliseconds; print('Real project generation:'); print(' Time: ${elapsedMs}ms'); print(' Code size: ${generatedCode.length} characters'); print(' Lines: ${generatedCode.split('\n').length}'); expect(generatedCode, isNotEmpty); expect(generatedCode, contains('class OAMobileApiService')); expect(generatedCode, contains('FollowManagerApi')); expect(generatedCode, contains('LoginApi')); expect(generatedCode, contains('IndexApi')); // 可选:将生成的代码写入文件以供检查 // final outputFile = File('generated_oa_mobile_api.dart'); // await outputFile.writeAsString(generatedCode); // print('Generated code written to: ${outputFile.path}'); }); }); }