This is an automated email from the ASF dual-hosted git repository.
gitgabrio pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-kie-drools.git
The following commit(s) were added to refs/heads/main by this push:
new 8dac313955 kie-issues#1448: `matches()` function wrongly behaves
(#6085)
8dac313955 is described below
commit 8dac313955aa6693bc024cdbb644c58968db7ec0
Author: Yeser Amer <[email protected]>
AuthorDate: Wed Sep 18 09:02:56 2024 +0200
kie-issues#1448: `matches()` function wrongly behaves (#6085)
* matches and replace using saxon
* saxon usage simplified and modified tests
* clean up code as per standards
* changes as per suggestions
* changes as per suggestions and restored the earlier tests
* changes as per suggestions and restored the earlier tests
* changes as per suggestions
* exceptions handled and changes to util class
* wip
* wip
* wip
* wip
* wip
* CR
* CR
* CR
* CR
* Notice updated
* CR
---------
Co-authored-by: bncriju <[email protected]>
---
NOTICE | 4 +
kie-dmn/kie-dmn-feel/pom.xml | 15 ++
.../feel/runtime/functions/MatchesFunction.java | 67 ++------
.../feel/runtime/functions/ReplaceFunction.java | 21 ++-
.../java/org/kie/dmn/feel/util/XQueryImplUtil.java | 62 +++++++
.../kie/dmn/feel/runtime/FEELFunctionsTest.java | 9 +-
.../runtime/functions/MatchesFunctionTest.java | 188 ++++++++++++---------
.../runtime/functions/ReplaceFunctionTest.java | 112 +++++++-----
.../org/kie/dmn/feel/util/XQueryImplUtilTest.java | 117 +++++++++++++
9 files changed, 409 insertions(+), 186 deletions(-)
diff --git a/NOTICE b/NOTICE
index 2fe21eeead..43c4b92efb 100644
--- a/NOTICE
+++ b/NOTICE
@@ -14,6 +14,10 @@ This product also includes the following third-party
components:
Downloaded from: https://lunrjs.com/
License: MIT
+* Saxon-HE
+ Downloaded from: https://www.saxonica.com/
+ License: Mozilla Public License 2.0
+
* search-ui
Downloaded from: https://gitlab.com/antora/antora-lunr-extension
License: Mozilla Public License 2.0
diff --git a/kie-dmn/kie-dmn-feel/pom.xml b/kie-dmn/kie-dmn-feel/pom.xml
index 51fbef420b..545d181c62 100644
--- a/kie-dmn/kie-dmn-feel/pom.xml
+++ b/kie-dmn/kie-dmn-feel/pom.xml
@@ -38,8 +38,19 @@
<java.module.name>org.kie.dmn.feel</java.module.name>
<surefire.forkCount>2</surefire.forkCount>
<enforcer.skip>true</enforcer.skip>
+ <version.net.sf.saxon.Saxon-HE>12.5</version.net.sf.saxon.Saxon-HE>
</properties>
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>net.sf.saxon</groupId>
+ <artifactId>Saxon-HE</artifactId>
+ <version>${version.net.sf.saxon.Saxon-HE}</version>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+
<dependencies>
<!-- Internal dependencies -->
<dependency>
@@ -52,6 +63,10 @@
</dependency>
<!-- External dependencies -->
+ <dependency>
+ <groupId>net.sf.saxon</groupId>
+ <artifactId>Saxon-HE</artifactId>
+ </dependency>
<dependency>
<groupId>org.antlr</groupId>
<artifactId>antlr4-runtime</artifactId>
diff --git
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/MatchesFunction.java
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/MatchesFunction.java
index 79ff2a0136..2acb38ad26 100644
---
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/MatchesFunction.java
+++
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/MatchesFunction.java
@@ -18,15 +18,9 @@
*/
package org.kie.dmn.feel.runtime.functions;
-import java.security.InvalidParameterException;
-import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.regex.PatternSyntaxException;
-import java.util.stream.Collectors;
-
import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity;
import org.kie.dmn.feel.runtime.events.InvalidParametersEvent;
+import org.kie.dmn.feel.util.XQueryImplUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -44,58 +38,23 @@ public class MatchesFunction
}
public FEELFnResult<Boolean> invoke(@ParameterName("input") String input,
@ParameterName("pattern") String pattern, @ParameterName("flags") String flags)
{
- try {
- return matchFunctionWithFlags(input,pattern,flags);
- } catch ( PatternSyntaxException t ) {
- return FEELFnResult.ofError( new InvalidParametersEvent(
Severity.ERROR, "pattern", "is invalid and can not be compiled", t ) );
- } catch (InvalidParameterException t ) {
- return FEELFnResult.ofError( new InvalidParametersEvent(
Severity.ERROR, t.getMessage(), "cannot be null", t ) );
- } catch (IllegalArgumentException t ) {
- return FEELFnResult.ofError( new InvalidParametersEvent(
Severity.ERROR, "flags", "contains unknown flags", t ) );
- } catch (Throwable t) {
- return FEELFnResult.ofError( new InvalidParametersEvent(
Severity.ERROR, "pattern", "is invalid and can not be compiled", t ) );
- }
- }
-
- static FEELFnResult<Boolean> matchFunctionWithFlags(String input, String
pattern, String flags) {
log.debug("Input: {} , Pattern: {}, Flags: {}", input, pattern,
flags);
+
if ( input == null ) {
- throw new InvalidParameterException("input");
+ return FEELFnResult.ofError( new InvalidParametersEvent(
Severity.ERROR, "input", "cannot be null" ) );
}
if ( pattern == null ) {
- throw new InvalidParameterException("pattern");
+ return FEELFnResult.ofError( new InvalidParametersEvent(
Severity.ERROR, "pattern", "cannot be null" ) );
}
- final String flagsString;
- if (flags != null && !flags.isEmpty()) {
- checkFlags(flags);
- if(!flags.contains("U")){
- flags += "U";
- }
- flagsString = String.format("(?%s)", flags);
- } else {
- flagsString = "";
- }
- log.debug("flagsString: {}", flagsString);
- String stringToBeMatched = flagsString + pattern;
- log.debug("stringToBeMatched: {}", stringToBeMatched);
- Pattern p=Pattern.compile(stringToBeMatched);
- Matcher m = p.matcher( input );
- boolean matchFound=m.find();
- log.debug("matchFound: {}", matchFound);
- return FEELFnResult.ofResult(matchFound);
- }
- static void checkFlags(String flags) {
- Set<Character> allowedChars = Set.of('s','i','x','m');
- boolean isValidFlag= flags.chars()
- .mapToObj(c -> (char) c)
- .allMatch(allowedChars::contains)
- && flags.chars()
- .mapToObj(c -> (char) c)
- .collect(Collectors.toSet())
- .size() == flags.length();
- if(!isValidFlag){
- throw new IllegalArgumentException("Not a valid flag parameter "
+flags);
- }
+ try {
+ return
FEELFnResult.ofResult(XQueryImplUtil.executeMatchesFunction(input, pattern,
flags));
+ } catch (Exception e) {
+ String errorMessage = String.format("Provided parameters lead to
an error. Input: '%s', Pattern: '%s', Flags: '%s'. ", input, pattern, flags);
+ if (e.getMessage() != null && !e.getMessage().isEmpty()) {
+ errorMessage += e.getMessage();
+ }
+ return FEELFnResult.ofError(new
InvalidParametersEvent(Severity.ERROR, errorMessage, e));
+ }
}
}
diff --git
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/ReplaceFunction.java
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/ReplaceFunction.java
index 723efcbdd3..a7ae497870 100644
---
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/ReplaceFunction.java
+++
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/ReplaceFunction.java
@@ -20,6 +20,7 @@ package org.kie.dmn.feel.runtime.functions;
import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity;
import org.kie.dmn.feel.runtime.events.InvalidParametersEvent;
+import org.kie.dmn.feel.util.XQueryImplUtil;
public class ReplaceFunction
extends BaseFEELFunction {
@@ -30,12 +31,12 @@ public class ReplaceFunction
super( "replace" );
}
- public FEELFnResult<Object> invoke(@ParameterName("input") String input,
@ParameterName("pattern") String pattern,
+ public FEELFnResult<String> invoke(@ParameterName("input") String input,
@ParameterName("pattern") String pattern,
@ParameterName( "replacement" ) String
replacement ) {
return invoke(input, pattern, replacement, null);
}
- public FEELFnResult<Object> invoke(@ParameterName("input") String input,
@ParameterName("pattern") String pattern,
+ public FEELFnResult<String> invoke(@ParameterName("input") String input,
@ParameterName("pattern") String pattern,
@ParameterName( "replacement" ) String
replacement, @ParameterName("flags") String flags) {
if ( input == null ) {
return FEELFnResult.ofError( new InvalidParametersEvent(
Severity.ERROR, "input", "cannot be null" ) );
@@ -47,14 +48,16 @@ public class ReplaceFunction
return FEELFnResult.ofError( new InvalidParametersEvent(
Severity.ERROR, "replacement", "cannot be null" ) );
}
- final String flagsString;
- if (flags != null && !flags.isEmpty()) {
- flagsString = "(?" + flags + ")";
- } else {
- flagsString = "";
+ try {
+ return
FEELFnResult.ofResult(XQueryImplUtil.executeReplaceFunction(input, pattern,
replacement, flags));
+ } catch (Exception e) {
+ String errorMessage = String.format("Provided parameters lead to
an error. Input: '%s', Pattern: '%s', Replacement: '%s', Flags: '%s'. ",
+ input, pattern, replacement, flags);
+ if (e.getMessage() != null && !e.getMessage().isEmpty()) {
+ errorMessage += e.getMessage();
+ }
+ return FEELFnResult.ofError(new
InvalidParametersEvent(Severity.ERROR, errorMessage, e));
}
-
- return FEELFnResult.ofResult( input.replaceAll( flagsString + pattern,
replacement ) );
}
}
diff --git
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/XQueryImplUtil.java
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/XQueryImplUtil.java
new file mode 100644
index 0000000000..a3ae1c6e53
--- /dev/null
+++
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/XQueryImplUtil.java
@@ -0,0 +1,62 @@
+/**
+ * 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.kie.dmn.feel.util;
+
+import net.sf.saxon.s9api.Processor;
+import net.sf.saxon.s9api.XdmAtomicValue;
+import net.sf.saxon.s9api.XdmItem;
+import net.sf.saxon.s9api.XQueryCompiler;
+import net.sf.saxon.s9api.XQueryEvaluator;
+import net.sf.saxon.s9api.XQueryExecutable;
+import net.sf.saxon.s9api.SaxonApiException;
+
+public class XQueryImplUtil {
+
+ public static Boolean executeMatchesFunction(String input, String pattern,
String flags) {
+ flags = flags == null ? "" : flags;
+ String xQueryExpression = String.format("matches('%s', '%s', '%s')",
input, pattern, flags);
+ return evaluateXQueryExpression(xQueryExpression, Boolean.class);
+ }
+
+ public static String executeReplaceFunction(String input, String pattern,
String replacement, String flags) {
+ flags = flags == null ? "" : flags;
+ String xQueryExpression = String.format("replace('%s', '%s', '%s',
'%s')", input, pattern, replacement, flags);
+ return evaluateXQueryExpression(xQueryExpression, String.class);
+ }
+
+ static <T> T evaluateXQueryExpression(String expression, Class<T>
expectedTypeResult) {
+ try {
+ Processor processor = new Processor(false);
+ XQueryCompiler compiler = processor.newXQueryCompiler();
+ XQueryExecutable executable = compiler.compile(expression);
+ XQueryEvaluator queryEvaluator = executable.load();
+ XdmItem resultItem = queryEvaluator.evaluateSingle();
+
+ Object value = switch (expectedTypeResult.getSimpleName()) {
+ case "Boolean" -> ((XdmAtomicValue)
resultItem).getBooleanValue();
+ case "String" -> resultItem.getStringValue();
+ default -> throw new UnsupportedOperationException("Type " +
expectedTypeResult.getSimpleName() + " is not managed.");
+ };
+
+ return expectedTypeResult.cast(value);
+ } catch (SaxonApiException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+}
diff --git
a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELFunctionsTest.java
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELFunctionsTest.java
index 3707929e3b..a199e8f1f6 100644
---
a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELFunctionsTest.java
+++
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELFunctionsTest.java
@@ -43,7 +43,6 @@ public class FEELFunctionsTest extends BaseFEELTest {
final Object[][] cases = new Object[][] {
// constants
{ "string(1.1)", "1.1" , null},
- { "replace( \" foo bar zed \",
\"^(\\s)+|(\\s)+$|\\s+(?=\\s)\", \"\" )", "foo bar zed", null },
{ "string(null)", null, null},
{ "string(date(\"2016-08-14\"))", "2016-08-14" , null},
{ "string(\"Happy %.0fth birthday, Mr %s!\", 38, \"Doe\")",
"Happy 38th birthday, Mr Doe!", null},
@@ -85,6 +84,14 @@ public class FEELFunctionsTest extends BaseFEELTest {
{ "matches(\"one\\ntwo\\nthree\", \"^two$\", \"m\")",
Boolean.TRUE , null}, // MULTILINE flag set by "m"
{ "matches(\"FoO\", \"foo\")", Boolean.FALSE , null},
{ "matches(\"FoO\", \"foo\", \"i\")", Boolean.TRUE , null}, //
CASE_INSENSITIVE flag set by "i"
+ { "matches(\"\\u212A\", \"k\", \"i\")", Boolean.TRUE , null},
+ { "matches(\"O\", \"[A-Z-[OI]]\", \"i\")", Boolean.FALSE ,
null},
+ { "matches(\"i\", \"[A-Z-[OI]]\", \"i\")", Boolean.FALSE ,
null},
+ { "matches(\"hello world\", \"hello\\ sworld\", \"x\")",
Boolean.TRUE , null},
+ { "matches(\"abracadabra\", \"bra\", \"p\")", null ,
FEELEvent.Severity.ERROR},
+ { "matches(\"input\", \"pattern\", \" \")", null ,
FEELEvent.Severity.ERROR},
+ { "matches(\"input\", \"pattern\", \"X\")", null ,
FEELEvent.Severity.ERROR},
+ { "matches(\"h\", \"(.)\\2\")", null ,
FEELEvent.Severity.ERROR},
{ "replace(\"banana\",\"a\",\"o\")", "bonono" , null},
{ "replace(\"banana\",\"(an)+\", \"**\")", "b**a" , null},
{ "replace(\"banana\",\"[aeiouy]\",\"[$0]\")", "b[a]n[a]n[a]"
, null},
diff --git
a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/functions/MatchesFunctionTest.java
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/functions/MatchesFunctionTest.java
index b12612bb04..589f37e3d2 100644
---
a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/functions/MatchesFunctionTest.java
+++
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/functions/MatchesFunctionTest.java
@@ -19,116 +19,146 @@
package org.kie.dmn.feel.runtime.functions;
import org.junit.jupiter.api.Test;
-import org.mockito.MockedStatic;
-import java.security.InvalidParameterException;
-import java.util.regex.PatternSyntaxException;
-
-import static
org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType;
-import static
org.assertj.core.api.AssertionsForClassTypes.assertThatNoException;
-import static org.mockito.Mockito.*;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.kie.dmn.feel.runtime.events.InvalidParametersEvent;
class MatchesFunctionTest {
- @Test
- void invokeNull() {
-
assertThatExceptionOfType(InvalidParameterException.class).isThrownBy(() ->
MatchesFunction.matchFunctionWithFlags(null, null, null));
-
assertThatExceptionOfType(InvalidParameterException.class).isThrownBy(() ->
MatchesFunction.matchFunctionWithFlags(null, "test", null));
-
assertThatExceptionOfType(InvalidParameterException.class).isThrownBy(() ->
MatchesFunction.matchFunctionWithFlags("test", null, null));
+ private static final MatchesFunction matchesFunction =
MatchesFunction.INSTANCE;
+
+ @ParameterizedTest
+ @MethodSource("invokeNullTestData")
+ void invokeNullTest(String input, String pattern) {
+ FunctionTestUtil.assertResultError(matchesFunction.invoke(input,
pattern), InvalidParametersEvent.class);
}
- @Test
- void invokeUnsupportedFlags() {
-
assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() ->
MatchesFunction.matchFunctionWithFlags("foobar", "fo.bar", "g"));
-
assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() ->
MatchesFunction.matchFunctionWithFlags("abracadabra", "bra", "p"));
-
assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() ->
MatchesFunction.matchFunctionWithFlags("abracadabra", "bra", "X"));
-
assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() ->
MatchesFunction.matchFunctionWithFlags("abracadabra", "bra", " "));
-
assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() ->
MatchesFunction.matchFunctionWithFlags("abracadabra", "bra", "iU"));
+ private static Object[][] invokeNullTestData() {
+ return new Object[][] {
+ { null, null },
+ { null, "test" },
+ { "test", null },
+ };
}
- @Test
- void invokeWithoutFlagsMatch() {
-
FunctionTestUtil.assertResult(MatchesFunction.matchFunctionWithFlags("test",
"test",null), true);
-
FunctionTestUtil.assertResult(MatchesFunction.matchFunctionWithFlags("foobar",
"^fo*b",null), true);
-
FunctionTestUtil.assertResult(MatchesFunction.matchFunctionWithFlags("abracadabra",
"bra", ""), true);
-
FunctionTestUtil.assertResult(MatchesFunction.matchFunctionWithFlags("abracadabra",
"bra",null), true);
-
FunctionTestUtil.assertResult(MatchesFunction.matchFunctionWithFlags("(?xi)[hello
world()]", "hello",null), true);
+ @ParameterizedTest
+ @MethodSource("invokeUnsupportedFlagsTestData")
+ void invokeUnsupportedFlagsTest(String input, String pattern, String
flags) {
+ FunctionTestUtil.assertResultError(matchesFunction.invoke(input,
pattern, flags), InvalidParametersEvent.class);
+ }
+
+ private static Object[][] invokeUnsupportedFlagsTestData() {
+ return new Object[][] {
+ { "foobar", "fo.bar", "g" },
+ { "abracadabra", "bra", "p" },
+ { "abracadabra", "bra", "X" },
+ { "abracadabra", "bra", "iU" },
+ { "abracadabra", "bra", "iU asd" },
+ };
}
- @Test
- void invokeWithoutFlagsNotMatch() {
-
FunctionTestUtil.assertResult(MatchesFunction.matchFunctionWithFlags("test",
"testt",null), false);
-
FunctionTestUtil.assertResult(MatchesFunction.matchFunctionWithFlags("foobar",
"^fo*bb",null), false);
-
FunctionTestUtil.assertResult(MatchesFunction.matchFunctionWithFlags("fo\nbar",
"fo.bar",null), false);
-
FunctionTestUtil.assertResult(MatchesFunction.matchFunctionWithFlags("h",
"(.)\3",null), false);
-
FunctionTestUtil.assertResult(MatchesFunction.matchFunctionWithFlags("h",
"(.)\2",null), false);
-
FunctionTestUtil.assertResult(MatchesFunction.matchFunctionWithFlags("input",
"\3",null), false);
-
FunctionTestUtil.assertResult(MatchesFunction.matchFunctionWithFlags("fo\nbar",
"(?iU)(?iU)(ab)[|cd]",null), false);
-
FunctionTestUtil.assertResult(MatchesFunction.matchFunctionWithFlags("fo\nbar",
"(?x)(?i)hello world","i"), false);
-
FunctionTestUtil.assertResult(MatchesFunction.matchFunctionWithFlags("fo\nbar",
"(?xi)hello world",null), false);
+ @ParameterizedTest
+ @MethodSource("invokeWithoutFlagsMatchTestData")
+ void invokeWithoutFlagsMatchTest(String input, String pattern, Boolean
expectedResult) {
+ FunctionTestUtil.assertResult(matchesFunction.invoke(input, pattern),
expectedResult);
}
- @Test
- void invokeWithFlagDotAll() {
-
FunctionTestUtil.assertResult(MatchesFunction.matchFunctionWithFlags("fo\nbar",
"fo.bar", "s"), true);
+ private static Object[][] invokeWithoutFlagsMatchTestData() {
+ return new Object[][] {
+ { "test", "test", true },
+ { "foobar", "^fo*b", true },
+ { "abracadabra", "bra", true },
+ { "abracadabra", "bra", true },
+ { "(?xi)[hello world()]", "hello", true }
+ };
}
- @Test
- void invokeWithFlagMultiline() {
-
FunctionTestUtil.assertResult(MatchesFunction.matchFunctionWithFlags("fo\nbar",
"^bar", "m"), true);
+ @ParameterizedTest
+ @MethodSource("invokeNullOrEmptyFlagsMatchTestData")
+ void invokeNullOrEmptyFlagsMatchTest(String input, String pattern, String
flags, Boolean expectedResult) {
+ FunctionTestUtil.assertResult(matchesFunction.invoke(input, pattern,
flags), expectedResult);
}
- @Test
- void invokeWithFlagCaseInsensitive() {
-
FunctionTestUtil.assertResult(MatchesFunction.matchFunctionWithFlags("foobar",
"^Fo*bar", "i"), true);
-
FunctionTestUtil.assertResult(MatchesFunction.matchFunctionWithFlags("foobar",
"^Fo*bar", "i"), true);
-
FunctionTestUtil.assertResult(MatchesFunction.matchFunctionWithFlags("\u212A",
"k","i"), true);
-
FunctionTestUtil.assertResult(MatchesFunction.matchFunctionWithFlags("\u212A",
"K","i"), true);
+ private static Object[][] invokeNullOrEmptyFlagsMatchTestData() {
+ return new Object[][] {
+ { "test", "test", null, true },
+ { "foobar", "^fo*b", null, true },
+ { "abracadabra", "bra", null, true },
+ { "abracadabra", "bra", "", true },
+ { "(?xi)[hello world()]", "hello", null, true }
+ };
+ }
+
+ @ParameterizedTest
+ @MethodSource("invokeInvalidRegexTestData")
+ void invokeInvalidRegexTest(String input, String pattern, String flags) {
+ FunctionTestUtil.assertResultError(matchesFunction.invoke(input,
pattern, flags), InvalidParametersEvent.class);
+ }
+
+ private static Object[][] invokeInvalidRegexTestData() {
+ return new Object[][] {
+ { "testString", "(?=\\\\s)", null },
+ { "fo\nbar", "(?iU)(?iU)(ab)[|cd]", null },
+ { "fo\nbar", "(?x)(?i)hello world", "i" },
+ { "fo\nbar", "(?xi)hello world", null },
+ };
+ }
+
+ @ParameterizedTest
+ @MethodSource("invokeWithoutFlagsNotMatchTestData")
+ void invokeWithoutFlagsNotMatchTest(String input, String pattern, String
flags, Boolean expectedResult) {
+ FunctionTestUtil.assertResult(matchesFunction.invoke(input, pattern,
flags), expectedResult);
+ }
+
+ private static Object[][] invokeWithoutFlagsNotMatchTestData() {
+ return new Object[][] {
+ { "test", "testt", null, false },
+ { "foobar", "^fo*bb", null, false },
+ { "h", "(.)\3", null, false },
+ { "h", "(.)\2", null, false },
+ { "input", "\3", null, false }
+ };
+ }
+
+ @ParameterizedTest
+ @MethodSource("invokeWithFlagCaseInsensitiveTestData")
+ void invokeWithoutFlagsPatternTest(String input, String pattern, String
flags, Boolean expectedResult) {
+ FunctionTestUtil.assertResult(matchesFunction.invoke(input, pattern,
flags), expectedResult);
+ }
+
+ private static Object[][] invokeWithFlagCaseInsensitiveTestData() {
+ return new Object[][] {
+ { "foobar", "^Fo*bar", "i", true },
+ { "foobar", "^Fo*bar", "i", true },
+ { "\u212A", "k", "i", true },
+ { "\u212A", "K", "i", true }
+ };
}
@Test
- void invokeWithFlagComments() {
-
FunctionTestUtil.assertResult(MatchesFunction.matchFunctionWithFlags("hello
world", "hello"+"\"+ sworld", "x"), false);
+ void invokeWithFlagDotAll() {
+ FunctionTestUtil.assertResult(matchesFunction.invoke("fo\nbar",
"fo.bar", "s"), true);
}
@Test
- void invokeWithAllFlags() {
-
FunctionTestUtil.assertResult(MatchesFunction.matchFunctionWithFlags("fo\nbar",
"Fo.^bar", "smi"), true);
+ void invokeWithFlagMultiline() {
+ FunctionTestUtil.assertResult(matchesFunction.invoke("fo\nbar",
"^bar", "m"), true);
}
@Test
- void checkForPatternTest() {
- assertThatExceptionOfType(PatternSyntaxException.class).isThrownBy(()
-> MatchesFunction.matchFunctionWithFlags("foobar", "(abc|def(ghi", "i"));
+ void invokeWithFlagComments() {
+ FunctionTestUtil.assertResult(matchesFunction.invoke("hello world",
"hello"+"\"+ sworld", "x"), false);
}
@Test
- void checkFlagsTest() {
- assertThatNoException().isThrownBy(() ->
MatchesFunction.checkFlags("s"));
- assertThatNoException().isThrownBy(() ->
MatchesFunction.checkFlags("i"));
- assertThatNoException().isThrownBy(() ->
MatchesFunction.checkFlags("sx"));
- assertThatNoException().isThrownBy(() ->
MatchesFunction.checkFlags("six"));
- assertThatNoException().isThrownBy(() ->
MatchesFunction.checkFlags("sixm"));
-
assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() ->
MatchesFunction.checkFlags("a"));
-
assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() ->
MatchesFunction.checkFlags("sa"));
-
assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() ->
MatchesFunction.checkFlags("siU@"));
-
assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() ->
MatchesFunction.checkFlags("siUxU"));
-
assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() ->
MatchesFunction.checkFlags("ss"));
-
assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() ->
MatchesFunction.checkFlags("siiU"));
-
assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() ->
MatchesFunction.checkFlags("si U"));
-
assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() ->
MatchesFunction.checkFlags("U"));
+ void invokeWithAllFlags() {
+ FunctionTestUtil.assertResult(matchesFunction.invoke("fo\nbar",
"Fo.^bar", "smi"), true);
}
@Test
- void checkMatchFunctionWithFlagsInvocation() {
- MatchesFunction matchesFunctionSpied = spy(MatchesFunction.INSTANCE);
- matchesFunctionSpied.invoke("input", "pattern");
- verify(matchesFunctionSpied, times(1)).invoke("input", "pattern",
null);
- try (MockedStatic<MatchesFunction> matchesFunctionMocked =
mockStatic(MatchesFunction.class)) {
- matchesFunctionSpied.invoke("input", "pattern");
- matchesFunctionMocked.verify(() ->
MatchesFunction.matchFunctionWithFlags("input", "pattern", null));
- matchesFunctionSpied.invoke("input", "pattern", "flags");
- matchesFunctionMocked.verify(() ->
MatchesFunction.matchFunctionWithFlags("input", "pattern", "flags"));
- }
+ void checkForPatternTest() {
+ FunctionTestUtil.assertResultError(matchesFunction.invoke("foobar",
"(abc|def(ghi", "i"), InvalidParametersEvent.class);
}
}
\ No newline at end of file
diff --git
a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/functions/ReplaceFunctionTest.java
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/functions/ReplaceFunctionTest.java
index 06e1bc4da0..45d1334f35 100644
---
a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/functions/ReplaceFunctionTest.java
+++
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/functions/ReplaceFunctionTest.java
@@ -19,62 +19,88 @@
package org.kie.dmn.feel.runtime.functions;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
import org.kie.dmn.feel.runtime.events.InvalidParametersEvent;
class ReplaceFunctionTest {
private static final ReplaceFunction replaceFunction =
ReplaceFunction.INSTANCE;
- @Test
- void invokeNull() {
- FunctionTestUtil.assertResultError(replaceFunction.invoke(null, null,
null), InvalidParametersEvent.class);
-
FunctionTestUtil.assertResultError(replaceFunction.invoke("testString", null,
null),
- InvalidParametersEvent.class);
-
FunctionTestUtil.assertResultError(replaceFunction.invoke("testString", "test",
null),
- InvalidParametersEvent.class);
- FunctionTestUtil.assertResultError(replaceFunction.invoke(null,
"test", null), InvalidParametersEvent.class);
- FunctionTestUtil.assertResultError(replaceFunction.invoke(null,
"test", "ttt"), InvalidParametersEvent.class);
- FunctionTestUtil.assertResultError(replaceFunction.invoke(null, null,
"ttt"), InvalidParametersEvent.class);
+ @ParameterizedTest
+ @MethodSource("invokeNullTestData")
+ void invokeNullTest(String input, String pattern, String replacement) {
+ FunctionTestUtil.assertResultError(replaceFunction.invoke(input,
pattern, replacement), InvalidParametersEvent.class);
}
- @Test
- void invokeNullWithFlags() {
- FunctionTestUtil.assertResultError(replaceFunction.invoke(null, null,
null, null),
- InvalidParametersEvent.class);
-
FunctionTestUtil.assertResultError(replaceFunction.invoke("testString", null,
null, null),
- InvalidParametersEvent.class);
-
FunctionTestUtil.assertResultError(replaceFunction.invoke("testString", "test",
null, null),
- InvalidParametersEvent.class);
- FunctionTestUtil.assertResultError(replaceFunction.invoke(null,
"test", null, null),
- InvalidParametersEvent.class);
- FunctionTestUtil.assertResultError(replaceFunction.invoke(null,
"test", "ttt", null),
- InvalidParametersEvent.class);
- FunctionTestUtil.assertResultError(replaceFunction.invoke(null, null,
"ttt", null),
- InvalidParametersEvent.class);
-
- FunctionTestUtil.assertResultError(replaceFunction.invoke(null, null,
null, "s"), InvalidParametersEvent.class);
-
FunctionTestUtil.assertResultError(replaceFunction.invoke("testString", null,
null, "s"),
- InvalidParametersEvent.class);
-
FunctionTestUtil.assertResultError(replaceFunction.invoke("testString", "test",
null, "s"),
- InvalidParametersEvent.class);
- FunctionTestUtil.assertResultError(replaceFunction.invoke(null,
"test", null, "s"),
- InvalidParametersEvent.class);
- FunctionTestUtil.assertResultError(replaceFunction.invoke(null,
"test", "ttt", "s"),
- InvalidParametersEvent.class);
- FunctionTestUtil.assertResultError(replaceFunction.invoke(null, null,
"ttt", "s"),
- InvalidParametersEvent.class);
+ private static Object[][] invokeNullTestData() {
+ return new Object[][] {
+ { null, null, null },
+ { "testString", null, null },
+ { "testString", "test", null },
+ { null, "test", null },
+ { null, "test", "ttt" },
+ { null, null, "ttt" }
+ };
}
- @Test
- void invokeWithoutFlagsPatternMatches() {
- FunctionTestUtil.assertResult(replaceFunction.invoke("testString",
"^test", "ttt"), "tttString");
- FunctionTestUtil.assertResult(replaceFunction.invoke("testStringtest",
"^test", "ttt"), "tttStringtest");
+ @ParameterizedTest
+ @MethodSource("invokeNullWithFlagsTestData")
+ void invokeNullWithFlagsTest(String input, String pattern, String
replacement, String flags) {
+ FunctionTestUtil.assertResultError(replaceFunction.invoke(input,
pattern, replacement, flags), InvalidParametersEvent.class);
+ }
+
+ private static Object[][] invokeNullWithFlagsTestData() {
+ return new Object[][] {
+ { null, null, null, null },
+ { "testString", null, null, null },
+ { "testString", "test", null, null },
+ { null, "test", null, null },
+ { null, "test", "ttt", null },
+ { null, null, "ttt", null },
+ { null, null, null, "s" },
+ { "testString", null, null, "s" },
+ { "testString", "test", null, "s" },
+ { null, "test", null, "s" },
+ { null, "test", "ttt", "s" },
+ { null, null, "ttt", "s" },
+ };
+ }
+
+ @ParameterizedTest
+ @MethodSource("invokeUnsupportedFlagsTestData")
+ void invokeUnsupportedFlagsTest(String input, String pattern, String
replacement, String flags) {
+ FunctionTestUtil.assertResultError(replaceFunction.invoke(input,
pattern, replacement, flags), InvalidParametersEvent.class);
+ }
+
+ private static Object[][] invokeUnsupportedFlagsTestData() {
+ return new Object[][] {
+ { "testString", "^test", "ttt", "g" },
+ { "testString", "^test", "ttt", "p" },
+ { "testString", "^test", "ttt", "X" },
+ { "testString", "^test", "ttt", "iU" },
+ { "testString", "^test", "ttt", "iU asd" },
+ };
+ }
+
+ @ParameterizedTest
+ @MethodSource("invokeWithoutFlagsPatternTestData")
+ void invokeWithoutFlagsPatternTest(String input, String pattern, String
replacement, String expectedResult) {
+ FunctionTestUtil.assertResult(replaceFunction.invoke(input, pattern,
replacement), expectedResult);
+ }
+
+ private static Object[][] invokeWithoutFlagsPatternTestData() {
+ return new Object[][] {
+ { "testString", "^test", "ttt", "tttString" },
+ { "testStringtest", "^test", "ttt", "tttStringtest" },
+ { "testString", "ttest", "ttt", "testString" },
+ { "testString", "$test", "ttt", "testString" }
+ };
}
@Test
- void invokeWithoutFlagsPatternNotMatches() {
- FunctionTestUtil.assertResult(replaceFunction.invoke("testString",
"ttest", "ttt"), "testString");
- FunctionTestUtil.assertResult(replaceFunction.invoke("testString",
"$test", "ttt"), "testString");
+ void invokeInvalidRegExPattern() {
+
FunctionTestUtil.assertResultError(replaceFunction.invoke("testString",
"(?=\\s)", "ttt"), InvalidParametersEvent.class);
}
@Test
diff --git
a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/util/XQueryImplUtilTest.java
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/util/XQueryImplUtilTest.java
new file mode 100644
index 0000000000..6cc71d38a6
--- /dev/null
+++
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/util/XQueryImplUtilTest.java
@@ -0,0 +1,117 @@
+/**
+ * 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.kie.dmn.feel.util;
+
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+class XQueryImplUtilTest {
+
+ @ParameterizedTest
+ @MethodSource("executeMatchesFunctionTestData")
+ void executeMatchesFunctionTest(String input, String pattern, String
flags, boolean expected) {
+ assertThat(XQueryImplUtil.executeMatchesFunction(input, pattern,
flags)).isEqualTo(expected);
+ }
+
+ private static Object[][] executeMatchesFunctionTestData() {
+ return new Object[][] {
+ { "test", "^test", "i", true },
+ { "fo\nbar", "o.b", null, false },
+ { "TEST", "test", "i", true },
+ };
+ }
+
+ @ParameterizedTest
+ @MethodSource("executeMatchesFunctionInvokingExceptionTestData")
+ void executeMatchesFunctionInvokingExceptionTest(String input, String
pattern, String flags,
+ String exceptionMessage) {
+ assertThatThrownBy(() -> XQueryImplUtil.executeMatchesFunction(input,
pattern, flags))
+
.isInstanceOf(IllegalArgumentException.class).hasMessageContaining(exceptionMessage);
+ }
+
+ private static Object[][]
executeMatchesFunctionInvokingExceptionTestData() {
+ return new Object[][] {
+ { "test", "^test", "g", "Unrecognized flag" },
+ { "test", "(?=\\s)", null, "No expression before quantifier" },
+ { "test", "(.)\\2", "i", "invalid backreference \\2" },
+ };
+ }
+
+ @ParameterizedTest
+ @MethodSource("executeReplaceFunctionTestData")
+ void executeReplaceFunctionTest(String input, String pattern, String
replacement, String flags, String expected) {
+ assertThat(XQueryImplUtil.executeReplaceFunction(input, pattern,
replacement, flags)).isEqualTo(expected);
+ }
+
+ private static Object[][] executeReplaceFunctionTestData() {
+ return new Object[][] {
+ { "testString", "^test", "ttt", "", "tttString" },
+ { "fo\nbar", "o.b", "ttt", "s", "ftttar" },
+ };
+ }
+
+ @ParameterizedTest
+ @MethodSource("executeReplaceFunctionInvokingExceptionTestData")
+ void executeReplaceFunctionInvokingExceptionTest(String input, String
pattern, String replacement, String flags,
+ Class<?>
expectedException, String exceptionMessage) {
+ assertThatThrownBy(() -> XQueryImplUtil.executeReplaceFunction(input,
pattern, replacement, flags))
+
.isInstanceOf(expectedException).hasMessageContaining(exceptionMessage);
+ }
+
+ private static Object[][]
executeReplaceFunctionInvokingExceptionTestData() {
+ return new Object[][] {
+ { "fo\nbar", "o.b", "ttt", "g",
IllegalArgumentException.class, "Unrecognized flag" },
+ { "test", "(?=\\s)", "ttt", null,
IllegalArgumentException.class, "No expression before quantifier" },
+ { "test", "(.)\\2", "ttt", null,
IllegalArgumentException.class, "invalid backreference \\2" },
+ };
+ }
+
+ @ParameterizedTest
+ @MethodSource("evaluateXQueryExpressionValidParametersTestData")
+ void evaluateXQueryExpressionValidParametersTest(String expression,
Class<?> returnTypeClass, Object expectedResult) {
+ assertThat(XQueryImplUtil.evaluateXQueryExpression(expression,
returnTypeClass)).isEqualTo(expectedResult);
+
+ }
+
+ private static Object[][]
evaluateXQueryExpressionValidParametersTestData() {
+ return new Object[][] {
+ { "matches('test', '^test', 'i')", Boolean.class, true },
+ { "matches('fo\\nbar', 'o.b', '')", Boolean.class, false },
+ { "replace('testString', '^test', 'ttt', '')", String.class,
"tttString" }
+ };
+ }
+
+ @ParameterizedTest
+ @MethodSource("evaluateXQueryExpressionInvalidParametersTestData")
+ void evaluateXQueryExpressionInvalidParametersTest(String expression,
Class<?> returnTypeClass) {
+ assertThatThrownBy(() ->
XQueryImplUtil.evaluateXQueryExpression(expression, returnTypeClass))
+ .isInstanceOf(UnsupportedOperationException.class);
+ }
+
+ private static Object[][]
evaluateXQueryExpressionInvalidParametersTestData() {
+ return new Object[][] {
+ { "matches('test', '^test', 'i')", Integer.class },
+ { "replace('testString', '^test', 'ttt', '')", Double.class },
+ };
+ }
+
+}
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]