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/11/04 07:32:55 UTC
[uima-uimafit] 01/01: [UIMA-6270] Add selectOverlapping to
(J)CasUtil
This is an automated email from the ASF dual-hosted git repository.
rec pushed a commit to branch feature/UIMA-6270-Add-selectOverlapping-to-JCasUtil
in repository https://gitbox.apache.org/repos/asf/uima-uimafit.git
commit acd427a5a59c6b088e676f42b29c906da38767cd
Author: Richard Eckart de Castilho <re...@apache.org>
AuthorDate: Wed Nov 4 08:32:26 2020 +0100
[UIMA-6270] Add selectOverlapping to (J)CasUtil
- Drop AnnotationPredicates again from uimaFIT and instead use the one meanwhile provided in uimaj-core
- Updated various unit tests to check for alignment of uimaFIT with the annotation predicates
---
.../apache/uima/fit/util/AnnotationPredicates.java | 217 ------------
.../uima/fit/util/AnnotationPredicatesTest.java | 382 ---------------------
.../java/org/apache/uima/fit/util/CasUtilTest.java | 136 +++++++-
.../org/apache/uima/fit/util/JCasUtilTest.java | 78 +----
.../org/apache/uima/fit/util/SelectionAssert.java | 292 ++++++++++++++++
uimafit-parent/pom.xml | 2 +-
6 files changed, 430 insertions(+), 677 deletions(-)
diff --git a/uimafit-core/src/main/java/org/apache/uima/fit/util/AnnotationPredicates.java b/uimafit-core/src/main/java/org/apache/uima/fit/util/AnnotationPredicates.java
deleted file mode 100644
index 75c7385..0000000
--- a/uimafit-core/src/main/java/org/apache/uima/fit/util/AnnotationPredicates.java
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * 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.util;
-
-import org.apache.uima.cas.text.AnnotationFS;
-
-public final class AnnotationPredicates {
- private AnnotationPredicates() {
- // No instances
- }
-
- public static boolean coveredBy(int aXBegin, int aXEnd, int aYBegin, int aYEnd) {
- return aYBegin <= aXBegin && aXEnd <= aYEnd && (aXBegin == aYBegin || aXBegin != aYEnd);
- }
-
- public static boolean coveredBy(AnnotationFS aX, int aYBegin, int aYEnd) {
- int xBegin = aX.getBegin();
- return aYBegin <= xBegin && (xBegin == aYBegin || xBegin != aYEnd) && aX.getEnd() <= aYEnd;
- }
-
- /**
- * Y is starting before or at the same position as A and ends after or at the same position as X.
- *
- * @param aX
- * X
- * @param aY
- * Y
- * @return whether X is covered by Y.
- */
- public static boolean coveredBy(AnnotationFS aX, AnnotationFS aY) {
- int xBegin = aX.getBegin();
- int yBegin = aY.getBegin();
- int yEnd = aY.getEnd();
- return yBegin <= xBegin && (xBegin == yBegin || xBegin != yEnd) && aX.getEnd() <= yEnd;
- }
-
- public static boolean covers(int aXBegin, int aXEnd, int aYBegin, int aYEnd) {
- return aXBegin <= aYBegin && aYEnd <= aXEnd && (aYBegin == aXBegin || aYBegin != aXEnd);
- }
-
- public static boolean covers(AnnotationFS aX, int aYBegin, int aYEnd) {
- int xBegin = aX.getBegin();
- int xEnd = aX.getEnd();
- return xBegin <= aYBegin && aYEnd <= xEnd && (aYBegin == xBegin || aYBegin != xEnd);
- }
-
- /**
- * X is starting before or at the same position as Y and ends after or at the same position as Y.
- *
- * @param aX
- * X
- * @param aY
- * Y
- * @return whether X is covering Y.
- */
- public static boolean covers(AnnotationFS aX, AnnotationFS aY) {
- int xBegin = aX.getBegin();
- int xEnd = aX.getEnd();
- int yBegin = aY.getBegin();
- return xBegin <= yBegin && (yBegin == xBegin || yBegin != xEnd) && aY.getEnd() <= xEnd;
- }
-
- public static boolean colocated(int aXBegin, int aXEnd, int aYBegin, int aYEnd) {
- return aXBegin == aYBegin && aXEnd == aYEnd;
- }
-
- public static boolean colocated(AnnotationFS aX, int aYBegin, int aYEnd) {
- return aX.getBegin() == aYBegin && aX.getEnd() == aYEnd;
- }
-
- /**
- * X starts and ends at the same position as Y.
- *
- * @param aX
- * X
- * @param aY
- * Y
- * @return whether X is at the same location as Y.
- */
- public static boolean colocated(AnnotationFS aX, AnnotationFS aY) {
- return aX.getBegin() == aY.getBegin() && aX.getEnd() == aY.getEnd();
- }
-
- public static boolean overlaps(int aXBegin, int aXEnd, int aYBegin, int aYEnd) {
- return aYBegin == aXBegin || (aXBegin < aYEnd && aYBegin < aXEnd);
- }
-
- public static boolean overlaps(AnnotationFS aX, int aYBegin, int aYEnd) {
- int xBegin = aX.getBegin();
- return aYBegin == xBegin || (xBegin < aYEnd && aYBegin < aX.getEnd());
- }
-
- /**
- * The intersection of the spans X and Y is non-empty. If either X or Y have a zero-width, then
- * the intersection is considered to be non-empty if the begin of X is either within Y or the same
- * as the begin of Y - and vice versa.
- *
- * @param aX
- * X
- * @param aY
- * Y
- * @return whether X overlaps with Y in any way.
- */
- public static boolean overlaps(AnnotationFS aX, AnnotationFS aY) {
- int xBegin = aX.getBegin();
- int yBegin = aY.getBegin();
- return yBegin == xBegin || (xBegin < aY.getEnd() && yBegin < aX.getEnd());
- }
-
- public static boolean overlapsLeft(int aXBegin, int aXEnd, int aYBegin, int aYEnd) {
- return aXBegin < aYBegin && aYBegin < aXEnd && aXEnd < aYEnd;
- }
-
- public static boolean overlapsLeft(AnnotationFS aX, int aYBegin, int aYEnd) {
- int xEnd = aX.getEnd();
- return aYBegin < xEnd && xEnd < aYEnd && aX.getBegin() < aYBegin;
- }
-
- /**
- * X is starting before or at the same position as Y and ends before Y ends.
- *
- * @param aX
- * X
- * @param aY
- * Y
- * @return whether X overlaps Y on the left.
- */
- public static boolean overlapsLeft(AnnotationFS aX, AnnotationFS aY) {
- int xEnd = aX.getEnd();
- int yBegin = aY.getBegin();
- return yBegin < xEnd && xEnd < aY.getEnd() && aX.getBegin() < yBegin;
- }
-
- public static boolean overlapsRight(int aXBegin, int aXEnd, int aYBegin, int aYEnd) {
- return aYBegin < aXBegin && aXBegin < aYEnd && aYEnd < aXEnd;
- }
-
- public static boolean overlapsRight(AnnotationFS aX, int aYBegin, int aYEnd) {
- int xBegin = aX.getBegin();
- return aYBegin < xBegin && xBegin < aYEnd && aYEnd < aX.getEnd();
- }
-
- /**
- * X is starting after Y starts and ends after or at the same position as Y.
- *
- * @param aX
- * X
- * @param aY
- * Y
- * @return whether X overlaps Y on the right.
- */
- public static boolean overlapsRight(AnnotationFS aX, AnnotationFS aY) {
- int xBegin = aX.getBegin();
- int yEnd = aY.getEnd();
- return xBegin < yEnd && aY.getBegin() < xBegin && yEnd < aX.getEnd();
- }
-
- public static boolean rightOf(int aXBegin, int aXEnd, int aYBegin, int aYEnd) {
- return aXBegin >= aYEnd && aXBegin != aYBegin;
- }
-
- public static boolean rightOf(AnnotationFS aX, int aYBegin, int aYEnd) {
- int xBegin = aX.getBegin();
- return xBegin >= aYEnd && xBegin != aYBegin;
- }
-
- /**
- * X starts at or after the position that Y ends.
- *
- * @param aX
- * X
- * @param aY
- * Y
- * @return whether X is right of Y.
- */
- public static boolean rightOf(AnnotationFS aX, AnnotationFS aY) {
- int xBegin = aX.getBegin();
- return xBegin >= aY.getEnd() && xBegin != aY.getBegin();
- }
-
- public static boolean leftOf(int aXBegin, int aXEnd, int aYBegin, int aYEnd) {
- return aYBegin >= aXEnd && aXBegin != aYBegin;
- }
-
- public static boolean leftOf(AnnotationFS aX, int aYBegin, int aYEnd) {
- return aYBegin >= aX.getEnd() && aX.getBegin() != aYBegin;
- }
-
- /**
- * X ends before or at the position that Y starts.
- *
- * @param aX
- * X
- * @param aY
- * Y
- * @return whether X left of Y.
- */
- public static boolean leftOf(AnnotationFS aX, AnnotationFS aY) {
- return aY.getBegin() >= aX.getEnd() && aX.getBegin() != aY.getBegin();
- }
-}
diff --git a/uimafit-core/src/test/java/org/apache/uima/fit/util/AnnotationPredicatesTest.java b/uimafit-core/src/test/java/org/apache/uima/fit/util/AnnotationPredicatesTest.java
deleted file mode 100644
index a5bdfb0..0000000
--- a/uimafit-core/src/test/java/org/apache/uima/fit/util/AnnotationPredicatesTest.java
+++ /dev/null
@@ -1,382 +0,0 @@
-/*
- * 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.util;
-
-import static java.lang.Integer.MAX_VALUE;
-import static java.util.Arrays.asList;
-import static org.apache.uima.fit.util.AnnotationPredicates.colocated;
-import static org.apache.uima.fit.util.AnnotationPredicates.coveredBy;
-import static org.apache.uima.fit.util.AnnotationPredicates.covers;
-import static org.apache.uima.fit.util.AnnotationPredicates.leftOf;
-import static org.apache.uima.fit.util.AnnotationPredicates.overlaps;
-import static org.apache.uima.fit.util.AnnotationPredicates.overlapsLeft;
-import static org.apache.uima.fit.util.AnnotationPredicates.overlapsRight;
-import static org.apache.uima.fit.util.AnnotationPredicates.rightOf;
-import static org.apache.uima.fit.util.AnnotationPredicatesTest.RelativePosition.COLOCATED;
-import static org.apache.uima.fit.util.AnnotationPredicatesTest.RelativePosition.COVERED_BY;
-import static org.apache.uima.fit.util.AnnotationPredicatesTest.RelativePosition.COVERING;
-import static org.apache.uima.fit.util.AnnotationPredicatesTest.RelativePosition.LEFT_OF;
-import static org.apache.uima.fit.util.AnnotationPredicatesTest.RelativePosition.OVERLAPPING;
-import static org.apache.uima.fit.util.AnnotationPredicatesTest.RelativePosition.OVERLAPPING_LEFT;
-import static org.apache.uima.fit.util.AnnotationPredicatesTest.RelativePosition.OVERLAPPING_RIGHT;
-import static org.apache.uima.fit.util.AnnotationPredicatesTest.RelativePosition.RIGHT_OF;
-
-import org.apache.uima.cas.CAS;
-import org.apache.uima.cas.Type;
-import org.apache.uima.fit.factory.CasFactory;
-import org.assertj.core.api.AutoCloseableSoftAssertions;
-import org.junit.Test;
-
-public class AnnotationPredicatesTest {
-
- static enum RelativePosition {
- COLOCATED,
- OVERLAPPING,
- OVERLAPPING_LEFT,
- OVERLAPPING_RIGHT,
- COVERING,
- COVERED_BY,
- LEFT_OF,
- RIGHT_OF
-}
-
- @Test
- public void thatCoveringWithIntervalsWorks() throws Exception {
- assertPosition(COVERING, AnnotationPredicates::covers);
- }
-
- @Test
- public void thatCoveringWithAnnotationAndIntervalWorks() throws Exception {
- CAS cas = CasFactory.createCas();
- Type type = cas.getAnnotationType();
-
- assertPosition(COVERING, (beginA, endA, beginB,
- endB) -> covers(cas.createAnnotation(type, beginA, endA), beginB, endB));
- }
-
- @Test
- public void thatCoveringWithAnnotationsWorks() throws Exception {
- CAS cas = CasFactory.createCas();
- Type type = cas.getAnnotationType();
-
- assertPosition(COVERING,
- (beginA, endA, beginB, endB) -> covers(cas.createAnnotation(type, beginA, endA),
- cas.createAnnotation(type, beginB, endB)));
- }
-
- @Test
- public void thatCoveredByWithIntervalsWorks() throws Exception {
- assertPosition(COVERED_BY, AnnotationPredicates::coveredBy);
- }
-
- @Test
- public void thatCoveredByWithAnnotationAndIntervalWorks() throws Exception {
- CAS cas = CasFactory.createCas();
- Type type = cas.getAnnotationType();
-
- assertPosition(COVERED_BY, (beginA, endA, beginB,
- endB) -> coveredBy(cas.createAnnotation(type, beginA, endA), beginB, endB));
- }
-
- @Test
- public void thatCoveredByWithAnnotationsWorks() throws Exception {
- CAS cas = CasFactory.createCas();
- Type type = cas.getAnnotationType();
-
- assertPosition(COVERED_BY,
- (beginA, endA, beginB, endB) -> coveredBy(cas.createAnnotation(type, beginA, endA),
- cas.createAnnotation(type, beginB, endB)));
- }
-
- @Test
- public void thatColocatedWithIntervalsWorks() throws Exception {
- assertPosition(COLOCATED, AnnotationPredicates::colocated);
-
- // It must also work if we switch the of the spans
- assertPosition(COLOCATED,
- (beginA, endA, beginB, endB) -> colocated(beginB, endB, beginA, endA));
- }
-
- @Test
- public void thatColocatedWithAnnotationAndIntervalWorks() throws Exception
- {
- CAS cas = CasFactory.createCas();
- Type type = cas.getAnnotationType();
-
- assertPosition(COLOCATED, (beginA, endA, beginB,
- endB) -> colocated(cas.createAnnotation(type, beginA, endA), beginB, endB));
-
- // It must also work if we switch the of the spans
- assertPosition(COLOCATED, (beginA, endA, beginB,
- endB) -> colocated(cas.createAnnotation(type, beginB, endB), beginA, endA));
- }
-
- @Test
- public void thatColocatedWithAnnotationsWorks() throws Exception
- {
- CAS cas = CasFactory.createCas();
- Type type = cas.getAnnotationType();
-
- assertPosition(COLOCATED,
- (beginA, endA, beginB, endB) -> colocated(cas.createAnnotation(type, beginA, endA),
- cas.createAnnotation(type, beginB, endB)));
-
- // It must also work if we switch the of the spans
- assertPosition(COLOCATED,
- (beginA, endA, beginB, endB) -> colocated(cas.createAnnotation(type, beginB, endB),
- cas.createAnnotation(type, beginA, endA)));
- }
-
- @Test
- public void thatOverlapsLeftWithIntervalsWorks() throws Exception {
- assertPosition(OVERLAPPING_LEFT, AnnotationPredicates::overlapsLeft);
- }
-
- @Test
- public void thatOverlapsLeftWithAnnotationAndIntervalWorks() throws Exception {
- CAS cas = CasFactory.createCas();
- Type type = cas.getAnnotationType();
-
- assertPosition(OVERLAPPING_LEFT, (beginA, endA, beginB,
- endB) -> overlapsLeft(cas.createAnnotation(type, beginA, endA), beginB, endB));
- }
-
- @Test
- public void thatOverlapsLeftWithAnnotationsWorks() throws Exception {
- CAS cas = CasFactory.createCas();
- Type type = cas.getAnnotationType();
-
- assertPosition(OVERLAPPING_LEFT,
- (beginA, endA, beginB, endB) -> overlapsLeft(cas.createAnnotation(type, beginA, endA),
- cas.createAnnotation(type, beginB, endB)));
- }
-
- @Test
- public void thatOverlapsRightWithIntervalsWorks() throws Exception {
- assertPosition(OVERLAPPING_RIGHT, AnnotationPredicates::overlapsRight);
- }
-
- @Test
- public void thatOverlapsRightWithAnnotationAndIntervalWorks() throws Exception {
- CAS cas = CasFactory.createCas();
- Type type = cas.getAnnotationType();
-
- assertPosition(OVERLAPPING_RIGHT, (beginA, endA, beginB,
- endB) -> overlapsRight(cas.createAnnotation(type, beginA, endA), beginB, endB));
- }
-
- @Test
- public void thatOverlapsRightWithAnnotationsWorks() throws Exception {
- CAS cas = CasFactory.createCas();
- Type type = cas.getAnnotationType();
-
- assertPosition(OVERLAPPING_RIGHT,
- (beginA, endA, beginB, endB) -> overlapsRight(cas.createAnnotation(type, beginA, endA),
- cas.createAnnotation(type, beginB, endB)));
- }
-
- @Test
- public void thatOverlapsWithIntervalsWorks() throws Exception {
- assertPosition(OVERLAPPING, AnnotationPredicates::overlaps);
-
- // It must also work if we switch the of the spans
- assertPosition(OVERLAPPING,
- (beginA, endA, beginB, endB) -> overlaps(beginB, endB, beginA, endA));
- }
-
- @Test
- public void thatOverlapsWithAnnotationAndIntervalWorks() throws Exception
- {
- CAS cas = CasFactory.createCas();
- Type type = cas.getAnnotationType();
-
- assertPosition(OVERLAPPING, (beginA, endA, beginB,
- endB) -> overlaps(cas.createAnnotation(type, beginA, endA), beginB, endB));
-
- // It must also work if we switch the of the spans
- assertPosition(OVERLAPPING, (beginA, endA, beginB,
- endB) -> overlaps(cas.createAnnotation(type, beginB, endB), beginA, endA));
- }
-
- @Test
- public void thatOverlapsWithAnnotationsWorks() throws Exception
- {
- CAS cas = CasFactory.createCas();
- Type type = cas.getAnnotationType();
-
- assertPosition(OVERLAPPING,
- (beginA, endA, beginB, endB) -> overlaps(cas.createAnnotation(type, beginA, endA),
- cas.createAnnotation(type, beginB, endB)));
-
- // It must also work if we switch the of the spans
- assertPosition(OVERLAPPING,
- (beginA, endA, beginB, endB) -> overlaps(cas.createAnnotation(type, beginB, endB),
- cas.createAnnotation(type, beginA, endA)));
- }
-
- @Test
- public void thatLeftOfWithIntervalsWorks() throws Exception {
- assertPosition(LEFT_OF, AnnotationPredicates::leftOf);
- }
-
- @Test
- public void thatLeftOfWithAnnotationAndIntervalWorks() throws Exception {
- CAS cas = CasFactory.createCas();
- Type type = cas.getAnnotationType();
-
- assertPosition(LEFT_OF, (beginA, endA, beginB,
- endB) -> leftOf(cas.createAnnotation(type, beginA, endA), beginB, endB));
- }
-
- @Test
- public void thatLeftOfWithAnnotationsWorks() throws Exception {
- CAS cas = CasFactory.createCas();
- Type type = cas.getAnnotationType();
-
- assertPosition(LEFT_OF,
- (beginA, endA, beginB, endB) -> leftOf(cas.createAnnotation(type, beginA, endA),
- cas.createAnnotation(type, beginB, endB)));
- }
-
- @Test
- public void thatRightOfWithIntervalsWorks() throws Exception {
- assertPosition(RIGHT_OF, AnnotationPredicates::rightOf);
- }
-
- @Test
- public void thatRightOfWithAnnotationAndIntervalWorks() throws Exception {
- CAS cas = CasFactory.createCas();
- Type type = cas.getAnnotationType();
-
- assertPosition(RIGHT_OF, (beginA, endA, beginB,
- endB) -> rightOf(cas.createAnnotation(type, beginA, endA), beginB, endB));
- }
-
- @Test
- public void thatRightOfWithAnnotationsWorks() throws Exception {
- CAS cas = CasFactory.createCas();
- Type type = cas.getAnnotationType();
-
- assertPosition(RIGHT_OF,
- (beginA, endA, beginB, endB) -> rightOf(cas.createAnnotation(type, beginA, endA),
- cas.createAnnotation(type, beginB, endB)));
- }
-
- @FunctionalInterface
- private static interface RelativePositionPredicate {
- boolean apply(int beginA, int endA, int beginB, int endB);
- }
-
- public void assertPosition(RelativePosition aCondition, RelativePositionPredicate aPredicate)
- throws Exception {
- // Define a fixed interval around which we build most of the tests by applying different
- // selections to it
- int begin = 10;
- int end = 20;
-
- try (AutoCloseableSoftAssertions softly = new AutoCloseableSoftAssertions()) {
- softly.assertThat(aPredicate.apply(begin, end, begin - 1, begin - 1))
- .as("Zero-width B before A begins (| ###)")
- .isEqualTo(asList(RIGHT_OF).contains(aCondition));
-
- softly.assertThat(aPredicate.apply(begin, end, 0, begin - 1))
- .as("B begins and ends before A begins ([---] ###)")
- .isEqualTo(asList(RIGHT_OF).contains(aCondition));
-
- softly.assertThat(aPredicate.apply(begin, end, 0, begin))
- .as("B begins before and ends where A begins ([---]###)")
- .isEqualTo(asList(RIGHT_OF).contains(aCondition));
-
- softly.assertThat(aPredicate.apply(begin, end, begin, begin))
- .as("Zero-width B where A begins (|###)")
- .isEqualTo(asList(OVERLAPPING, COVERING).contains(aCondition));
-
- softly.assertThat(aPredicate.apply(begin, end, 0, begin + 1))
- .as("B begins before and ends within A ([--#]##)")
- .isEqualTo(asList(OVERLAPPING, OVERLAPPING_RIGHT).contains(aCondition));
-
- softly.assertThat(aPredicate.apply(begin, end, begin + 1, end - 1))
- .as("B begins and ends within A (#[#]#)")
- .isEqualTo(asList(OVERLAPPING, COVERING).contains(aCondition));
-
- softly.assertThat(aPredicate.apply(begin, end, begin + 1, end))
- .as("B begins after and ends at A's boundries (#[##])")
- .isEqualTo(asList(OVERLAPPING, COVERING).contains(aCondition));
-
- softly.assertThat(aPredicate.apply(begin, end, begin - 1, end + 1))
- .as("B begins and ends at A's boundries ([-###-])")
- .isEqualTo(asList(OVERLAPPING, COVERED_BY).contains(aCondition));
-
- softly.assertThat(aPredicate.apply(begin, end, begin, end))
- .as("B begins and ends at A's boundries ([###])")
- .isEqualTo(asList(OVERLAPPING, COLOCATED, COVERED_BY, COVERING).contains(aCondition));
-
- softly.assertThat(aPredicate.apply(begin, end, begin + 1, begin + 1))
- .as("Zero-width B within A (#|#)")
- .isEqualTo(asList(OVERLAPPING, COVERING).contains(aCondition));
-
- softly.assertThat(aPredicate.apply(begin, end, begin, end - 1))
- .as("B begins at and ends before A's boundries ([##]#)")
- .isEqualTo(asList(OVERLAPPING, COVERING).contains(aCondition));
-
- softly.assertThat(aPredicate.apply(begin, end, end - 1 , MAX_VALUE))
- .as("B begins before and ends within A (##[#--])")
- .isEqualTo(asList(OVERLAPPING, OVERLAPPING_LEFT).contains(aCondition));
-
- softly.assertThat(aPredicate.apply(begin, end, end, MAX_VALUE))
- .as("B begins at A's end and ends after A (###[---])")
- .isEqualTo(asList(LEFT_OF).contains(aCondition));
-
- softly.assertThat(aPredicate.apply(begin, end, end, end))
- .as("Zero-width B at A's end (###|)")
- .isEqualTo(asList(LEFT_OF).contains(aCondition));
-
- softly.assertThat(aPredicate.apply(begin, end, end + 1, MAX_VALUE))
- .as("B begins and ends after A (### [---])")
- .isEqualTo(asList(LEFT_OF).contains(aCondition));
-
- softly.assertThat(aPredicate.apply(begin, end, end + 1, end + 1))
- .as("Zero-width B after A's end (### |)")
- .isEqualTo(asList(LEFT_OF).contains(aCondition));
-
- begin = 10;
- end = 10;
-
- softly.assertThat(aPredicate.apply(begin, end, 20, 30))
- .as("Zero-width A before B start (# [---])")
- .isEqualTo(asList(LEFT_OF).contains(aCondition));
-
- softly.assertThat(aPredicate.apply(begin, end, 10, 20))
- .as("Zero-width A at B's start (#---])")
- .isEqualTo(asList(OVERLAPPING, COVERED_BY).contains(aCondition));
-
- softly.assertThat(aPredicate.apply(begin, end, 0, 10))
- .as("Zero-width A at B's end ([---#)")
- .isEqualTo(asList(RIGHT_OF).contains(aCondition));
-
- softly.assertThat(aPredicate.apply(begin, end, 10, 10))
- .as("Zero-width A matches zero-width B start/end (#)")
- .isEqualTo(asList(OVERLAPPING, COVERED_BY, COVERING, COLOCATED).contains(aCondition));
-
- softly.assertThat(aPredicate.apply(begin, end, 0, 5))
- .as("Zero-width A after B's end ([---] #)")
- .isEqualTo(asList(RIGHT_OF).contains(aCondition));
- }
- }
-}
\ No newline at end of file
diff --git a/uimafit-core/src/test/java/org/apache/uima/fit/util/CasUtilTest.java b/uimafit-core/src/test/java/org/apache/uima/fit/util/CasUtilTest.java
index 769502e..7ccf685 100644
--- a/uimafit-core/src/test/java/org/apache/uima/fit/util/CasUtilTest.java
+++ b/uimafit-core/src/test/java/org/apache/uima/fit/util/CasUtilTest.java
@@ -18,24 +18,47 @@
*/
package org.apache.uima.fit.util;
+import static java.lang.Integer.MAX_VALUE;
import static java.util.Arrays.asList;
+import static java.util.stream.Collectors.toList;
+import static org.apache.uima.cas.text.AnnotationPredicates.colocated;
+import static org.apache.uima.cas.text.AnnotationPredicates.coveredBy;
+import static org.apache.uima.cas.text.AnnotationPredicates.covering;
+import static org.apache.uima.cas.text.AnnotationPredicates.following;
+import static org.apache.uima.cas.text.AnnotationPredicates.preceding;
import static org.apache.uima.fit.factory.TypeSystemDescriptionFactory.createTypeSystemDescription;
+import static org.apache.uima.fit.util.CasUtil.exists;
import static org.apache.uima.fit.util.CasUtil.getAnnotationType;
import static org.apache.uima.fit.util.CasUtil.getType;
import static org.apache.uima.fit.util.CasUtil.iterator;
import static org.apache.uima.fit.util.CasUtil.iteratorFS;
import static org.apache.uima.fit.util.CasUtil.select;
+import static org.apache.uima.fit.util.CasUtil.selectAt;
import static org.apache.uima.fit.util.CasUtil.selectByIndex;
+import static org.apache.uima.fit.util.CasUtil.selectCovered;
+import static org.apache.uima.fit.util.CasUtil.selectCovering;
import static org.apache.uima.fit.util.CasUtil.selectFS;
+import static org.apache.uima.fit.util.CasUtil.selectFollowing;
+import static org.apache.uima.fit.util.CasUtil.selectPreceding;
import static org.apache.uima.fit.util.CasUtil.toText;
-import static org.apache.uima.fit.util.CasUtil.exists;
+import static org.apache.uima.fit.util.SelectionAssert.NON_ZERO_WIDTH_TEST_CASES;
+import static org.apache.uima.fit.util.SelectionAssert.ZERO_WIDTH_TEST_CASES;
+import static org.apache.uima.fit.util.SelectionAssert.assertSelection;
+import static org.apache.uima.fit.util.SelectionAssert.assertSelectionIsEqualOnRandomData;
+import static org.apache.uima.fit.util.SelectionAssert.RelativePosition.COLOCATED;
+import static org.apache.uima.fit.util.SelectionAssert.RelativePosition.COVERED_BY;
+import static org.apache.uima.fit.util.SelectionAssert.RelativePosition.COVERING;
+import static org.apache.uima.fit.util.SelectionAssert.RelativePosition.FOLLOWING;
+import static org.apache.uima.fit.util.SelectionAssert.RelativePosition.PRECEDING;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
+import java.util.List;
import org.apache.uima.UIMAException;
import org.apache.uima.cas.ArrayFS;
@@ -45,6 +68,7 @@ import org.apache.uima.cas.Type;
import org.apache.uima.cas.text.AnnotationFS;
import org.apache.uima.fit.ComponentTestBase;
import org.apache.uima.fit.type.Token;
+import org.apache.uima.fit.util.SelectionAssert.TestCase;
import org.apache.uima.jcas.cas.TOP;
import org.apache.uima.jcas.tcas.Annotation;
import org.apache.uima.util.CasCreationUtils;
@@ -55,6 +79,9 @@ import org.junit.Test;
*
*/
public class CasUtilTest extends ComponentTestBase {
+ private List<TestCase> defaultPredicatesTestCases = union(NON_ZERO_WIDTH_TEST_CASES,
+ ZERO_WIDTH_TEST_CASES);
+
@Test
public void testGetType() {
String text = "Rot wood cheeses dew?";
@@ -205,4 +232,111 @@ public class CasUtilTest extends ComponentTestBase {
assertTrue(exists(cas, tokenType));
}
+
+ @Test
+ public void thatSelectFollowingBehaviorAlignsWithPrecedingPredicate() throws Exception {
+ // In order to find annotations that X is preceding, we select the following annotations
+ assertSelection(
+ PRECEDING,
+ (cas, type, x, y) -> selectFollowing(cas, type, x, MAX_VALUE).contains(y),
+ defaultPredicatesTestCases);
+ }
+
+ @Test
+ public void thatSelectPrecedingBehaviorAlignsWithPrecedingPredicateOnRandomData() throws Exception
+ {
+ assertSelectionIsEqualOnRandomData(
+ (cas, type, context) -> cas.getAnnotationIndex(type).select()
+ .filter(candidate -> preceding(candidate, context))
+ .collect(toList()),
+ (cas, type, context) -> selectPreceding(cas, type, context, MAX_VALUE));
+ }
+
+ @Test
+ public void thatSelectPrecedingBehaviorAlignsWithFollowingPredicate() throws Exception {
+ // In order to find annotations that X is following, we select the preceding annotations
+ assertSelection(
+ FOLLOWING,
+ (cas, type, x, y) -> selectPreceding(cas, type, x, MAX_VALUE).contains(y),
+ defaultPredicatesTestCases);
+ }
+
+ @Test
+ public void thatSelectFollowingBehaviorAlignsWithFollowingPredicateOnRandomData() throws Exception
+ {
+ assertSelectionIsEqualOnRandomData(
+ (cas, type, context) -> cas.getAnnotationIndex(type).select()
+ .filter(candidate -> following(candidate, context))
+ .collect(toList()),
+ (cas, type, context) -> selectFollowing(cas, type, context, MAX_VALUE));
+ }
+
+ @Test
+ public void thatSelectCoveringBehaviorAlignsWithCoveredByPredicate() throws Exception {
+ // X covered by Y means that Y is covering X, so we need to select the covering annotations
+ // below.
+ assertSelection(
+ COVERED_BY,
+ (cas, type, x, y) -> selectCovering(cas, type, x).contains(y),
+ defaultPredicatesTestCases);
+ }
+
+ @Test
+ public void thatSelectCoveredBehaviorAlignsWithCoveredByPredicateOnRandomData() throws Exception
+ {
+ assertSelectionIsEqualOnRandomData(
+ (cas, type, context) -> cas.getAnnotationIndex(type).select()
+ .filter(candidate -> coveredBy(candidate, context))
+ .collect(toList()),
+ (cas, type, context) -> selectCovered(cas, type, context));
+ }
+
+ @Test
+ public void thatSelectCoveredBehaviorAlignsWithCoveringPredicate() throws Exception {
+ // X covering Y means that Y is covered by Y, so we need to select the covered by annotations
+ // below.
+ assertSelection(
+ COVERING,
+ (cas, type, x, y) -> selectCovered(cas, type, x).contains(y),
+ defaultPredicatesTestCases);
+ }
+
+ @Test
+ public void thatSelectFsBehaviorAlignsWithCoveringPredicateOnRandomData() throws Exception
+ {
+ assertSelectionIsEqualOnRandomData(
+ (cas, type, context) -> cas.getAnnotationIndex(type).select()
+ .filter(candidate -> covering(candidate, context))
+ .collect(toList()),
+ (cas, type, context) -> selectCovering(cas, type, context));
+ }
+
+ @Test
+ public void thatSelectAtBehaviorAlignsWithColocatedPredicate() throws Exception {
+ // X covering Y means that Y is covered by Y, so we need to select the covered by annotations
+ // below.
+ assertSelection(
+ COLOCATED,
+ (cas, type, x, y) -> selectAt(cas, type, x.getBegin(), x.getEnd()).contains(y),
+ defaultPredicatesTestCases);
+ }
+
+ @Test
+ public void thatSelectAtBehaviorAlignsWithColocatedPredicateOnRandomData() throws Exception
+ {
+ assertSelectionIsEqualOnRandomData(
+ (cas, type, context) -> cas.getAnnotationIndex(type).select()
+ .filter(candidate -> colocated(candidate, context))
+ .collect(toList()),
+ (cas, type, context) -> selectAt(cas, type, context.getBegin(), context.getEnd()));
+ }
+
+ @SafeVarargs
+ public static <T> List<T> union(List<T>... aLists) {
+ List<T> all = new ArrayList<>();
+ for (List<T> list : aLists) {
+ all.addAll(list);
+ }
+ return all;
+ }
}
diff --git a/uimafit-core/src/test/java/org/apache/uima/fit/util/JCasUtilTest.java b/uimafit-core/src/test/java/org/apache/uima/fit/util/JCasUtilTest.java
index c3817a0..5acf940 100644
--- a/uimafit-core/src/test/java/org/apache/uima/fit/util/JCasUtilTest.java
+++ b/uimafit-core/src/test/java/org/apache/uima/fit/util/JCasUtilTest.java
@@ -23,9 +23,7 @@ package org.apache.uima.fit.util;
import static java.lang.Integer.MAX_VALUE;
import static java.util.Arrays.asList;
-import static java.util.stream.Collectors.toList;
import static org.apache.uima.fit.factory.TypeSystemDescriptionFactory.createTypeSystemDescription;
-import static org.apache.uima.fit.util.AnnotationPredicates.overlaps;
import static org.apache.uima.fit.util.JCasUtil.contains;
import static org.apache.uima.fit.util.JCasUtil.exists;
import static org.apache.uima.fit.util.JCasUtil.getAnnotationType;
@@ -87,6 +85,7 @@ import org.junit.Test;
* Test cases for {@link JCasUtil}.
*/
public class JCasUtilTest extends ComponentTestBase {
+
/**
* Test Tokens (Stems + Lemmas) overlapping with each other.
*/
@@ -202,25 +201,12 @@ public class JCasUtilTest extends ComponentTestBase {
assertOverlapBehavior(JCasUtilTest::selectOverlappingNaive);
}
- @Test
- public void thatSelectOverlappingNaiveV3Works() throws Exception
- {
- assertOverlapBehavior(JCasUtilTest::selectOverlappingNaiveV3);
- }
-
- @Test
- public void thatSelectOverlappingV3Works() throws Exception
- {
- assertOverlapBehavior(JCasUtilTest::selectOverlappingV3);
- }
-
private static void assertOverlapBehavior(TypeByOffsetSelector aSelector) throws Exception
{
JCas jcas = JCasFactory.createJCas();
Token t = new Token(jcas, 10, 20);
t.addToIndexes();
-
try (AutoCloseableSoftAssertions softly = new AutoCloseableSoftAssertions()) {
softly.assertThat(aSelector.select(jcas, Token.class, t.getBegin() - 1, t.getBegin() - 1))
.as("Zero-width selection before annotation begin (| ###)")
@@ -322,9 +308,7 @@ public class JCasUtilTest extends ComponentTestBase {
Collection<Sentence> sentences = select(jcas, Sentence.class);
long timeNaive = 0;
- long timeNaiveV3 = 0;
long timeOptimized = 0;
- long timeOptimizedV3 = 0;
for (Sentence s : sentences) {
// The naive approach is assumed to be correct
@@ -333,46 +317,20 @@ public class JCasUtilTest extends ComponentTestBase {
s.getEnd());
timeNaive += System.currentTimeMillis() - ti;
- // Record time for the naive V3 approach
- ti = System.currentTimeMillis();
- List<Token> actualNaiveV3 = selectOverlappingNaiveV3(jcas, Token.class, s.getBegin(),
- s.getEnd());
- timeNaiveV3 += System.currentTimeMillis() - ti;
-
// Record time for the optimized approach
ti = System.currentTimeMillis();
List<Token> actual = selectOverlapping(jcas, Token.class, s.getBegin(), s.getEnd());
timeOptimized += System.currentTimeMillis() - ti;
- // Record time for the optimized v3 approach
- ti = System.currentTimeMillis();
- List<Token> actualV3 = selectOverlappingV3(jcas, Token.class, s.getBegin(),
- s.getEnd());
- timeOptimizedV3 += System.currentTimeMillis() - ti;
-
assertThat(actual)
.as("Selection : [" + s.getBegin() + ".." + s.getEnd() + "]")
.containsExactlyElementsOf(expected);
- assertThat(actualNaiveV3)
- .as("Selection (naive V3): [" + s.getBegin() + ".." + s.getEnd() + "]")
- .containsExactlyElementsOf(expected);
- assertThat(actualV3)
- .as("Selection (V3) : [" + s.getBegin() + ".." + s.getEnd() + "]")
- .containsExactlyElementsOf(expected);
}
System.out.printf(
"%3d Optimized : speed up x%3.2f [baseline:%4d current:%4d (diff:%4d)]%n",
i, (double) timeNaive / (double) timeOptimized, timeNaive, timeOptimized,
timeNaive - timeOptimized);
- System.out.printf(
- "%3d Naive V3 : speed up x%3.2f [baseline:%4d current:%4d (diff:%4d)]%n",
- i, (double) timeNaive / (double) timeNaiveV3, timeNaive, timeNaiveV3,
- timeNaive - timeNaiveV3);
- System.out.printf(
- "%3d Optimized V3: speed up x%3.2f [baseline:%4d current:%4d (diff:%4d)]%n",
- i, (double) timeNaive / (double) timeOptimizedV3, timeNaive, timeOptimizedV3,
- timeNaive - timeOptimizedV3);
System.out.println();
}
}
@@ -413,38 +371,6 @@ public class JCasUtilTest extends ComponentTestBase {
.collect(Collectors.toList());
}
- public static <T extends Annotation> List<T> selectOverlappingNaiveV3(JCas aCas, Class<T> aType,
- int aSelBegin, int aSelEnd) {
- return aCas.select(aType)
- // Commented out because due to UIMA-6269, some annotations may be missed
- // .coveredBy(0, aSelEnd)
- // .includeAnnotationsWithEndBeyondBounds()
- .filter(ann -> naiveOverlappingCondition(ann, aSelBegin, aSelEnd))
- .collect(Collectors.toList());
- }
-
- public static <T extends Annotation> List<T> selectOverlappingV3(JCas aCas, Class<T> aType,
- int aSelBegin, int aSelEnd) {
-
- return aCas.getAnnotationIndex(aType).select()
- .filter(ann -> overlaps(ann, aSelBegin, aSelEnd))
- .collect(toList());
-
- // These are alternative implementations, but just as the version above, they are also slow
- // compared to the implementation we use in CasUtil.selectOverlapping() right now.
- // Also, they suffer from UIMA-6269, some annotations may be missed
-// return aCas.getAnnotationIndex(aType).select()
-// .coveredBy(0, aSelEnd)
-// .includeAnnotationsWithEndBeyondBounds()
-// .filter(ann -> isOverlapping(ann, aSelBegin, aSelEnd))
-// .collect(Collectors.toList());
-
-// return aCas.select(aType)
-// .coveredBy(0, aSelEnd)
-// .includeAnnotationsWithEndBeyondBounds()
-// .filter(ann -> isOverlapping(ann, aSelBegin, aSelEnd))
-// .collect(Collectors.toList());
- }
/**
* Test what happens if there is actually nothing overlapping with the Token.
*/
@@ -1193,7 +1119,7 @@ public class JCasUtilTest extends ComponentTestBase {
assertEquals(b.getBegin(), tokenAt.getBegin());
assertEquals(b.getEnd(), tokenAt.getEnd());
}
-
+
@FunctionalInterface
private static interface TypeByOffsetSelector {
<T extends Annotation> List<T> select(JCas aCas, Class<T> aType,
diff --git a/uimafit-core/src/test/java/org/apache/uima/fit/util/SelectionAssert.java b/uimafit-core/src/test/java/org/apache/uima/fit/util/SelectionAssert.java
new file mode 100644
index 0000000..2bf7b0e
--- /dev/null
+++ b/uimafit-core/src/test/java/org/apache/uima/fit/util/SelectionAssert.java
@@ -0,0 +1,292 @@
+/*
+ * 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.util;
+
+import static java.lang.Integer.MAX_VALUE;
+import static java.util.Arrays.asList;
+import static org.apache.uima.fit.util.SelectionAssert.RelativePosition.BEGINNING_WITH;
+import static org.apache.uima.fit.util.SelectionAssert.RelativePosition.COLOCATED;
+import static org.apache.uima.fit.util.SelectionAssert.RelativePosition.COVERED_BY;
+import static org.apache.uima.fit.util.SelectionAssert.RelativePosition.COVERING;
+import static org.apache.uima.fit.util.SelectionAssert.RelativePosition.ENDING_WITH;
+import static org.apache.uima.fit.util.SelectionAssert.RelativePosition.FOLLOWING;
+import static org.apache.uima.fit.util.SelectionAssert.RelativePosition.OVERLAPPING;
+import static org.apache.uima.fit.util.SelectionAssert.RelativePosition.OVERLAPPING_AT_BEGIN;
+import static org.apache.uima.fit.util.SelectionAssert.RelativePosition.OVERLAPPING_AT_END;
+import static org.apache.uima.fit.util.SelectionAssert.RelativePosition.PRECEDING;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.function.Function;
+
+import org.apache.uima.UIMAFramework;
+import org.apache.uima.cas.CAS;
+import org.apache.uima.cas.Type;
+import org.apache.uima.cas.text.AnnotationFS;
+import org.apache.uima.jcas.tcas.Annotation;
+import org.apache.uima.resource.metadata.TypeSystemDescription;
+import org.apache.uima.util.CasCreationUtils;
+import org.assertj.core.api.AutoCloseableSoftAssertions;
+
+public class SelectionAssert {
+ public static enum RelativePosition {
+ COLOCATED,
+ OVERLAPPING,
+ OVERLAPPING_AT_BEGIN,
+ OVERLAPPING_AT_END,
+ COVERING,
+ COVERED_BY,
+ PRECEDING,
+ FOLLOWING,
+ BEGINNING_WITH,
+ ENDING_WITH
+ }
+
+ // Used as fixed references for the annotation relation cases.
+ private static final int BEGIN = 10;
+ private static final int END = 20;
+ private static final int Z_POS = 10;
+
+ public static final List<TestCase> NON_ZERO_WIDTH_TEST_CASES = asList(
+ new TestCase("1) Y begins and ends after X (### [---])",
+ p -> p.apply(BEGIN, END, END + 1, MAX_VALUE),
+ asList(PRECEDING)),
+ new TestCase("2) Y begins at X's end and ends after X (###[---])",
+ p -> p.apply(BEGIN, END, END, MAX_VALUE),
+ asList(PRECEDING)),
+ new TestCase("3) Y begins within and ends after X (##[#--])",
+ p -> p.apply(BEGIN, END, END - 1 , MAX_VALUE),
+ asList(OVERLAPPING, OVERLAPPING_AT_BEGIN)),
+ new TestCase("4) Y begins and ends at X's boundries ([###])",
+ p -> p.apply(BEGIN, END, BEGIN, END),
+ asList(OVERLAPPING, COLOCATED, COVERED_BY, COVERING, BEGINNING_WITH, ENDING_WITH)),
+ new TestCase("5) Y begins and ends within X (#[#]#)",
+ p -> p.apply(BEGIN, END, BEGIN + 1, END - 1),
+ asList(OVERLAPPING, COVERING)),
+ new TestCase("6) Y begins at and ends before X's boundries ([##]#)",
+ p -> p.apply(BEGIN, END, BEGIN, END - 1),
+ asList(OVERLAPPING, COVERING, BEGINNING_WITH)),
+ new TestCase("7) Y begins after and ends at X's boundries (#[##])",
+ p -> p.apply(BEGIN, END, BEGIN + 1, END),
+ asList(OVERLAPPING, COVERING, ENDING_WITH)),
+ new TestCase("8) Y begins before and ends after X's boundries ([-###-])",
+ p -> p.apply(BEGIN, END, BEGIN - 1, END + 1),
+ asList(OVERLAPPING, COVERED_BY)),
+ new TestCase("9) X starts where Y begins and ends within Y ([##-])",
+ p -> p.apply(BEGIN, END, BEGIN, END + 1),
+ asList(OVERLAPPING, COVERED_BY, BEGINNING_WITH)),
+ new TestCase("10) X starts within Y and ends where Y ends ([-##])",
+ p -> p.apply(BEGIN, END, BEGIN - 1, END),
+ asList(OVERLAPPING, COVERED_BY, ENDING_WITH)),
+ new TestCase("11) Y begins before and ends within X ([--#]##)",
+ p -> p.apply(BEGIN, END, 0, BEGIN + 1),
+ asList(OVERLAPPING, OVERLAPPING_AT_END)),
+ new TestCase("12) Y begins before and ends where X begins ([---]###)",
+ p -> p.apply(BEGIN, END, 0, BEGIN),
+ asList(FOLLOWING)),
+ new TestCase("13) Y begins and ends before X begins ([---] ###)",
+ p -> p.apply(BEGIN, END, 0, BEGIN - 1),
+ asList(FOLLOWING)));
+
+ public static final List<TestCase> ZERO_WIDTH_TEST_CASES = asList(
+ new TestCase("Z1) Zero-width X before Y start (# [---])",
+ p -> p.apply(Z_POS, Z_POS, Z_POS + 10, Z_POS + 20),
+ asList(PRECEDING)),
+ new TestCase("Z2) Zero-width Y after X's end (### |)",
+ p -> p.apply(BEGIN, END, END + 1, END + 1),
+ asList(PRECEDING)),
+ new TestCase("Z3) Zero-width X at Y's start (#---])",
+ p -> p.apply(Z_POS, Z_POS, Z_POS, Z_POS + 10),
+ asList(OVERLAPPING, COVERED_BY, BEGINNING_WITH)),
+ new TestCase("Z4) Zero-width X at Y's end ([---#)",
+ p -> p.apply(Z_POS, Z_POS, Z_POS-10, Z_POS),
+ asList(OVERLAPPING, COVERED_BY, ENDING_WITH)),
+ new TestCase("Z5) Zero-width Y where X begins (|###)",
+ p -> p.apply(BEGIN, END, BEGIN, BEGIN),
+ asList(OVERLAPPING, COVERING, BEGINNING_WITH)),
+ new TestCase("Z6) Zero-width Y within X (#|#)",
+ p -> p.apply(BEGIN, END, BEGIN + 1, BEGIN + 1),
+ asList(OVERLAPPING, COVERING)),
+ new TestCase("Z7) Zero-width Y at X's end (###|)",
+ p -> p.apply(BEGIN, END, END, END),
+ asList(OVERLAPPING, COVERING, ENDING_WITH)),
+ new TestCase("Z8) Zero-width X with Y (-|-)",
+ p -> p.apply(Z_POS, Z_POS, Z_POS - 5, Z_POS + 5),
+ asList(OVERLAPPING, COVERED_BY)),
+ new TestCase("Z9) Zero-width X after Y's end ([---] #)",
+ p -> p.apply(Z_POS, Z_POS, Z_POS - 10, Z_POS - 5),
+ asList(FOLLOWING)),
+ new TestCase("Z10) Zero-width Y before X begins (| ###)",
+ p -> p.apply(BEGIN, END, BEGIN - 1, BEGIN - 1),
+ asList(FOLLOWING)),
+ new TestCase("Z11) Zero-width X matches zero-width Y start/end (#)",
+ p -> p.apply(Z_POS, Z_POS, Z_POS, Z_POS),
+ asList(OVERLAPPING, COVERED_BY, COVERING, COLOCATED, BEGINNING_WITH, ENDING_WITH)));
+
+ public static void assertSelection(RelativePosition aCondition, RelativeAnnotationPredicate aPredicate,
+ List<TestCase> aTestCases)
+ throws Exception {
+ CAS cas = CasCreationUtils.createCas();
+ Type type = cas.getAnnotationType();
+
+ try (AutoCloseableSoftAssertions softly = new AutoCloseableSoftAssertions()) {
+ for (TestCase testCase : aTestCases) {
+ cas.reset();
+
+ // Create annotations
+ Annotation x = (Annotation) cas.createAnnotation(type, 0, 0);
+ Annotation y = (Annotation) cas.createAnnotation(type, 0, 0);
+
+ // Position the annotations according to the test data
+ testCase.getTest().apply((beginA, endA, beginB, endB) -> {
+ x.setBegin(beginA);
+ x.setEnd(endA);
+ y.setBegin(beginB);
+ y.setEnd(endB);
+ cas.addFsToIndexes(x);
+ cas.addFsToIndexes(y);
+ return true;
+ });
+
+ softly.assertThat(aPredicate.apply(cas, type, x, y)).as(testCase.getDescription())
+ .isEqualTo(testCase.getValidPositions().contains(aCondition));
+ }
+ }
+ }
+
+ public static void assertSelectionIsEqualOnRandomData(TypeByContextSelector aExpected, TypeByContextSelector aActual)
+ throws Exception {
+ final int ITERATIONS = 30;
+ final int TYPES = 5;
+
+ TypeSystemDescription tsd = UIMAFramework.getResourceSpecifierFactory().createTypeSystemDescription();
+
+ Map<String, Type> types = new LinkedHashMap<>();
+ for (int i = 0; i < TYPES; i++) {
+ String typeName = "test.Type" + (i + 1);
+ tsd.addType(typeName, "", CAS.TYPE_NAME_ANNOTATION);
+ types.put(typeName, null);
+ }
+
+ CAS randomCas = CasCreationUtils.createCas(tsd, null, null, null);
+
+ for (String typeName : types.keySet()) {
+ types.put(typeName, randomCas.getTypeSystem().getType(typeName));
+ }
+
+ System.out.print("Iteration: ");
+ try {
+ Iterator<Type> ti = types.values().iterator();
+ Type type1 = ti.next();
+ Type type2 = ti.next();
+
+ for (int i = 0; i < ITERATIONS; i++) {
+ if (i % 10 == 0) {
+ System.out.print(i);
+ }
+ else {
+ System.out.print(".");
+ }
+
+ initRandomCas(randomCas, 3 * i, 0, types.values().toArray(new Type[types.size()]));
+
+ for (Annotation context : randomCas.<Annotation>select(type1)) {
+ List<AnnotationFS> expected = aExpected.select(randomCas, type2, context);
+ List<AnnotationFS> actual = aActual.select(randomCas, type2, context);
+
+ assertThat(actual)
+ .as("Selected [%s] with context [%s]@[%d..%d]", type2.getShortName(),
+ type1.getShortName(), context.getBegin(), context.getEnd())
+ .containsExactlyElementsOf(expected);
+ }
+ }
+ System.out.print(ITERATIONS);
+ }
+ finally {
+ System.out.println();
+ }
+ }
+
+ private static void initRandomCas(CAS aCas, int aSize, int aMinimumWidth, Type... aTypes) {
+ Random rnd = new Random();
+
+ List<Type> types = new ArrayList<>(asList(aTypes));
+
+ // Shuffle the types
+ for (int n = 0; n < 10; n++) {
+ Type t = types.remove(rnd.nextInt(types.size()));
+ types.add(t);
+ }
+
+ // Randomly generate annotations
+ for (int n = 0; n < aSize; n++) {
+ for (Type t : types) {
+ int begin = rnd.nextInt(100);
+ int end = begin + rnd.nextInt(30) + aMinimumWidth;
+ aCas.addFsToIndexes(aCas.createAnnotation(t, begin, end));
+ }
+ }
+ }
+
+ @FunctionalInterface
+ public static interface RelativeAnnotationPredicate {
+ boolean apply(CAS cas, Type type, Annotation x, Annotation y);
+ }
+
+ @FunctionalInterface
+ public static interface TypeByContextSelector {
+ List<AnnotationFS> select(CAS aCas, Type aType, Annotation aContext);
+ }
+
+ @FunctionalInterface
+ public static interface RelativePositionPredicate {
+ boolean apply(int beginA, int endA, int beginB, int endB);
+ }
+
+ public static class TestCase {
+ private final String description;
+
+ private final Function<RelativePositionPredicate, Boolean> predicate;
+
+ private final List<RelativePosition> validPositions;
+
+ public TestCase(String aDescription, Function<RelativePositionPredicate, Boolean> aPredicate, List<RelativePosition> aValidPositions) {
+ description = aDescription;
+ predicate = aPredicate;
+ validPositions = aValidPositions;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public Function<RelativePositionPredicate, Boolean> getTest() {
+ return predicate;
+ }
+
+ public List<RelativePosition> getValidPositions() {
+ return validPositions;
+ }
+ }
+}
diff --git a/uimafit-parent/pom.xml b/uimafit-parent/pom.xml
index 4f6ba2e..6cba377 100644
--- a/uimafit-parent/pom.xml
+++ b/uimafit-parent/pom.xml
@@ -33,7 +33,7 @@
<inceptionYear>2012</inceptionYear>
<properties>
<spring.version>4.3.26.RELEASE</spring.version>
- <uima.version>3.1.1</uima.version>
+ <uima.version>3.1.2-SNAPSHOT</uima.version>
<slf4j.version>1.7.26</slf4j.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>