JJ_MKVMaker/test/large_text_test.dart

173 lines
9.4 KiB
Dart
Raw 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 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:jj_mkvmaker/app/app_controller.dart';
import 'package:jj_mkvmaker/app/download_manager.dart';
import 'package:jj_mkvmaker/app/settings.dart';
import 'package:jj_mkvmaker/core/models.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:archive/archive_io.dart';
import 'package:jj_mkvmaker/core/file_ops.dart';
import 'package:jj_mkvmaker/ui/archive_ui.dart';
import 'package:jj_mkvmaker/ui/batch_rename_dialog.dart';
import 'package:jj_mkvmaker/ui/downloads_page.dart';
import 'package:jj_mkvmaker/ui/explorer_drag.dart';
import 'package:jj_mkvmaker/ui/explorer_page.dart';
import 'package:jj_mkvmaker/ui/explorer_search.dart';
import 'package:jj_mkvmaker/ui/home_page.dart';
import 'package:jj_mkvmaker/ui/monitor_page.dart';
import 'package:jj_mkvmaker/ui/quick_look.dart';
import 'package:jj_mkvmaker/ui/settings_page.dart';
import 'package:jj_mkvmaker/ui/storage_page.dart';
import 'package:path/path.dart' as p;
/// 253: 글자를 크게 (기기 설정 글꼴 크기 · 접근성) 해도 화면이 넘치지 않는다 - 줄 높이가 고정이던 목록이 넘쳤다
void main() {
late Directory tmp;
setUp(() => tmp = Directory.systemTemp.createTempSync('jj_big_'));
tearDown(() => tmp.deleteSync(recursive: true));
final pages = <String, Widget Function(AppController, DownloadManager)>{
'MKV': (c, d) => HomePage(c: c),
'파일 탐색기': (c, d) => ExplorerPage(c: c),
'Rsync': (c, d) => ExplorerPage(c: c, rsync: true),
'모니터링': (c, d) => MonitorPage(c: c),
'다운로드': (c, d) => DownloadsPage(d: d),
'환경 설정': (c, d) => SettingsPage(c: c),
};
for (final MapEntry(key: name, value: page) in pages.entries) {
for (final size in [const Size(412, 900), const Size(900, 412), const Size(1280, 800)]) {
testWidgets('253: $name (${size.width.round()}×${size.height.round()}, 글자 1.6배) 넘치지 않는다', (tester) async {
tester.view.physicalSize = size;
tester.view.devicePixelRatio = 1;
addTearDown(tester.view.reset);
const pp = MethodChannel('plugins.flutter.io/path_provider');
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(pp, (_) async => tmp.path);
addTearDown(() => tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(pp, null));
File(p.join(tmp.path, '아주 긴 이름의 동영상 파일 - 시험용 2026.mp4')).writeAsStringSync('v');
Directory(p.join(tmp.path, 'sub')).createSync();
final c = AppController(PlatformServices(mediaTool: ProcessMediaTool('x', 'y'), storage: DesktopStorageService()));
c.settings
..explorer.paths = [tmp.path, tmp.path]
..copy.rsyncPaths = [tmp.path, tmp.path]
..copy.tasks = [CopyTask(id: '1', sources: [tmp.path], dest: p.join(tmp.path, 'sub'), method: 'rsync', options: '-av')]
..copy.liveSyncPairs = [LiveSyncPair(tmp.path, p.join(tmp.path, 'x'))];
c.videos.add(VideoItem(p.join(tmp.path, '아주 긴 이름의 동영상 파일 - 시험용 2026.mp4')));
c.selected = c.videos.first;
final d = DownloadManager(backends: const [], settings: () => c.settings, readClipboard: () async => null);
addTearDown(d.dispose);
await tester.runAsync(() => tester.pumpWidget(MaterialApp(
builder: (ctx, child) => MediaQuery(data: MediaQuery.of(ctx).copyWith(textScaler: const TextScaler.linear(1.6)), child: child!),
home: page(c, d))));
for (var i = 0; i < 15; i++) {
await tester.runAsync(() => Future<void>.delayed(const Duration(milliseconds: 30)));
await tester.pump();
}
expect(tester.takeException(), isNull);
// 화면을 내리고 남은 타이머 (탐색기 목록 읽기 등) 가 끝나게
await tester.pumpWidget(const SizedBox());
await tester.pump(const Duration(seconds: 1));
});
}
}
// 관리자 지시 8 (묶음6 릴리스 전 점검): 새 창 · 화면도 폭 412 · 글자 1.6배에서 넘치지 않는다
for (final size in [const Size(412, 900), const Size(900, 412)]) {
testWidgets('253: 묶음6 새 창 (78 · 79 · 81 · 82 · 85 · 86 · 87, ${size.width.round()}×${size.height.round()}, 글자 1.6배) 넘치지 않는다',
(tester) async {
tester.view.physicalSize = size;
tester.view.devicePixelRatio = 1;
addTearDown(tester.view.reset);
final show = Directory(p.join(tmp.path, '아주 긴 이름의 폴더 - 시험용', 'Show'))..createSync(recursive: true);
final eps = [
for (final n in ['아주 긴 이름의 동영상 파일 - 시험용 2026 ep01.mkv', 'ep02.mkv'])
(File(p.join(show.path, n))..writeAsBytesSync(List.filled(3000, 0))).path,
];
File(p.join(show.path, 'ep01.srt')).writeAsStringSync('1\n00:00:01,000 --> 00:00:02,000\n안녕\n');
final zip = p.join(tmp.path, '아주 긴 이름의 압축 파일 - 시험용.zip');
File(zip).writeAsBytesSync(ZipEncoder().encode(Archive()
..addFile(ArchiveFile.string('ok/a.txt', 'a'))
..addFile(ArchiveFile.string('../evil.txt', 'x'))
..addFile(ArchiveFile.string('CON.txt', 'x'))
..addFile(ArchiveFile.string('lnk', '../x')..mode = 0xA1FF)));
final c = AppController(PlatformServices(mediaTool: ProcessMediaTool('x', 'y'), storage: DesktopStorageService()));
final nav = GlobalKey<NavigatorState>();
await tester.pumpWidget(MaterialApp(
navigatorKey: nav,
builder: (ctx, child) => MediaQuery(data: MediaQuery.of(ctx).copyWith(textScaler: const TextScaler.linear(1.6)), child: child!),
home: const Scaffold(body: SizedBox.expand())));
BuildContext ctx() => nav.currentContext!;
Future<void> settle([int n = 10]) async {
for (var i = 0; i < n; i++) {
await tester.runAsync(() => Future<void>.delayed(const Duration(milliseconds: 30)));
// 화면 · 창이 열리는 움직임이 끝나게 (시험 시계를 앞으로)
await tester.pump(const Duration(milliseconds: 60));
}
}
Future<void> check(String what) async {
await settle();
expect(tester.takeException(), isNull, reason: what);
// 넘침 오류 없이 옆으로 밀려나는 것도 본다: 누르는 것 (단추 · 고르기 · 입력 칸) 은 화면 폭 안에
final hit = find.byWidgetPredicate((w) =>
w is ButtonStyleButton || w is IconButton || w is Checkbox || w is DropdownButton || w is TextField || w is ChoiceChip || w is Radio);
for (final e in hit.evaluate()) {
final r = tester.getRect(find.byElementPredicate((x) => x == e));
expect(r.left >= -0.5 && r.right <= size.width + 0.5, isTrue, reason: '$what: ${e.widget.runtimeType} $r');
}
nav.currentState!.popUntil((r) => r.isFirst);
await settle(4);
}
showBatchRename(ctx(), eps, isDir: (_) => false);
await check('78 이름 일괄');
nav.currentState!.push(MaterialPageRoute<void>(
builder: (_) => SearchResultsPage(
root: tmp.path, cond: const SearchConditions(name: 'ep', minBytes: 1024), showHidden: false, otherDir: tmp.path, onOpen: (_) async {})));
await settle(15);
await tester.tap(find.byType(Checkbox).first);
await check('79 찾기 결과 (고른 뒤 아래 줄)');
final list = await tester.runAsync(() => listEntries(show.path));
showDialog<void>(
context: ctx(),
builder: (_) => QuickLook(
entries: list!,
index: list.indexWhere((e) => e.name == 'ep01.srt'),
probe: (_) async => const MediaInfo(streams: []),
thumbnail: (_) async => null,
imageExts: const ['jpg'],
onOpen: (_) {}));
await check('81 빠른 보기');
askDropAction(ctx(), eps, tmp.path);
await check('82 놓기 묻기');
nav.currentState!.push(MaterialPageRoute<void>(
builder: (_) => Scaffold(
body: Align(
alignment: Alignment.bottomRight,
child: TransferProgressChip(running: 0, failed: true, onTap: () {})))));
await check('85 멈춤 표시');
extractArchiveFlow(ctx(), c, zip, otherDir: show.path);
await settle(20);
// 글자가 크면 창 아래쪽이라 내려서 누른다 (창은 스크롤)
await tester.ensureVisible(find.byType(DropdownButton<NameConflict>));
await tester.pump();
// 고르기 상자가 화면 안에 다 있어야 한다 (넘침 오류 없이 화면 밖으로 밀려났었다)
expect(tester.getRect(find.byType(DropdownButton<NameConflict>)).right, lessThanOrEqualTo(size.width));
await tester.tap(find.byType(DropdownButton<NameConflict>));
await settle(4);
await tester.tap(find.text('덮어쓰기').last);
await check('86 풀기 확인 (경고 줄 · 덮어쓰기)');
createZipFlow(ctx(), c, eps, dir: show.path, otherDir: tmp.path);
await check('86 ZIP 묶기');
nav.currentState!.push(MaterialPageRoute<void>(builder: (_) => StorageAnalysisPage(root: tmp.path)));
await settle(20);
await tester.tap(find.byType(ChoiceChip).last);
await check('87 저장 공간 분석 (큰 파일)');
});
}
}