Files
BadNote/test/pdf_document_source_test.dart
Akiba So 6b7cc14836
Some checks failed
CI / Windows build (push) Has been cancelled
feat(p0.5): PageDocumentSource seam + fit-to-width metrics glue (step 10)
Connects the two pure P0.5 pieces: a minimal PageDocumentSource abstraction
(pageCount + pageSize, a pdfrx PdfDocument in production) and
pageStackMetricsForWidth() which fits every page to a single column width
(continuous-single) — height = columnWidth × aspect — feeding
PageStackMetrics.visibleRange. Defensive against non-positive page width.

This makes the windowing math consumable + unit-testable against a fake source
(no pdfium/GPU); the production pdfrx adapter is the thin device-side wrapper
added with the page-mounting widget.

flutter analyze lib/editor clean; 120/120 tests (+5: fit-to-width, gap, empty,
zero-width guard, windowing composition).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 03:10:05 +08:00

65 lines
2.5 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Tests for the document→layout glue (P0.5 step 10, automatable slice):
// fit-to-width metrics built from a fake PageDocumentSource. No pdfium.
import 'dart:ui' show Size;
import 'package:flutter_test/flutter_test.dart';
import 'package:badnote/editor/layout/page_viewport.dart';
import 'package:badnote/editor/pdf/pdf_document_source.dart';
class _FakeSource implements PageDocumentSource {
_FakeSource(this._sizes);
final List<Size> _sizes;
@override
int get pageCount => _sizes.length;
@override
Size pageSize(int index) => _sizes[index];
}
void main() {
test('fit-to-width scales each page height by its aspect at the column width',
() {
// A4-ish portrait 600×800 and a square 500×500 at column width 300.
final source = _FakeSource([const Size(600, 800), const Size(500, 500)]);
final m = pageStackMetricsForWidth(source, 300);
expect(m.pageCount, 2);
expect(m.heightOf(0), closeTo(300 * 800 / 600, 1e-9)); // 400
expect(m.heightOf(1), closeTo(300.0, 1e-9)); // square → 300
expect(m.totalExtent, closeTo(700, 1e-9));
});
test('gap is threaded into the metrics', () {
final source = _FakeSource([const Size(100, 100), const Size(100, 100)]);
final m = pageStackMetricsForWidth(source, 100, gap: 25);
expect(m.offsetOf(1), closeTo(125, 1e-9)); // 100 + 25 gap
});
test('empty document yields empty metrics', () {
final m = pageStackMetricsForWidth(_FakeSource(const []), 300);
expect(m.pageCount, 0);
expect(m.totalExtent, 0);
});
test('non-positive page width is treated as zero height (no divide-by-zero)',
() {
final source = _FakeSource([const Size(0, 800), const Size(400, 200)]);
final m = pageStackMetricsForWidth(source, 300);
expect(m.heightOf(0), 0.0);
expect(m.heightOf(1), closeTo(150, 1e-9)); // 300 * 200/400
});
test('windowing composes on top of the fit-to-width metrics', () {
// 5 portrait pages 600×800 at width 300 → each 400 tall, total 2000.
final source =
_FakeSource(List.filled(5, const Size(600, 800)));
final m = pageStackMetricsForWidth(source, 300);
expect(m.totalExtent, closeTo(2000, 1e-9));
// viewport [350, 850) → page1 [400,800) and page2 [800,1200) just touched?
// page0 [0,400), page1 [400,800), page2 [800,1200). window [350,850]:
// first bottom>350 → page0 bottom 400>350 → 0; last top<850 → page2 top
// 800<850 → 2.
expect(m.visibleRange(350, 500), const PageWindow(0, 2));
});
}