-
Notifications
You must be signed in to change notification settings - Fork 366
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
#642 Test runner for repeat content with some tests
But need more...
- Loading branch information
Showing
5 changed files
with
337 additions
and
0 deletions.
There are no files selected for viewing
203 changes: 203 additions & 0 deletions
203
...src/test/java/com/openhtmltopdf/nonvisualregressiontests/RepeatContentRegressionTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,203 @@ | ||
package com.openhtmltopdf.nonvisualregressiontests; | ||
|
||
import static org.junit.Assert.assertEquals; | ||
import static org.junit.Assert.fail; | ||
|
||
import java.io.ByteArrayOutputStream; | ||
import java.io.File; | ||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.util.ArrayList; | ||
import java.util.Arrays; | ||
import java.util.Collections; | ||
import java.util.HashSet; | ||
import java.util.List; | ||
import java.util.Set; | ||
import java.util.function.Predicate; | ||
import java.util.regex.Pattern; | ||
import java.util.stream.Collectors; | ||
|
||
import org.apache.commons.io.FileUtils; | ||
import org.apache.pdfbox.io.IOUtils; | ||
import org.apache.pdfbox.pdmodel.PDDocument; | ||
import org.apache.pdfbox.text.PDFTextStripper; | ||
import org.apache.pdfbox.util.Charsets; | ||
import org.junit.Test; | ||
|
||
import com.openhtmltopdf.pdfboxout.PdfRendererBuilder; | ||
import com.openhtmltopdf.testcases.TestcaseRunner; | ||
import com.openhtmltopdf.visualtest.VisualTester.BuilderConfig; | ||
|
||
public class RepeatContentRegressionTest { | ||
private static final String RES_PATH = "/repeated-content-tests/"; | ||
private static final String OUT_PATH = "target/test/visual-tests/test-output/"; | ||
|
||
interface StringMatcher { | ||
List<String> problems(String expected, String actual); | ||
void doAssert(String expected, String actual, String fileName, List<String> problems); | ||
} | ||
|
||
/** | ||
* Simple tests with content all in one layer | ||
* (ie. no z-index, absolute, relative, fixed, transform) | ||
* should generally use an ordered matcher. | ||
*/ | ||
private static class OrderedMatcher implements StringMatcher { | ||
public List<String> problems(String expected, String actual) { | ||
if (!expected.equals(actual)) { | ||
return Collections.singletonList("Mismatched ordered"); | ||
} | ||
|
||
return Collections.emptyList(); | ||
} | ||
|
||
public void doAssert(String expected, String actual, String fileName, List<String> problems) { | ||
assertEquals("Mismatched: " + fileName, expected, actual); | ||
} | ||
} | ||
|
||
/** | ||
* Layers have to follow a specific painting order so they may be out of order. | ||
*/ | ||
private static class UnOrderedMatcher implements StringMatcher { | ||
public List<String> problems(String expected, String actual) { | ||
String[] expWords = expected.split("\\s"); | ||
String[] actWords = actual.split("\\s"); | ||
|
||
Predicate<String> filter = w -> !w.trim().isEmpty(); | ||
|
||
Set<String> exp = Arrays.stream(expWords) | ||
.filter(filter) | ||
.collect(Collectors.toSet()); | ||
|
||
List<String> act = Arrays.stream(actWords) | ||
.filter(filter) | ||
.collect(Collectors.toList()); | ||
|
||
Set<String> seen = new HashSet<>(); | ||
|
||
List<String> problems = new ArrayList<>(); | ||
|
||
for (String word : act) { | ||
if (seen.contains(word)) { | ||
problems.add("Repeat content: " + word); | ||
} | ||
|
||
seen.add(word); | ||
|
||
if (!exp.contains(word)) { | ||
problems.add("Unexpected content: " + word); | ||
} | ||
} | ||
|
||
for (String word : exp) { | ||
if (!act.contains(word)) { | ||
problems.add("Missing: " + word); | ||
} | ||
} | ||
|
||
return problems; | ||
} | ||
|
||
public void doAssert(String expected, String actual, String fileName, List<String> problems) { | ||
fail(problems.stream().collect(Collectors.joining("\n"))); | ||
} | ||
} | ||
|
||
private static final StringMatcher ORDERED = new OrderedMatcher(); | ||
private static final StringMatcher UNORDERED = new UnOrderedMatcher(); | ||
|
||
private static void render(String fileName, String html, BuilderConfig config, String proof, StringMatcher matcher) throws IOException { | ||
ByteArrayOutputStream actual = new ByteArrayOutputStream(); | ||
|
||
PdfRendererBuilder builder = new PdfRendererBuilder(); | ||
builder.withHtmlContent(html, NonVisualRegressionTest.class.getResource(RES_PATH).toString()); | ||
builder.toStream(actual); | ||
builder.useFastMode(); | ||
builder.testMode(true); | ||
config.configure(builder); | ||
|
||
try { | ||
builder.run(); | ||
} catch (IOException e) { | ||
System.err.println("Failed to render resource (" + fileName + ")"); | ||
e.printStackTrace(); | ||
throw e; | ||
} | ||
|
||
byte[] pdfBytes = actual.toByteArray(); | ||
|
||
try (PDDocument doc = PDDocument.load(pdfBytes)) { | ||
PDFTextStripper stripper = new PDFTextStripper(); | ||
stripper.setSuppressDuplicateOverlappingText(false); | ||
stripper.setLineSeparator("\n"); | ||
|
||
String text = stripper.getText(doc).trim(); | ||
String expected = proof.trim().replace("\r\n", "\n"); | ||
|
||
List<String> problems = matcher.problems(expected, text); | ||
|
||
if (!problems.isEmpty()) { | ||
FileUtils.writeByteArrayToFile(new File(OUT_PATH, fileName + ".pdf"), pdfBytes); | ||
|
||
matcher.doAssert(expected, text, fileName, problems); | ||
} | ||
} | ||
} | ||
|
||
private static void run(String fileName, BuilderConfig config, StringMatcher matcher) throws IOException { | ||
String absResPath = RES_PATH + fileName + ".html"; | ||
|
||
try (InputStream is = TestcaseRunner.class.getResourceAsStream(absResPath)) { | ||
byte[] htmlBytes = IOUtils.toByteArray(is); | ||
String htmlWithProof = new String(htmlBytes, Charsets.UTF_8); | ||
|
||
String[] parts = htmlWithProof.split(Pattern.quote("=======")); | ||
String html = parts[0]; | ||
String proof = parts[1]; | ||
|
||
render(fileName, html, config, proof, matcher); | ||
} | ||
} | ||
|
||
private static void runOrdered(String fileName) throws IOException { | ||
run(fileName, builder -> { }, ORDERED); | ||
} | ||
|
||
private static void runUnOrdered(String fileName) throws IOException { | ||
run(fileName, builder -> { }, UNORDERED); | ||
} | ||
|
||
/** | ||
* inline-blocks/relative/absolute with z-index. | ||
*/ | ||
@Test | ||
public void testInlineBlockZIndex() throws IOException { | ||
runOrdered("inline-block-z-index"); | ||
} | ||
|
||
/** | ||
* Multiple in-flow inline-blocks on the one page. | ||
*/ | ||
@Test | ||
public void testInlineBlockMultiple() throws IOException { | ||
runUnOrdered("inline-block-multiple"); | ||
} | ||
|
||
/** | ||
* Multiple in-flow inline-blocks across pages with large page margin. | ||
*/ | ||
@Test | ||
public void testInlineBlockPages() throws IOException { | ||
runUnOrdered("inline-block-pages"); | ||
} | ||
|
||
/** | ||
* Float that goes over two pages. | ||
*/ | ||
@Test | ||
public void testFloatsPages() throws IOException { | ||
runUnOrdered("floats-pages"); | ||
} | ||
|
||
} |
50 changes: 50 additions & 0 deletions
50
openhtmltopdf-examples/src/test/resources/repeated-content-tests/floats-pages.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
<html> | ||
<head> | ||
<style> | ||
@page { | ||
size: 180px 100px; | ||
margin: 20px; | ||
} | ||
body { | ||
font-size: 14px; | ||
margin: 0; | ||
} | ||
.flt-l { | ||
float: left; | ||
border: 1px solid red; | ||
margin: 3px; | ||
} | ||
.flt-r { | ||
float: right; | ||
border: 1px solid green; | ||
width: 60%; | ||
} | ||
</style> | ||
</head> | ||
<body> | ||
<div class="flt-l">one two three</div> | ||
four five six seven eleven | ||
<div class="flt-r">eight nine ten sixteen seventeen eighteen</div> | ||
twelve thirteen fourteen | ||
fifteen | ||
</body> | ||
</html> | ||
======= | ||
one | ||
two | ||
three | ||
four | ||
five | ||
six | ||
seven | ||
eight | ||
nine | ||
ten | ||
eleven | ||
twelve | ||
thirteen | ||
fourteen | ||
fifteen | ||
sixteen | ||
seventeen | ||
eighteen |
28 changes: 28 additions & 0 deletions
28
openhtmltopdf-examples/src/test/resources/repeated-content-tests/inline-block-multiple.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
<html> | ||
<head> | ||
<style> | ||
span { | ||
display: inline-block; | ||
} | ||
</style> | ||
</head> | ||
<body> | ||
<div><span>one</span></div> | ||
<div> <span>two</span> </div> | ||
<span>three</span> | ||
<span>four</span> | ||
<div><span>five</span> <span>six</span></div> | ||
<div> seven <span>eight</span> nine <span>ten</span></div> | ||
</body> | ||
</html> | ||
======= | ||
one | ||
two | ||
three | ||
four | ||
five | ||
six | ||
seven | ||
eight | ||
nine | ||
ten |
36 changes: 36 additions & 0 deletions
36
openhtmltopdf-examples/src/test/resources/repeated-content-tests/inline-block-pages.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
<html> | ||
<head> | ||
<style> | ||
@page { | ||
size: 100px 100px; | ||
margin: 20px; | ||
} | ||
body { | ||
font-size: 9px; | ||
margin: 0; | ||
} | ||
span { | ||
display: inline-block; | ||
} | ||
</style> | ||
</head> | ||
<body> | ||
<div><span>one</span></div> | ||
<div> <span>two</span> </div> | ||
<span>three</span> | ||
<span>four</span> | ||
<div><span>five</span> <span>six</span></div> | ||
<div> seven <span>eight</span> nine <span>ten</span></div> | ||
</body> | ||
</html> | ||
======= | ||
one | ||
two | ||
three | ||
four | ||
five | ||
six | ||
seven | ||
eight | ||
nine | ||
ten |
20 changes: 20 additions & 0 deletions
20
openhtmltopdf-examples/src/test/resources/repeated-content-tests/inline-block-z-index.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
<html> | ||
<head> | ||
<style> | ||
span { | ||
display: inline-block; | ||
} | ||
</style> | ||
</head> | ||
<body> | ||
<div><span style="position: relative; z-index: 100;">one</span></div> | ||
<div> <span style="position: relative; z-index: 101;">two</span> </div> | ||
<span style="position: relative; z-index: 102;">three</span> | ||
<span style="position: absolute; z-index: 103; top: 100px;">four</span> | ||
</body> | ||
</html> | ||
======= | ||
one | ||
two | ||
three | ||
four |