-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathShapeContainerVisualRegressionTest.java
More file actions
165 lines (153 loc) · 7.87 KB
/
ShapeContainerVisualRegressionTest.java
File metadata and controls
165 lines (153 loc) · 7.87 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
package com.demcha.testing.visual;
import com.demcha.compose.GraphCompose;
import com.demcha.compose.document.api.DocumentSession;
import com.demcha.compose.document.dsl.ParagraphBuilder;
import com.demcha.compose.document.dsl.SectionBuilder;
import com.demcha.compose.document.dsl.ShapeBuilder;
import com.demcha.compose.document.node.LayerAlign;
import com.demcha.compose.document.node.TextAlign;
import com.demcha.compose.document.style.DocumentColor;
import com.demcha.compose.document.style.DocumentInsets;
import com.demcha.compose.document.style.DocumentStroke;
import com.demcha.compose.document.style.DocumentTextDecoration;
import com.demcha.compose.document.style.DocumentTextStyle;
import com.demcha.compose.font.FontName;
import com.demcha.compose.testing.visual.PdfVisualRegression;
import org.junit.jupiter.api.Test;
class ShapeContainerVisualRegressionTest {
// The baselines are committed as Windows-rendered PNGs, but PDFBox
// font rendering drifts slightly across platforms (different system
// fonts, different antialiasing). On Linux CI we observe up to ~2%
// of pixels disagree even when the document is structurally
// identical. Allow a 2 500-pixel budget — that comfortably covers
// observed cross-platform drift (the worst case so far is ~1 300
// mismatched pixels on a 67 200-pixel image, i.e. 1.9 %) while
// still failing the test on a real visual regression that shifts
// shape geometry or fill colour (those touch many more pixels).
private static final PdfVisualRegression VISUAL = PdfVisualRegression.standard()
.perPixelTolerance(6)
.mismatchedPixelBudget(2_500);
private static final DocumentColor TEAL = DocumentColor.rgb(20, 60, 75);
private static final DocumentColor GOLD = DocumentColor.rgb(196, 153, 76);
private static final DocumentColor PAPER = DocumentColor.rgb(252, 248, 240);
private static final DocumentColor INK = DocumentColor.rgb(34, 38, 50);
private static final DocumentColor RULE = DocumentColor.rgb(212, 200, 178);
@Test
void circleWithTextMatchesVisualBaseline() throws Exception {
VISUAL.assertMatchesBaseline("shape-container-circle-with-text", circleWithText());
}
@Test
void ellipseWithOverlayMatchesVisualBaseline() throws Exception {
VISUAL.assertMatchesBaseline("shape-container-ellipse-overlay", ellipseWithOverlay());
}
@Test
void roundedRectCardMatchesVisualBaseline() throws Exception {
VISUAL.assertMatchesBaseline("shape-container-rounded-card", roundedRectCard());
}
private static byte[] circleWithText() throws Exception {
try (DocumentSession document = baseDocument(240, 180)) {
document.pageFlow()
.name("VisualCircle")
.spacing(8)
.addCircle(98, TEAL, circle -> circle
.name("VisualInitialCircle")
.padding(10)
.stroke(DocumentStroke.of(GOLD, 1.3))
.center(label("GC", 24, DocumentColor.WHITE, true))
.position(label("CLIP", 7, GOLD, true), 0, -10, LayerAlign.BOTTOM_CENTER))
.addParagraph(paragraph -> paragraph
.text("Path-clipped circle")
.textStyle(style(9, INK, false))
.align(TextAlign.CENTER)
.margin(DocumentInsets.zero()))
.build();
return document.toPdfBytes();
}
}
private static byte[] ellipseWithOverlay() throws Exception {
try (DocumentSession document = baseDocument(300, 190)) {
document.pageFlow()
.name("VisualEllipse")
.spacing(8)
.addEllipse(180, 92, GOLD, ellipse -> ellipse
.name("VisualOffsetEllipse")
.padding(10)
.stroke(DocumentStroke.of(TEAL, 1.0))
.center(label("Overlay", 16, INK, true))
.topRight(new ShapeBuilder()
.name("VisualBadge")
.size(44, 18)
.fillColor(TEAL)
.cornerRadius(9)
.build())
.position(label("TOP", 7, DocumentColor.WHITE, true), -6, 5, LayerAlign.TOP_RIGHT))
.addParagraph(paragraph -> paragraph
.text("Anchor plus offset")
.textStyle(style(9, INK, false))
.align(TextAlign.CENTER)
.margin(DocumentInsets.zero()))
.build();
return document.toPdfBytes();
}
}
private static byte[] roundedRectCard() throws Exception {
try (DocumentSession document = baseDocument(320, 210)) {
document.pageFlow()
.name("VisualRoundedCard")
.spacing(8)
.addContainer(card -> card
.name("VisualFeatureCard")
.roundedRect(190, 112, 16)
.fillColor(DocumentColor.WHITE)
.stroke(DocumentStroke.of(RULE, 0.8))
.padding(13)
.center(new SectionBuilder()
.name("CardCopy")
.spacing(5)
.addParagraph(paragraph -> paragraph
.text("Feature card")
.textStyle(style(14, TEAL, true))
.margin(DocumentInsets.zero()))
.addRich(rich -> rich
.plain("Children stay ")
.bold("semantic")
.plain(" and clipped."))
.build())
.topRight(new ShapeBuilder()
.name("CardBadge")
.size(46, 18)
.fillColor(TEAL)
.cornerRadius(9)
.build())
.position(label("NEW", 7, DocumentColor.WHITE, true), -6, 5, LayerAlign.TOP_RIGHT))
.build();
return document.toPdfBytes();
}
}
private static DocumentSession baseDocument(double width, double height) {
return GraphCompose.document()
.pageSize(width, height)
.pageBackground(PAPER)
.margin(DocumentInsets.of(18))
.create();
}
private static com.demcha.compose.document.node.DocumentNode label(String text,
double size,
DocumentColor color,
boolean bold) {
return new ParagraphBuilder()
.text(text)
.textStyle(style(size, color, bold))
.align(TextAlign.CENTER)
.margin(DocumentInsets.zero())
.build();
}
private static DocumentTextStyle style(double size, DocumentColor color, boolean bold) {
return DocumentTextStyle.builder()
.fontName(bold ? FontName.HELVETICA_BOLD : FontName.HELVETICA)
.decoration(bold ? DocumentTextDecoration.BOLD : DocumentTextDecoration.DEFAULT)
.size(size)
.color(color)
.build();
}
}