From 7d54304ffe301dd7825ff513a1fe30afc197f978 Mon Sep 17 00:00:00 2001 From: Thomas Scheffler Date: Fri, 23 Feb 2024 08:43:27 +0100 Subject: [PATCH] MCR-3050 add "xor" support * fixes bug in order of child conditions * add JUnit tests --- mycore-base/pom.xml | 17 ++++--- .../MCRAbstractCombinedCondition.java | 20 ++++++-- .../condition/combined/MCRAndCondition.java | 9 +--- .../condition/combined/MCRNotCondition.java | 22 ++------- .../condition/combined/MCROrCondition.java | 8 +-- .../condition/combined/MCRXorCondition.java | 31 ++++++++++++ .../main/resources/config/mycore.properties | 1 + .../combined/MCRAndConditionTest.java | 48 ++++++++++++++++++ .../combined/MCRNotConditionTest.java | 44 +++++++++++++++++ .../combined/MCROrConditionTest.java | 49 +++++++++++++++++++ .../condition/combined/MCRTestCondition.java | 37 ++++++++++++++ .../combined/MCRXorConditionTest.java | 48 ++++++++++++++++++ 12 files changed, 294 insertions(+), 40 deletions(-) create mode 100644 mycore-base/src/main/java/org/mycore/access/facts/condition/combined/MCRXorCondition.java create mode 100644 mycore-base/src/test/java/org/mycore/access/facts/condition/combined/MCRAndConditionTest.java create mode 100644 mycore-base/src/test/java/org/mycore/access/facts/condition/combined/MCRNotConditionTest.java create mode 100644 mycore-base/src/test/java/org/mycore/access/facts/condition/combined/MCROrConditionTest.java create mode 100644 mycore-base/src/test/java/org/mycore/access/facts/condition/combined/MCRTestCondition.java create mode 100644 mycore-base/src/test/java/org/mycore/access/facts/condition/combined/MCRXorConditionTest.java diff --git a/mycore-base/pom.xml b/mycore-base/pom.xml index 37be30e9b9..e3837c99bc 100644 --- a/mycore-base/pom.xml +++ b/mycore-base/pom.xml @@ -135,13 +135,6 @@ false - - - org.apache.maven.surefire - surefire-junit47 - 3.1.2 - - org.apache.maven.plugins @@ -458,6 +451,16 @@ hibernate-hikaricp test + + org.junit.jupiter + junit-jupiter-api + test + + + org.junit.vintage + junit-vintage-engine + test + org.mycore mycore-classifications diff --git a/mycore-base/src/main/java/org/mycore/access/facts/condition/combined/MCRAbstractCombinedCondition.java b/mycore-base/src/main/java/org/mycore/access/facts/condition/combined/MCRAbstractCombinedCondition.java index 427900d051..c5c24f9b5f 100644 --- a/mycore-base/src/main/java/org/mycore/access/facts/condition/combined/MCRAbstractCombinedCondition.java +++ b/mycore-base/src/main/java/org/mycore/access/facts/condition/combined/MCRAbstractCombinedCondition.java @@ -17,11 +17,13 @@ */ package org.mycore.access.facts.condition.combined; -import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.Objects; import java.util.Set; import org.jdom2.Element; import org.mycore.access.facts.MCRFactsAccessSystemHelper; +import org.mycore.access.facts.MCRFactsHolder; import org.mycore.access.facts.condition.MCRAbstractCondition; import org.mycore.access.facts.model.MCRCombinedCondition; import org.mycore.access.facts.model.MCRCondition; @@ -33,9 +35,10 @@ * @author Robert Stephan * */ -public abstract class MCRAbstractCombinedCondition extends MCRAbstractCondition implements MCRCombinedCondition { +sealed public abstract class MCRAbstractCombinedCondition extends MCRAbstractCondition implements MCRCombinedCondition + permits MCRAndCondition, MCRNotCondition, MCROrCondition, MCRXorCondition { - protected Set conditions = new HashSet<>(); + protected Set conditions = new LinkedHashSet<>(); public void add(MCRCondition condition) { conditions.add(condition); @@ -55,6 +58,7 @@ public Set getChildConditions() { return conditions; } + @Deprecated public void debugInfoForMatchingChildElement(MCRCondition c, boolean matches) { if (isDebug()) { Element el = c.getBoundElement(); @@ -64,4 +68,14 @@ public void debugInfoForMatchingChildElement(MCRCondition c, boolean matches) { } } + boolean addDebugInfoIfRequested(MCRCondition c, MCRFactsHolder facts) { + if (!isDebug()) { + return c.matches(facts); + } + boolean matches = c.matches(facts); + Objects.requireNonNull(c.getBoundElement(), "Condition is not bound to an element.") + .setAttribute("_matches", Boolean.toString(matches)); + return matches; + } + } diff --git a/mycore-base/src/main/java/org/mycore/access/facts/condition/combined/MCRAndCondition.java b/mycore-base/src/main/java/org/mycore/access/facts/condition/combined/MCRAndCondition.java index f9396241ab..12eca5019c 100644 --- a/mycore-base/src/main/java/org/mycore/access/facts/condition/combined/MCRAndCondition.java +++ b/mycore-base/src/main/java/org/mycore/access/facts/condition/combined/MCRAndCondition.java @@ -25,15 +25,10 @@ * @author Robert Stephan * */ -public class MCRAndCondition extends MCRAbstractCombinedCondition { +public final class MCRAndCondition extends MCRAbstractCombinedCondition { public boolean matches(MCRFactsHolder facts) { - return conditions.stream().allMatch(c -> { - boolean matches = c.matches(facts); - debugInfoForMatchingChildElement(c, matches); - - return matches; - }); + return conditions.stream().allMatch(c -> addDebugInfoIfRequested(c, facts)); } } diff --git a/mycore-base/src/main/java/org/mycore/access/facts/condition/combined/MCRNotCondition.java b/mycore-base/src/main/java/org/mycore/access/facts/condition/combined/MCRNotCondition.java index cb2ff7c67d..d1d95a4833 100644 --- a/mycore-base/src/main/java/org/mycore/access/facts/condition/combined/MCRNotCondition.java +++ b/mycore-base/src/main/java/org/mycore/access/facts/condition/combined/MCRNotCondition.java @@ -17,9 +17,7 @@ */ package org.mycore.access.facts.condition.combined; -import org.jdom2.Element; import org.mycore.access.facts.MCRFactsHolder; -import org.mycore.access.facts.model.MCRCondition; /** * This condition negates its child condition @@ -31,22 +29,12 @@ * @author Robert Stephan * */ -public class MCRNotCondition extends MCRAbstractCombinedCondition { +public final class MCRNotCondition extends MCRAbstractCombinedCondition { public boolean matches(MCRFactsHolder facts) { - MCRCondition negatedCondition = conditions.stream().findFirst().get(); - boolean result = negatedCondition.matches(facts); - boolean negated = !result; - if (isDebug()) { - Element boundElement = negatedCondition.getBoundElement(); - if (boundElement != null) { - boundElement.setAttribute("_matched", Boolean.toString(result)); - } - - if (this.getBoundElement() != null) { - this.getBoundElement().setAttribute("_matched", Boolean.toString(negated)); - } - } - return negated; + return conditions.stream() + .limit(1) + .filter(c -> !addDebugInfoIfRequested(c, facts)) + .count() == 1; } } diff --git a/mycore-base/src/main/java/org/mycore/access/facts/condition/combined/MCROrCondition.java b/mycore-base/src/main/java/org/mycore/access/facts/condition/combined/MCROrCondition.java index 1d5ef58f4e..e11fc7c11b 100644 --- a/mycore-base/src/main/java/org/mycore/access/facts/condition/combined/MCROrCondition.java +++ b/mycore-base/src/main/java/org/mycore/access/facts/condition/combined/MCROrCondition.java @@ -26,13 +26,9 @@ * @author Robert Stephan * */ -public class MCROrCondition extends MCRAbstractCombinedCondition { +public final class MCROrCondition extends MCRAbstractCombinedCondition { public boolean matches(MCRFactsHolder facts) { - return conditions.stream().anyMatch(c -> { - boolean matches = c.matches(facts); - debugInfoForMatchingChildElement(c, matches); - return matches; - }); + return conditions.stream().anyMatch(c -> addDebugInfoIfRequested(c, facts)); } } diff --git a/mycore-base/src/main/java/org/mycore/access/facts/condition/combined/MCRXorCondition.java b/mycore-base/src/main/java/org/mycore/access/facts/condition/combined/MCRXorCondition.java new file mode 100644 index 0000000000..ba40d28c8a --- /dev/null +++ b/mycore-base/src/main/java/org/mycore/access/facts/condition/combined/MCRXorCondition.java @@ -0,0 +1,31 @@ +/* + * This file is part of *** M y C o R e *** + * See http://www.mycore.de/ for details. + * + * MyCoRe is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MyCoRe is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MyCoRe. If not, see . + */ + +package org.mycore.access.facts.condition.combined; + +import org.mycore.access.facts.MCRFactsHolder; + +public final class MCRXorCondition extends MCRAbstractCombinedCondition { + @Override + public boolean matches(MCRFactsHolder facts) { + return conditions.stream() + .filter(c -> addDebugInfoIfRequested(c, facts)) + .limit(2) + .count() == 1; + } +} diff --git a/mycore-base/src/main/resources/config/mycore.properties b/mycore-base/src/main/resources/config/mycore.properties index c98b5b0d46..7ab9e02225 100644 --- a/mycore-base/src/main/resources/config/mycore.properties +++ b/mycore-base/src/main/resources/config/mycore.properties @@ -206,6 +206,7 @@ MCR.Access.Cache.Size=200 MCR.Access.Facts.Condition.and=org.mycore.access.facts.condition.combined.MCRAndCondition MCR.Access.Facts.Condition.or=org.mycore.access.facts.condition.combined.MCROrCondition +MCR.Access.Facts.Condition.xor=org.mycore.access.facts.condition.combined.MCRXorCondition MCR.Access.Facts.Condition.not=org.mycore.access.facts.condition.combined.MCRNotCondition MCR.Access.Facts.Condition.id=org.mycore.access.facts.condition.fact.MCRStringCondition MCR.Access.Facts.Condition.target=org.mycore.access.facts.condition.fact.MCRStringCondition diff --git a/mycore-base/src/test/java/org/mycore/access/facts/condition/combined/MCRAndConditionTest.java b/mycore-base/src/test/java/org/mycore/access/facts/condition/combined/MCRAndConditionTest.java new file mode 100644 index 0000000000..e1076d3a86 --- /dev/null +++ b/mycore-base/src/test/java/org/mycore/access/facts/condition/combined/MCRAndConditionTest.java @@ -0,0 +1,48 @@ +/* + * This file is part of *** M y C o R e *** + * See http://www.mycore.de/ for details. + * + * MyCoRe is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MyCoRe is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MyCoRe. If not, see . + */ + +package org.mycore.access.facts.condition.combined; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +class MCRAndConditionTest { + + @Test + void matches() { + MCRAndCondition xor=new MCRAndCondition(); + xor.add(new MCRTestCondition(()->false)); + assertFalse(xor.matches(null)); + xor.add(new MCRTestCondition(()->false)); + assertFalse(xor.matches(null)); + xor.getChildConditions().clear(); + xor.add(new MCRTestCondition(()->true)); + assertTrue(xor.matches(null)); + xor.add(new MCRTestCondition(()->true)); + assertTrue(xor.matches(null)); + xor.add(new MCRTestCondition(()->false)); + assertFalse(xor.matches(null)); + xor.add(new MCRTestCondition(() -> { + throw new UnsupportedOperationException("Should not be checked"); + })); + assertFalse(xor.matches(null)); + } + +} diff --git a/mycore-base/src/test/java/org/mycore/access/facts/condition/combined/MCRNotConditionTest.java b/mycore-base/src/test/java/org/mycore/access/facts/condition/combined/MCRNotConditionTest.java new file mode 100644 index 0000000000..3680180414 --- /dev/null +++ b/mycore-base/src/test/java/org/mycore/access/facts/condition/combined/MCRNotConditionTest.java @@ -0,0 +1,44 @@ +/* + * This file is part of *** M y C o R e *** + * See http://www.mycore.de/ for details. + * + * MyCoRe is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MyCoRe is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MyCoRe. If not, see . + */ + +package org.mycore.access.facts.condition.combined; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +class MCRNotConditionTest { + + @Test + void matches() { + MCRNotCondition xor = new MCRNotCondition(); + xor.add(new MCRTestCondition(() -> false)); + xor.add(new MCRTestCondition(() -> { + throw new UnsupportedOperationException("Should not be checked"); + })); + assertTrue(xor.matches(null)); + xor.getChildConditions().clear(); + xor.add(new MCRTestCondition(() -> true)); + xor.add(new MCRTestCondition(() -> { + throw new UnsupportedOperationException("Should not be checked"); + })); + assertFalse(xor.matches(null)); + } + +} diff --git a/mycore-base/src/test/java/org/mycore/access/facts/condition/combined/MCROrConditionTest.java b/mycore-base/src/test/java/org/mycore/access/facts/condition/combined/MCROrConditionTest.java new file mode 100644 index 0000000000..9fe8ec8fa0 --- /dev/null +++ b/mycore-base/src/test/java/org/mycore/access/facts/condition/combined/MCROrConditionTest.java @@ -0,0 +1,49 @@ +/* + * This file is part of *** M y C o R e *** + * See http://www.mycore.de/ for details. + * + * MyCoRe is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MyCoRe is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MyCoRe. If not, see . + */ + +package org.mycore.access.facts.condition.combined; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +class MCROrConditionTest { + + @Test + void matches() { + MCROrCondition xor = new MCROrCondition(); + xor.add(new MCRTestCondition(() -> false)); + assertFalse(xor.matches(null)); + xor.add(new MCRTestCondition(() -> false)); + assertFalse(xor.matches(null)); + xor.add(new MCRTestCondition(() -> false)); + assertFalse(xor.matches(null)); + xor.add(new MCRTestCondition(() -> true)); + assertTrue(xor.matches(null)); + xor.add(new MCRTestCondition(() -> false)); + assertTrue(xor.matches(null)); + xor.add(new MCRTestCondition(() -> true)); + assertTrue(xor.matches(null)); + xor.add(new MCRTestCondition(() -> { + throw new UnsupportedOperationException("Should not be checked"); + })); + assertTrue(xor.matches(null)); + } + +} diff --git a/mycore-base/src/test/java/org/mycore/access/facts/condition/combined/MCRTestCondition.java b/mycore-base/src/test/java/org/mycore/access/facts/condition/combined/MCRTestCondition.java new file mode 100644 index 0000000000..23027f3e8b --- /dev/null +++ b/mycore-base/src/test/java/org/mycore/access/facts/condition/combined/MCRTestCondition.java @@ -0,0 +1,37 @@ +/* + * This file is part of *** M y C o R e *** + * See http://www.mycore.de/ for details. + * + * MyCoRe is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MyCoRe is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MyCoRe. If not, see . + */ + +package org.mycore.access.facts.condition.combined; + +import org.mycore.access.facts.MCRFactsHolder; +import org.mycore.access.facts.condition.MCRAbstractCondition; + +import java.util.function.Supplier; + +class MCRTestCondition extends MCRAbstractCondition { + Supplier match; + + MCRTestCondition(Supplier match) { + this.match = match; + } + + @Override + public boolean matches(MCRFactsHolder facts) { + return match.get(); + } +} diff --git a/mycore-base/src/test/java/org/mycore/access/facts/condition/combined/MCRXorConditionTest.java b/mycore-base/src/test/java/org/mycore/access/facts/condition/combined/MCRXorConditionTest.java new file mode 100644 index 0000000000..901130dce9 --- /dev/null +++ b/mycore-base/src/test/java/org/mycore/access/facts/condition/combined/MCRXorConditionTest.java @@ -0,0 +1,48 @@ +/* + * This file is part of *** M y C o R e *** + * See http://www.mycore.de/ for details. + * + * MyCoRe is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MyCoRe is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MyCoRe. If not, see . + */ + +package org.mycore.access.facts.condition.combined; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +class MCRXorConditionTest { + + @Test + void matches() { + MCRXorCondition xor = new MCRXorCondition(); + xor.add(new MCRTestCondition(() -> false)); + assertFalse(xor.matches(null)); + xor.add(new MCRTestCondition(() -> false)); + assertFalse(xor.matches(null)); + xor.add(new MCRTestCondition(() -> false)); + assertFalse(xor.matches(null)); + xor.add(new MCRTestCondition(() -> true)); + assertTrue(xor.matches(null)); + xor.add(new MCRTestCondition(() -> false)); + assertTrue(xor.matches(null)); + xor.add(new MCRTestCondition(() -> true)); + assertFalse(xor.matches(null)); + xor.add(new MCRTestCondition(() -> { + throw new UnsupportedOperationException("Should not be checked"); + })); + assertFalse(xor.matches(null)); + } +}