From ffd1e0da6b73e2737f5cad0a6d3e82dbc3de206f Mon Sep 17 00:00:00 2001 From: Andreas Fitzek Date: Fri, 29 Aug 2014 15:09:54 +0200 Subject: Integrated PDF-AS Testing library --- .../serialization/html/HTMLSerializer.java | 204 +++++++++++++++++++++ .../serialization/html/HTMLTestSummaryWriter.java | 150 +++++++++++++++ .../serialization/html/PDFAHTMLSerizalier.java | 147 +++++++++++++++ .../html/SignaturePositionHTMLSerializer.java | 176 ++++++++++++++++++ 4 files changed, 677 insertions(+) create mode 100644 pdf-as-tests/src/test/java/at/gv/egiz/param_tests/serialization/html/HTMLSerializer.java create mode 100644 pdf-as-tests/src/test/java/at/gv/egiz/param_tests/serialization/html/HTMLTestSummaryWriter.java create mode 100644 pdf-as-tests/src/test/java/at/gv/egiz/param_tests/serialization/html/PDFAHTMLSerizalier.java create mode 100644 pdf-as-tests/src/test/java/at/gv/egiz/param_tests/serialization/html/SignaturePositionHTMLSerializer.java (limited to 'pdf-as-tests/src/test/java/at/gv/egiz/param_tests/serialization/html') diff --git a/pdf-as-tests/src/test/java/at/gv/egiz/param_tests/serialization/html/HTMLSerializer.java b/pdf-as-tests/src/test/java/at/gv/egiz/param_tests/serialization/html/HTMLSerializer.java new file mode 100644 index 00000000..9bbb0497 --- /dev/null +++ b/pdf-as-tests/src/test/java/at/gv/egiz/param_tests/serialization/html/HTMLSerializer.java @@ -0,0 +1,204 @@ +package at.gv.egiz.param_tests.serialization.html; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.Map.Entry; + +import at.gv.egiz.param_tests.provider.BaseSignatureTestData; +import at.gv.egiz.param_tests.serialization.TestInfoSerializer; +import at.gv.egiz.param_tests.testinfo.TestInfo; +import at.gv.egiz.param_tests.testinfo.TestVerdict; + +/** + * A subclass implementing some methods, which can be implemented independent of + * concrete test type. It uses the Twitter-bootstrap framework, which must be + * provided for the files to be correctly displayed in a browser. + * + * @author mtappler + * + * @param + * the type of TestInfo which instance of this class, respectively + * subclasses of it can serialize + */ +public abstract class HTMLSerializer extends + TestInfoSerializer { + + @Override + public String fileEnding() { + return "html"; + } + + @Override + protected void writeHeader(PrintWriter pw) { + BaseSignatureTestData baseData = baseTestInfo.getBaseTestData(); + pw.println(""); + pw.println(""); + pw.println(""); + pw.println("Test results for " + baseData.getTestName() + + ""); + pw.println(""); + pw.println(""); + pw.println(""); + pw.println(""); + pw.println(""); + pw.println("
"); + pw.println("
"); + pw.println("

Detailed test results " + baseData.getTestName() + + "

"); + pw.println("
"); + String basicTestDataPanel = createBasicTestData(); + writePanel(pw, "Basic test data", basicTestDataPanel); + } + + /** + * Helper method which creates three tabs, one for basic test parameter, one + * for the standard output and one for standard error. + * + * @return HTML-string defining the tabs + */ + protected String createBasicTestData() { + BaseSignatureTestData baseData = baseTestInfo.getBaseTestData(); + String basicParameterBody = createBasicParameterRepresentation(baseData); + StringBuilder basicTestDataPanel = new StringBuilder(); + basicTestDataPanel + .append(""); + basicTestDataPanel + .append("
"); + basicTestDataPanel + .append("
"); + basicTestDataPanel.append(basicParameterBody); + basicTestDataPanel.append("
"); + basicTestDataPanel.append("
"); + basicTestDataPanel.append("
"
+                + baseTestInfo.getStdOut() + "
"); + basicTestDataPanel.append("
"); + basicTestDataPanel.append("
"); + basicTestDataPanel.append("
"
+                + baseTestInfo.getStdErr() + "
"); + basicTestDataPanel.append("
"); + basicTestDataPanel.append("
"); + return basicTestDataPanel.toString(); + } + + /** + * This method creates a definition list for basic parameters of a test. + * + * @param baseData + * basic test parameters + * @return HTML-string defining a definition list + */ + private String createBasicParameterRepresentation( + BaseSignatureTestData baseData) { + StringBuilder sb = new StringBuilder(); + sb.append("
"); + sb.append(createDescription("Input file", baseData.getPdfFile())); + sb.append(createDescription("Output file", baseData.getOutputFile())); + sb.append(createDescription("Signature profile", baseData.getProfilID())); + sb.append(createDescription("Connector Type", baseData + .getConnectorData().getConnectorType())); + if (baseData.getConnectorData().getConnectorParameters().size() > 0) { + StringBuilder connectorParameters = new StringBuilder(); + connectorParameters.append("
"); + for (Entry e : baseData.getConnectorData() + .getConnectorParameters().entrySet()) + connectorParameters.append(createDescription(e.getKey(), + e.getValue())); + connectorParameters.append("
"); + sb.append(createDescription("Connector Parameters", + connectorParameters.toString())); + } + sb.append(createDescription("Test Type", getTestType())); + sb.append("
"); + return sb.toString(); + } + + /** + * Helper for writing a bootstrap panel with some title and content. + * + * @param pw + * PrintWriter-object to which the panel should be + * written + * @param panelTitle + * title of the panel + * @param panelBody + * panel content + */ + protected void writePanel(PrintWriter pw, String panelTitle, + String panelBody) { + pw.println("
"); + pw.println("
"); + pw.println("

" + panelTitle + "

"); + pw.println("
"); + pw.println("
"); + pw.println(panelBody); + pw.println("
"); + pw.println("
"); + } + + @Override + protected void writeTestResult(PrintWriter pw) { + StringBuilder panelBody = new StringBuilder(); + panelBody.append("

" + + HTMLTestSummaryWriter.verdictToLabel(baseTestInfo + .getVerdict()) + "

"); + if (baseTestInfo.getVerdict().equals(TestVerdict.FAILED) + || baseTestInfo.getVerdict().equals(TestVerdict.INCONCLUSIVE)) { + panelBody.append(createExceptionDataString(baseTestInfo + .getFailCause())); + } + writePanel(pw, "Test result", panelBody.toString()); + + } + + /** + * This method creates a HTML-representation for data contained in a + * throwable. + * + * @param t + * Throwable-object which should be displayed + * @return HTML-string for the throwable + */ + protected String createExceptionDataString(Throwable t) { + StringBuilder exceptionData = new StringBuilder(); + exceptionData.append("
"); + exceptionData.append(createDescription("Cause", t.toString())); + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + t.printStackTrace(pw); + exceptionData.append(createDescription("Stacktrace", sw.toString())); + exceptionData.append("
"); + return exceptionData.toString(); + } + + /** + * Helper method for creating an item of a definition list. + * + * @param term + * the term of the item (the key) + * @param definition + * the definition of the item (the value) + * @return an HTML-string for the definition list item + */ + protected String createDescription(String term, String definition) { + return String.format("
%s
%s
%n", term, definition); + } + + @Override + protected void writeFooter(PrintWriter pw) { + pw.println("Back to summary"); + pw.println(""); + pw.println(""); + pw.println("
"); + pw.println(""); + pw.println(""); + } +} diff --git a/pdf-as-tests/src/test/java/at/gv/egiz/param_tests/serialization/html/HTMLTestSummaryWriter.java b/pdf-as-tests/src/test/java/at/gv/egiz/param_tests/serialization/html/HTMLTestSummaryWriter.java new file mode 100644 index 00000000..0734a3ec --- /dev/null +++ b/pdf-as-tests/src/test/java/at/gv/egiz/param_tests/serialization/html/HTMLTestSummaryWriter.java @@ -0,0 +1,150 @@ +package at.gv.egiz.param_tests.serialization.html; + +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.io.UnsupportedEncodingException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.gv.egiz.param_tests.serialization.TestSummaryWriter; +import at.gv.egiz.param_tests.testinfo.TestInfo; +import at.gv.egiz.param_tests.testinfo.TestVerdict; + +/** + * Concrete implementation of the TestSummaryWriter, which creates + * HTML output and uses the Twitter-bootstrap framework. + * + * @author mtappler + * + */ +public class HTMLTestSummaryWriter implements TestSummaryWriter { + + /** + * the location of the test directory + */ + private String testDir; + /** + * the print writer which is used for writing + */ + private PrintWriter pw; + /** + * the logger for this class + */ + private static final Logger logger = LoggerFactory + .getLogger(HTMLTestSummaryWriter.class); + + /** + * Constructor which sets the test directory. + * + * @param testDir + * location of the test directory + */ + public HTMLTestSummaryWriter(String testDir) { + this.testDir = testDir; + } + + public void writeHeader() { + if (pw == null) + return; + pw.println(""); + pw.println(""); + pw.println(""); + pw.println("Summary of test results"); + pw.println(""); + pw.println(""); + pw.println(""); + pw.println(""); + pw.println(""); + pw.println("
"); + pw.println("
"); + pw.println("

Test result summary

"); + pw.println("
"); + pw.println(""); + pw.println(""); + pw.println(""); + pw.println(""); + pw.println(""); + pw.println(""); + pw.println(""); + pw.println(""); + pw.println(""); + + } + + public void writeSummaryOfTest(TestInfo tInfo, String testType) { + if (pw == null) + return; + pw.println(""); + pw.println(String.format( + "", tInfo + .getBaseTestData().getTestDirectory(), tInfo + .getBaseTestData().getTestName())); + pw.println(String.format("", tInfo.getBaseTestData() + .getTestDirectory())); + pw.println(String.format("", testType)); + pw.println(String.format("", + verdictToLabel(tInfo.getVerdict()))); + pw.println(""); + } + + // intentionally package protected + /** + * Static method for creating bootstrap label for a test verdict. Since it + * is technology dependent (HTML + bootstrap) it is defined as package + * protected. + * + * @param verdict + * the verdict of a test + * @return HTML-string for a verdict label + */ + static String verdictToLabel(TestVerdict verdict) { + switch (verdict) { + case FAILED: + return "Fail"; + case INCONCLUSIVE: + return "Inconclusive"; + case SUCCEEDED: + return "Success"; + default: + return "Unknown"; + } + } + + public void writeFooter() { + if (pw == null) + return; + + pw.println("
Test nameTest directoryTest typeVerdict
%s%s%s%s
"); + pw.println(""); + pw.println(""); + pw.println("
"); + pw.println(""); + pw.println(""); + } + + public void init() { + OutputStream os; + try { + os = new FileOutputStream(testDir + "/index.html"); + pw = new PrintWriter(new OutputStreamWriter(os, "UTF8")); + } catch (FileNotFoundException e) { + logger.debug("Could not find output file, not writing any summary", + e); + } catch (UnsupportedEncodingException e) { + logger.debug("Used unsupported encoding for writing summary file.", + e); + } + + } + + public void close() { + if (pw != null) + pw.close(); + } + +} diff --git a/pdf-as-tests/src/test/java/at/gv/egiz/param_tests/serialization/html/PDFAHTMLSerizalier.java b/pdf-as-tests/src/test/java/at/gv/egiz/param_tests/serialization/html/PDFAHTMLSerizalier.java new file mode 100644 index 00000000..fdaa80fa --- /dev/null +++ b/pdf-as-tests/src/test/java/at/gv/egiz/param_tests/serialization/html/PDFAHTMLSerizalier.java @@ -0,0 +1,147 @@ +package at.gv.egiz.param_tests.serialization.html; + +import java.io.PrintWriter; +import java.util.List; + +import org.apache.commons.lang3.tuple.Pair; +import org.apache.pdfbox.preflight.ValidationResult; +import org.apache.pdfbox.preflight.ValidationResult.ValidationError; + +import at.gv.egiz.param_tests.serialization.TestInfoSerializer; +import at.gv.egiz.param_tests.testinfo.PDFATestInfo; + +/** + * Concrete test information serializer for PDF-A conformance tests using HTML + * and Twitter-bootstrap. + * + * @author mtappler + * + */ +public class PDFAHTMLSerizalier extends HTMLSerializer { + + /** + * the test information object which is serialized, it is the same as + * TestInfoSerializer.baseTestInfo + */ + private PDFATestInfo testInfo; + + /** + * Default contructor used for registering it as prototype. + */ + public PDFAHTMLSerizalier() { + this(null); + } + + /** + * Package protected constructor used for cloning + * + * @param testInfo + */ + PDFAHTMLSerizalier(PDFATestInfo testInfo) { + this.testInfo = testInfo; + } + + @Override + public PDFATestInfo createTestInfo() { + testInfo = new PDFATestInfo(); + baseTestInfo = testInfo; + return testInfo; + } + + @Override + public TestInfoSerializer cloneSerializer() { + return new PDFAHTMLSerizalier(testInfo); + } + + @Override + protected void writeTestData(PrintWriter pw) { + pw.println("

Validation status before signing

"); + writeValidationResult(pw, testInfo.getResultBeforeSign()); + if (testInfo.getResultAfterSign() != null) { + pw.println("

Validation status after signing

"); + writeValidationResult(pw, testInfo.getResultAfterSign()); + } + } + + /** + * This method writes the validation result to the given print writer, i.e. + * an information about the success of the validation or an exception which + * was thrown during the validation or a list of validation errors. + * + * @param pw + * the PrintWriter-object to which the HTML-code is + * written + * @param validationResult + * the pair which defines the result of a validation + */ + private void writeValidationResult(PrintWriter pw, + Pair validationResult) { + if (validationResult.getRight() != null) { + StringBuilder exceptionString = new StringBuilder(); + exceptionString + .append("p>An exception happened during the validation process:

"); + exceptionString.append(createExceptionDataString(validationResult + .getRight())); + writePanel(pw, "Validation exception details", + exceptionString.toString()); + } + if (validationResult.getLeft() != null) { + + StringBuilder conformanceString = new StringBuilder(); + if (validationResult.getLeft().isValid()) { + conformanceString + .append("

The document conforms to the PDF-A standard.

"); + } else { + List errors = validationResult.getLeft() + .getErrorsList(); + conformanceString.append("

With to the PDF-A standard, " + + "the document contains the following errors:

"); + conformanceString + .append(""); + conformanceString.append(""); + conformanceString.append(""); + conformanceString.append(""); + conformanceString.append(""); + conformanceString.append(""); + conformanceString.append(""); + conformanceString.append(""); + for (ValidationError error : errors) { + writeValidationError(conformanceString, error); + } + conformanceString.append("
Error codeError detailsWarning
"); + } + writePanel(pw, "PDF-A conformance", conformanceString.toString()); + } + } + + /** + * Helper method for writing a table line for a single validation error. + * + * @param conformanceString + * the string builder to which the table line is appended + * @param error + * the error which should be serialized + */ + private void writeValidationError(StringBuilder conformanceString, + ValidationError error) { + conformanceString.append(""); + conformanceString.append(String.format("%s", + error.getErrorCode())); + conformanceString.append(String.format("%s", + error.getDetails())); + conformanceString.append(String.format("%s", + error.isWarning() ? "x" : "")); + conformanceString.append(""); + } + + @Override + public String getTestType() { + return "PDF-A"; + } + + @Override + protected void writeTestSpecificParameters(PrintWriter pw) { + // intentionally left blank, no pdf-a specific parameters + } + +} diff --git a/pdf-as-tests/src/test/java/at/gv/egiz/param_tests/serialization/html/SignaturePositionHTMLSerializer.java b/pdf-as-tests/src/test/java/at/gv/egiz/param_tests/serialization/html/SignaturePositionHTMLSerializer.java new file mode 100644 index 00000000..6cebb9ef --- /dev/null +++ b/pdf-as-tests/src/test/java/at/gv/egiz/param_tests/serialization/html/SignaturePositionHTMLSerializer.java @@ -0,0 +1,176 @@ +package at.gv.egiz.param_tests.serialization.html; + +import java.awt.Rectangle; +import java.io.PrintWriter; +import java.util.List; + +import at.gv.egiz.param_tests.serialization.TestInfoSerializer; +import at.gv.egiz.param_tests.testinfo.SignaturePositionTestInfo; +import at.gv.egiz.param_tests.testinfo.SignaturePositionTestInfo.SignaturePositionParameters; + +/** + * Concrete test information serializer for signature position tests using HTML + * and Twitter-bootstrap. + * + * @author mtappler + * + */ +public class SignaturePositionHTMLSerializer extends + HTMLSerializer { + /** + * the test information object which is serialized, it is the same as + * TestInfoSerializer.baseTestInfo + */ + private SignaturePositionTestInfo testInfo; + + /** + * Default contructor used for registering it as prototype. + */ + public SignaturePositionHTMLSerializer() { + this(null); + } + + /** + * Package protected constructor used for cloning + * + * @param testInfo + */ + SignaturePositionHTMLSerializer(SignaturePositionTestInfo testInfo) { + this.testInfo = testInfo; + } + + @Override + public SignaturePositionTestInfo createTestInfo() { + testInfo = new SignaturePositionTestInfo(); + baseTestInfo = testInfo; + return testInfo; + } + + @Override + public TestInfoSerializer cloneSerializer() { + return new SignaturePositionHTMLSerializer(testInfo); + } + + @Override + protected void writeTestData(PrintWriter pw) { + if (testInfo.getAdditionParameters().isCaptureReferenceImage()) { + writeTestDataCapture(pw); + } else { + writeTestDataTest(pw); + } + } + + /** + * Method for writing test data if only a reference image was captured + * + * @param pw + * object which should be used for writing + */ + private void writeTestDataCapture(PrintWriter pw) { + pw.println("

Captured reference image

"); + writePanel( + pw, + "Reference image", + getImageString(testInfo.getAdditionParameters() + .getRefImageFileName(), "reference image")); + if (testInfo.getRefImageIgnored() != null) { + writePanel( + pw, + "Reference image with ignored areas", + getImageString(testInfo.getRefImageIgnored(), + "reference image (ignored)")); + } + } + + /** + * Method for writing test data if an actual signature position test was + * performed. + * + * @param pw + * object which should be used for writing + */ + private void writeTestDataTest(PrintWriter pw) { + pw.println("

Image data captured during test

"); + writePanel( + pw, + "Reference image with ignored areas", + getImageString(testInfo.getRefImageIgnored(), + "reference image (ignored)")); + writePanel( + pw, + "Signature page image with ignored areas", + getImageString(testInfo.getSigPageImageIgnored(), + "signature page image (ignored)")); + writePanel(pw, "Difference image", + getImageString(testInfo.getDiffImage(), "difference image")); + } + + /** + * This method creates HTML-image-tag for an image file. + * + * @param imageFileName + * location of the image file + * @param altText + * the alternative text + * @return HTML-image-tag + */ + private String getImageString(String imageFileName, String altText) { + String imageString; + if (imageFileName != null) + imageString = String.format( + "\"%s\"", + imageFileName, altText); + else + imageString = "

This image was not captured correctly. " + + "The test may have been aborted before because of an IO error.

"; + return imageString; + } + + @Override + public String getTestType() { + return "Signature Position"; + } + + @Override + protected void writeTestSpecificParameters(PrintWriter pw) { + + SignaturePositionParameters additionalParameters = testInfo + .getAdditionParameters(); + StringBuilder panelBody = new StringBuilder(); + + panelBody.append("
"); + panelBody.append(createDescription("Signature positioning string", + additionalParameters.getPositionString())); + panelBody.append(createDescription("Signature page number", + Integer.toString(additionalParameters.getSigPageNumber()))); + panelBody.append(createDescription("Reference image file name", + additionalParameters.getRefImageFileName())); + panelBody.append(createDescription("Ignored Areas", + createIgnoredAreasDescription(additionalParameters + .getIgnoredAreas()))); + panelBody.append("
"); + writePanel(pw, "Test specific parameters", panelBody.toString()); + } + + /** + * This method creates an unordered HTML list for the ignored areas for a + * signature position test. + * + * @param ignoredAreas + * list of ignored areas + * @return HTML-string representing the ignored areas + */ + private String createIgnoredAreasDescription(List ignoredAreas) { + StringBuilder sb = new StringBuilder(); + sb.append("
    "); + for (Rectangle r : ignoredAreas) { + sb.append("
  • "); + sb.append(String.format("x:%d y:%d width:%d height:%d", r.x, r.y, + r.width, r.height)); + sb.append("
  • "); + } + sb.append("
"); + return sb.toString(); + } + +} -- cgit v1.2.3