import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/integration_test.dart'; import 'package:jj_mkvmaker/app/app_controller.dart'; import 'package:jj_mkvmaker/app/settings.dart'; import 'package:jj_mkvmaker/app/version_snapshot.dart'; import 'package:jj_mkvmaker/platform/windows/data_dir_override.dart'; import 'package:jj_mkvmaker/platform/windows/desktop_storage_service.dart'; import 'package:jj_mkvmaker/platform/windows/github_updater.dart'; import 'package:jj_mkvmaker/platform/windows/process_media_tool.dart'; import 'package:jj_mkvmaker/services/platform_services.dart'; import 'package:jj_mkvmaker/ui/theme.dart'; import 'package:jj_mkvmaker/ui/update_dialog.dart'; import 'package:path/path.dart' as p; /// 관리자 지시 (10/20): 정식 판 업데이트 길을 사용자 데이터 없이 끝까지 - 앱 안의 [지금 설치] 를 가짜 누르기로. /// 바깥 스크립트 (tool/update_path_check.ps1) 가 준비 · 확인 · 정리를 하고, 이 시험은 그 사이의 앱 쪽만 한다: /// 예전 판 배포 폴더 (JJ_UPD_APP) · 예전 판 데이터 (JJ_MKVMAKER_DATA) 에서 시험 길 (JJ_UPDATE_LOCAL_ZIP) 로 최신 확인 → 받기 · /// SHA256 · 풀기 → 설정 보관 → 교체 예약 (이 시험 프로세스가 끝나면 교체하고 새 판을 띄움). /// 실제 GitHub · 사용자 %APPDATA% · 시작 메뉴는 건드리지 않는다. 그 환경 변수가 없으면 건너뜀. void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); final env = Platform.environment; final app = env['JJ_UPD_APP'] ?? ''; final from = env['JJ_UPD_FROM'] ?? ''; final skip = !Platform.isWindows || app.isEmpty || from.isEmpty || dataDirOverride == null || (env['JJ_UPDATE_LOCAL_ZIP'] ?? '').isEmpty ? 'JJ_UPD_APP · JJ_UPD_FROM · JJ_MKVMAKER_DATA · JJ_UPDATE_LOCAL_ZIP 이 없음 (tool/update_path_check.ps1 이 준다)' : null; testWidgets('업데이트 길: 시험 길로 [지금 설치] → 설정 보관 → 교체 예약', (t) async { applyDataDirOverride(); final data = dataDirOverride!; VersionSnapshot.instance = VersionSnapshot(data); final work = Directory(p.join(p.dirname(app), 'upd_tmp'))..createSync(recursive: true); final up = GitHubUpdater(appDir: app, versionOverride: from, tempRoot: work.path); final c = AppController(PlatformServices( mediaTool: ProcessMediaTool('x', 'y'), storage: DesktopStorageService(), updater: up), settingsStore: SettingsStore()); await t.runAsync(c.init); expect(c.settings.run.lastRunVersion, from, reason: '예전 판이 쓴 데이터를 읽음'); final r = (await t.runAsync(up.latest))!; expect(r.name, contains('시험 길')); t.view.physicalSize = const Size(1200, 900); t.view.devicePixelRatio = 1; addTearDown(t.view.reset); await t.pumpWidget(MaterialApp( theme: buildTheme(), home: Builder(builder: (ctx) => Scaffold(body: Center(child: FilledButton(onPressed: () => installRelease(ctx, c, r, from), child: const Text('go'))))), )); await t.tap(find.text('go')); Future until(bool Function() done, {int ms = 60000}) async { for (var i = 0; i < ms ~/ 100 && !done(); i++) { await t.runAsync(() => Future.delayed(const Duration(milliseconds: 100))); await t.pump(); } } // 받기 · SHA256 · 풀기 (실제 시간) → "설치 준비 완료" await until(() => find.text('지금 설치').evaluate().isNotEmpty); expect(find.text('지금 설치'), findsOneWidget, reason: '받기 · 검증 끝'); await t.tap(find.text('지금 설치')); await until(() => File(p.join(work.path, 'jj_mkvmaker_update.ps1')).existsSync(), ms: 20000); expect(File(p.join(work.path, 'jj_mkvmaker_update.ps1')).existsSync(), isTrue, reason: '교체 스크립트 예약'); expect(VersionSnapshot.instance!.has(from), isTrue, reason: '지금 판 ($from) 설정 보관'); // ignore: avoid_print print('UPD_SCHEDULED pid=$pid'); }, skip: skip != null, timeout: const Timeout(Duration(minutes: 5))); }