Repository navigation
Rendering Invariant Tests Design & Coverage
Property-based rendering invariant test harness implemented in Pdfe.Rendering.Tests/RenderingInvariantTests.cs. These tests verify mathematical correctness of the PDF rendering pipeline by asserting invariants that must hold across varied random inputs.
32 passing tests covering 10 rendering invariants:
- 5 determinism tests (different seeds)
- 3 DPI scaling tests (72↔144, 100↔200, 150↔300)
- 4 background fill tests (white, red, green, blue)
- 2 translation invariance tests (horizontal, vertical)
- 1 identity transform test
- 4 empty page invariant tests (612x792, 595x842, 100x100, 2400x3000)
- 1 page-size proportionality test
- 5 RGB color round-trip tests (red, green, blue, gray, yellow)
- 4 CMYK color tests
- 1 stroke width visibility test
- 1 anti-aliasing existence test
- 1 scaling transform test
- Render same PDF twice with same DPI, compare byte-for-byte.
- Tests: seeds 42, 123, 456, 789, 999
- Verifies: Random rectangles + text render identically across renders.
- Render page at DPI1 and DPI2, verify bitmap dimensions scale correctly.
- Tests: 72↔144, 100↔200, 150↔300
- Verifies:
(bitmap_at_DPI2.width / bitmap_at_DPI1.width) ≈ (DPI2 / DPI1)
- Empty content stream with different background colors.
- Tests: white (0xFFFFFFFF), red (0xFFFF0000), green (0xFF00FF00), blue (0xFF0000FF)
- Verifies: All pixels match the specified background color.
- Render rectangle with/without CTM translation.
- Tests: horizontal (50pt), vertical (75pt)
- Verifies: Content renders with translation applied (CTM math correctness).
- Compare rendering with explicit identity matrix (
1 0 0 1 0 0 cm) vs. no transform. - Verifies: Identity transformation is a no-op, produces byte-identical output.
- Empty pages of different sizes, verify bitmap dimensions match formula.
- Tests: 612x792 (Letter), 595x842 (A4), 100x100 (small), 2400x3000 (large)
- Verifies:
bitmap_width = ⌊page_width * dpi / 72⌋,bitmap_height = ⌊page_height * dpi / 72⌋
- Two pages: (612, 792) and (612, 396) — half-height.
- Verifies: Half-height page renders to half bitmap height.
- Render PDF with RGB colors, sample pixel from rendered region.
- Tests: red (1,0,0), green (0,1,0), blue (0,0,1), gray (0.5,0.5,0.5), yellow (1,1,0)
- Verifies: Rendered pixels have dominant color channels matching the fill color.
- Render PDF with CMYK colors, verify non-background pixels.
- Tests: red (0,1,1,0), cyan (1,0,0,0), magenta (0,1,0,0), yellow (0,0,1,0)
- Verifies: CMYK colors render to non-background pixels (color space conversion works).
- Render same line with 10pt and 1pt strokes, compare pixel counts.
- Verifies: Thicker stroke produces significantly more pixels (10× scale factor).
- Render text at 100 DPI with AA enabled.
- Verifies: Scan line through text edge contains ≥3 distinct intermediate gray values.
- Small rectangle with 1.5× scaling.
- Verifies: Both unscaled and scaled versions render, scaled has more pixel coverage.
Static class that generates synthetic single-page PDFs with:
- N random-colored, random-positioned rectangles
- M random text lines
- Seeded Random for reproducibility
Used by determinism tests to verify rendering consistency.
Static utility class with three methods:
-
AreIdentical(bitmap1, bitmap2): Byte-for-byte equality check. -
PixelDifferenceCount(bitmap, expectedColor, tolerance): Count non-matching pixels. -
SampleColor(bitmap, x, y): Sample RGBA at position with bounds checking.
dotnet test Pdfe.Rendering.Tests --filter "FullyQualifiedName~RenderingInvariant"All 32 tests complete in ~5 seconds.
These invariants catch subtle bugs that hand-written tests miss:
- Determinism: Catches non-deterministic rendering (e.g., uninitialized state, timing-dependent code).
- DPI Scaling: Catches CTM (Current Transformation Matrix) scaling bugs.
- Color Round-Trip: Catches color space conversion errors (RGB↔CMYK).
- Transform Invariants: Catches coordinate system confusion (PDF bottom-left vs. Avalonia top-left).
- Anti-Aliasing: Catches rendering correctness (edge pixel sharpness).
By testing across random inputs rather than hand-crafted cases, we discover edge cases and regressions before they reach users.
- Inline images (BI/ID/EI) - Parser support incomplete, content rendering may not reflect parsed positions.
-
Clipping paths with rotation - Rotation operator (
/Rotate) not fully supported. - Gradient shading - Shading operators not yet implemented in coverage test suite.
- PDF transparency groups - Group state and blending modes require deeper operator support.
-
Inline images:
BI...ID...EIoperators are low-priority for the current redaction-focused feature set. - Rotation: Page rotation is tracked but not applied during rendering; requires coordinate flip in canvas setup.
- Gradients/Shading: Would require significant SkiaSharp shader plumbing.
- Transparency Groups: Requires tracking GS stack state and group scope; orthogonal to current invariant focus.
These can be added as future test enhancements without modifying production code.
Tests run in normal xUnit test suite (not separate benchmark project), capturing trends on every CI run. Thresholds are loose enough to avoid flakiness but tight enough to catch 2-3× regressions.