diff --git a/src/main/java/org/caosdb/server/query/POV.java b/src/main/java/org/caosdb/server/query/POV.java index 89ea9ad46e6205dfe0583e8f54551effd82a2658..7c5176b9a78ced6104601649355ecbd0ee82a825 100644 --- a/src/main/java/org/caosdb/server/query/POV.java +++ b/src/main/java/org/caosdb/server/query/POV.java @@ -51,6 +51,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class POV implements EntityFilterInterface { + public static final Pattern NUMBER_PATTERN = + Pattern.compile("^((?:-\\s*)?[0-9]+(?:\\.[0-9]+)?(?:[eE][+-]?[0-9]+)?)\\s*([^-]*)$"); private SubProperty subp = null; public static int retry = 10; private int retry_count = 0; @@ -116,14 +118,13 @@ public class POV implements EntityFilterInterface { // try and parse as integer try { - final Pattern dp = Pattern.compile("^(-?[0-9]++)\\s*([^(\\.[0-9])-][^-]*)?$"); - final Matcher m = dp.matcher(value); + final Matcher m = NUMBER_PATTERN.matcher(value); if (!m.matches()) { throw new NumberFormatException(); } final String vIntStr = m.group(1); - this.unitStr = m.group(2); this.vInt = Integer.parseInt(vIntStr); + this.unitStr = m.group(2); } catch (final NumberFormatException e) { this.vInt = null; } @@ -132,15 +133,14 @@ public class POV implements EntityFilterInterface { if (this.vInt == null) { try { // Doubles are allowed without dots, for example when the integer overflows. - final Pattern dp = Pattern.compile("^(-?[0-9]+(?:\\.)?(?:[0-9]+))\\s*([^-]*)$"); - final Matcher m = dp.matcher(value); + final Matcher m = NUMBER_PATTERN.matcher(value); if (!m.matches()) { throw new NumberFormatException(); } final String vDoubleStr = m.group(1); - this.unitStr = m.group(2); this.vDouble = Double.parseDouble(vDoubleStr); + this.unitStr = m.group(2); } catch (final NumberFormatException e) { this.vDouble = null; } diff --git a/src/test/java/org/caosdb/server/query/POVTest.java b/src/test/java/org/caosdb/server/query/POVTest.java new file mode 100644 index 0000000000000000000000000000000000000000..9f2b957608763144ea67ec287140d6983efca457 --- /dev/null +++ b/src/test/java/org/caosdb/server/query/POVTest.java @@ -0,0 +1,60 @@ +package org.caosdb.server.query; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.regex.Matcher; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class POVTest { + + public static final String MAX_INT = "2147483647"; + public static final String MIN_INT = "-2147483648"; + + @ParameterizedTest + @ValueSource(strings = {"16", MAX_INT, MIN_INT, "0", "-0", "1", "- 1", "-1"}) + void testNumberPatternMatchInteger(String intValue) { + + Matcher matcher = POV.NUMBER_PATTERN.matcher(intValue); + assertTrue(matcher.matches()); + assertEquals(intValue, matcher.group(1).toString()); + + Integer.valueOf(intValue.replaceAll("\\s", "")); + + Matcher matcherWithUnit = POV.NUMBER_PATTERN.matcher(intValue + " m^2"); + assertTrue(matcherWithUnit.matches()); + assertEquals(intValue, matcherWithUnit.group(1).toString()); + assertEquals("m^2", matcherWithUnit.group(2).toString()); + + Matcher matcherWithStrangeUnit = POV.NUMBER_PATTERN.matcher(intValue + " e"); + assertTrue(matcherWithStrangeUnit.matches()); + assertEquals(intValue, matcherWithStrangeUnit.group(1).toString()); + assertEquals("e", matcherWithStrangeUnit.group(2).toString()); + } + + @ParameterizedTest + @ValueSource( + strings = { + "1e+3", "1E+3", "5e9", "5E9", "16", MAX_INT, MIN_INT, "0", "-0", "1", "- 1", "-1", "2e-323", + "2E-323" + }) + void testNumberPatternMatchDouble(String doubleValue) { + + Matcher matcher = POV.NUMBER_PATTERN.matcher(doubleValue); + assertTrue(matcher.matches()); + assertEquals(doubleValue, matcher.group(1).toString()); + + Double.valueOf(doubleValue.replaceAll("\\s", "")); + + Matcher matcherWithUnit = POV.NUMBER_PATTERN.matcher(doubleValue + " m^2"); + assertTrue(matcherWithUnit.matches()); + assertEquals(doubleValue, matcherWithUnit.group(1).toString()); + assertEquals("m^2", matcherWithUnit.group(2).toString()); + + Matcher matcherWithStrangeUnit = POV.NUMBER_PATTERN.matcher(doubleValue + " e"); + assertTrue(matcherWithStrangeUnit.matches()); + assertEquals(doubleValue, matcherWithStrangeUnit.group(1).toString()); + assertEquals("e", matcherWithStrangeUnit.group(2).toString()); + } +} diff --git a/src/test/java/org/caosdb/server/query/TestCQL.java b/src/test/java/org/caosdb/server/query/TestCQL.java index fe73e2b2c33749fac6d72a4c5b478eca5d154465..053a482718af9780d9753e2ddf553b2d1e45c4a9 100644 --- a/src/test/java/org/caosdb/server/query/TestCQL.java +++ b/src/test/java/org/caosdb/server/query/TestCQL.java @@ -46,6 +46,8 @@ import org.caosdb.server.query.Query.QueryException; import org.caosdb.server.utils.Initialization; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; public class TestCQL { @@ -272,6 +274,7 @@ public class TestCQL { String issue131d = "FIND ename WITH (pname1.x) AND pname2"; String issue131e = "FIND ename WITH (pname1.pname2 > 30) AND (pname1.pname2 < 40)"; String issue131f = "FIND ename WITH (pname1.pname2 > 30) AND pname1.pname2 < 40"; + String issue144 = "FIND ename WITH pname = "; // https://gitlab.com/caosdb/caosdb-server/-/issues/130 String issue130a = @@ -7013,4 +7016,19 @@ public class TestCQL { assertEquals("POV(null,LIKE ,%nothin'%)", conj.getFilters().get(4).toString()); assertEquals("POV(null,LIKE ,%\"'bla%)", conj.getFilters().get(5).toString()); } + + @ParameterizedTest + @ValueSource(strings = {"1e+23", "1E+23", "5e22", "5E22", "2e-323", "2E-323"}) + public void testIssue144(String scientific_notation) { + CQLLexer lexer; + lexer = new CQLLexer(CharStreams.fromString(this.issue144 + scientific_notation)); + final CommonTokenStream tokens = new CommonTokenStream(lexer); + + final CQLParser parser = new CQLParser(tokens); + final CqContext sfq = parser.cq(); + + assertTrue(sfq.filter instanceof POV); + POV pov = (POV) sfq.filter; + assertEquals("POV(pname,=," + scientific_notation + ")", pov.toString()); + } }