126 lines
6.4 KiB
Dart
126 lines
6.4 KiB
Dart
// 보기 화면 모듈 (lib/ui/reader/) 의 약속 시험 - 실제 구성 요소로 (가짜 원본 없음, 사용자 설정 저장소 쓰지 않음)
|
||
import 'dart:io';
|
||
|
||
import 'package:flutter/material.dart';
|
||
import 'package:flutter/services.dart';
|
||
import 'package:flutter_test/flutter_test.dart';
|
||
import 'package:image/image.dart' as img;
|
||
import 'package:jj_mkvmaker/core/reader_sources.dart';
|
||
import 'package:jj_mkvmaker/ui/reader/reader_bars.dart';
|
||
import 'package:jj_mkvmaker/ui/reader/reader_controls.dart';
|
||
import 'package:jj_mkvmaker/ui/reader/reader_images.dart';
|
||
import 'package:jj_mkvmaker/ui/reader/reader_slots.dart';
|
||
import 'package:path/path.dart' as p;
|
||
|
||
String _png(Directory dir, String name, {int w = 40, int h = 60}) {
|
||
final im = img.Image(width: w, height: h);
|
||
img.fill(im, color: img.ColorRgb8(200, 10, 10));
|
||
return (File(p.join(dir.path, name))..writeAsBytesSync(img.encodePng(im))).path;
|
||
}
|
||
|
||
void main() {
|
||
late Directory tmp;
|
||
setUp(() => tmp = Directory.systemTemp.createTempSync('jj_reader_mod_'));
|
||
tearDown(() => tmp.deleteSync(recursive: true));
|
||
|
||
test('reader_slots: 쪽 만들기 · relocateSlot (반쪽 ↔ 통째) · pageAfterRemoval · 이름', () {
|
||
final split = buildSlots(3, (i) => i == 1);
|
||
expect(split, [(page: 0, part: -1), (page: 1, part: 0), (page: 1, part: 1), (page: 2, part: -1)]);
|
||
final whole = buildSlots(3, (_) => false);
|
||
// 둘째 반쪽을 보다 나누기를 끄면 그 장 통째로, 통째를 보다 켜면 첫 반쪽으로
|
||
expect(relocateSlot(whole, (page: 1, part: 1), 2), 1);
|
||
expect(relocateSlot(split, (page: 2, part: -1), 2), 3);
|
||
// 장이 없어지면 옛 번호를 범위 안으로
|
||
expect(relocateSlot(buildSlots(1, (_) => false), (page: 5, part: -1), 4), 0);
|
||
// 보던 1 이 없어지면 뒤의 2 (새 번호 1), 뒤가 다 없으면 앞, 모두 없으면 -1
|
||
expect(pageAfterRemoval(1, {1}, 3), 1);
|
||
expect(pageAfterRemoval(2, {1, 2}, 3), 0);
|
||
expect(pageAfterRemoval(0, {0, 1}, 2), -1);
|
||
expect([slotLabel((page: 11, part: -1)), slotLabel((page: 11, part: 1))], ['12', '12-2']);
|
||
expect(slotAt(const [], 3), (page: 0, part: -1));
|
||
expect(slotBaseWidth((page: 0, part: 0), 5000), 8192);
|
||
});
|
||
|
||
test('reader_slots: splitsPage - 켜기 · 끄기 · 자동 (회전 반영)', () {
|
||
final dims = {0: const Size(200, 100), 1: const Size(100, 200), 2: const Size(100, 200)};
|
||
expect(splitsPage('on', 1, dims, turns: 0, bundle: false), isTrue);
|
||
expect(splitsPage('off', 0, dims, turns: 0, bundle: true), isFalse);
|
||
expect(splitsPage('auto', 0, dims, turns: 0, bundle: false), isTrue, reason: '세로 사이의 가로 한 장');
|
||
expect(splitsPage('auto', 0, dims, turns: 1, bundle: false), isFalse, reason: '돌리면 세로');
|
||
expect(splitsPage('auto', 9, dims, turns: 0, bundle: true), isFalse, reason: '크기를 모르면 나누지 않음');
|
||
});
|
||
|
||
test('reader_controls: tapZone · volumeKeyStep', () {
|
||
expect([tapZone(90, 100, rtl: false), tapZone(10, 100, rtl: false), tapZone(50, 100, rtl: false)], [1, -1, 0]);
|
||
expect([tapZone(90, 100, rtl: true), tapZone(10, 100, rtl: true)], [-1, 1]);
|
||
const down = KeyDownEvent(
|
||
physicalKey: PhysicalKeyboardKey.audioVolumeDown, logicalKey: LogicalKeyboardKey.audioVolumeDown, timeStamp: Duration.zero);
|
||
const upRelease = KeyUpEvent(
|
||
physicalKey: PhysicalKeyboardKey.audioVolumeUp, logicalKey: LogicalKeyboardKey.audioVolumeUp, timeStamp: Duration.zero);
|
||
const other = KeyDownEvent(physicalKey: PhysicalKeyboardKey.keyA, logicalKey: LogicalKeyboardKey.keyA, timeStamp: Duration.zero);
|
||
expect(volumeKeyStep(down, enabled: true), 1);
|
||
expect(volumeKeyStep(upRelease, enabled: true), 0, reason: '뗄 때도 처리 (볼륨 안 바뀜)');
|
||
expect(volumeKeyStep(down, enabled: false), isNull);
|
||
expect(volumeKeyStep(other, enabled: true), isNull);
|
||
});
|
||
|
||
testWidgets('reader_controls: 계속 보기 시계는 장이 보인 뒤부터 재고, 끄면 멈춘다', (tester) async {
|
||
var ticks = 0;
|
||
final show = ReaderSlideshow(seconds: () => 2, onTick: () => ticks++);
|
||
addTearDown(show.dispose);
|
||
expect(show.set(true, '0:0'), isTrue);
|
||
await tester.pump(const Duration(seconds: 3));
|
||
expect(ticks, 0, reason: '아직 보이지 않은 장');
|
||
show.markShown('0:0');
|
||
await tester.pump(const Duration(seconds: 2));
|
||
expect(ticks, 1);
|
||
show.markShown('0:1');
|
||
expect(show.set(false, '0:1'), isTrue);
|
||
await tester.pump(const Duration(seconds: 3));
|
||
expect(ticks, 1);
|
||
final z = ReaderZoom();
|
||
expect([z.finger(1), z.finger(1), z.holdPage], [false, true, true]);
|
||
z.reset();
|
||
});
|
||
|
||
testWidgets('reader_images: 장마다 한 번 읽기 · forget 뒤 새로 · 그림 크기 (실제 PNG)', (tester) async {
|
||
final src = ImageFilesSource([_png(tmp, 'a.png', w: 40, h: 60), _png(tmp, 'b.png')], tempDir: tmp.path, title: 't');
|
||
final cache = ReaderImageCache(src);
|
||
final a = cache.full(0, 800);
|
||
expect(identical(a, cache.full(0, 800)), isTrue);
|
||
cache.forget(0, 0);
|
||
final b = cache.full(0, 800);
|
||
expect(identical(a, b), isFalse);
|
||
final size = await tester.runAsync(() async => ReaderImageCache.imageSize(await b));
|
||
expect(size, const Size(40, 60));
|
||
expect(cache.sharpWidthFor(0, 1.2, 800), isNull);
|
||
expect(cache.sharpWidthFor(0, 2, 800), 1600);
|
||
await tester.runAsync(() async {
|
||
await a;
|
||
cache.dispose();
|
||
});
|
||
});
|
||
|
||
testWidgets('reader_bars: fitBarItems (넘치면 ⋮ 자리 빼고) · 갤러리 줄 키 · 누름', (tester) async {
|
||
final items = [for (var i = 0; i < 5; i++) ReaderBarItem(48, [ReaderAct(const Icon(Icons.add), 't$i', () {})])];
|
||
expect(fitBarItems(items, 240), 5);
|
||
expect(fitBarItems(items, 239), 3, reason: '48 (⋮) + 48 × 3 = 192');
|
||
final src = ImageFilesSource([_png(tmp, 'a.png'), _png(tmp, 'b.png'), _png(tmp, 'c.png')], tempDir: tmp.path, title: 't');
|
||
final cache = ReaderImageCache(src);
|
||
final gallery = ScrollController();
|
||
addTearDown(gallery.dispose);
|
||
int? tapped;
|
||
await tester.pumpWidget(MaterialApp(
|
||
home: Scaffold(
|
||
body: ReaderGalleryStrip(controller: gallery, count: 3, current: 1, rtl: false, thumb: cache.thumb, onTap: (i) => tapped = i),
|
||
),
|
||
));
|
||
expect(find.byKey(const ValueKey('thumb2')), findsOneWidget);
|
||
await tester.tap(find.byKey(const ValueKey('thumb2')));
|
||
expect(tapped, 2);
|
||
expect(galleryOffset(1, 128, 1000), 32);
|
||
await tester.pumpWidget(const SizedBox());
|
||
await tester.runAsync(() async => cache.dispose());
|
||
});
|
||
}
|