#58 Fix schematron evaluation

add tests with schematron
This commit is contained in:
Andreas Penski (init) 2020-07-28 17:05:59 +02:00
parent 5a7c6775b1
commit ecf1e1cef4
17 changed files with 340 additions and 12 deletions

View file

@ -134,7 +134,8 @@ public class DefaultResult implements Result {
private <T> List<T> filterSchematronResult(final Class<T> type) {
return getSchematronResult() != null
? getSchematronResult().stream().filter(type::isInstance).map(type::cast).collect(Collectors.toList())
? getSchematronResult().stream().flatMap(e -> e.getActivePatternAndFiredRuleAndFailedAssert().stream())
.filter(type::isInstance).map(type::cast).collect(Collectors.toList())
: Collections.emptyList();
}

View file

@ -77,7 +77,7 @@ public class InputFactoryTest {
public void testHashCodeGeneration() throws IOException {
final byte[] s1 = drain(InputFactory.read(Simple.SIMPLE_VALID.toURL())).getHashCode();
final byte[] s2 = drain(InputFactory.read(Simple.SIMPLE_VALID.toURL())).getHashCode();
final byte[] s3 = drain(InputFactory.read(Simple.INVALID.toURL())).getHashCode();
final byte[] s3 = drain(InputFactory.read(Simple.SCHEMA_INVALID.toURL())).getHashCode();
assertThat(s1).isNotEmpty();
assertThat(s1).isEqualTo(s2);
assertThat(s3).isNotEmpty();

View file

@ -141,7 +141,7 @@ public class CommandlineApplicationTest {
final String[] args = new String[] { "-s", Paths.get(Simple.SCENARIOS).toString(), "-o", this.output.toString(), "-r",
Paths.get(Simple.REPOSITORY_URI).toString(), Paths.get(Simple.EXAMPLES).toString() };
CommandLineApplication.mainProgram(args);
assertThat(this.commandLine.getErrorOutput()).contains("Processing 6 object(s) completed");
assertThat(this.commandLine.getErrorOutput()).contains("Processing 8 object(s) completed");
}
@Test

View file

@ -50,7 +50,7 @@ public class SchemaBuilderTest {
@Test
public void testInvalidSchema() {
final SchemaBuilder builder = schema("myname").schemaLocation(Simple.INVALID);
final SchemaBuilder builder = schema("myname").schemaLocation(Simple.SCHEMA_INVALID);
final Result<Pair<ValidateWithXmlSchema, Schema>, String> result = builder.build(Simple.createContentRepository());
assertThat(result).isNotNull();
assertThat(result.isValid()).isFalse();

View file

@ -38,7 +38,7 @@ public class CheckHandlerIT extends BaseIT {
@Test
@Ignore // no default error report yet
public void internalServerErrorTest() throws IOException {
try ( final InputStream io = Simple.INVALID.toURL().openStream() ) {
try ( final InputStream io = Simple.SCHEMA_INVALID.toURL().openStream() ) {
given().contentType(APPLICATION_XML).body(toContent(io)).when().post("/").then().statusCode(200);
}
}

View file

@ -20,9 +20,11 @@
package de.kosit.validationtool.impl;
import static de.kosit.validationtool.api.InputFactory.read;
import static de.kosit.validationtool.impl.Helper.Simple.FOO_SCHEMATRON_INVALID;
import static de.kosit.validationtool.impl.Helper.Simple.GARBAGE;
import static de.kosit.validationtool.impl.Helper.Simple.NOT_WELLFORMED;
import static de.kosit.validationtool.impl.Helper.Simple.REJECTED;
import static de.kosit.validationtool.impl.Helper.Simple.SCHEMATRON_INVALID;
import static de.kosit.validationtool.impl.Helper.Simple.UNKNOWN;
import static org.assertj.core.api.Assertions.assertThat;
@ -48,8 +50,6 @@ import de.kosit.validationtool.impl.Helper.Simple;
*/
public class DefaultCheckTest {
public static final int MULTI_COUNT = 5;
private DefaultCheck implementation;
@ -67,6 +67,8 @@ public class DefaultCheckTest {
assertThat(doc).isNotNull();
assertThat(doc.getReport()).isNotNull();
assertThat(doc.isAcceptable()).isTrue();
assertThat(doc.isSchematronValid()).isTrue();
assertThat(doc.isSchemaValid()).isTrue();
assertThat(doc.getAcceptRecommendation()).isEqualTo(AcceptRecommendation.ACCEPTABLE);
}
@ -157,4 +159,37 @@ public class DefaultCheckTest {
assertThat(result.getReportDocument()).isNotNull();
}
@Test
public void testSchematronFailed() {
final Result result = this.implementation.checkInput(read(SCHEMATRON_INVALID));
assertThat(result).isNotNull();
assertThat(result.isWellformed()).isTrue();
assertThat(result.isSchemaValid()).isTrue();
assertThat(result.getFailedAsserts()).isNotEmpty();
assertThat(result.isSchematronValid()).isFalse();
assertThat(result.isProcessingSuccessful()).isTrue();
// acceptMatch overules schematron!!!
assertThat(result.getAcceptRecommendation()).isEqualTo(AcceptRecommendation.ACCEPTABLE);
assertThat(result.isAcceptable()).isTrue();
assertThat(result.getReport()).isNotNull();
assertThat(result.getReportDocument()).isNotNull();
}
@Test
public void testSchematronFailedWithoutAcceptMatch() {
final Result result = this.implementation.checkInput(read(FOO_SCHEMATRON_INVALID));
assertThat(result).isNotNull();
assertThat(result.isWellformed()).isTrue();
assertThat(result.isSchemaValid()).isTrue();
result.getFailedAsserts();
assertThat(result.isSchematronValid()).isFalse();
assertThat(result.getFailedAsserts()).isNotEmpty();
assertThat(result.isProcessingSuccessful()).isTrue();
assertThat(result.getAcceptRecommendation()).isEqualTo(AcceptRecommendation.REJECT);
assertThat(result.isAcceptable()).isFalse();
assertThat(result.getReport()).isNotNull();
assertThat(result.getReportDocument()).isNotNull();
}
}

View file

@ -58,13 +58,17 @@ public class Helper {
public static final URI FOO = Simple.ROOT.resolve("input/foo.xml");
public static final URI FOO_SCHEMATRON_INVALID = EXAMPLES.resolve("foo-schematron-invalid.xml");
public static final URI REJECTED = Simple.ROOT.resolve("input/withManualReject.xml");
public static final URI SCENARIOS = ROOT.resolve("scenarios.xml");
public static final URI REPOSITORY_URI = ROOT.resolve("repository/");
public static final URI INVALID = ROOT.resolve("input/simple-invalid.xml");
public static final URI SCHEMA_INVALID = ROOT.resolve("input/simple-schema-invalid.xml");
public static final URI SCHEMATRON_INVALID = ROOT.resolve("input/simple-schematron-invalid.xml");
public static final URI NOT_WELLFORMED = ROOT.resolve("input/simple-not-wellformed.xml");
@ -95,6 +99,7 @@ public class Helper {
public static final URI SCENARIOS = ROOT.resolve("scenarios.xml");
public static final URI SCENARIOS_ILLFORMED = ROOT.resolve("scenarios-illformed.xml");
}
public static class Resolving {

View file

@ -38,7 +38,7 @@ public class SimpleScenarioCheckTest {
@Test
public void testInvalid() throws MalformedURLException {
final Result result = this.implementation.checkInput(InputFactory.read(Simple.INVALID.toURL()));
final Result result = this.implementation.checkInput(InputFactory.read(Simple.SCHEMA_INVALID.toURL()));
assertThat(result).isNotNull();
assertThat(result.getAcceptRecommendation()).isEqualTo(AcceptRecommendation.REJECT);
assertThat(result.getSchemaViolations()).isNotEmpty();

View file

@ -78,7 +78,7 @@ public class SchemaValidatorActionTest {
@Test
public void testValidationFailure() throws MalformedURLException {
final Input input = InputFactory.read(Simple.INVALID.toURL());
final Input input = InputFactory.read(Simple.SCHEMA_INVALID.toURL());
final CheckAction.Bag bag = createBag(input);
this.service.check(bag);
assertThat(bag.getSchemaValidationResult().isValid()).isFalse();

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<foo xmlns="http://validator.kosit.de/test-sample">
<content>
<rejected/>
</content>
</foo>

View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<simple xmlns="http://validator.kosit.de/test-sample">
<inner>ads</inner>
<inner>ds</inner>
<content>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<!--nothing-->
</head>
<body>
<div>some data</div>
</body>
</html>
</content>
</simple>

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://purl.oclc.org/dsdl/schematron" queryBinding="xslt2">
<title>Schematron Simple</title>
<ns prefix="xs" uri="http://www.w3.org/2001/XMLSchema"/>
<ns uri="http://validator.kosit.de/test-sample" prefix="s"/>
<pattern xmlns="http://purl.oclc.org/dsdl/schematron" name="Check structure">
<rule context="s:simple">
<assert id="content-1" test="count(s:inner) = 1">The element inner appears exactly once.</assert>
</rule>
<rule context="s:foo">
<assert id="content-2" test="count(s:inner) = 1">The element inner appears exactly once.</assert>
</rule>
</pattern>
</schema>

View file

@ -7,7 +7,7 @@
<xs:complexType name="SimpleType">
<xs:sequence>
<xs:element name="inner" type="xs:string" />
<xs:element name="inner" type="xs:string" minOccurs="0" maxOccurs="unbounded" />
<xs:element name="content" type="xs:anyType" />
</xs:sequence>
</xs:complexType>

View file

@ -0,0 +1,232 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:s="http://validator.kosit.de/test-sample"
version="2.0"><!--Implementers: please note that overriding process-prolog or process-root is
the preferred method for meta-stylesheets to use where possible. -->
<xsl:param name="archiveDirParameter" />
<xsl:param name="archiveNameParameter" />
<xsl:param name="fileNameParameter" />
<xsl:param name="fileDirParameter" />
<xsl:variable name="document-uri">
<xsl:value-of select="document-uri(/)" />
</xsl:variable>
<!--PHASES-->
<!--PROLOG-->
<xsl:output xmlns:svrl="http://purl.oclc.org/dsdl/svrl"
method="xml"
omit-xml-declaration="no"
standalone="yes"
indent="yes" />
<!--XSD TYPES FOR XSLT2-->
<!--KEYS AND FUNCTIONS-->
<!--DEFAULT RULES-->
<!--MODE: SCHEMATRON-SELECT-FULL-PATH-->
<!--This mode can be used to generate an ugly though full XPath for locators-->
<xsl:template match="*" mode="schematron-select-full-path">
<xsl:apply-templates select="." mode="schematron-get-full-path" />
</xsl:template>
<!--MODE: SCHEMATRON-FULL-PATH-->
<!--This mode can be used to generate an ugly though full XPath for locators-->
<xsl:template match="*" mode="schematron-get-full-path">
<xsl:apply-templates select="parent::*" mode="schematron-get-full-path" />
<xsl:text>/</xsl:text>
<xsl:choose>
<xsl:when test="namespace-uri()=''">
<xsl:value-of select="name()" />
</xsl:when>
<xsl:otherwise>
<xsl:text>*:</xsl:text>
<xsl:value-of select="local-name()" />
<xsl:text>[namespace-uri()='</xsl:text>
<xsl:value-of select="namespace-uri()" />
<xsl:text>']</xsl:text>
</xsl:otherwise>
</xsl:choose>
<xsl:variable name="preceding"
select="count(preceding-sibling::*[local-name()=local-name(current()) and namespace-uri() = namespace-uri(current())])" />
<xsl:text>[</xsl:text>
<xsl:value-of select="1+ $preceding" />
<xsl:text>]</xsl:text>
</xsl:template>
<xsl:template match="@*" mode="schematron-get-full-path">
<xsl:apply-templates select="parent::*" mode="schematron-get-full-path" />
<xsl:text>/</xsl:text>
<xsl:choose>
<xsl:when test="namespace-uri()=''">@<xsl:value-of select="name()" />
</xsl:when>
<xsl:otherwise>
<xsl:text>@*[local-name()='</xsl:text>
<xsl:value-of select="local-name()" />
<xsl:text>' and namespace-uri()='</xsl:text>
<xsl:value-of select="namespace-uri()" />
<xsl:text>']</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!--MODE: SCHEMATRON-FULL-PATH-2-->
<!--This mode can be used to generate prefixed XPath for humans-->
<xsl:template match="node() | @*" mode="schematron-get-full-path-2">
<xsl:for-each select="ancestor-or-self::*">
<xsl:text>/</xsl:text>
<xsl:value-of select="name(.)" />
<xsl:if test="preceding-sibling::*[name(.)=name(current())]">
<xsl:text>[</xsl:text>
<xsl:value-of select="count(preceding-sibling::*[name(.)=name(current())])+1" />
<xsl:text>]</xsl:text>
</xsl:if>
</xsl:for-each>
<xsl:if test="not(self::*)">
<xsl:text />/@<xsl:value-of select="name(.)" />
</xsl:if>
</xsl:template>
<!--MODE: SCHEMATRON-FULL-PATH-3-->
<!--This mode can be used to generate prefixed XPath for humans
(Top-level element has index)-->
<xsl:template match="node() | @*" mode="schematron-get-full-path-3">
<xsl:for-each select="ancestor-or-self::*">
<xsl:text>/</xsl:text>
<xsl:value-of select="name(.)" />
<xsl:if test="parent::*">
<xsl:text>[</xsl:text>
<xsl:value-of select="count(preceding-sibling::*[name(.)=name(current())])+1" />
<xsl:text>]</xsl:text>
</xsl:if>
</xsl:for-each>
<xsl:if test="not(self::*)">
<xsl:text />/@<xsl:value-of select="name(.)" />
</xsl:if>
</xsl:template>
<!--MODE: GENERATE-ID-FROM-PATH -->
<xsl:template match="/" mode="generate-id-from-path" />
<xsl:template match="text()" mode="generate-id-from-path">
<xsl:apply-templates select="parent::*" mode="generate-id-from-path" />
<xsl:value-of select="concat('.text-', 1+count(preceding-sibling::text()), '-')" />
</xsl:template>
<xsl:template match="comment()" mode="generate-id-from-path">
<xsl:apply-templates select="parent::*" mode="generate-id-from-path" />
<xsl:value-of select="concat('.comment-', 1+count(preceding-sibling::comment()), '-')" />
</xsl:template>
<xsl:template match="processing-instruction()" mode="generate-id-from-path">
<xsl:apply-templates select="parent::*" mode="generate-id-from-path" />
<xsl:value-of select="concat('.processing-instruction-', 1+count(preceding-sibling::processing-instruction()), '-')" />
</xsl:template>
<xsl:template match="@*" mode="generate-id-from-path">
<xsl:apply-templates select="parent::*" mode="generate-id-from-path" />
<xsl:value-of select="concat('.@', name())" />
</xsl:template>
<xsl:template match="*" mode="generate-id-from-path" priority="-0.5">
<xsl:apply-templates select="parent::*" mode="generate-id-from-path" />
<xsl:text>.</xsl:text>
<xsl:value-of select="concat('.',name(),'-',1+count(preceding-sibling::*[name()=name(current())]),'-')" />
</xsl:template>
<!--MODE: GENERATE-ID-2 -->
<xsl:template match="/" mode="generate-id-2">U</xsl:template>
<xsl:template match="*" mode="generate-id-2" priority="2">
<xsl:text>U</xsl:text>
<xsl:number level="multiple" count="*" />
</xsl:template>
<xsl:template match="node()" mode="generate-id-2">
<xsl:text>U.</xsl:text>
<xsl:number level="multiple" count="*" />
<xsl:text>n</xsl:text>
<xsl:number count="node()" />
</xsl:template>
<xsl:template match="@*" mode="generate-id-2">
<xsl:text>U.</xsl:text>
<xsl:number level="multiple" count="*" />
<xsl:text>_</xsl:text>
<xsl:value-of select="string-length(local-name(.))" />
<xsl:text>_</xsl:text>
<xsl:value-of select="translate(name(),':','.')" />
</xsl:template>
<!--Strip characters-->
<xsl:template match="text()" priority="-1" />
<!--SCHEMA SETUP-->
<xsl:template match="/">
<svrl:schematron-output xmlns:svrl="http://purl.oclc.org/dsdl/svrl"
title="Schematron Simple"
schemaVersion="">
<xsl:comment>
<xsl:value-of select="$archiveDirParameter" />  
<xsl:value-of select="$archiveNameParameter" />  
<xsl:value-of select="$fileNameParameter" />  
<xsl:value-of select="$fileDirParameter" />
</xsl:comment>
<svrl:ns-prefix-in-attribute-values uri="http://www.w3.org/2001/XMLSchema" prefix="xs" />
<svrl:ns-prefix-in-attribute-values uri="http://validator.kosit.de/test-sample" prefix="s" />
<svrl:active-pattern>
<xsl:attribute name="document">
<xsl:value-of select="document-uri(/)" />
</xsl:attribute>
<xsl:apply-templates />
</svrl:active-pattern>
<xsl:apply-templates select="/" mode="M3" />
</svrl:schematron-output>
</xsl:template>
<!--SCHEMATRON PATTERNS-->
<svrl:text xmlns:svrl="http://purl.oclc.org/dsdl/svrl">Schematron Simple</svrl:text>
<!--PATTERN -->
<!--RULE -->
<xsl:template match="s:simple" priority="1001" mode="M3">
<svrl:fired-rule xmlns:svrl="http://purl.oclc.org/dsdl/svrl" context="s:simple" />
<!--ASSERT -->
<xsl:choose>
<xsl:when test="count(s:inner) = 1" />
<xsl:otherwise>
<svrl:failed-assert xmlns:svrl="http://purl.oclc.org/dsdl/svrl" test="count(s:inner) = 1">
<xsl:attribute name="id">content-1</xsl:attribute>
<xsl:attribute name="location">
<xsl:apply-templates select="." mode="schematron-select-full-path" />
</xsl:attribute>
<svrl:text>The element inner appears exactly once.</svrl:text>
</svrl:failed-assert>
</xsl:otherwise>
</xsl:choose>
<xsl:apply-templates select="*|comment()|processing-instruction()" mode="M3" />
</xsl:template>
<!--RULE -->
<xsl:template match="s:foo" priority="1000" mode="M3">
<svrl:fired-rule xmlns:svrl="http://purl.oclc.org/dsdl/svrl" context="s:foo" />
<!--ASSERT -->
<xsl:choose>
<xsl:when test="count(s:inner) = 1" />
<xsl:otherwise>
<svrl:failed-assert xmlns:svrl="http://purl.oclc.org/dsdl/svrl" test="count(s:inner) = 1">
<xsl:attribute name="id">content-2</xsl:attribute>
<xsl:attribute name="location">
<xsl:apply-templates select="." mode="schematron-select-full-path" />
</xsl:attribute>
<svrl:text>The element inner appears exactly once.</svrl:text>
</svrl:failed-assert>
</xsl:otherwise>
</xsl:choose>
<xsl:apply-templates select="*|comment()|processing-instruction()" mode="M3" />
</xsl:template>
<xsl:template match="text()" priority="-1" mode="M3" />
<xsl:template match="@*|node()" priority="-2" mode="M3">
<xsl:apply-templates select="*|comment()|processing-instruction()" mode="M3" />
</xsl:template>
</xsl:stylesheet>

View file

@ -41,6 +41,12 @@
<location>simple.xsd</location>
</resource>
</validateWithXmlSchema>
<validateWithSchematron>
<resource>
<name>Sample Schematron</name>
<location>simple.xsl</location>
</resource>
</validateWithSchematron>
<createReport>
<resource>
<name>Report für eRechnung</name>
@ -58,13 +64,18 @@
</description>
<namespace prefix="test">http://validator.kosit.de/test-sample</namespace>
<match>/test:foo</match>
<validateWithXmlSchema>
<resource>
<name>Sample Schema</name>
<location>simple.xsd</location>
</resource>
</validateWithXmlSchema>
<validateWithSchematron>
<resource>
<name>Sample Schematron</name>
<location>simple.xsl</location>
</resource>
</validateWithSchematron>
<createReport>
<resource>
<name>Report für eRechnung</name>