JJ_MKVMaker/test/subtitle_editor_panes_contr...

90 lines
4.2 KiB
Dart

// subtitle_editor_panes.dart 약속 시험: 실제 SubtitleEditorController 로 조각의 입력 · 출력 (편집기 · 콜백) · 오류 표시를 본다.
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:jj_mkvmaker/app/subtitle_editor_controller.dart';
import 'package:jj_mkvmaker/core/srt.dart';
import 'package:jj_mkvmaker/ui/subtitle_editor_panes.dart';
SubtitleEditorController _editor() => SubtitleEditorController([
Cue(const Duration(seconds: 1), const Duration(seconds: 2), '첫 줄'),
Cue(const Duration(seconds: 3), const Duration(seconds: 4), '둘째 줄'),
], saveCharset: 'UTF-8');
Widget _host(Widget child) => MaterialApp(home: Scaffold(body: child));
void main() {
testWidgets('SubtitleCueTable: 번호를 누르면 onSelect · 시간 고치기 · 틀린 형식 · 줄 추가 · 삭제는 편집기로', (tester) async {
tester.view.physicalSize = const Size(1200, 700);
tester.view.devicePixelRatio = 1;
addTearDown(tester.view.reset);
final e = _editor();
final active = ValueNotifier<Cue?>(null);
final picked = <Cue>[];
await tester.pumpWidget(_host(ListenableBuilder(
listenable: e, builder: (_, _) => SubtitleCueTable(editor: e, active: active, onSelect: picked.add))));
await tester.tap(find.text('2'));
expect(picked, [e.cues[1]]);
await tester.enterText(find.text('00:00:01,000'), '00:00:01,500');
expect(e.cues[0].start, const Duration(milliseconds: 1500));
await tester.enterText(find.text('00:00:03,000'), '말도 안 됨');
await tester.pump();
expect(find.text('형식 오류'), findsOneWidget);
expect(e.cues[1].start, const Duration(seconds: 3));
await tester.tap(find.byTooltip('아래에 줄 추가').first);
await tester.pump();
expect(e.cues.length, 3);
await tester.tap(find.byTooltip('줄 삭제').last);
await tester.pump();
expect(e.cues.length, 2);
});
testWidgets('SubtitleTransportBar: 고른 줄이 없으면 줄 단추 꺼짐 · 누르면 콜백', (tester) async {
// 줄 단추가 모두 보이는 넓은 화면 (좁으면 밀어서 본다)
tester.view.physicalSize = const Size(1800, 600);
tester.view.devicePixelRatio = 1;
addTearDown(tester.view.reset);
final calls = <String>[];
Widget bar(bool sel) => _host(SubtitleTransportBar(
position: ValueNotifier(const Duration(seconds: 5)),
duration: const Duration(minutes: 1),
playing: false,
rate: 1.0,
hasSelection: sel,
onSeekBy: (ms) => calls.add('seek $ms'),
onPlayPause: () => calls.add('play'),
onRate: (r) => calls.add('rate $r'),
onInsert: () => calls.add('insert'),
onPlaySelected: () => calls.add('playSel'),
onSetStart: () => calls.add('start'),
onSetEnd: () => calls.add('end'),
onAlign: () => calls.add('align'),
));
await tester.pumpWidget(bar(false));
expect(find.text('00:00:05,000 / 00:01:00,000'), findsOneWidget);
expect(tester.widget<OutlinedButton>(find.widgetWithText(OutlinedButton, '시작 = 현재')).onPressed, isNull);
await tester.tap(find.byIcon(Icons.replay_5));
await tester.tap(find.byIcon(Icons.play_circle));
await tester.tap(find.text('+ 여기에 새 줄'));
await tester.pumpWidget(bar(true));
await tester.tap(find.text('끝 = 현재'));
await tester.tap(find.text('1.0x'));
await tester.pumpAndSettle();
await tester.tap(find.text('2.0x').last);
await tester.pumpAndSettle();
expect(calls, ['seek -5000', 'play', 'insert', 'end', 'rate 2.0']);
});
testWidgets('SubtitleVideoPane: 지금 위치의 줄 · 재생 오류를 겹쳐 보인다', (tester) async {
final e = _editor();
final pos = ValueNotifier(const Duration(milliseconds: 1200));
await tester.pumpWidget(_host(SubtitleVideoPane(view: const SizedBox(), editor: e, position: pos, error: '열 수 없음')));
expect(find.text('첫 줄'), findsOneWidget);
expect(find.textContaining('열 수 없음'), findsOneWidget);
pos.value = const Duration(milliseconds: 2500);
await tester.pump();
expect(find.text('첫 줄'), findsNothing);
});
}