import 'dart:io'; import 'package:flutter_test/flutter_test.dart'; import 'package:jj_mkvmaker/app/app_controller.dart'; import 'package:jj_mkvmaker/app/live_sync.dart'; import 'package:jj_mkvmaker/app/settings.dart'; import 'package:jj_mkvmaker/core/sync_preview.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/platform_services.dart'; import 'package:path/path.dart' as p; import 'support/rsync_scenes.dart'; /// 관리자 지시 (10/20): 실시간 동기화 (로컬 rsync 쌍) 를 28 의 장면 · 옵션으로 - 결과 트리 = 실제 rsync, /// 지울지 묻는 목록 = rsync 가 지우는 것, 맞춘 뒤 "맞출 것" 이 남지 않음 (거른 것을 기다리는 것으로 세지 않음) void main() { TestWidgetsFlutterBinding.ensureInitialized(); test('실시간 동기화 (로컬 rsync 쌍) 결과 = 실제 rsync 결과 · 지울지 묻는 목록 = rsync 가 지우는 것 (28 의 장면 · 옵션 28개)', () async { final rsync = sceneRsync; if (rsync == null) return markTestSkipped('앱에 든 rsync 가 없음 (tool\\fetch_rsync.ps1)'); final tmp = Directory.systemTemp.createTempSync('jj_livescene_'); addTearDown(() => tmp.deleteSync(recursive: true)); final src = p.join(tmp.path, 'src'), want = p.join(tmp.path, 'rsync'), got = p.join(tmp.path, 'live'); final c = AppController(PlatformServices(mediaTool: ProcessMediaTool('x', 'y'), storage: DesktopStorageService())); // 앱에 든 rsync 를 그대로 (시험 환경에는 앱 폴더 (path_provider) 가 없어 '직접 지정' 으로) c.settings ..rsyncSource = 'custom' ..rsyncPath = rsync; final bad = []; for (final opts in sceneOptions) { writeScene(src, want); final w = await realRsyncTree(rsync, src, want, opts); writeScene(src, got); final before = treeOf(got); final gone = [for (final k in before.keys) if (!w.containsKey(k)) k]; c.settings.rsyncOptions = opts; final pair = LiveSyncPair(src, got, method: 'rsync', delete: optionsDelete(opts)); c.settings.liveSyncPairs = [pair]; final live = LiveSync(c); final k = LiveSync.keyOf(pair); final why = []; await live.syncNow(pair); if (live.status[k]!.$2.contains('실패')) why.add('상태: ${live.status[k]!.$2}'); final asked = live.toDelete[k] ?? const []; for (final g in gone) { if (!asked.any((a) => g == a || g.startsWith('$a/'))) why.add('rsync 는 지우는데 묻지 않음: $g'); } for (final a in asked) { if (!gone.contains(a)) why.add('rsync 는 지우지 않는데 물음: $a'); } if (asked.isNotEmpty) await live.decideDelete(c.settings.liveSyncPairs.single, delete: true); why.addAll(treeDiff(w, treeOf(got))); if ((live.pending[k] ?? const []).isNotEmpty) why.add('맞춘 뒤에도 맞출 것: ${live.pending[k]}'); live.dispose(); if (why.isNotEmpty) bad.add('$opts\n ${why.join('\n ')}'); } expect(bad, isEmpty, reason: bad.join('\n')); }, timeout: const Timeout(Duration(minutes: 5))); }