refactor(p0): extract pure input_arbiter from pen_canvas (step 4) + truth-table test
P0 step 4: the draw-vs-pan/zoom decision (single-pointer + device-kind + palm rejection + hardware-pan-button suppression) is lifted verbatim out of the PenCanvas StatefulWidget into pure functions in input/input_arbiter.dart, and pen_canvas now delegates _shouldDraw/_isStylus to them. Behavior-identical (same expressions), now decided by ONE unit-tested place. Adds test/input_arbiter_test.dart pinning the full truth table: stylus/mouse always draw, finger draws only with the toggle, >=2 pointers never draw (pinch owns it), hardware pan button suppresses, trackpad/unknown never draw. flutter analyze clean; 74/74 tests pass (+8). No live-path behavior change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
73
test/input_arbiter_test.dart
Normal file
73
test/input_arbiter_test.dart
Normal file
@@ -0,0 +1,73 @@
|
||||
// Truth-table tests for the pure draw-vs-pan arbitration (P0 step 4/8). These
|
||||
// pin the make-or-break gesture rules (palm rejection, finger toggle, hardware
|
||||
// pan button, multi-pointer = pinch) so a refactor of pen_canvas can't silently
|
||||
// change behavior.
|
||||
|
||||
import 'package:flutter/gestures.dart' show PointerDeviceKind;
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import 'package:badnote/editor/input/input_arbiter.dart';
|
||||
|
||||
void main() {
|
||||
group('isStylusKind', () {
|
||||
test('stylus and invertedStylus are pens; others are not', () {
|
||||
expect(isStylusKind(PointerDeviceKind.stylus), isTrue);
|
||||
expect(isStylusKind(PointerDeviceKind.invertedStylus), isTrue);
|
||||
expect(isStylusKind(PointerDeviceKind.touch), isFalse);
|
||||
expect(isStylusKind(PointerDeviceKind.mouse), isFalse);
|
||||
expect(isStylusKind(PointerDeviceKind.trackpad), isFalse);
|
||||
expect(isStylusKind(PointerDeviceKind.unknown), isFalse);
|
||||
});
|
||||
});
|
||||
|
||||
group('shouldDraw', () {
|
||||
bool draw(
|
||||
int count,
|
||||
PointerDeviceKind kind, {
|
||||
bool finger = false,
|
||||
bool hwPan = false,
|
||||
}) =>
|
||||
shouldDraw(
|
||||
activePointerCount: count,
|
||||
kind: kind,
|
||||
fingerDrawingEnabled: finger,
|
||||
hwPanActive: hwPan,
|
||||
);
|
||||
|
||||
test('a single stylus always draws', () {
|
||||
expect(draw(1, PointerDeviceKind.stylus), isTrue);
|
||||
expect(draw(1, PointerDeviceKind.invertedStylus), isTrue);
|
||||
});
|
||||
|
||||
test('a single mouse draws (desktop authoring)', () {
|
||||
expect(draw(1, PointerDeviceKind.mouse), isTrue);
|
||||
});
|
||||
|
||||
test('a single finger draws ONLY when finger-drawing is enabled', () {
|
||||
expect(draw(1, PointerDeviceKind.touch, finger: false), isFalse);
|
||||
expect(draw(1, PointerDeviceKind.touch, finger: true), isTrue);
|
||||
});
|
||||
|
||||
test('>= 2 pointers never draw (pinch owns it), even a stylus', () {
|
||||
expect(draw(2, PointerDeviceKind.stylus), isFalse);
|
||||
expect(draw(2, PointerDeviceKind.touch, finger: true), isFalse);
|
||||
expect(draw(3, PointerDeviceKind.mouse), isFalse);
|
||||
});
|
||||
|
||||
test('zero pointers never draw', () {
|
||||
expect(draw(0, PointerDeviceKind.stylus), isFalse);
|
||||
});
|
||||
|
||||
test('a hardware pan button suppresses drawing for any device', () {
|
||||
expect(draw(1, PointerDeviceKind.stylus, hwPan: true), isFalse);
|
||||
expect(draw(1, PointerDeviceKind.mouse, hwPan: true), isFalse);
|
||||
expect(draw(1, PointerDeviceKind.touch, finger: true, hwPan: true),
|
||||
isFalse);
|
||||
});
|
||||
|
||||
test('trackpad / unknown never draw', () {
|
||||
expect(draw(1, PointerDeviceKind.trackpad, finger: true), isFalse);
|
||||
expect(draw(1, PointerDeviceKind.unknown, finger: true), isFalse);
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user