Skip to content

Commit 19a53f6

Browse files
committed
feat(CORE-1196): migrate to JUnit 5, add Levi Symbol Font Tests
1 parent 2a86007 commit 19a53f6

5 files changed

Lines changed: 310 additions & 154 deletions

File tree

pom.xml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,30 @@
5454
<version>${docp.core.version}</version>
5555
<scope>test</scope>
5656
</dependency>
57+
58+
<!-- Test are migrated to JUnit 5
59+
only ImageComparison Test needs AssertionFailedError
60+
we need a JUnit 5 alternative ImageComparison -->
5761
<dependency>
5862
<groupId>junit</groupId>
5963
<artifactId>junit</artifactId>
6064
<version>4.13.1</version>
6165
<scope>test</scope>
6266
</dependency>
67+
68+
69+
<dependency>
70+
<groupId>org.junit.jupiter</groupId>
71+
<artifactId>junit-jupiter-api</artifactId>
72+
<version>5.10.0</version>
73+
<scope>test</scope>
74+
</dependency>
75+
<dependency>
76+
<groupId>org.junit.jupiter</groupId>
77+
<artifactId>junit-jupiter-engine</artifactId>
78+
<version>5.10.0</version>
79+
<scope>test</scope>
80+
</dependency>
6381
<!-- Needed if you want an image-diff (by setting env-var: ICT_SHOW_DIFFS=true) -->
6482
<dependency>
6583
<groupId>org.swinglabs.swingx</groupId>
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package com.levigo.jadice.fonts;
2+
3+
4+
import static com.levigo.jadice.document.io.IOUtils.wrap;
5+
6+
import java.awt.image.BufferedImage;
7+
import java.io.IOException;
8+
import java.lang.reflect.Method;
9+
10+
import org.junit.jupiter.api.TestTemplate;
11+
import org.junit.jupiter.api.extension.ExtendWith;
12+
13+
import com.levigo.jadice.document.ImageComparisonTest;
14+
import com.levigo.jadice.document.io.SeekableInputStream;
15+
import com.levigo.jadice.format.truetype.internal.TrueTypeFont;
16+
import com.levigo.jadice.format.truetype.internal.TrueTypeFontLoader;
17+
18+
@ExtendWith(ParameterizedTestProvider.class)
19+
public abstract class AbstractFontResourceTest {
20+
21+
static final class PublicImageComparisonTest extends ImageComparisonTest {
22+
@Override
23+
public void compareWithExpected(BufferedImage bufferedImage, String s) throws IOException, ClassNotFoundException {
24+
super.compareWithExpected(bufferedImage, s);
25+
}
26+
}
27+
protected String fontResourceName;
28+
protected SeekableInputStream fontStream;
29+
protected TrueTypeFont fontResource;
30+
protected PublicImageComparisonTest imageComparisonTest;
31+
32+
public void initializeResource() throws Exception {
33+
fontStream = wrap(getClass().getResourceAsStream(fontResourceName));
34+
final TrueTypeFontLoader fontLoader = new TrueTypeFontLoader();
35+
fontResource = (TrueTypeFont) fontLoader.load(fontStream);
36+
imageComparisonTest = new PublicImageComparisonTest();
37+
System.err.println("Initialize Resource: " + fontResourceName);
38+
}
39+
40+
public void freeResource() throws Exception {
41+
System.err.println("Free Resource: " + fontResourceName);
42+
fontStream.close();
43+
fontStream = null;
44+
fontResource = null;
45+
imageComparisonTest = null;
46+
}
47+
48+
public abstract Iterable<String> fontResourceNames();
49+
50+
51+
@TestTemplate
52+
public void runAllTests() throws Exception {
53+
for (Method method : this.getClass().getDeclaredMethods()) {
54+
if (method.isAnnotationPresent(FontResourceTestCase.class)) {
55+
System.err.println("→ Start: " + method.getName() + " with " + fontResourceName);
56+
method.setAccessible(true);
57+
method.invoke(this);
58+
}
59+
}
60+
}
61+
}

