95 lines
4.1 KiB
Dart
95 lines
4.1 KiB
Dart
import 'dart:convert';
|
|
import 'dart:io';
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter/services.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:jj_mkvmaker/core/file_ops.dart';
|
|
import 'package:jj_mkvmaker/core/models.dart';
|
|
import 'package:jj_mkvmaker/ui/quick_look.dart';
|
|
import 'package:path/path.dart' as p;
|
|
|
|
/// 81: 빠른 보기 - 글 파일은 앞 64KB (깨지면 "미리 볼 수 없음"), ← → 로 앞 · 다음, Space 로 닫기, [열기]
|
|
void main() {
|
|
late Directory tmp;
|
|
setUp(() => tmp = Directory.systemTemp.createTempSync('jj_ql81_'));
|
|
tearDown(() => tmp.deleteSync(recursive: true));
|
|
|
|
test('글 앞부분: UTF-8 · CP949 .smi · UTF-16 (BOM) .srt · UTF-8 BOM .txt 를 읽고, 글이 아니면 null · 64KB 끝에서 잘린 한 글자는 괜찮음', () async {
|
|
final a = File(p.join(tmp.path, 'a.txt'))..writeAsStringSync('안녕 hello');
|
|
expect(await readTextHead(a.path), '안녕 hello');
|
|
// 81 보충 (15 지적): 한국어 자막에 흔한 CP949 · 메모장의 UTF-16 · UTF-8 BOM
|
|
final b = File(p.join(tmp.path, 'b.smi'))..writeAsBytesSync([0xBE, 0xC8, 0xB3, 0xE7, 0x20, 0xC0, 0xDA, 0xB8, 0xB7]); // CP949 "안녕 자막"
|
|
expect(await readTextHead(b.path), '안녕 자막');
|
|
final u16 = <int>[0xFF, 0xFE];
|
|
for (final r in '자막 1'.codeUnits) {
|
|
u16.addAll([r & 0xFF, r >> 8]);
|
|
}
|
|
final s = File(p.join(tmp.path, 's.srt'))..writeAsBytesSync(u16);
|
|
expect(await readTextHead(s.path), '자막 1');
|
|
final bom = File(p.join(tmp.path, 'bom.txt'))..writeAsBytesSync([0xEF, 0xBB, 0xBF, ...utf8.encode('hi 안녕')]);
|
|
expect(await readTextHead(bom.path), 'hi 안녕');
|
|
final bin = File(p.join(tmp.path, 'bin.txt'))..writeAsBytesSync([0x00, 0x01, 0x02, 0x00, 0xFF]);
|
|
expect(await readTextHead(bin.path), isNull, reason: '글이 아님');
|
|
// 64KB 경계에 3바이트 글자가 걸리게
|
|
final c = File(p.join(tmp.path, 'c.txt'))..writeAsStringSync('${'x' * (64 * 1024 - 1)}가나다');
|
|
final head = await readTextHead(c.path);
|
|
expect(head, isNotNull);
|
|
expect(head!.length, 64 * 1024 - 1);
|
|
});
|
|
|
|
testWidgets('← → 로 앞 · 다음 (보이는 차례), Space 로 닫기, [열기]', (tester) async {
|
|
tester.view.physicalSize = const Size(1000, 800);
|
|
tester.view.devicePixelRatio = 1;
|
|
addTearDown(tester.view.reset);
|
|
final now = DateTime(2026, 10, 17);
|
|
final entries = [
|
|
FileEntry(p.join(tmp.path, 'one.bin'), isDir: false, size: 10, modified: now),
|
|
FileEntry(p.join(tmp.path, 'two.bin'), isDir: false, size: 20, modified: now),
|
|
];
|
|
final opened = <String>[];
|
|
final nav = GlobalKey<NavigatorState>();
|
|
await tester.pumpWidget(MaterialApp(navigatorKey: nav, home: const Scaffold()));
|
|
showDialog<void>(
|
|
context: nav.currentContext!,
|
|
builder: (_) => QuickLook(
|
|
entries: entries,
|
|
index: 0,
|
|
probe: (_) async => const MediaInfo(streams: []),
|
|
thumbnail: (_) async => null,
|
|
imageExts: const ['jpg'],
|
|
onOpen: (e) => opened.add(e.name),
|
|
),
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('one.bin'), findsOneWidget);
|
|
expect(find.text('1/2'), findsOneWidget);
|
|
await tester.sendKeyEvent(LogicalKeyboardKey.arrowRight);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('two.bin'), findsOneWidget);
|
|
await tester.sendKeyEvent(LogicalKeyboardKey.arrowRight);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('2/2'), findsOneWidget, reason: '끝에서 더 가지 않음');
|
|
await tester.tap(find.text('열기 · 재생'));
|
|
await tester.pumpAndSettle();
|
|
expect(opened, ['two.bin']);
|
|
expect(find.byType(QuickLook), findsNothing);
|
|
|
|
showDialog<void>(
|
|
context: nav.currentContext!,
|
|
builder: (_) => QuickLook(
|
|
entries: entries,
|
|
index: 1,
|
|
probe: (_) async => const MediaInfo(streams: []),
|
|
thumbnail: (_) async => null,
|
|
imageExts: const ['jpg'],
|
|
onOpen: (_) {},
|
|
),
|
|
);
|
|
await tester.pumpAndSettle();
|
|
await tester.sendKeyEvent(LogicalKeyboardKey.space);
|
|
await tester.pumpAndSettle();
|
|
expect(find.byType(QuickLook), findsNothing, reason: 'Space 로 닫기');
|
|
});
|
|
}
|