This is an automated email from the ASF dual-hosted git repository. rec pushed a commit to branch feature/205-Managed-CASes-in-tests-should-consider-validators in repository https://gitbox.apache.org/repos/asf/uima-uimafit.git
commit f4f1d3cf7a8ba296eda9524587eae6b329cef811 Author: Richard Eckart de Castilho <[email protected]> AuthorDate: Thu Nov 10 12:03:50 2022 +0100 Issue #205: Managed CASes in tests should consider validators - Validate managed (J)CASes by default --- .../org/apache/uima/fit/validation/Validator.java | 24 +++++---- .../apache/uima/fit/testing/junit/ManagedCas.java | 62 +++++++++++++++++++--- .../apache/uima/fit/testing/junit/ManagedJCas.java | 60 ++++++++++++++++++--- 3 files changed, 120 insertions(+), 26 deletions(-) diff --git a/uimafit-core/src/main/java/org/apache/uima/fit/validation/Validator.java b/uimafit-core/src/main/java/org/apache/uima/fit/validation/Validator.java index d8ccf30..f9d8fe0 100644 --- a/uimafit-core/src/main/java/org/apache/uima/fit/validation/Validator.java +++ b/uimafit-core/src/main/java/org/apache/uima/fit/validation/Validator.java @@ -6,9 +6,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -47,6 +47,7 @@ public class Validator { for (ValidationCheck check : checks) { try { + summary.add(ValidationResult.trace(check, "Trying check...")); if (check instanceof CasValidationCheck) { summary.addAll(((CasValidationCheck) check).validate(aJCas.getCas())); } else if (check instanceof JCasValidationCheck) { @@ -56,7 +57,7 @@ public class Validator { "Unknown ValidationCheck type: [" + check.getClass().getName() + "]"); } } catch (ValidationCheckSkippedException e) { - summary.add(ValidationResult.info(check, "Skipped: %s", e.getMessage())); + summary.add(ValidationResult.info(check, "Skipped check: %s", e.getMessage())); } catch (ValidationCheckException e) { summary.add(ValidationResult.error(check, "%s", e.getMessage())); } @@ -70,6 +71,7 @@ public class Validator { for (ValidationCheck check : checks) { try { + summary.add(ValidationResult.trace(check, "Trying check...")); if (check instanceof CasValidationCheck) { summary.addAll(((CasValidationCheck) check).validate(cas)); } else if (check instanceof JCasValidationCheck) { @@ -83,7 +85,7 @@ public class Validator { "Unknown ValidationCheck type: [" + check.getClass().getName() + "]"); } } catch (ValidationCheckSkippedException e) { - summary.add(ValidationResult.info(check, "Skipped: %s", e.getMessage())); + summary.add(ValidationResult.info(check, "Skipped check: %s", e.getMessage())); } catch (ValidationCheckException e) { summary.add(ValidationResult.error(check, "%s", e.getMessage())); } @@ -111,7 +113,7 @@ public class Validator { * (assuming that the resulting validator is not shared between threads). * <p> * <b>Note:</b> Includes/excludes do also apply do checks added via this method. - * + * * @param check * a check instance to use. */ @@ -140,7 +142,7 @@ public class Validator { * Skip any checks with the given names. Subtypes of the given classes are not skipped. * <p> * <b>Note:</b> Excludes are applied after includes. - * + * * @param className * names of check classes to be excluded. */ @@ -153,7 +155,7 @@ public class Validator { * Skip any checks with names matching the given regular expressions. * <p> * <b>Note:</b> Excludes are applied after includes. - * + * * @param patterns * regular expressions matching check class names to be excluded. */ @@ -167,7 +169,7 @@ public class Validator { * of the given types). * <p> * <b>Note:</b> Excludes are applied after includes. - * + * * @param types * check type names to be excluded. */ @@ -180,7 +182,7 @@ public class Validator { * Retain only checks with the given names. Subtypes of the given classes are not retained. * <p> * <b>Note:</b> Excludes are applied after includes. - * + * * @param className * names of check classes to be included. */ @@ -193,7 +195,7 @@ public class Validator { * Retain any checks with names matching the given regular expressions. * <p> * <b>Note:</b> Excludes are applied after includes. - * + * * @param patterns * regular expressions matching check class names to be included. */ @@ -207,7 +209,7 @@ public class Validator { * of the given types). * <p> * <b>Note:</b> Excludes are applied after includes. - * + * * @param types * check type names to be included. */ diff --git a/uimafit-junit/src/main/java/org/apache/uima/fit/testing/junit/ManagedCas.java b/uimafit-junit/src/main/java/org/apache/uima/fit/testing/junit/ManagedCas.java index 2bf3e88..5031171 100644 --- a/uimafit-junit/src/main/java/org/apache/uima/fit/testing/junit/ManagedCas.java +++ b/uimafit-junit/src/main/java/org/apache/uima/fit/testing/junit/ManagedCas.java @@ -18,17 +18,26 @@ */ package org.apache.uima.fit.testing.junit; +import static java.lang.String.format; import static java.util.Collections.newSetFromMap; import static java.util.Collections.synchronizedSet; +import static java.util.stream.Collectors.joining; import static org.apache.uima.fit.factory.CasFactory.createCas; +import static org.apache.uima.fit.validation.ValidationResult.Severity.ERROR; +import static org.junit.jupiter.api.Assertions.fail; import java.util.Set; import java.util.WeakHashMap; import org.apache.uima.UIMAException; import org.apache.uima.cas.CAS; +import org.apache.uima.fit.validation.ValidationException; +import org.apache.uima.fit.validation.ValidationSummary; +import org.apache.uima.fit.validation.Validator; import org.apache.uima.resource.metadata.TypeSystemDescription; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.extension.AfterAllCallback; +import org.junit.jupiter.api.extension.AfterTestExecutionCallback; import org.junit.jupiter.api.extension.BeforeTestExecutionCallback; import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.TestWatcher; @@ -41,11 +50,13 @@ import org.junit.jupiter.api.extension.TestWatcher; * handed out to any thread are reset (except any CASes which may meanwhile have been garbage * collected). */ -public final class ManagedCas - implements TestWatcher, BeforeTestExecutionCallback, AfterAllCallback { +public final class ManagedCas implements TestWatcher, BeforeTestExecutionCallback, + AfterTestExecutionCallback, AfterAllCallback { private final ThreadLocal<CAS> casHolder; - private final static Set<CAS> managedCases = synchronizedSet(newSetFromMap(new WeakHashMap<>())); + private final Set<CAS> managedCases = synchronizedSet(newSetFromMap(new WeakHashMap<>())); + + private Validator validator = new Validator.Builder().build(); /** * Provides a CAS with an auto-detected type system. @@ -57,7 +68,7 @@ public final class ManagedCas managedCases.add(cas); return cas; } catch (UIMAException e) { - throw new RuntimeException(e); + return fail("Unable to initialize managed CAS", e); } }); } @@ -75,7 +86,7 @@ public final class ManagedCas managedCases.add(cas); return cas; } catch (UIMAException e) { - throw new RuntimeException(e); + return fail("Unable to initialize managed CAS", e); } }); } @@ -87,13 +98,48 @@ public final class ManagedCas return casHolder.get(); } + @Override + public void afterAll(ExtensionContext aContext) throws Exception { + casHolder.remove(); + } + @Override public void beforeTestExecution(ExtensionContext aContext) throws Exception { - managedCases.forEach(cas -> cas.reset()); + managedCases.forEach(CAS::reset); } @Override - public void afterAll(ExtensionContext aContext) throws Exception { - casHolder.set(null); + public void afterTestExecution(ExtensionContext context) throws Exception { + managedCases.forEach(this::assertValid); + } + + public ManagedCas skipValidation() { + validator = null; + return this; + } + + public ManagedCas withValidator(Validator aValidator) { + this.validator = aValidator; + return this; + } + + private void assertValid(CAS aJCas) { + if (validator == null) { + return; + } + + try { + ValidationSummary summary = validator.check(aJCas); + + String messageBuffer = summary.getResults().stream() + .filter(r -> r.getSeverity().isEquallyOrMoreSevereThan(ERROR)) + .map(r -> format("[%s] %s", r.getSource(), r.getMessage())).collect(joining("\n")); + + if (messageBuffer.length() > 0) { + Assertions.fail(messageBuffer); + } + } catch (ValidationException e) { + Assertions.fail("Unable to validate CAS", e); + } } } \ No newline at end of file diff --git a/uimafit-junit/src/main/java/org/apache/uima/fit/testing/junit/ManagedJCas.java b/uimafit-junit/src/main/java/org/apache/uima/fit/testing/junit/ManagedJCas.java index 7879453..759c1f7 100644 --- a/uimafit-junit/src/main/java/org/apache/uima/fit/testing/junit/ManagedJCas.java +++ b/uimafit-junit/src/main/java/org/apache/uima/fit/testing/junit/ManagedJCas.java @@ -18,17 +18,26 @@ */ package org.apache.uima.fit.testing.junit; +import static java.lang.String.format; import static java.util.Collections.newSetFromMap; import static java.util.Collections.synchronizedSet; +import static java.util.stream.Collectors.joining; import static org.apache.uima.fit.factory.JCasFactory.createJCas; +import static org.apache.uima.fit.validation.ValidationResult.Severity.ERROR; +import static org.junit.jupiter.api.Assertions.fail; import java.util.Set; import java.util.WeakHashMap; import org.apache.uima.UIMAException; +import org.apache.uima.fit.validation.ValidationException; +import org.apache.uima.fit.validation.ValidationSummary; +import org.apache.uima.fit.validation.Validator; import org.apache.uima.jcas.JCas; import org.apache.uima.resource.metadata.TypeSystemDescription; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.extension.AfterAllCallback; +import org.junit.jupiter.api.extension.AfterTestExecutionCallback; import org.junit.jupiter.api.extension.BeforeTestExecutionCallback; import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.TestWatcher; @@ -41,11 +50,13 @@ import org.junit.jupiter.api.extension.TestWatcher; * handed out to any thread are reset (except any JCases which may meanwhile have been garbage * collected). */ -public final class ManagedJCas - implements TestWatcher, BeforeTestExecutionCallback, AfterAllCallback { +public final class ManagedJCas implements TestWatcher, BeforeTestExecutionCallback, + AfterTestExecutionCallback, AfterAllCallback { private final ThreadLocal<JCas> casHolder; - private final static Set<JCas> managedCases = synchronizedSet(newSetFromMap(new WeakHashMap<>())); + private final Set<JCas> managedCases = synchronizedSet(newSetFromMap(new WeakHashMap<>())); + + private Validator validator = new Validator.Builder().build(); /** * Provides a JCas with an auto-detected type system. @@ -57,7 +68,7 @@ public final class ManagedJCas managedCases.add(cas); return cas; } catch (UIMAException e) { - throw new RuntimeException(e); + return fail("Unable to initialize managed JCas", e); } }); } @@ -75,7 +86,7 @@ public final class ManagedJCas managedCases.add(cas); return cas; } catch (UIMAException e) { - throw new RuntimeException(e); + return fail("Unable to initialize managed JCas", e); } }); } @@ -89,11 +100,46 @@ public final class ManagedJCas @Override public void afterAll(ExtensionContext aContext) throws Exception { - casHolder.set(null); + casHolder.remove(); } @Override public void beforeTestExecution(ExtensionContext aContext) throws Exception { - managedCases.forEach(cas -> cas.reset()); + managedCases.forEach(JCas::reset); + } + + @Override + public void afterTestExecution(ExtensionContext context) throws Exception { + managedCases.forEach(this::assertValid); + } + + public ManagedJCas skipValidation() { + validator = null; + return this; + } + + public ManagedJCas withValidator(Validator aValidator) { + this.validator = aValidator; + return this; + } + + private void assertValid(JCas aJCas) { + if (validator == null) { + return; + } + + try { + ValidationSummary summary = validator.check(aJCas); + + String messageBuffer = summary.getResults().stream() + .filter(r -> r.getSeverity().isEquallyOrMoreSevereThan(ERROR)) + .map(r -> format("[%s] %s", r.getSource(), r.getMessage())).collect(joining("\n")); + + if (messageBuffer.length() > 0) { + Assertions.fail(messageBuffer); + } + } catch (ValidationException e) { + Assertions.fail("Unable to validate CAS", e); + } } } \ No newline at end of file
