mirror of
https://github.com/kuhyx/testsAndMisc-archive.git
synced 2026-07-04 13:43:02 +02:00
Two-package monorepo: - horatio_core: pure Dart package (parser, SRS, planner) - horatio_app: Flutter UI (Bloc/Cubit, GoRouter, TTS) Features: - Script import (txt, docx, pdf) with drag-and-drop - Four script format parsers (colon, bracketed, parenthetical, screenplay) - SM-2 spaced repetition for line memorization - Rehearsal mode with TTS and line comparison - 5 bundled public domain scripts Quality: - 83 core tests + 160 app tests, both 100% branch coverage - Strict analysis (130+ lint rules, fatal-infos) - Dead code detection script (dead_code.sh) - run.sh pipeline: analyze, test, dead-code, run, web - Pre-commit hook for horatio test coverage
171 lines
4.7 KiB
Dart
171 lines
4.7 KiB
Dart
import 'dart:async';
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:horatio_app/bloc/script_import/script_import_cubit.dart';
|
|
import 'package:horatio_app/bloc/srs_review/srs_review_cubit.dart';
|
|
import 'package:horatio_app/router.dart';
|
|
import 'package:horatio_app/services/script_repository.dart';
|
|
import 'package:horatio_core/horatio_core.dart';
|
|
|
|
Widget _wrapRouter() {
|
|
final repository = ScriptRepository();
|
|
return MultiRepositoryProvider(
|
|
providers: [
|
|
RepositoryProvider<ScriptRepository>(create: (_) => repository),
|
|
],
|
|
child: MultiBlocProvider(
|
|
providers: [
|
|
BlocProvider<ScriptImportCubit>(
|
|
create: (_) => ScriptImportCubit(repository: repository),
|
|
),
|
|
BlocProvider<SrsReviewCubit>(create: (_) => SrsReviewCubit()),
|
|
],
|
|
child: MaterialApp.router(routerConfig: appRouter),
|
|
),
|
|
);
|
|
}
|
|
|
|
void main() {
|
|
group('Router with valid extras', () {
|
|
testWidgets('import route shows ImportScreen', (tester) async {
|
|
await tester.pumpWidget(_wrapRouter());
|
|
await tester.pumpAndSettle();
|
|
|
|
appRouter.go(RoutePaths.import_);
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.text('Import Script'), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('role-selection route with Script extra', (tester) async {
|
|
await tester.pumpWidget(_wrapRouter());
|
|
await tester.pumpAndSettle();
|
|
|
|
const role = Role(name: 'Hero');
|
|
const script = Script(
|
|
title: 'Valid',
|
|
roles: [role],
|
|
scenes: [
|
|
Scene(
|
|
lines: [
|
|
ScriptLine(
|
|
text: 'Line.',
|
|
role: role,
|
|
sceneIndex: 0,
|
|
lineIndex: 0,
|
|
),
|
|
],
|
|
),
|
|
],
|
|
);
|
|
|
|
unawaited(appRouter.push(RoutePaths.roleSelection, extra: script));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.text('Choose Your Role'), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('schedule route with map extra', (tester) async {
|
|
await tester.pumpWidget(_wrapRouter());
|
|
await tester.pumpAndSettle();
|
|
|
|
const role = Role(name: 'Hero');
|
|
const script = Script(
|
|
title: 'Play',
|
|
roles: [role],
|
|
scenes: [
|
|
Scene(
|
|
lines: [
|
|
ScriptLine(
|
|
text: 'Hi.',
|
|
role: role,
|
|
sceneIndex: 0,
|
|
lineIndex: 0,
|
|
),
|
|
],
|
|
),
|
|
],
|
|
);
|
|
|
|
unawaited(appRouter.push(
|
|
RoutePaths.schedule,
|
|
extra: {'script': script, 'role': role},
|
|
));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.text('Memorization Schedule'), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('rehearsal route with map extra', (tester) async {
|
|
await tester.pumpWidget(_wrapRouter());
|
|
await tester.pumpAndSettle();
|
|
|
|
const role = Role(name: 'Hero');
|
|
const script = Script(
|
|
title: 'Rehearse',
|
|
roles: [role],
|
|
scenes: [
|
|
Scene(
|
|
lines: [
|
|
ScriptLine(
|
|
text: 'A.',
|
|
role: role,
|
|
sceneIndex: 0,
|
|
lineIndex: 0,
|
|
),
|
|
],
|
|
),
|
|
],
|
|
);
|
|
|
|
unawaited(appRouter.push(
|
|
RoutePaths.rehearsal,
|
|
extra: {'script': script, 'role': role},
|
|
));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.text('Rehearsing: Hero'), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('srs-review route with cards extra', (tester) async {
|
|
await tester.pumpWidget(_wrapRouter());
|
|
await tester.pumpAndSettle();
|
|
|
|
final cards = [
|
|
SrsCard(id: 'c1', cueText: 'Cue', answerText: 'Ans'),
|
|
];
|
|
|
|
unawaited(appRouter.push(RoutePaths.srsReview, extra: cards));
|
|
await tester.pumpAndSettle();
|
|
|
|
// SrsReviewScreen is visible.
|
|
expect(find.text('No review session active.'), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('error route shows 404', (tester) async {
|
|
await tester.pumpWidget(_wrapRouter());
|
|
await tester.pumpAndSettle();
|
|
|
|
appRouter.go('/nonexistent-route');
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.text('Not Found'), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('schedule route with wrong extra type falls back',
|
|
(tester) async {
|
|
await tester.pumpWidget(_wrapRouter());
|
|
await tester.pumpAndSettle();
|
|
|
|
// Push schedule with a non-Map extra → the builder returns SizedBox.
|
|
unawaited(appRouter.push(RoutePaths.schedule, extra: 'wrong'));
|
|
await tester.pumpAndSettle();
|
|
|
|
// Should not crash — shows SizedBox.shrink or redirects.
|
|
expect(tester.takeException(), isNull);
|
|
});
|
|
});
|
|
}
|