// Proves the InkStroke<->PenStroke bridge used to host notes/slides on the // pen-first canvas: normalization round-trips within the logical page, the // tool<->kind mapping is correct, and non-freehand strokes (shapes/text) are // dropped because the pen canvas cannot render them. import 'dart:ui' show Size; import 'package:flutter_test/flutter_test.dart'; import 'package:badnote/editor/canvas/pen_stroke.dart'; import 'package:badnote/editor/notebook/ink_stroke_adapter.dart'; import 'package:badnote/models/ink_point.dart'; import 'package:badnote/models/ink_stroke.dart'; import 'package:badnote/models/pen_tool.dart'; void main() { const page = Size(1000, 1414); final t0 = DateTime.fromMillisecondsSinceEpoch(0); InkStroke ink( List pts, { PenTool tool = PenTool.pen, double width = 2.0, int color = 0xFF112233, }) => InkStroke( id: 'a', points: pts, tool: tool, color: color, strokeWidth: width, createdAt: t0, ); InkPoint ip(double x, double y, {double pressure = 0.7}) => InkPoint(x: x, y: y, pressure: pressure, timestamp: 0); test('ink -> pen normalizes against the page', () { final pen = penStrokeFromInk( ink([ip(250, 707), ip(500, 1414)], width: 10), page)!; expect(pen.points.first.x, closeTo(0.25, 1e-9)); expect(pen.points.first.y, closeTo(0.5, 1e-9)); expect(pen.points[1].x, closeTo(0.5, 1e-9)); expect(pen.points[1].y, closeTo(1.0, 1e-9)); expect(pen.width, closeTo(10 / 1000, 1e-9)); expect(pen.color, 0xFF112233); expect(pen.kind, PenStrokeKind.pen); }); test('round-trip ink -> pen -> ink preserves coords, width, color', () { final original = ink([ip(123, 456), ip(789, 1000)], width: 7, color: 0xFFABCDEF); final pen = penStrokeFromInk(original, page)!; final back = inkStrokeFromPen(pen, page, id: 'b', createdAt: t0); for (var i = 0; i < original.points.length; i++) { expect(back.points[i].x, closeTo(original.points[i].x, 1e-6)); expect(back.points[i].y, closeTo(original.points[i].y, 1e-6)); } expect(back.strokeWidth, closeTo(7, 1e-6)); expect(back.color, 0xFFABCDEF); expect(back.tool, PenTool.pen); }); test('highlighter maps to the highlighter kind both ways', () { final pen = penStrokeFromInk( ink([ip(10, 10), ip(20, 20)], tool: PenTool.highlighter), page)!; expect(pen.kind, PenStrokeKind.highlighter); final back = inkStrokeFromPen(pen, page, id: 'c', createdAt: t0); expect(back.tool, PenTool.highlighter); }); test('non-freehand strokes (shapes/text) are dropped', () { for (final tool in [ PenTool.rectangle, PenTool.ellipse, PenTool.line, PenTool.arrow, PenTool.text, ]) { expect(penStrokeFromInk(ink([ip(0, 0), ip(5, 5)], tool: tool), page), isNull, reason: '$tool has no pen-canvas representation'); } }); test('penStrokesFromInk preserves order and filters non-freehand', () { final strokes = [ ink([ip(0, 0), ip(1, 1)], tool: PenTool.pen, color: 0xFF000001), ink([ip(2, 2), ip(3, 3)], tool: PenTool.rectangle), ink([ip(4, 4), ip(5, 5)], tool: PenTool.highlighter, color: 0xFF000002), ]; final pens = penStrokesFromInk(strokes, page); expect(pens, hasLength(2)); expect(pens[0].color, 0xFF000001); expect(pens[1].color, 0xFF000002); expect(pens[1].kind, PenStrokeKind.highlighter); }); }