97 lines
3.6 KiB
Dart
97 lines
3.6 KiB
Dart
|
|
// Behavioral test of the absolute-snapshot pinch fix (6829076) — device-
|
||
|
|
// independent (no pdfrx). Simulates a two-finger pinch over PenCanvas and
|
||
|
|
// samples the shared transform's scale each frame: a steady spread must grow
|
||
|
|
// the scale MONOTONICALLY, never spiking above the final value and snapping
|
||
|
|
// back (the reported flicker the fix removes).
|
||
|
|
|
||
|
|
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(TransformationController controller) => MaterialApp(
|
||
|
|
home: Scaffold(
|
||
|
|
body: Center(
|
||
|
|
child: SizedBox(
|
||
|
|
width: pageSize.width,
|
||
|
|
height: pageSize.height,
|
||
|
|
child: PenCanvas(
|
||
|
|
pageWidget: Container(color: const Color(0xFFEEEEEE)),
|
||
|
|
pageSize: pageSize,
|
||
|
|
strokes: const <PenStroke>[],
|
||
|
|
transformationController: controller,
|
||
|
|
tool: CanvasTool.pen,
|
||
|
|
color: const Color(0xFF000000),
|
||
|
|
strokeWidth: 0.004,
|
||
|
|
onStrokeComplete: (_) {},
|
||
|
|
onEraseStroke: (_, __) {},
|
||
|
|
),
|
||
|
|
),
|
||
|
|
),
|
||
|
|
),
|
||
|
|
);
|
||
|
|
|
||
|
|
testWidgets('a steady two-finger spread grows scale monotonically (no spike)',
|
||
|
|
(tester) async {
|
||
|
|
final controller = TransformationController();
|
||
|
|
addTearDown(controller.dispose);
|
||
|
|
await tester.pumpWidget(host(controller));
|
||
|
|
|
||
|
|
final center = tester.getCenter(find.byType(PenCanvas));
|
||
|
|
final f1 = await tester.startGesture(
|
||
|
|
center + const Offset(-20, 0), kind: PointerDeviceKind.touch);
|
||
|
|
final f2 = await tester.startGesture(
|
||
|
|
center + const Offset(20, 0), kind: PointerDeviceKind.touch);
|
||
|
|
|
||
|
|
final scales = <double>[];
|
||
|
|
for (var i = 0; i < 8; i++) {
|
||
|
|
// Spread the fingers apart symmetrically (pure zoom-in, focal steady).
|
||
|
|
await f1.moveBy(const Offset(-8, 0));
|
||
|
|
await f2.moveBy(const Offset(8, 0));
|
||
|
|
await tester.pump();
|
||
|
|
scales.add(controller.value.getMaxScaleOnAxis());
|
||
|
|
}
|
||
|
|
await f1.up();
|
||
|
|
await f2.up();
|
||
|
|
await tester.pump();
|
||
|
|
|
||
|
|
final maxScale = scales.reduce((a, b) => a > b ? a : b);
|
||
|
|
final finalScale = scales.last;
|
||
|
|
|
||
|
|
// Zoom actually happened.
|
||
|
|
expect(finalScale, greaterThan(1.0));
|
||
|
|
// No frame spiked ABOVE the final scale and snapped back — the fix's
|
||
|
|
// invariant. (Allow a tiny epsilon for fp.)
|
||
|
|
expect(maxScale, lessThanOrEqualTo(finalScale + 1e-6),
|
||
|
|
reason: 'a frame popped bigger than the final scale — flicker');
|
||
|
|
// Monotonic non-decreasing across the steady spread.
|
||
|
|
for (var i = 1; i < scales.length; i++) {
|
||
|
|
expect(scales[i], greaterThanOrEqualTo(scales[i - 1] - 1e-6),
|
||
|
|
reason: 'scale went backwards at frame $i: $scales');
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
testWidgets('the stylus never pans/zooms (excluded from the recognizer)',
|
||
|
|
(tester) async {
|
||
|
|
final controller = TransformationController();
|
||
|
|
addTearDown(controller.dispose);
|
||
|
|
await tester.pumpWidget(host(controller));
|
||
|
|
|
||
|
|
final center = tester.getCenter(find.byType(PenCanvas));
|
||
|
|
// A single stylus drag must DRAW, not pan — the transform stays identity.
|
||
|
|
final g = await tester.startGesture(center, kind: PointerDeviceKind.stylus);
|
||
|
|
await g.moveBy(const Offset(40, 40));
|
||
|
|
await g.up();
|
||
|
|
await tester.pump();
|
||
|
|
|
||
|
|
expect(controller.value.getMaxScaleOnAxis(), closeTo(1.0, 1e-9));
|
||
|
|
expect(controller.value.getTranslation().x, closeTo(0, 1e-6));
|
||
|
|
expect(controller.value.getTranslation().y, closeTo(0, 1e-6));
|
||
|
|
});
|
||
|
|
}
|