diff --git a/src/main/java/de/kosit/validationtool/impl/model/BaseScenario.java b/src/main/java/de/kosit/validationtool/impl/model/BaseScenario.java index 71c723f..b983c61 100644 --- a/src/main/java/de/kosit/validationtool/impl/model/BaseScenario.java +++ b/src/main/java/de/kosit/validationtool/impl/model/BaseScenario.java @@ -69,9 +69,13 @@ public abstract class BaseScenario { private XPathExecutable matchExecutable; private XPathExecutable acceptExecutable; + private Schema schema; + private List schematronValidations; + private ContentRepository repository; + private Transformation reportTransformation; /** diff --git a/src/main/java/de/kosit/validationtool/impl/tasks/ComputeAcceptanceAction.java b/src/main/java/de/kosit/validationtool/impl/tasks/ComputeAcceptanceAction.java index e24ba4c..f4c5ca2 100644 --- a/src/main/java/de/kosit/validationtool/impl/tasks/ComputeAcceptanceAction.java +++ b/src/main/java/de/kosit/validationtool/impl/tasks/ComputeAcceptanceAction.java @@ -2,15 +2,19 @@ package de.kosit.validationtool.impl.tasks; import static org.apache.commons.lang3.StringUtils.isNotBlank; +import org.oclc.purl.dsdl.svrl.FailedAssert; + import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import de.kosit.validationtool.api.AcceptRecommendation; +import net.sf.saxon.s9api.SaxonApiException; import net.sf.saxon.s9api.XPathSelector; /** - * Berechnet die Akzeptanz-Empfehlung gemäß konfigurierten 'acceptMatch' des aktuellen Szenarios. + * Computes a {@link AcceptRecommendation} for this instance. This is either based on an 'acceptMatch'-configuration of + * the active scenario or based on overall evaluation about schema and semantic (schematron) correctness of the * * @author Andreas Penski */ @@ -20,23 +24,49 @@ public class ComputeAcceptanceAction implements CheckAction { @Override public void check(final Bag results) { - final String acceptMatch = results.getScenarioSelectionResult().getObject().getAcceptMatch(); - if (isNotBlank(acceptMatch)) { - - try { - - final XPathSelector selector = results.getScenarioSelectionResult().getObject().getAcceptSelector(); - selector.setContextItem(results.getReport()); - results.setAcceptStatus(selector.effectiveBooleanValue() ? AcceptRecommendation.ACCEPTABLE : AcceptRecommendation.REJECT); - } catch (final Exception e) { - log.error("Fehler bei Evaluierung des Accept-Status: {}", e.getMessage(), e); + if (preCondtionsMatch(results)) { + final String acceptMatch = results.getScenarioSelectionResult().getObject().getAcceptMatch(); + if (results.getSchemaValidationResult().isValid() && isNotBlank(acceptMatch)) { + evaluateAcceptanceMatch(results); + } else { + evaluateSchemaAndSchematron(results); } + } else { + results.setAcceptStatus(AcceptRecommendation.REJECT); } } - @Override - public boolean isSkipped(final Bag results) { - return results.getReport() == null; + private void evaluateSchemaAndSchematron(final Bag results) { + if (results.getSchemaValidationResult().isValid() && isSchematronValid(results)) { + results.setAcceptStatus(AcceptRecommendation.ACCEPTABLE); + } else { + results.setAcceptStatus(AcceptRecommendation.REJECT); + } + } + + private boolean isSchematronValid(final Bag results) { + return !hasSchematronErrors(results); + } + + private boolean hasSchematronErrors(final Bag results) { + return results.getReportInput().getValidationResultsSchematron().stream().map(e -> e.getResults().getSchematronOutput()) + .flatMap(e -> e.getActivePatternAndFiredRuleAndFailedAssert().stream()).anyMatch(FailedAssert.class::isInstance); + } + + private static void evaluateAcceptanceMatch(final Bag results) { + try { + final XPathSelector selector = results.getScenarioSelectionResult().getObject().getAcceptSelector(); + selector.setContextItem(results.getReport()); + results.setAcceptStatus(selector.effectiveBooleanValue() ? AcceptRecommendation.ACCEPTABLE : AcceptRecommendation.REJECT); + } catch (final SaxonApiException e) { + final String msg = "Error evaluating accept recommendation: %s"; + log.error(msg); + results.addProcessingError(msg); + } + } + + private static boolean preCondtionsMatch(final Bag results) { + return results.getReport() != null && results.getSchemaValidationResult() != null && results.getScenarioSelectionResult() != null; } } diff --git a/src/test/java/de/kosit/validationtool/impl/tasks/ComputeAcceptanceActionTest.java b/src/test/java/de/kosit/validationtool/impl/tasks/ComputeAcceptanceActionTest.java new file mode 100644 index 0000000..5798467 --- /dev/null +++ b/src/test/java/de/kosit/validationtool/impl/tasks/ComputeAcceptanceActionTest.java @@ -0,0 +1,138 @@ +package de.kosit.validationtool.impl.tasks; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import org.junit.Test; +import org.oclc.purl.dsdl.svrl.FailedAssert; +import org.oclc.purl.dsdl.svrl.SchematronOutput; + +import de.kosit.validationtool.api.AcceptRecommendation; +import de.kosit.validationtool.api.InputFactory; +import de.kosit.validationtool.impl.ContentRepository; +import de.kosit.validationtool.impl.Helper.Simple; +import de.kosit.validationtool.impl.ObjectFactory; +import de.kosit.validationtool.impl.model.Result; +import de.kosit.validationtool.impl.tasks.CheckAction.Bag; +import de.kosit.validationtool.model.reportInput.CreateReportInput; +import de.kosit.validationtool.model.reportInput.ValidationResultsSchematron; +import de.kosit.validationtool.model.reportInput.ValidationResultsSchematron.Results; +import de.kosit.validationtool.model.reportInput.XMLSyntaxError; +import de.kosit.validationtool.model.scenarios.ScenarioType; + +import net.sf.saxon.s9api.XdmNode; + +/** + * Tests the 'acceptMatch' functionality. + * + * @author Andreas Penski + */ +public class ComputeAcceptanceActionTest { + + private final ComputeAcceptanceAction action = new ComputeAcceptanceAction(); + + @Test + public void simpleTest() { + final Bag bag = createBag(true, true); + assertThat(bag.getAcceptStatus()).isEqualTo(AcceptRecommendation.UNDEFINED); + this.action.check(bag); + assertThat(bag.getAcceptStatus()).isEqualTo(AcceptRecommendation.ACCEPTABLE); + } + + @Test + public void testSchemaFailed() { + final Bag bag = createBag(false, true); + this.action.check(bag); + assertThat(bag.getAcceptStatus()).isEqualTo(AcceptRecommendation.REJECT); + } + + @Test + public void testSchematronFailed() { + final Bag bag = createBag(true, false); + this.action.check(bag); + assertThat(bag.getAcceptStatus()).isEqualTo(AcceptRecommendation.REJECT); + } + + @Test + public void testValidAcceptMatch() { + final Bag bag = createBag(true, true); + bag.getScenarioSelectionResult().getObject().setAcceptMatch("count(//doesnotExist) = 0"); + this.action.check(bag); + assertThat(bag.getAcceptStatus()).isEqualTo(AcceptRecommendation.ACCEPTABLE); + } + + @Test + public void testAcceptMatchNotSatisfied() { + final Bag bag = createBag(true, true); + bag.getScenarioSelectionResult().getObject().setAcceptMatch("count(//doesnotExist) = 1"); + this.action.check(bag); + assertThat(bag.getAcceptStatus()).isEqualTo(AcceptRecommendation.REJECT); + } + + @Test + public void testValidAcceptMatchOnSchematronFailed() { + final Bag bag = createBag(true, false); + bag.getScenarioSelectionResult().getObject().setAcceptMatch("count(//doesnotExist) = 0"); + this.action.check(bag); + assertThat(bag.getAcceptStatus()).isEqualTo(AcceptRecommendation.ACCEPTABLE); + } + + @Test + public void testValidAcceptMatchOnSchemaFailed() { + final Bag bag = createBag(false, true); + bag.getScenarioSelectionResult().getObject().setAcceptMatch("count(//doesnotExist) = 0"); + this.action.check(bag); + assertThat(bag.getAcceptStatus()).isEqualTo(AcceptRecommendation.REJECT); + } + + @Test + public void testMissingSchemaCheck() { + final Bag bag = createBag(null, Collections.emptyList()); + this.action.check(bag); + assertThat(bag.getAcceptStatus()).isEqualTo(AcceptRecommendation.REJECT); + } + + @Test + public void testMissingReport() { + final Bag bag = createBag(false, true); + bag.setReport(null); + this.action.check(bag); + assertThat(bag.getAcceptStatus()).isEqualTo(AcceptRecommendation.REJECT); + } + + private static Bag createBag(final boolean schemaValid, final boolean schematronValid) { + final Result schemaResult = schemaValid ? new Result<>(true) + : new Result<>(Collections.singletonList(new XMLSyntaxError())); + final List schematronResult = schematronValid ? Collections.emptyList() : createSchematronError(); + return createBag(schemaResult, schematronResult); + } + + private static List createSchematronError() { + final ValidationResultsSchematron v = new ValidationResultsSchematron(); + final SchematronOutput out = new SchematronOutput(); + final FailedAssert f = new FailedAssert(); + out.getActivePatternAndFiredRuleAndFailedAssert().add(f); + final Results r = new Results(); + r.setSchematronOutput(out); + v.setResults(r); + return Collections.singletonList(v); + } + + private static Bag createBag(final Result schemaResult, + final Collection schematronResult) { + final ScenarioType t = new ScenarioType(); + t.initialize(new ContentRepository(ObjectFactory.createProcessor(), Simple.REPOSITORY), true); + final CreateReportInput reportInput = new CreateReportInput(); + reportInput.getValidationResultsSchematron().addAll(schematronResult); + final Bag b = new Bag(InputFactory.read("".getBytes(), "someCheck"), reportInput); + final Result parseREsult = DocumentParseAction.parseDocument(b.getInput()); + b.setReport(parseREsult.getObject()); + b.setParserResult(parseREsult); + b.setSchemaValidationResult(schemaResult); + b.setScenarioSelectionResult(new Result<>(t)); + return b; + } +}