import 'package:flutter_test/flutter_test.dart'; import 'package:flutter/services.dart'; import 'package:yx_asr/yx_asr.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); group('模型文件路径测试', () { test('应该能够访问库内置的模型文件', () async { // 测试库内置模型文件是否存在 final modelFiles = [ 'packages/yx_asr/assets/models/encoder-epoch-99-avg-1.int8.onnx', 'packages/yx_asr/assets/models/decoder-epoch-99-avg-1.int8.onnx', 'packages/yx_asr/assets/models/joiner-epoch-99-avg-1.int8.onnx', 'packages/yx_asr/assets/models/tokens.txt', ]; for (final filePath in modelFiles) { try { final data = await rootBundle.load(filePath); expect(data.lengthInBytes, greaterThan(0), reason: '模型文件 $filePath 应该存在且不为空'); print('✅ 找到模型文件: $filePath (${data.lengthInBytes} bytes)'); } catch (e) { fail('无法加载模型文件 $filePath: $e'); } } }); test('默认初始化应该使用正确的模型路径', () async { final service = YxAsrService(); // 测试默认初始化方法 try { // 注意:这个测试可能会失败,因为需要实际的sherpa_onnx环境 // 但我们可以验证路径是否正确传递 await service.initializeWithDefaultModel(); } catch (e) { // 预期可能会失败,但错误信息应该包含正确的路径 final errorMessage = e.toString(); print('初始化错误(预期): $errorMessage'); // 验证错误信息不是因为找不到文件 expect( errorMessage.contains('packages/yx_asr/assets/models') || errorMessage.contains('No such file'), isFalse, reason: '错误不应该是因为找不到模型文件路径'); } }); test('自定义路径初始化应该正常工作', () async { final service = YxAsrService(); // 测试使用自定义路径 try { await service .initialize({'modelPath': 'packages/yx_asr/assets/models'}); } catch (e) { final errorMessage = e.toString(); print('自定义路径初始化错误(预期): $errorMessage'); // 验证路径传递正确 expect( errorMessage.contains('packages/yx_asr/assets/models') || errorMessage.contains('No such file'), isFalse, reason: '错误不应该是因为路径问题'); } }); test('验证模型文件的基本格式', () async { // 检查 tokens.txt 文件内容 try { final tokensData = await rootBundle .loadString('packages/yx_asr/assets/models/tokens.txt'); expect(tokensData.isNotEmpty, true, reason: 'tokens.txt 不应该为空'); // tokens.txt 应该包含一些基本的token final lines = tokensData .split('\n') .where((line) => line.trim().isNotEmpty) .toList(); expect(lines.length, greaterThan(10), reason: 'tokens.txt 应该包含足够的token'); print('✅ tokens.txt 验证通过: ${lines.length} 个token'); print(' 前几个token: ${lines.take(5).join(", ")}'); } catch (e) { fail('无法读取或解析 tokens.txt: $e'); } }); test('验证ONNX模型文件格式', () async { // 检查ONNX文件的基本格式 final onnxFiles = [ 'packages/yx_asr/assets/models/encoder-epoch-99-avg-1.int8.onnx', 'packages/yx_asr/assets/models/decoder-epoch-99-avg-1.int8.onnx', 'packages/yx_asr/assets/models/joiner-epoch-99-avg-1.int8.onnx', ]; for (final filePath in onnxFiles) { try { final data = await rootBundle.load(filePath); final bytes = data.buffer.asUint8List(); // ONNX文件应该以特定的魔数开头 expect(bytes.length, greaterThan(100), reason: '$filePath 文件大小应该合理'); // 检查是否是有效的二进制文件 expect(bytes[0], isNot(equals(0)), reason: '$filePath 应该是有效的二进制文件'); print('✅ ONNX文件验证通过: $filePath (${bytes.length} bytes)'); } catch (e) { fail('无法验证ONNX文件 $filePath: $e'); } } }); }); group('路径解析测试', () { test('应该正确构建模型文件的完整路径', () { final basePath = 'packages/yx_asr/assets/models'; final expectedPaths = { 'encoder': '$basePath/encoder-epoch-99-avg-1.int8.onnx', 'decoder': '$basePath/decoder-epoch-99-avg-1.int8.onnx', 'joiner': '$basePath/joiner-epoch-99-avg-1.int8.onnx', 'tokens': '$basePath/tokens.txt', }; for (final entry in expectedPaths.entries) { expect(entry.value.startsWith('packages/yx_asr/'), true, reason: '${entry.key} 路径应该以包名开头'); expect(entry.value.contains('assets/models'), true, reason: '${entry.key} 路径应该包含assets/models'); print('✅ ${entry.key} 路径: ${entry.value}'); } }); test('验证路径格式的一致性', () { final service = YxAsrService(); // 验证默认路径 expect(() => service.initializeWithDefaultModel(), returnsNormally, reason: '默认初始化方法应该可以调用'); // 验证自定义路径 expect( () => service .initialize({'modelPath': 'packages/yx_asr/assets/models'}), returnsNormally, reason: '自定义路径初始化方法应该可以调用'); }); }); }