193 lines
11 KiB
Dart
193 lines
11 KiB
Dart
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) 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));
|
||
});
|
||
}
|