// 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 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 = []; 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 = []; 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 = []; 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 = []; 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); }); }