Files
BadNote/test/pen_canvas_widget_test.dart

166 lines
5.2 KiB
Dart
Raw Normal View History

// Widget test of the INTEGRATED live drawing path (device-independent: uses a
// plain Container as the page widget, so no pdfrx/pdfium). Exercises the input
// arbiter + stroke lifecycle + the revision-gated render-cache swap (eca5141)
// end-to-end via simulated stylus / finger / pinch gestures.
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:badnote/editor/canvas/pen_canvas.dart';
import 'package:badnote/editor/canvas/pen_stroke.dart';
void main() {
const pageSize = Size(400, 600);
Widget host({
required List<PenStroke> strokes,
required void Function(PenStroke) onComplete,
required TransformationController controller,
bool allowFinger = false,
CanvasTool tool = CanvasTool.pen,
}) {
return MaterialApp(
home: Scaffold(
body: Center(
child: SizedBox(
width: pageSize.width,
height: pageSize.height,
child: PenCanvas(
pageWidget: Container(color: const Color(0xFFEEEEEE)),
pageSize: pageSize,
strokes: strokes,
transformationController: controller,
tool: tool,
color: const Color(0xFF000000),
strokeWidth: 0.004,
allowFingerDrawing: allowFinger,
onStrokeComplete: onComplete,
onEraseStroke: (_, _) {},
),
),
),
),
);
}
testWidgets('a stylus drag produces a committed stroke', (tester) async {
final committed = <PenStroke>[];
final controller = TransformationController();
addTearDown(controller.dispose);
await tester.pumpWidget(host(
strokes: const [],
onComplete: committed.add,
controller: controller,
));
final center = tester.getCenter(find.byType(PenCanvas));
final g = await tester.startGesture(center,
kind: PointerDeviceKind.stylus);
await g.moveBy(const Offset(20, 10));
await g.moveBy(const Offset(20, 30));
await g.moveBy(const Offset(10, 20));
await g.up();
await tester.pump();
expect(committed, hasLength(1));
expect(committed.single.points.length, greaterThan(1),
reason: 'a multi-segment drag is not a single dot');
});
testWidgets('a single finger does NOT draw when finger-drawing is off',
(tester) async {
final committed = <PenStroke>[];
final controller = TransformationController();
addTearDown(controller.dispose);
await tester.pumpWidget(host(
strokes: const [],
onComplete: committed.add,
controller: controller,
allowFinger: false,
));
final center = tester.getCenter(find.byType(PenCanvas));
final g = await tester.startGesture(center, kind: PointerDeviceKind.touch);
await g.moveBy(const Offset(30, 30));
await g.up();
await tester.pump();
expect(committed, isEmpty, reason: 'palm/finger rejection');
});
testWidgets('a finger DOES draw when finger-drawing is on', (tester) async {
final committed = <PenStroke>[];
final controller = TransformationController();
addTearDown(controller.dispose);
await tester.pumpWidget(host(
strokes: const [],
onComplete: committed.add,
controller: controller,
allowFinger: true,
));
final center = tester.getCenter(find.byType(PenCanvas));
final g = await tester.startGesture(center, kind: PointerDeviceKind.touch);
await g.moveBy(const Offset(30, 30));
await g.up();
await tester.pump();
expect(committed, hasLength(1));
});
testWidgets('a second pointer cancels an in-progress stylus stroke (pinch)',
(tester) async {
final committed = <PenStroke>[];
final controller = TransformationController();
addTearDown(controller.dispose);
await tester.pumpWidget(host(
strokes: const [],
onComplete: committed.add,
controller: controller,
));
final center = tester.getCenter(find.byType(PenCanvas));
final g1 = await tester.startGesture(center, kind: PointerDeviceKind.stylus);
await g1.moveBy(const Offset(10, 10));
// A second finger lands → the stroke must be discarded (pinch/palm).
final g2 = await tester.startGesture(
center + const Offset(60, 0), kind: PointerDeviceKind.touch);
await g1.moveBy(const Offset(10, 10));
await g1.up();
await g2.up();
await tester.pump();
expect(committed, isEmpty, reason: '2nd pointer cancels the stroke');
});
testWidgets('renders committed strokes through the render cache without error',
(tester) async {
final controller = TransformationController();
addTearDown(controller.dispose);
final strokes = [
PenStroke(
points: const [PenPoint(0.1, 0.1, 0.5), PenPoint(0.4, 0.5, 0.6)],
color: 0xFF000000,
width: 0.004,
kind: PenStrokeKind.pen,
),
];
await tester.pumpWidget(host(
strokes: strokes,
onComplete: (_) {},
controller: controller,
));
await tester.pump();
// Built + painted the StaticInkPainter (render cache) with no exception.
expect(tester.takeException(), isNull);
expect(find.byType(PenCanvas), findsOneWidget);
});
}