You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@uima.apache.org by re...@apache.org on 2020/09/07 06:58:26 UTC
[uima-uimafit] 01/01: [UIMA-6263] CAS validation support
This is an automated email from the ASF dual-hosted git repository.
rec pushed a commit to branch UIMA-6263-CAS-validation-support
in repository https://gitbox.apache.org/repos/asf/uima-uimafit.git
commit 97a260d04f8c4cc37c583ba0079d3238d49ac02b
Author: Richard Eckart de Castilho <re...@apache.org>
AuthorDate: Mon Sep 7 08:58:15 2020 +0200
[UIMA-6263] CAS validation support
- Initial version of the CAS validation framework
- Added a JUnit and AssertJ modules
---
README | 3 +
pom.xml | 12 ++
uimafit-assertj/pom.xml | 41 +++++++
.../testing/assertj/CasValidationCheckAssert.java | 60 ++++++++++
.../uima/fit/validation/CasValidationCheck.java | 42 +++++++
.../uima/fit/validation/CasValidationResult.java | 121 +++++++++++++++++++
.../uima/fit/validation/CasValidationSummary.java | 54 +++++++++
.../apache/uima/fit/validation/CasValidator.java | 130 +++++++++++++++++++++
.../fit/validation/CasValidatorBuilderTest.java | 60 ++++++++++
.../checks/EndAfterBeginCheckForTesting.java | 51 ++++++++
.../checks/EndSameAsBeginCheckForTesting.java | 51 ++++++++
...g.apache.uima.fit.validation.CasValidationCheck | 2 +
uimafit-junit/pom.xml | 45 +++++++
.../org/apache/uima/fit/testing/junit/CasRule.java | 78 +++++++++++++
uimafit-parent/pom.xml | 3 +
15 files changed, 753 insertions(+)
diff --git a/README b/README
index 30a74d7..59e67fb 100644
--- a/README
+++ b/README
@@ -95,6 +95,9 @@ uimafit-core - the main uimaFIT module
uimafit-cpe - support for the Collection Processing Engine (multi-threaded pipelines)
uimafit-maven - a Maven plugin to automatically enhance UIMA components with uimaFIT
metadata and to generate XML descriptors for uimaFIT-enabled components.
+uimafit-junit - convenience code facilitating the implementation of UIMA/uimaFIT tests
+ in JUnit tests
+uimafit-assertj - adds assertions for UIMA/uimaFIT types via the AssertJ framework
uimafit-legacy-support - allows uimaFIT 2.x.0 to use uimaFIT 1.4.x meta data like Java annotations
and META-INF/org.uimafit/types.txt files. Pipelines mixing uimaFIT 1.4.x
and 2.x components MUST be created using the 2.x factories, because the
diff --git a/pom.xml b/pom.xml
index ea84744..75e6e08 100644
--- a/pom.xml
+++ b/pom.xml
@@ -60,6 +60,16 @@
</dependency>
<dependency>
<groupId>org.apache.uima</groupId>
+ <artifactId>uimafit-junit</artifactId>
+ <version>2.5.1-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.uima</groupId>
+ <artifactId>uimafit-assertj</artifactId>
+ <version>2.5.1-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.uima</groupId>
<artifactId>uimafit-legacy-support</artifactId>
<version>2.5.1-SNAPSHOT</version>
</dependency>
@@ -124,6 +134,8 @@
<modules>
<module>uimafit-core</module>
+ <module>uimafit-junit</module>
+ <module>uimafit-assertj</module>
<module>uimafit-examples</module>
<module>uimafit-spring</module>
<module>uimafit-maven-plugin</module>
diff --git a/uimafit-assertj/pom.xml b/uimafit-assertj/pom.xml
new file mode 100644
index 0000000..8f888a0
--- /dev/null
+++ b/uimafit-assertj/pom.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ 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
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.uima</groupId>
+ <artifactId>uimafit-parent</artifactId>
+ <version>2.5.1-SNAPSHOT</version>
+ <relativePath>../uimafit-parent</relativePath>
+ </parent>
+ <artifactId>uimafit-assertj</artifactId>
+ <name>Apache UIMA uimaFIT - AssertJ support</name>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.uima</groupId>
+ <artifactId>uimafit-core</artifactId>
+ <version>2.5.1-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.assertj</groupId>
+ <artifactId>assertj-core</artifactId>
+ </dependency>
+ </dependencies>
+</project>
\ No newline at end of file
diff --git a/uimafit-assertj/src/main/java/org/apache/uima/fit/testing/assertj/CasValidationCheckAssert.java b/uimafit-assertj/src/main/java/org/apache/uima/fit/testing/assertj/CasValidationCheckAssert.java
new file mode 100644
index 0000000..dee603a
--- /dev/null
+++ b/uimafit-assertj/src/main/java/org/apache/uima/fit/testing/assertj/CasValidationCheckAssert.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * 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
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.uima.fit.testing.assertj;
+
+import static java.util.ServiceLoader.load;
+import static java.util.stream.StreamSupport.stream;
+
+import java.util.ServiceLoader;
+
+import org.apache.uima.fit.validation.CasValidationCheck;
+import org.assertj.core.api.AbstractAssert;
+
+/**
+ * Asserts related to {@link CasValidationCheck} implementations.
+ */
+public class CasValidationCheckAssert
+ extends AbstractAssert<CasValidationCheckAssert, CasValidationCheck> {
+ public CasValidationCheckAssert(CasValidationCheck actual) {
+ super(actual, CasValidationCheckAssert.class);
+ }
+
+ public static CasValidationCheckAssert assertThat(CasValidationCheck actual) {
+ return new CasValidationCheckAssert(actual);
+ }
+
+ /**
+ * Checks that the check is correctly registered and available to the Java Service Locator.
+ */
+ public CasValidationCheckAssert isAvailableToServiceLoader() {
+ isNotNull();
+
+ ServiceLoader<CasValidationCheck> loader = load(CasValidationCheck.class);
+ boolean found = stream(loader.spliterator(), false)
+ .anyMatch(check -> check.getClass().equals(actual.getClass()));
+
+ if (!found) {
+ failWithMessage(
+ "[%s] cannot be found by the service loader. Ensure it is registered in [META-INF/services/%s]",
+ actual.getClass(), CasValidationCheck.class.getName());
+ }
+
+ return this;
+ }
+}
\ No newline at end of file
diff --git a/uimafit-core/src/main/java/org/apache/uima/fit/validation/CasValidationCheck.java b/uimafit-core/src/main/java/org/apache/uima/fit/validation/CasValidationCheck.java
new file mode 100644
index 0000000..02c07ab
--- /dev/null
+++ b/uimafit-core/src/main/java/org/apache/uima/fit/validation/CasValidationCheck.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * 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
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.uima.fit.validation;
+
+import java.util.List;
+
+import org.apache.uima.cas.CAS;
+
+/**
+ * CAS validation check.
+ * <p>
+ * <b>Note:</b> Implementations of this class are typically singletons which are obtained through
+ * the Java Service Locator mechanism. This means that the implementations must be stateless to
+ * ensure that they can be used by multiple threads concurrently.
+ */
+public interface CasValidationCheck {
+
+ /**
+ * Apply this check to the given CAS.
+ *
+ * @param cas
+ * the CAS to check.
+ * @return the results of the check.
+ */
+ List<CasValidationResult> check(CAS cas);
+}
diff --git a/uimafit-core/src/main/java/org/apache/uima/fit/validation/CasValidationResult.java b/uimafit-core/src/main/java/org/apache/uima/fit/validation/CasValidationResult.java
new file mode 100644
index 0000000..9802b1d
--- /dev/null
+++ b/uimafit-core/src/main/java/org/apache/uima/fit/validation/CasValidationResult.java
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * 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
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.uima.fit.validation;
+
+import static java.lang.String.format;
+import static org.apache.uima.fit.validation.CasValidationResult.Severity.DEBUG;
+import static org.apache.uima.fit.validation.CasValidationResult.Severity.ERROR;
+import static org.apache.uima.fit.validation.CasValidationResult.Severity.INFO;
+import static org.apache.uima.fit.validation.CasValidationResult.Severity.TRACE;
+import static org.apache.uima.fit.validation.CasValidationResult.Severity.WARN;
+
+import java.util.Objects;
+
+/**
+ * Individual result from a CAS validation check.
+ */
+public class CasValidationResult {
+
+ public enum Severity {
+
+ ERROR(5), WARN(4), INFO(3), DEBUG(2), TRACE(1);
+
+ private final int level;
+
+ private Severity(int level) {
+ this.level = level;
+ }
+
+ public boolean isEquallyOrMoreSevereThan(Severity other) {
+ return level >= other.level;
+ }
+ }
+
+ private final Severity severity;
+ private final String source;
+ private final String message;
+
+ public CasValidationResult(Object source, Severity severity, String format, Object... args) {
+
+ super();
+
+ if (source instanceof String) {
+ this.source = (String) source;
+ } else if (source instanceof Class) {
+ this.source = ((Class<?>) source).getSimpleName();
+ } else {
+ this.source = source != null ? source.getClass().getSimpleName() : null;
+ }
+
+ this.severity = severity;
+ message = format(format, args);
+ }
+
+ public String getSource() {
+ return source;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public Severity getSeverity() {
+ return severity;
+ }
+
+ public static CasValidationResult error(Object source, String format, Object... args) {
+ return new CasValidationResult(source, ERROR, format, args);
+ }
+
+ public static CasValidationResult warn(Object source, String format, Object... args) {
+ return new CasValidationResult(source, WARN, format, args);
+ }
+
+ public static CasValidationResult info(Object source, String format, Object... args) {
+ return new CasValidationResult(source, INFO, format, args);
+ }
+
+ public static CasValidationResult debug(Object source, String format, Object... args) {
+ return new CasValidationResult(source, DEBUG, format, args);
+ }
+
+ public static CasValidationResult trace(Object source, String format, Object... args) {
+ return new CasValidationResult(source, TRACE, format, args);
+ }
+
+ @Override
+ public boolean equals(final Object other) {
+ if (!(other instanceof CasValidationResult)) {
+ return false;
+ }
+ CasValidationResult castOther = (CasValidationResult) other;
+ return Objects.equals(severity, castOther.severity) && Objects.equals(source, castOther.source)
+ && Objects.equals(message, castOther.message);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(severity, source, message);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("[%s] %s", source != null ? source : "<unknown>", message);
+ }
+}
diff --git a/uimafit-core/src/main/java/org/apache/uima/fit/validation/CasValidationSummary.java b/uimafit-core/src/main/java/org/apache/uima/fit/validation/CasValidationSummary.java
new file mode 100644
index 0000000..4d064b0
--- /dev/null
+++ b/uimafit-core/src/main/java/org/apache/uima/fit/validation/CasValidationSummary.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * 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
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.uima.fit.validation;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.uima.fit.validation.CasValidationResult.Severity;
+
+/**
+ * Container for {@link CasValidationResult CasValidationResults}.
+ */
+public class CasValidationSummary {
+
+ private List<CasValidationResult> results;
+
+ public CasValidationSummary() {
+ results = new ArrayList<>();
+ }
+
+ public void addAll(CasValidationResult result) {
+ results.add(result);
+ }
+
+ public void addAll(Collection<CasValidationResult> moreResults) {
+ results.addAll(moreResults);
+ }
+
+ public List<CasValidationResult> getResults() {
+ return results;
+ }
+
+ public boolean containsResultsEquallyOrMoreSevereThan(Severity threshold) {
+ return results.stream()
+ .anyMatch(result -> result.getSeverity().isEquallyOrMoreSevereThan(threshold));
+ }
+}
diff --git a/uimafit-core/src/main/java/org/apache/uima/fit/validation/CasValidator.java b/uimafit-core/src/main/java/org/apache/uima/fit/validation/CasValidator.java
new file mode 100644
index 0000000..76898a5
--- /dev/null
+++ b/uimafit-core/src/main/java/org/apache/uima/fit/validation/CasValidator.java
@@ -0,0 +1,130 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * 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
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.uima.fit.validation;
+
+import static java.util.Arrays.stream;
+import static java.util.ServiceLoader.load;
+import static java.util.stream.StreamSupport.stream;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+import org.apache.uima.cas.CAS;
+
+/**
+ * Validate a CAS.
+ */
+public class CasValidator {
+
+ private Collection<CasValidationCheck> checks;
+
+ public CasValidator(Collection<CasValidationCheck> checks) {
+ this.checks = checks;
+ }
+
+ public CasValidationSummary check(CAS cas) {
+ CasValidationSummary summary = new CasValidationSummary();
+
+ for (CasValidationCheck check : checks) {
+ summary.addAll(check.check(cas));
+ }
+
+ return summary;
+ }
+
+ public Collection<CasValidationCheck> getChecks() {
+ return checks;
+ }
+
+ public static class Builder {
+
+ private Set<CasValidationCheck> checks = new LinkedHashSet<>();
+ private Set<Pattern> excludePatterns = new HashSet<>();
+ private Set<Class<?>> excludeTypes = new HashSet<>();
+ private boolean skipAutoDetection = false;
+
+ /**
+ * Add the given check instance to the validator. This allows even adding checks which are not
+ * available via the Java Service Locator, which take parameters or which are otherwise stateful
+ * (assuming that the resulting validator is not shared between threads).
+ *
+ * @param check
+ * a check instance to use.
+ */
+ public void withCheck(CasValidationCheck check) {
+ checks.add(check);
+ }
+
+ public void withoutAutoDetectedChecks() {
+ skipAutoDetection = true;
+ }
+
+ public void witAutoDetectedChecks() {
+ skipAutoDetection = false;
+ }
+
+ /**
+ * Skip auto-detection of any checks with the given names. Subtypes of the given classes are not
+ * excluded from auto-detection.
+ */
+ public void excludingFromAutoDetectionByName(String... className) {
+ stream(className)
+ .map(Pattern::quote)
+ .map(Pattern::compile)
+ .forEach(excludePatterns::add);
+ }
+
+ /**
+ * Skip auto-detection of any checks with the given regular expressions.
+ */
+ public void excludingFromAutoDetectionByPattern(String... patterns) {
+ stream(patterns)
+ .map(Pattern::compile)
+ .forEach(excludePatterns::add);
+ }
+
+ /**
+ * Skips auto-detection of any checks of the given types (includes checks that are subclasses or
+ * implementations of the given types).
+ */
+ public void excludingFromAutoDetectionByType(Class<?>... classes) {
+ stream(classes).forEach(excludeTypes::add);
+ }
+
+ private void autoDetectChecks() {
+ stream(load(CasValidationCheck.class).spliterator(), false)
+ .filter(check -> excludePatterns.stream()
+ .noneMatch(p -> p.matcher(check.getClass().getName()).matches()))
+ .filter(check -> excludeTypes.stream()
+ .noneMatch(t -> t.isAssignableFrom(check.getClass())))
+ .forEachOrdered(checks::add);
+ }
+
+ public CasValidator build() {
+ if (!skipAutoDetection) {
+ autoDetectChecks();
+ }
+
+ return new CasValidator(checks);
+ }
+ }
+}
diff --git a/uimafit-core/src/test/java/org/apache/uima/fit/validation/CasValidatorBuilderTest.java b/uimafit-core/src/test/java/org/apache/uima/fit/validation/CasValidatorBuilderTest.java
new file mode 100644
index 0000000..82e857a
--- /dev/null
+++ b/uimafit-core/src/test/java/org/apache/uima/fit/validation/CasValidatorBuilderTest.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * 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
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.uima.fit.validation;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.apache.uima.fit.validation.checks.EndAfterBeginCheckForTesting;
+import org.apache.uima.fit.validation.checks.EndSameAsBeginCheckForTesting;
+import org.junit.Before;
+import org.junit.Test;
+
+public class CasValidatorBuilderTest {
+
+ private CasValidator.Builder sut;
+
+ @Before
+ public void setup() {
+ sut = new CasValidator.Builder();
+ }
+
+ @Test
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public void thatExcludeByNameWorks() {
+ sut.excludingFromAutoDetectionByName(EndAfterBeginCheckForTesting.class.getName());
+
+ CasValidator validator = sut.build();
+
+ assertThat(validator.getChecks())
+ .extracting(Object::getClass)
+ .containsExactly((Class) EndSameAsBeginCheckForTesting.class);
+ }
+
+ @Test
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public void thatExcludeByTypeWorks() {
+ sut.excludingFromAutoDetectionByType(EndAfterBeginCheckForTesting.class);
+
+ CasValidator validator = sut.build();
+
+ assertThat(validator.getChecks())
+ .extracting(Object::getClass)
+ .containsExactly((Class) EndSameAsBeginCheckForTesting.class);
+ }
+}
diff --git a/uimafit-core/src/test/java/org/apache/uima/fit/validation/checks/EndAfterBeginCheckForTesting.java b/uimafit-core/src/test/java/org/apache/uima/fit/validation/checks/EndAfterBeginCheckForTesting.java
new file mode 100644
index 0000000..f19ed94
--- /dev/null
+++ b/uimafit-core/src/test/java/org/apache/uima/fit/validation/checks/EndAfterBeginCheckForTesting.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * 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
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.uima.fit.validation.checks;
+
+import static org.apache.uima.fit.util.CasUtil.selectAll;
+import static org.apache.uima.fit.validation.CasValidationResult.error;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.uima.cas.CAS;
+import org.apache.uima.cas.text.AnnotationFS;
+import org.apache.uima.fit.validation.CasValidationCheck;
+import org.apache.uima.fit.validation.CasValidationResult;
+
+/**
+ * Simple CAS validation check ensuring that annotations do not end before they start.
+ * <p>
+ * <b>Note:</b> This is used for testing in uimaFIT. It is not meant for general use!
+ */
+public class EndAfterBeginCheckForTesting implements CasValidationCheck {
+ @Override
+ public List<CasValidationResult> check(CAS cas) {
+ List<CasValidationResult> results = new ArrayList<>();
+
+ for (AnnotationFS anno : selectAll(cas)) {
+ if (anno.getEnd() < anno.getBegin()) {
+ results.add(error(this, "%s ends (%d) before it begins (%d)", anno.getType().getShortName(),
+ anno.getEnd(), anno.getBegin()));
+ }
+ }
+
+ return results;
+ }
+}
diff --git a/uimafit-core/src/test/java/org/apache/uima/fit/validation/checks/EndSameAsBeginCheckForTesting.java b/uimafit-core/src/test/java/org/apache/uima/fit/validation/checks/EndSameAsBeginCheckForTesting.java
new file mode 100644
index 0000000..ac1f29c
--- /dev/null
+++ b/uimafit-core/src/test/java/org/apache/uima/fit/validation/checks/EndSameAsBeginCheckForTesting.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * 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
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.uima.fit.validation.checks;
+
+import static org.apache.uima.fit.util.CasUtil.selectAll;
+import static org.apache.uima.fit.validation.CasValidationResult.error;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.uima.cas.CAS;
+import org.apache.uima.cas.text.AnnotationFS;
+import org.apache.uima.fit.validation.CasValidationCheck;
+import org.apache.uima.fit.validation.CasValidationResult;
+
+/**
+ * Simple CAS validation check ensuring that annotations do not have the same start/end position.
+ * <p>
+ * <b>Note:</b> This is used for testing in uimaFIT. It is not meant for general use!
+ */
+public class EndSameAsBeginCheckForTesting implements CasValidationCheck {
+ @Override
+ public List<CasValidationResult> check(CAS cas) {
+ List<CasValidationResult> results = new ArrayList<>();
+
+ for (AnnotationFS anno : selectAll(cas)) {
+ if (anno.getEnd() == anno.getBegin()) {
+ results.add(error(this, "%s starts and ends at the same position (%d)",
+ anno.getType().getShortName(), anno.getBegin()));
+ }
+ }
+
+ return results;
+ }
+}
diff --git a/uimafit-core/src/test/resources/META-INF/services/org.apache.uima.fit.validation.CasValidationCheck b/uimafit-core/src/test/resources/META-INF/services/org.apache.uima.fit.validation.CasValidationCheck
new file mode 100644
index 0000000..f52edea
--- /dev/null
+++ b/uimafit-core/src/test/resources/META-INF/services/org.apache.uima.fit.validation.CasValidationCheck
@@ -0,0 +1,2 @@
+org.apache.uima.fit.validation.checks.EndAfterBeginCheckForTesting
+org.apache.uima.fit.validation.checks.EndSameAsBeginCheckForTesting
diff --git a/uimafit-junit/pom.xml b/uimafit-junit/pom.xml
new file mode 100644
index 0000000..1349632
--- /dev/null
+++ b/uimafit-junit/pom.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ 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
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.uima</groupId>
+ <artifactId>uimafit-parent</artifactId>
+ <version>2.5.1-SNAPSHOT</version>
+ <relativePath>../uimafit-parent</relativePath>
+ </parent>
+ <artifactId>uimafit-junit</artifactId>
+ <name>Apache UIMA uimaFIT - JUnit support</name>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.uima</groupId>
+ <artifactId>uimafit-core</artifactId>
+ <version>2.5.1-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.uima</groupId>
+ <artifactId>uimaj-core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ </dependency>
+ </dependencies>
+</project>
\ No newline at end of file
diff --git a/uimafit-junit/src/main/java/org/apache/uima/fit/testing/junit/CasRule.java b/uimafit-junit/src/main/java/org/apache/uima/fit/testing/junit/CasRule.java
new file mode 100644
index 0000000..b4f9a01
--- /dev/null
+++ b/uimafit-junit/src/main/java/org/apache/uima/fit/testing/junit/CasRule.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * 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
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.uima.fit.testing.junit;
+
+import org.apache.uima.UIMAException;
+import org.apache.uima.cas.CAS;
+import org.apache.uima.fit.factory.CasFactory;
+import org.apache.uima.resource.metadata.TypeSystemDescription;
+import org.junit.rules.TestWatcher;
+import org.junit.runner.Description;
+
+/**
+ * Provides a {@link CAS} object which is automatically reset before the test.
+ */
+public final class CasRule
+ extends TestWatcher
+{
+ private final CAS cas;
+
+ /**
+ * Provides a CAS with an auto-detected type system.
+ */
+ public CasRule()
+ {
+ try {
+ cas = CasFactory.createCas();
+ }
+ catch (UIMAException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Provides a CAS with the specified type system.
+ *
+ * @param aTypeSystemDescription
+ * the type system used to initialize the CAS.
+ */
+ public CasRule(TypeSystemDescription aTypeSystemDescription)
+ {
+ try {
+ cas = CasFactory.createCas(aTypeSystemDescription);
+ }
+ catch (UIMAException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * @return the CAS object managed by this rule.
+ */
+ public CAS get()
+ {
+ return cas;
+ }
+
+ @Override
+ protected void starting(Description description)
+ {
+ cas.reset();
+ }
+}
\ No newline at end of file
diff --git a/uimafit-parent/pom.xml b/uimafit-parent/pom.xml
index e069ca4..a67d1af 100644
--- a/uimafit-parent/pom.xml
+++ b/uimafit-parent/pom.xml
@@ -173,6 +173,9 @@
</executions>
<configuration>
<failOnWarning>true</failOnWarning>
+ <ignoredDependencies>
+ <ignoredDependency>junit:junit</ignoredDependency>
+ </ignoredDependencies>
</configuration>
</plugin>
<plugin>