import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:jj_mkvmaker/app/app_controller.dart'; import 'package:jj_mkvmaker/platform/windows/desktop_storage_service.dart'; import 'package:jj_mkvmaker/platform/windows/process_media_tool.dart'; import 'package:jj_mkvmaker/services/model_store.dart'; import 'package:jj_mkvmaker/services/platform_services.dart'; import 'package:jj_mkvmaker/ui/ai_subtitle_models.dart'; import 'package:path/path.dart' as p; /// 260: 받은 AI 자막 모델 (Whisper · NLLB) 을 앱 안에서 크기 보고 지우기 void main() { late Directory tmp; late ModelStore models; setUp(() async { tmp = Directory.systemTemp.createTempSync('jj_m260_'); models = ModelStore(tmp.path); // whisper base 만 받음 (small 은 받다 만 조각), NLLB 는 Android 가 바꿔 둔 파일까지 File(await models.pathOf(whisperModels[0])) ..createSync(recursive: true) ..writeAsBytesSync(List.filled(3000, 1)); File('${await models.pathOf(whisperModels[1])}.part').writeAsBytesSync(List.filled(500, 1)); final nllb = await models.folderOf(nllbModel); for (final n in ['tokenizer.json', 'encoder_model_quantized_jj2.onnx', 'encoder_model_quantized_jj2.onnx.data', 'decoder_model_merged_quantized_jj2.onnx', 'decoder_model_merged_quantized_jj2.onnx.data']) { File(p.join(nllb, n)) ..createSync(recursive: true) ..writeAsBytesSync(List.filled(1000, 1)); } }); tearDown(() => tmp.deleteSync(recursive: true)); test('크기 · 지우기: 같은 폴더의 다른 Whisper 는 남기고, NLLB 는 폴더째', () async { expect(await models.usedBytes(whisperModels[0]), 3000); expect(await models.usedBytes(whisperModels[1]), 500, reason: '받다 만 조각도 셈'); expect(await models.usedBytes(nllbModel), 5000); await models.remove(whisperModels[0]); expect(File(await models.pathOf(whisperModels[0])).existsSync(), isFalse); expect(File('${await models.pathOf(whisperModels[1])}.part').existsSync(), isTrue, reason: '다른 모델 것은 남김'); await models.remove(nllbModel); expect(Directory(await models.folderOf(nllbModel)).existsSync(), isFalse); expect(await models.usedBytes(nllbModel), 0); }); testWidgets('환경 설정 목록: 받은 것은 크기 · [지우기] → 확인 뒤 지움', (tester) async { final c = AppController(PlatformServices( mediaTool: ProcessMediaTool('x', 'y'), storage: DesktopStorageService(), models: models)); await tester.runAsync(() async { await tester.pumpWidget(MaterialApp(home: Scaffold(body: ListView(children: [AiSubtitleModels(c: c)])))); await Future.delayed(const Duration(milliseconds: 300)); }); await tester.pump(); expect(find.text(whisperModels[0].label), findsOneWidget); expect(find.textContaining('받음'), findsNWidgets(2)); expect(find.textContaining('받다 만 조각'), findsOneWidget); expect(find.text('지우기'), findsNWidgets(3)); await tester.tap(find.text('지우기').last); await tester.pumpAndSettle(); await tester.tap(find.widgetWithText(FilledButton, '지우기')); await tester.pumpAndSettle(); // 지우기는 실제 파일을 하나씩 지운다 - 다 지워질 때까지 실제 시간을 조금씩 준다 final nllbDir = Directory((await tester.runAsync(() => models.folderOf(nllbModel)))!); for (var i = 0; i < 50 && find.textContaining('받지 않음').evaluate().isEmpty; i++) { await tester.runAsync(() => Future.delayed(const Duration(milliseconds: 20))); await tester.pump(); } expect(nllbDir.existsSync(), isFalse); expect(find.text('지우기'), findsNWidgets(2)); expect(find.textContaining('받지 않음'), findsOneWidget); }); }