src/test/java/com/levigo/jadice/fonts/CompatibilityTest.java renamed to src/test/java/com/levigo/jadice/fonts/FontResourceTest.java

Lines changed: 135 additions & 154 deletions
Original file line numberDiff line numberDiff line change
@@ -1,154 +1,135 @@
1-
package com.levigo.jadice.fonts;
2-
3-
import static com.levigo.jadice.document.io.IOUtils.wrap;
4-
import static com.levigo.jadice.format.truetype.internal.FSType.FSTYPE_EMBEDDING_INSTALLABLE;
5-
import static com.levigo.jadice.format.truetype.internal.structure.TrueTypeConstants.PLATFORM_ID_MS;
6-
import static com.levigo.jadice.format.truetype.internal.structure.TrueTypeConstantsMS.ENCODING_ID_MS_UNICODE_BMP;
7-
import static java.awt.geom.AffineTransform.getScaleInstance;
8-
import static org.hamcrest.CoreMatchers.is;
9-
import static org.junit.Assert.assertThat;
10-
11-
import java.awt.Color;
12-
import java.awt.Graphics2D;
13-
import java.awt.Rectangle;
14-
import java.awt.geom.Rectangle2D;
15-
import java.awt.image.BufferedImage;
16-
import java.io.IOException;
17-
18-
import org.junit.Before;
19-
import org.junit.Test;
20-
import org.junit.runner.RunWith;
21-
import org.junit.runners.Parameterized;
22-
23-
import com.levigo.jadice.document.ImageComparisonTest;
24-
import com.levigo.jadice.document.JadiceException;
25-
import com.levigo.jadice.document.internal.model.font.JadiceGlyphVector;
26-
import com.levigo.jadice.document.internal.render.font.GraphicsContextOutlineFontRenderer;
27-
import com.levigo.jadice.document.internal.render.j2d.Graphics2DBridge;
28-
import com.levigo.jadice.document.io.SeekableInputStream;
29-
import com.levigo.jadice.format.truetype.internal.TrueTypeFont;
30-
import com.levigo.jadice.format.truetype.internal.TrueTypeFontLoader;
31-
import com.levigo.jadice.format.truetype.internal.structure.CMap;
32-
33-
@RunWith(Parameterized.class)
34-
public class CompatibilityTest extends ImageComparisonTest {
35-
36-
private static final String SAMPLE_TEXT = "ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜ " + "abcdefghijklmnopqrstuvwxyzäöüß "
37-
+ "1234567890 " + "@€!\"§$%&/()=?{}[]\\<>|,;.:-_#'+*~´`µ°^²³";
38-
39-
private static final int FONT_SIZE = 40;
40-
41-
private static final int MARKER_SIZE = 3;
42-
43-
@Parameterized.Parameters(name = "{index} - {0}")
44-
public static Object[] parameters() {
45-
return new Object[]{
46-
"mono/Cousine-Regular.ttf", "mono/Cousine-Bold.ttf", "mono/Cousine-Italic.ttf", "mono/Cousine-BoldItalic.ttf",
47-
"sans/Arimo-Regular.ttf", "sans/Arimo-Bold.ttf", "sans/Arimo-Italic.ttf", "sans/Arimo-BoldItalic.ttf",
48-
"serif/Tinos-Regular.ttf", "serif/Tinos-Bold.ttf", "serif/Tinos-Italic.ttf", "serif/Tinos-BoldItalic.ttf",
49-
"symbol/Levibats-Regular.ttf"
50-
};
51-
}
52-
53-
@Parameterized.Parameter(0)
54-
public String fontResource;
55-
56-
public TrueTypeFont font;
57-
58-
@Before
59-
public void setUpTrueTypeFont() throws IOException, JadiceException {
60-
final SeekableInputStream inputStream = wrap(getClass().getResourceAsStream(fontResource));
61-
final TrueTypeFontLoader fontLoader = new TrueTypeFontLoader();
62-
font = (TrueTypeFont) fontLoader.load(inputStream);
63-
}
64-
65-
@Test
66-
public void assertThat_fsType_allowsEditing() {
67-
assertThat(font.getFsType(), is(FSTYPE_EMBEDDING_INSTALLABLE.getMask()));
68-
}
69-
70-
@Test
71-
public void assertThat_renderedGlyphVector_hasExpectedVisualOutput() throws Exception {
72-
final CMap microsoftUnicodeCMap = font.getCMap(PLATFORM_ID_MS, ENCODING_ID_MS_UNICODE_BMP);
73-
final int[] codePoints = new int[SAMPLE_TEXT.length()];
74-
final char[] sampleTextChars = SAMPLE_TEXT.toCharArray();
75-
for (int i = 0; i < sampleTextChars.length; i++) {
76-
codePoints[i] = microsoftUnicodeCMap.map(sampleTextChars[i]);
77-
}
78-
79-
final JadiceGlyphVector glyphVector = new JadiceGlyphVector(0, 0, font, codePoints, sampleTextChars);
80-
glyphVector.setTransform(getScaleInstance(FONT_SIZE, FONT_SIZE));
81-
82-
final BufferedImage renderedGlyphVector = render(glyphVector);
83-
compareWithExpected(renderedGlyphVector, fontResource);
84-
}
85-
86-
private BufferedImage render(final JadiceGlyphVector glv) {
87-
final GraphicsContextOutlineFontRenderer renderer = new GraphicsContextOutlineFontRenderer();
88-
89-
final Rectangle2D b = glv.getGlyphLogicalBounds(0).getBounds2D();
90-
b.add(glv.getGlyphLogicalBounds(glv.getNumGlyphs() - 1).getBounds2D());
91-
b.add(0, 0); // make sure to include origin!
92-
93-
final Rectangle bounds = b.getBounds();
94-
final int gap = bounds.height / 2;
95-
final BufferedImage img = new BufferedImage(bounds.width + gap, bounds.height + gap, BufferedImage.TYPE_INT_RGB);
96-
final Graphics2D g = img.createGraphics();
97-
g.setColor(Color.WHITE);
98-
g.fillRect(0, 0, img.getWidth(), img.getHeight());
99-
100-
g.setColor(Color.BLACK);
101-
102-
final Graphics2DBridge gc = new Graphics2DBridge(g);
103-
gc.scale(1, -1);
104-
gc.translate(gap / 2, -(bounds.height + bounds.y + gap / 2));
105-
106-
// draw bounding box
107-
g.setColor(Color.RED);
108-
g.draw(glv.getVisualBounds());
109-
110-
// draw glyph info
111-
final float p1[] = new float[2];
112-
final float p0[] = new float[2];
113-
for (int i = 0; i < glv.getNumGlyphs(); i++) {
114-
g.setColor(Color.ORANGE);
115-
g.draw(glv.getGlyphVisualBounds(i));
116-
117-
g.setColor(Color.BLUE);
118-
g.draw(glv.getGlyphLogicalBounds(i));
119-
120-
// position
121-
g.setColor(Color.GREEN.darker());
122-
glv.getGlyphPosition(i, p1);
123-
p1[0] += glv.getPosX();
124-
p1[1] += glv.getPosY();
125-
drawX(g, (int) p1[0], (int) p1[1]);
126-
127-
// advance
128-
if (i > 0) {
129-
glv.getGlyphPosition(i - 1, p0);
130-
p0[0] += glv.getPosX();
131-
p0[1] += glv.getPosY();
132-
g.drawLine((int) p0[0], (int) p0[1], (int) p1[0], (int) p1[1]);
133-
}
134-
}
135-
136-
// draw origin
137-
g.setColor(Color.MAGENTA);
138-
drawX(g, 0, 0);
139-
140-
// draw outline
141-
final com.levigo.jadice.document.internal.model.Color color = com.levigo.jadice.document.internal.model.Color.BLACK;
142-
gc.setColor(color);
143-
final Color awtColor = color.toAWTColor();
144-
renderer.render(glv, gc, null, null, awtColor, awtColor);
145-
146-
return img;
147-
}
148-
149-
private void drawX(final Graphics2D g, int x, int y) {
150-
g.drawLine(x - MARKER_SIZE, y - MARKER_SIZE, x + MARKER_SIZE, y + MARKER_SIZE);
151-
g.drawLine(x - MARKER_SIZE, y + MARKER_SIZE, x + MARKER_SIZE, y - MARKER_SIZE);
152-
}
153-
154-
}
1+
package com.levigo.jadice.fonts;
2+
3+
import static com.levigo.jadice.format.truetype.internal.FSType.FSTYPE_EMBEDDING_INSTALLABLE;
4+
import static com.levigo.jadice.format.truetype.internal.structure.TrueTypeConstants.PLATFORM_ID_MS;
5+
import static com.levigo.jadice.format.truetype.internal.structure.TrueTypeConstantsMS.ENCODING_ID_MS_UNICODE_BMP;
6+
import static java.awt.geom.AffineTransform.getScaleInstance;
7+
8+
import java.awt.Color;
9+
import java.awt.Graphics2D;
10+
import java.awt.Rectangle;
11+
import java.awt.geom.Rectangle2D;
12+
import java.awt.image.BufferedImage;
13+
import java.util.Arrays;
14+
15+
import org.junit.jupiter.api.Assertions;
16+
17+
import com.levigo.jadice.document.internal.model.font.JadiceGlyphVector;
18+
import com.levigo.jadice.document.internal.render.font.GraphicsContextOutlineFontRenderer;
19+
import com.levigo.jadice.document.internal.render.j2d.Graphics2DBridge;
20+
import com.levigo.jadice.format.truetype.internal.TrueTypeFont;
21+
import com.levigo.jadice.format.truetype.internal.structure.CMap;
22+
23+
public class FontResourceTest extends AbstractFontResourceTest {
24+
private static final String LEVI_SYMBOL_REGULAR = "LeviSymbol-Regular";
25+
26+
private static final String SAMPLE_TEXT = "ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜ " + "abcdefghijklmnopqrstuvwxyzäöüß "
27+
+ "1234567890 " + "@€!\"§$%&/()=?{}[]\\<>|,;.:-_#'+*~´`µ°^²³";
28+
private static final int FONT_SIZE = 40;
29+
private static final int MARKER_SIZE = 3;
30+
31+
@Override
32+
public Iterable<String> fontResourceNames() {
33+
return Arrays.asList(
34+
"mono/Cousine-Regular.ttf", "mono/Cousine-Bold.ttf", "mono/Cousine-Italic.ttf", "mono/Cousine-BoldItalic.ttf",
35+
"sans/Arimo-Regular.ttf", "sans/Arimo-Bold.ttf", "sans/Arimo-Italic.ttf", "sans/Arimo-BoldItalic.ttf",
36+
"serif/Tinos-Regular.ttf", "serif/Tinos-Bold.ttf", "serif/Tinos-Italic.ttf", "serif/Tinos-BoldItalic.ttf",
37+
"symbol/Levibats-Regular.ttf", "symbol/LeviSymbol-Regular.ttf");
38+
}
39+
40+
@FontResourceTestCase
41+
public void assertThat_fsType_allowsEditing() {
42+
Assertions.assertEquals(fontResource.getFsType(), FSTYPE_EMBEDDING_INSTALLABLE.getMask());
43+
}
44+
45+
@FontResourceTestCase
46+
public void assertThat_renderedGlyphVector_hasExpectedVisualOutput() throws Exception {
47+
if (skipRenderTest(fontResource))
48+
return;
49+
50+
final CMap microsoftUnicodeCMap = fontResource.getCMap(PLATFORM_ID_MS, ENCODING_ID_MS_UNICODE_BMP);
51+
final int[] codePoints = new int[SAMPLE_TEXT.length()];
52+
final char[] sampleTextChars = SAMPLE_TEXT.toCharArray();
53+
for (int i = 0; i < sampleTextChars.length; i++) {
54+
codePoints[i] = microsoftUnicodeCMap.map(sampleTextChars[i]);
55+
}
56+
57+
final JadiceGlyphVector glyphVector = new JadiceGlyphVector(0, 0, fontResource, codePoints, sampleTextChars);
58+
glyphVector.setTransform(getScaleInstance(FONT_SIZE, FONT_SIZE));
59+
60+
final BufferedImage renderedGlyphVector = render(glyphVector);
61+
imageComparisonTest.compareWithExpected(renderedGlyphVector, fontResourceName);
62+
}
63+
64+
private BufferedImage render(final JadiceGlyphVector glv) {
65+
final GraphicsContextOutlineFontRenderer renderer = new GraphicsContextOutlineFontRenderer();
66+
67+
final Rectangle2D b = glv.getGlyphLogicalBounds(0).getBounds2D();
68+
b.add(glv.getGlyphLogicalBounds(glv.getNumGlyphs() - 1).getBounds2D());
69+
b.add(0, 0); // make sure to include origin!
70+
71+
final Rectangle bounds = b.getBounds();
72+
final int gap = bounds.height / 2;
73+
final BufferedImage img = new BufferedImage(bounds.width + gap, bounds.height + gap, BufferedImage.TYPE_INT_RGB);
74+
final Graphics2D g = img.createGraphics();
75+
g.setColor(Color.WHITE);
76+
g.fillRect(0, 0, img.getWidth(), img.getHeight());
77+
78+
g.setColor(Color.BLACK);
79+
80+
final Graphics2DBridge gc = new Graphics2DBridge(g);
81+
gc.scale(1, -1);
82+
gc.translate(gap / 2, -(bounds.height + bounds.y + gap / 2));
83+
84+
// draw bounding box
85+
g.setColor(Color.RED);
86+
g.draw(glv.getVisualBounds());
87+
88+
// draw glyph info
89+
final float[] p1 = new float[2];
90+
final float[] p0 = new float[2];
91+
for (int i = 0; i < glv.getNumGlyphs(); i++) {
92+
g.setColor(Color.ORANGE);
93+
g.draw(glv.getGlyphVisualBounds(i));
94+
95+
g.setColor(Color.BLUE);
96+
g.draw(glv.getGlyphLogicalBounds(i));
97+
98+
// position
99+
g.setColor(Color.GREEN.darker());
100+
glv.getGlyphPosition(i, p1);
101+
p1[0] += glv.getPosX();
102+
p1[1] += glv.getPosY();
103+
drawX(g, (int) p1[0], (int) p1[1]);
104+
105+
// advance
106+
if (i > 0) {
107+
glv.getGlyphPosition(i - 1, p0);
108+
p0[0] += glv.getPosX();
109+
p0[1] += glv.getPosY();
110+
g.drawLine((int) p0[0], (int) p0[1], (int) p1[0], (int) p1[1]);
111+
}
112+
}
113+
114+
// draw origin
115+
g.setColor(Color.MAGENTA);
116+
drawX(g, 0, 0);
117+
118+
// draw outline
119+
final com.levigo.jadice.document.internal.model.Color color = com.levigo.jadice.document.internal.model.Color.BLACK;
120+
gc.setColor(color);
121+
final Color awtColor = color.toAWTColor();
122+
renderer.render(glv, gc, null, null, awtColor, awtColor);
123+
124+
return img;
125+
}
126+
127+
private void drawX(final Graphics2D g, int x, int y) {
128+
g.drawLine(x - MARKER_SIZE, y - MARKER_SIZE, x + MARKER_SIZE, y + MARKER_SIZE);
129+
g.drawLine(x - MARKER_SIZE, y + MARKER_SIZE, x + MARKER_SIZE, y - MARKER_SIZE);
130+
}
131+
132+
private boolean skipRenderTest(TrueTypeFont font) {
133+
return LEVI_SYMBOL_REGULAR.equals(font.getDescriptor().getPostscriptName());
134+
}
135+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.levigo.jadice.fonts;
2+
3+
import java.lang.annotation.ElementType;
4+
import java.lang.annotation.Retention;
5+
import java.lang.annotation.RetentionPolicy;
6+
import java.lang.annotation.Target;
7+
8+
@Retention(RetentionPolicy.RUNTIME)
9+
@Target(ElementType.METHOD)
10+
public @interface FontResourceTestCase {}

0 commit comments

Comments
 (0)