// Tests for the host-agnostic ink host (plan principle #2). import 'dart:ui' show Rect, Size; import 'package:flutter_test/flutter_test.dart'; import 'package:badnote/editor/engine/stroke_host.dart'; import 'package:badnote/editor/engine/stroke_model.dart'; EditorStroke _at(String id, double x, double y) => EditorStroke.create( id: id, points: [EditorPoint(x: x, y: y), EditorPoint(x: x + 0.05, y: y + 0.05)], ); void main() { test('exposes identity, content size, and a fresh store', () { final host = StrokeHost(hostId: 'doc:a:page:0', contentSize: const Size(595, 842)); expect(host.hostId, 'doc:a:page:0'); expect(host.contentSize, const Size(595, 842)); expect(host.revision, 0); }); test('revision tracks the store', () { final host = StrokeHost(hostId: 'h', contentSize: const Size(100, 100)); host.store.add(_at('s1', 0.1, 0.1)); expect(host.revision, 1); }); test('strokesIn culls strokes outside the viewport (board broad-phase)', () { final host = StrokeHost(hostId: 'board', contentSize: const Size(1000, 1000)); host.store ..add(_at('in', 0.1, 0.1)) // inside [0,0.5] ..add(_at('out', 0.8, 0.8)) // outside ..add(_at('edge', 0.48, 0.48)); // partial overlap with [0,0.5] final visible = host.strokesIn(const Rect.fromLTRB(0, 0, 0.5, 0.5)); expect(visible.map((s) => s.id).toSet(), {'in', 'edge'}); }); test('an injected store is adopted (load path)', () { final host = StrokeHost(hostId: 'h', contentSize: const Size(10, 10)); host.store.replaceAll([_at('a', 0.1, 0.1), _at('b', 0.2, 0.2)]); expect(host.store.committed.length, 2); expect(host.strokesIn(const Rect.fromLTRB(0, 0, 1, 1)).length, 2); }); }