Files
BadNote/test/pen_eraser_mode_widget_test.dart

102 lines
3.4 KiB
Dart
Raw Normal View History

// Guards the two eraser modes (the "优化橡皮擦工具" work): the default point
// eraser cuts a stroke into surviving segments, while the new stroke-eraser
// mode removes the entire stroke on contact. Both are driven by the same
// stylus pass; only the eraserWholeStroke flag differs.
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);
// A long horizontal stroke spanning the page through the vertical center.
PenStroke longStroke() => PenStroke(
points: const [
PenPoint(0.1, 0.5, 0.5),
PenPoint(0.3, 0.5, 0.5),
PenPoint(0.5, 0.5, 0.5),
PenPoint(0.7, 0.5, 0.5),
PenPoint(0.9, 0.5, 0.5),
],
color: 0xFF000000,
width: 0.004,
kind: PenStrokeKind.pen,
);
Widget host({
required void Function(int, List<PenStroke>) onErase,
required bool wholeStroke,
}) {
final controller = TransformationController();
addTearDown(controller.dispose);
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: [longStroke()],
transformationController: controller,
tool: CanvasTool.eraser,
color: const Color(0xFF000000),
strokeWidth: 0.004,
eraserWholeStroke: wholeStroke,
onStrokeComplete: (_) {},
onEraseStroke: onErase,
),
),
),
),
);
}
// Drag the eraser vertically through the page center (normalized 0.5, 0.5),
// grazing the MIDDLE of the long horizontal stroke.
Future<void> erasePass(WidgetTester tester) async {
final center = tester.getCenter(find.byType(PenCanvas));
final g = await tester.startGesture(center + const Offset(0, -15),
kind: PointerDeviceKind.stylus);
await g.moveBy(const Offset(0, 15));
await g.moveBy(const Offset(0, 15));
await g.up();
await tester.pump();
}
testWidgets('point eraser (default) splits the stroke into surviving pieces',
(tester) async {
List<PenStroke>? replacement;
await tester.pumpWidget(host(
onErase: (_, pieces) => replacement = pieces,
wholeStroke: false,
));
await erasePass(tester);
expect(replacement, isNotNull, reason: 'an erase should have fired');
// Grazing the middle leaves the two ends as surviving sub-strokes.
expect(replacement!.length, greaterThanOrEqualTo(1));
expect(replacement, isNotEmpty,
reason: 'point eraser keeps the untouched ends');
});
testWidgets('stroke eraser removes the entire stroke on contact',
(tester) async {
List<PenStroke>? replacement;
await tester.pumpWidget(host(
onErase: (_, pieces) => replacement = pieces,
wholeStroke: true,
));
await erasePass(tester);
expect(replacement, isNotNull, reason: 'an erase should have fired');
expect(replacement, isEmpty,
reason: 'stroke eraser deletes the whole stroke, leaving no pieces');
});
}