import 'dart:io'; import 'dart:ui' as ui; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/integration_test.dart'; import 'package:jj_mkvmaker/app/download_manager.dart'; import 'package:jj_mkvmaker/app/i18n_controller.dart'; import 'package:jj_mkvmaker/app/settings.dart'; import 'package:jj_mkvmaker/core/download_detect.dart'; import 'package:jj_mkvmaker/l10n/tr.dart'; import 'package:jj_mkvmaker/services/downloader.dart'; import 'package:jj_mkvmaker/ui/downloads_page.dart'; import 'package:jj_mkvmaker/ui/theme.dart'; import 'package:path/path.dart' as p; /// 이름을 바꾸지 않는 가짜 백엔드 (아무것도 받지 않음 - 줄의 상태는 시험이 정한다) class _Quiet implements DownloadBackend { @override final DownloadKind kind; _Quiet(this.kind); @override Future<(String, List)?> expandPlaylist(String url) async => null; @override Future start(DownloadTask t, void Function() changed) async { t ..state = DownloadState.downloading ..progress = null; changed(); } @override Future pause(DownloadTask t) async => t.state = DownloadState.paused; @override Future cancel(DownloadTask t) async => t.state = DownloadState.cancelled; @override Future shutdown() async {} } /// 관리자 지시 (10/20, 28 확인): 마그넷 줄 - 메타데이터 전에도 dn 이름 · 멈춘 줄의 막대는 움직이지 않고 주황 "멈춤". /// 크기 412 · 960, 언어 ko · en · ja 로 찍는다 (가짜 백엔드 - 아무것도 받지 않음). /// 실행: flutter test integration_test\windows_magnet_shot_test.dart -d windows (JJ_SHOT_DIR 에 PNG) void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); // ⑦ 밝은 화면 캡처: JJ_SHOT_THEME=light (JJ_SHOT_DIR 를 따로 두어 어두운 것과 견줌) if (Platform.environment['JJ_SHOT_THEME'] == 'light') JjColors.use(Brightness.light); final out = Platform.environment['JJ_SHOT_DIR'] ?? p.join(Directory.systemTemp.path, 'jj_shots_magnet'); const h = 'magnet:?xt=urn:btih:0123456789abcdef0123456789abcdef0123456'; for (final lang in ['ko', 'en', 'ja']) { for (final (w, hh) in [(412, 900), (960, 600)]) { testWidgets('마그넷 줄 $lang ${w}x$hh', (t) async { t.view.physicalSize = Size(w.toDouble(), hh.toDouble()); t.view.devicePixelRatio = 1; addTearDown(t.view.reset); await t.runAsync(() => i18n.apply(lang, save: false)); addTearDown(() => i18n.apply('ko', save: false)); final d = DownloadManager( backends: [_Quiet(DownloadKind.video), _Quiet(DownloadKind.torrent)], settings: () => AppSettings()..download.root = r'D:\dl', readClipboard: () async => null, ); // ① 메타데이터를 받는 중 (dn 이름 · 움직이는 "준비 중…") ② 멈춤 (이유 후보 · [다시 시도]) ③ 이름이 없는 마그넷 d.add('${h}1&dn=${Uri.encodeQueryComponent('[시험] 아주 긴 이름의 토렌트 묶음 - Big Buck Bunny 1080p (2008) 한글 자막 포함')}&tr=udp%3A%2F%2Ft.example%3A80'); d.add('${h}2&dn=Ubuntu+24.04.1+Desktop+amd64&tr=udp%3A%2F%2Ft.example%3A80'); d.add('${h}3'); final stalled = d.tasks.firstWhere((x) => x.title.startsWith('Ubuntu')); stalled.extra ..['stalled'] = true ..['stallSince'] = DateTime.now().millisecondsSinceEpoch - 75000 ..['stallReasons'] = ['dns', 'firewall']; d.useSystemDns = () async {}; final shotKey = GlobalKey(); // 움직이는 "준비 중…" 막대는 찍히는 때에 따라 달라 멈춰 둔다 (TickerMode - 캡처가 흔들리지 않게, 시험 쪽에서만 · 관리자 10/24) await t.pumpWidget(RepaintBoundary( key: shotKey, child: MaterialApp(theme: buildTheme(), debugShowCheckedModeBanner: false, home: TickerMode(enabled: false, child: DownloadsPage(d: d))), )); for (var i = 0; i < 6; i++) { await t.runAsync(() => Future.delayed(const Duration(milliseconds: 60))); await t.pump(const Duration(milliseconds: 60)); } expect(t.takeException(), isNull, reason: '넘침'); expect(find.textContaining('[시험] 아주 긴 이름'), findsOneWidget); expect(find.textContaining('Ubuntu 24.04.1 Desktop amd64'), findsOneWidget); expect(find.text(tr('멈춤 (시작 안 됨)')), findsOneWidget); final b = shotKey.currentContext!.findRenderObject()! as RenderRepaintBoundary; final img = await t.runAsync(() => b.toImage()); final bytes = await t.runAsync(() => img!.toByteData(format: ui.ImageByteFormat.png)); Directory(out).createSync(recursive: true); File(p.join(out, 'magnet_${lang}_$w.png')).writeAsBytesSync(bytes!.buffer.asUint8List()); }); } } }