JJ_MKVMaker/integration_test/windows_xplore_shot_test.dart

115 lines
6.2 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import 'dart:io';
import 'dart:ui' as ui;
import 'package:archive/archive.dart' show Archive, ArchiveFile, ZipEncoder;
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/app_controller.dart';
import 'package:jj_mkvmaker/app/i18n_controller.dart';
import 'package:jj_mkvmaker/app/settings.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:jj_mkvmaker/ui/explorer_page.dart';
import 'package:jj_mkvmaker/ui/theme.dart';
import 'support/temp_dir.dart';
import 'package:path/path.dart' as p;
import '../test/support/test_explorer_device.dart';
/// X-plore 비교 P1 (관리자 지시 10/18): X-plore 스타일 탐색기를 PNG 로 (JJ_SHOT_DIR, 없으면 임시 폴더).
/// 트리 맨 위 저장 장치 · 즐겨찾기 (c) · 표시 동그라미 늘 보이기 (⚖) · 한 창의 "갈 곳" 줄 (a) · 압축을 폴더처럼 (f).
/// 크기 412 (폰 세로, 한 창) · 960 (두 창), 언어 ko · en. 시험 파일은 임시 폴더에만, 설정은 메모리에만.
void main() {
late TestExplorerDevice device;
setUp(() => device = TestExplorerDevice());
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_xplore');
for (final lang in ['ko', 'en']) {
for (final (w, h) in [(412, 900), (960, 600)]) {
testWidgets('X-plore 화면 $lang ${w}x$h', (t) async {
t.view.physicalSize = Size(w.toDouble(), h.toDouble());
t.view.devicePixelRatio = 1;
addTearDown(t.view.reset);
await t.runAsync(() => i18n.apply(lang, save: false));
addTearDown(() => i18n.apply('ko', save: false));
// 관리자 지시 (10/24): 실행마다 다른 값 (폴더 이름 · 시각 · CPU · 메모리) 을 정한 값으로 (캡처가 흔들리지 않게 - 시험 쪽에서만)
final tmp = testFixedTempDir('jj_xpshot_fixed');
appTempInto(tmp); // 앱 임시 폴더 (jj_mkvmaker) 도 이 아래로 - 끝에 함께 지움 (관리자 지시 10/20)
final a = Directory(p.join(tmp.path, 'Videos'))..createSync();
final b = Directory(p.join(tmp.path, 'Backup'))..createSync();
for (final n in ['Show S01', 'Movies']) {
Directory(p.join(a.path, n)).createSync();
}
File(p.join(a.path, 'Show S01', 'ep01.mkv')).writeAsBytesSync(List.filled(5000, 0));
File(p.join(a.path, 'notes.txt')).writeAsStringSync('memo');
File(p.join(a.path, 'Photos.zip')).writeAsBytesSync(ZipEncoder().encode(Archive()
// 압축 안 항목의 시각도 정해 둔다 (처음 값은 만든 때 - 캡처가 흔들림)
..addFile(ArchiveFile.string('2026/beach.jpg', 'x')..lastModTime = _fixedZipTime)
..addFile(ArchiveFile.string('readme.txt', 'readme')..lastModTime = _fixedZipTime)));
pinTestTimes(tmp);
device.volumes = () => [(a.path, 'C:'), (b.path, 'D:')];
final c = AppController(PlatformServices(mediaTool: ProcessMediaTool('x', 'y'), storage: DesktopStorageService()));
c.settings
..explorer.style = 'xplore'
..explorer.layout = w < 720 ? 'single' : 'dual'
..explorer.onePaneCopy = 'other'
..explorer.paths = [a.path, b.path]
..general.folderBookmarks = [FolderBookmark(name: 'Show S01', path: p.join(a.path, 'Show S01'))];
final shotKey = GlobalKey();
await t.runAsync(() => t.pumpWidget(RepaintBoundary(
key: shotKey,
child: MaterialApp(theme: buildTheme(), debugShowCheckedModeBanner: false, home: ExplorerPage(device: device, c: c)),
)));
Future<void> settle([int n = 12]) async {
for (var i = 0; i < n; i++) {
await t.runAsync(() => Future<void>.delayed(const Duration(milliseconds: 60)));
await t.pump();
}
}
Future<void> shot(String name) async {
await settle(3);
final r = shotKey.currentContext!.findRenderObject()! as RenderRepaintBoundary;
final img = await t.runAsync(() => r.toImage());
final bytes = await t.runAsync(() => img!.toByteData(format: ui.ImageByteFormat.png));
Directory(out).createSync(recursive: true);
File(p.join(out, 'xplore_${name}_${lang}_$w.png')).writeAsBytesSync(bytes!.buffer.asUint8List());
}
await settle(20);
// 관리자 지시 (10/20): 목록은 따로 읽혀 늦게 올 수 있다 (회귀에서 en 412 가 1.2초 안에 못 받아 실패) - 정해진 시간이 아니라 그 줄이 올 때까지 (최대 약 10초)
final load = Stopwatch()..start();
for (var i = 0; i < 160 && find.text('Show S01').evaluate().isEmpty; i++) {
await settle(1);
}
// ignore: avoid_print
print('목록 받음: $lang $w - 1.2초 뒤 ${load.elapsedMilliseconds}ms 더');
// Show S01 펼치기 · 즐겨찾기 펼치기
await t.tap(find.text('Show S01').first);
await settle();
await t.tap(find.byKey(const ValueKey<String>('k2:\u0000favorites')).first);
await settle();
await shot('tree');
// f: 압축을 › 로 펼치기 (안의 폴더도)
Finder chevron(String name) => find.descendant(
of: find.ancestor(of: find.text(name), matching: find.byType(InkWell)).first, matching: find.byIcon(Icons.chevron_right));
await t.tap(chevron('Photos.zip').first);
await settle();
await t.tap(chevron('2026').first);
await settle();
await shot('archive');
await t.pumpWidget(const SizedBox());
await settle(4);
});
}
}
}
/// 캡처용 압축 안 항목 시각 (유닉스 초)
final _fixedZipTime = DateTime(2026, 10, 22, 9).millisecondsSinceEpoch ~/ 1000;