JJ_MKVMaker/test/explorer_archive_trash_test...

193 lines
11 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 'package:archive/archive.dart' show Archive, ArchiveFile, ZipEncoder;
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:jj_mkvmaker/ui/explorer_page.dart';
import 'package:jj_mkvmaker/ui/explorer_grid.dart';
import 'package:jj_mkvmaker/ui/text_viewer.dart';
import 'package:path/path.dart' as p;
import 'support/explorer_clock_keys.dart';
import 'support/explorer_harness.dart';
/// E5e: 예전 explorer_test.dart 에서 나눈 탐색기 화면 시험 - 압축을 폴더처럼 · 격자 · 글 뷰어 · 앱 휴지통 · 원본 지우기 옵션 알림 · 바로 실행
void main() {
useExplorerFixture();
testWidgets('X-plore f: 압축을 트리 안에서 폴더처럼 펼치기 · 안은 읽기 전용 · 복사는 꺼내기', (tester) async {
final zip = p.join(left, 'pack.zip');
File(zip).writeAsBytesSync(ZipEncoder().encode(Archive()
..addFile(ArchiveFile.string('top.txt', 'top'))
..addFile(ArchiveFile.string('a/b.txt', 'bee'))));
await open(tester);
await settle(tester, () => find.text('pack.zip').evaluate().isNotEmpty);
// › 로 펼치면 압축 안의 것이 폴더처럼 (목록에 폴더 이름이 없어도 경로에서 폴더를 만든다)
await act(tester, () => tester.tap(chevronOf('pack.zip').first));
await settle(tester, () => find.text('top.txt').evaluate().isNotEmpty);
expect(find.text('a'), findsOneWidget);
await act(tester, () => tester.tap(chevronOf('a').first));
await settle(tester, () => find.text('b.txt').evaluate().isNotEmpty);
expect(find.text('b.txt'), findsOneWidget);
// 안의 것을 지우려 하면 막는다 (압축은 그대로)
await act(tester, () => tester.tap(find.text('top.txt')));
await settle(tester, () => false, rounds: 10);
await act(tester, () => tester.tap(find.text('삭제').first));
await settle(tester, () => find.textContaining('읽기 전용').evaluate().isNotEmpty);
expect(find.textContaining('압축 안은 읽기 전용'), findsOneWidget);
expect(File(zip).existsSync(), isTrue);
expect(Directory(p.join(left, 'pack')).existsSync(), isFalse, reason: '풀지 않음');
ScaffoldMessenger.of(tester.element(find.byType(ExplorerPage))).clearSnackBars();
await tester.pump(const Duration(seconds: 1));
// 압축 안의 폴더를 펼쳐 지금 폴더가 압축 안이면 [새 폴더] 도 막는다 (이름을 묻지 않음)
await act(tester, () => tester.tap(find.text('a')));
await settle(tester, () => false, rounds: 10);
await act(tester, () => tester.tap(find.text('새 폴더').first));
await settle(tester, () => find.textContaining('읽기 전용').evaluate().isNotEmpty);
expect(find.textContaining('압축 안은 읽기 전용'), findsOneWidget);
expect(find.byType(TextField), findsNothing, reason: '이름 묻는 창 없음');
ScaffoldMessenger.of(tester.element(find.byType(ExplorerPage))).clearSnackBars();
await tester.pump(const Duration(seconds: 1));
// 데이터 검토 (10/18): 압축 안의 것 메뉴에는 [ZIP 으로 묶기] · [Wi-Fi 로 공유] 가 없다 (실제 파일이 아니라서). 압축 밖은 그대로
await tester.longPress(find.text('a'));
await calm(tester);
expect(find.text('ZIP 으로 묶기'), findsNothing);
expect(find.text('Wi-Fi 로 공유'), findsNothing);
await tester.tapAt(const Offset(5, 5));
await calm(tester);
await tester.longPress(find.text('sub'));
await calm(tester);
expect(find.text('ZIP 으로 묶기'), findsOneWidget);
await tester.tapAt(const Offset(5, 5));
await calm(tester);
});
testWidgets('X-plore f 보충: 펼친 뒤 압축 파일이 바뀌면 새로 고칠 때 목록을 다시 읽는다 (관리자 지시 10/19)', (tester) async {
final zip = p.join(left, 'pack.zip');
File(zip).writeAsBytesSync(ZipEncoder().encode(Archive()..addFile(ArchiveFile.string('old.txt', 'old'))));
await open(tester);
await settle(tester, () => find.text('pack.zip').evaluate().isNotEmpty);
await act(tester, () => tester.tap(chevronOf('pack.zip').first));
await settle(tester, () => find.text('old.txt').evaluate().isNotEmpty);
expect(find.text('old.txt'), findsOneWidget);
// 다른 프로그램이 압축을 바꿈 (크기 · 바뀐 때가 달라짐)
await tester.runAsync(() async {
await Future<void>.delayed(const Duration(milliseconds: 1100));
File(zip).writeAsBytesSync(ZipEncoder().encode(Archive()
..addFile(ArchiveFile.string('new.txt', 'new content'))
..addFile(ArchiveFile.string('more.txt', 'more'))));
});
await act(tester, () => refreshKey(tester));
await settle(tester, () => find.text('new.txt').evaluate().isNotEmpty);
expect(find.text('new.txt'), findsOneWidget);
expect(find.text('more.txt'), findsOneWidget);
expect(find.text('old.txt'), findsNothing);
});
testWidgets('X-plore g · h: 폴더 메뉴 [격자로 보기] (길게 = 그 자리로) · 파일 메뉴 [글 뷰어로 보기]', (tester) async {
File(p.join(left, 'sub', 'pic.png')).writeAsBytesSync([0x89, 0x50]);
await open(tester);
// g: 폴더를 길게 → 격자로 보기 → 그림만 (글 파일은 빠짐)
await tester.longPress(find.text('sub'));
await calm(tester);
await act(tester, () => tester.tap(find.text('격자로 보기 (그림 · 동영상)')));
await settle(tester, () => find.byType(ExplorerGridPage).evaluate().isNotEmpty);
expect(find.descendant(of: find.byType(ExplorerGridPage), matching: find.text('pic.png')), findsOneWidget);
expect(find.descendant(of: find.byType(ExplorerGridPage), matching: find.text('inner.txt')), findsNothing);
// 칸을 길게 누르면 탐색기에서 그 자리로 (격자 닫힘)
await tester.longPress(find.descendant(of: find.byType(ExplorerGridPage), matching: find.text('pic.png')));
await settle(tester, () => find.byType(ExplorerGridPage).evaluate().isEmpty && find.descendant(of: find.byType(ExplorerPage), matching: find.text('pic.png')).evaluate().isNotEmpty);
expect(find.descendant(of: find.byType(ExplorerPage), matching: find.text('pic.png')), findsOneWidget, reason: '탐색기에 그 폴더가 펼쳐져 보임 (길게 누른 칸의 이름 풍선은 빼고)');
// h: 파일을 길게 → 글 뷰어로 보기 (읽기 전용)
await tester.longPress(find.text('doc.txt'));
await calm(tester);
await act(tester, () => tester.tap(find.text('글 뷰어로 보기')));
await settle(tester, () => find.text('hello').evaluate().isNotEmpty);
expect(find.byType(TextViewerPage), findsOneWidget);
expect(shell.opened, isEmpty, reason: '다른 앱으로 열지 않음');
await act(tester, () async => Navigator.of(tester.element(find.byType(TextViewerPage))).pop());
await settle(tester, () => find.byType(TextViewerPage).evaluate().isEmpty);
});
testWidgets('X-plore e: Android 앱 휴지통 - 지우기 = 휴지통으로 · [되돌리기] · [휴지통] 화면에서 되살리기', (tester) async {
// 저장 장치는 시험 폴더 (실제 C:\ 에 .jj_trash 를 만들지 않게)
device.trash = true;
device.volumes = () => [(tmp.path, 'T:')];
// [휴지통] 버튼이 줄에 보이게 (처음 구성은 좁으면 [더 보기] 로 간다)
c.settings.explorer.buttons = ['trash', for (final b in ExplorerButton.defaultOrder(android: false)) if (b != ExplorerButton.trash) b.name];
addTearDown(() {
});
await open(tester);
final doc = p.join(left, 'doc.txt');
await act(tester, () => tester.tap(find.text('doc.txt')));
await settle(tester, () => false, rounds: 10);
await act(tester, () => tester.tap(find.text('삭제').first));
await calm(tester);
expect(find.textContaining('앱 휴지통에 14일'), findsOneWidget);
await act(tester, () => tester.tap(find.widgetWithText(FilledButton, '휴지통으로')));
await settle(tester, () => !File(doc).existsSync() && find.text('되돌리기').evaluate().isNotEmpty);
expect(File(doc).existsSync(), isFalse);
expect(Directory(p.join(tmp.path, '.jj_trash')).existsSync(), isTrue);
// [되돌리기]
await act(tester, () => tester.tap(find.text('되돌리기')));
await settle(tester, () => File(doc).existsSync());
expect(File(doc).readAsStringSync(), 'hello');
ScaffoldMessenger.of(tester.element(find.byType(ExplorerPage))).clearSnackBars();
await calm(tester);
// 다시 지우고 [휴지통] 화면에서 되살리기
await act(tester, () => tester.tap(find.text('doc.txt')));
await settle(tester, () => false, rounds: 10);
await act(tester, () => tester.tap(find.text('삭제').first));
await calm(tester);
await act(tester, () => tester.tap(find.widgetWithText(FilledButton, '휴지통으로')));
await settle(tester, () => !File(doc).existsSync());
ScaffoldMessenger.of(tester.element(find.byType(ExplorerPage))).clearSnackBars();
await calm(tester);
// [휴지통] 버튼으로 휴지통 화면을 연다
await act(tester, () => tester.tap(find.text('휴지통').first));
await settle(tester, () => find.byType(CheckboxListTile).evaluate().isNotEmpty);
await act(tester, () => tester.tap(find.byType(CheckboxListTile).first));
await settle(tester, () => find.text('되살리기').hitTestable().evaluate().isNotEmpty); // 화면 넘김이 끝나 눌릴 때까지
await act(tester, () => tester.tap(find.text('되살리기')));
await settle(tester, () => File(doc).existsSync());
expect(File(doc).readAsStringSync(), 'hello');
await tester.pageBack();
await calm(tester);
ScaffoldMessenger.of(tester.element(find.byType(ExplorerPage))).clearSnackBars();
await tester.pump(const Duration(seconds: 2));
});
testWidgets('178 보충: 설정의 원본 지우기 옵션은 복사 창에서 빠진 까닭을 알린다 (이동 창에는 없음)', (tester) async {
c.settings
..copy.methodFile = 'robocopy'
..copy.robocopyOptions = '/E /MOV';
await open(tester);
await act(tester, () => tester.tap(find.text('doc.txt')));
await settle(tester, () => false, rounds: 15);
await act(tester, () => tester.tap(find.text('복사').first));
await calm(tester);
expect(find.textContaining('방법: robocopy'), findsOneWidget);
expect(find.text('환경 설정의 /MOV 는 복사에서는 쓰지 않습니다 (이동은 [이동] 으로)'), findsOneWidget);
await act(tester, () => tester.tap(find.text('취소').last));
await calm(tester);
await act(tester, () => tester.tap(find.text('이동').first));
await calm(tester);
expect(find.textContaining('옮길까요?'), findsOneWidget);
expect(find.textContaining('복사에서는 쓰지 않습니다'), findsNothing);
await act(tester, () => tester.tap(find.text('취소').last));
await calm(tester);
expect(File(p.join(left, 'doc.txt')).existsSync(), isTrue);
expect(File(p.join(right, 'doc.txt')).existsSync(), isFalse);
}, skip: !Platform.isWindows);
testWidgets('바로 실행 모드: 폴더를 누르면 펼치고, 파일을 누르면 바로 실행', (tester) async {
c.settings.explorer.click = 'open';
await open(tester);
await act(tester, () => tester.tap(find.text('sub')));
await settle(tester, () => find.text('inner.txt').evaluate().isNotEmpty);
expect(find.text('inner.txt'), findsOneWidget);
await act(tester, () => tester.tap(find.text('doc.txt')));
await settle(tester, () => shell.opened.isNotEmpty);
expect(shell.opened.single, (p.join(left, 'doc.txt'), false));
});
}