diff --git a/doc/devel/Development.md b/doc/devel/Development.md index d0887fcfd98cc4dcc7cb8df5f34257ccf8045fc6..246f80db14eeadfd1b95e062f0b43636d5f6960c 100644 --- a/doc/devel/Development.md +++ b/doc/devel/Development.md @@ -20,4 +20,5 @@ writing tests. ### Running tests with Maven ### - Automatic testing can be done with `make test` or, after compilation, `mvn test`. -- Tests of single modules can be started with `mvn test -Dtest=TextClass` +- Tests of single modules can be started with `mvn test -Dtest=TestClass` +- Test of a single method `footest`: `mvn test -Dtest=TestClass#footest` diff --git a/src/main/java/caosdb/server/query/CQLLexer.g4 b/src/main/java/caosdb/server/query/CQLLexer.g4 index ecf00fada057c7aff99b76642c065709423943e4..62cb12c09c00a2f0005a8b9e2b7d5cc8f6b753e5 100644 --- a/src/main/java/caosdb/server/query/CQLLexer.g4 +++ b/src/main/java/caosdb/server/query/CQLLexer.g4 @@ -349,8 +349,9 @@ ID: [Ii][Dd] ; -SLASH: - '/' +// Multiple slashes should be allowed in paths instead of a single slash. +SLASHES: + '/'+ ; STAR: diff --git a/src/main/java/caosdb/server/query/CQLParser.g4 b/src/main/java/caosdb/server/query/CQLParser.g4 index 48205d1fece3309570f40e566078f51c96cab1bd..531b61951c508e7cb4e068a4ee061e05ffa5b847 100644 --- a/src/main/java/caosdb/server/query/CQLParser.g4 +++ b/src/main/java/caosdb/server/query/CQLParser.g4 @@ -456,8 +456,8 @@ location returns [String str] : atom {$str = $atom.str;} | - SLASH ? - ((WHICH | WITH)+ SLASH |( TXT | COLON | HYPHEN | NUM | DOT | ESC_STAR | ESC_BS | ESC_REGEXP_END | STAR )+ SLASH ?)* {$str = $text; } + SLASHES ? + ((WHICH | WITH)+ SLASHES |( TXT | COLON | HYPHEN | NUM | DOT | ESC_STAR | ESC_BS | ESC_REGEXP_END | STAR )+ SLASHES ?)* {$str = $text; } ; atom returns [String str] diff --git a/src/main/java/caosdb/server/query/StoredAt.java b/src/main/java/caosdb/server/query/StoredAt.java index cfd2be97fe19906f52986f0b124756cd02952649..543968c76f6df525d5460b88d288a9d4054a9f5e 100644 --- a/src/main/java/caosdb/server/query/StoredAt.java +++ b/src/main/java/caosdb/server/query/StoredAt.java @@ -25,6 +25,8 @@ package caosdb.server.query; import static java.sql.Types.VARCHAR; import caosdb.server.query.Query.QueryException; +import java.nio.file.Path; +import java.nio.file.Paths; import java.sql.CallableStatement; import java.sql.SQLException; import java.util.regex.Matcher; @@ -34,47 +36,73 @@ import org.jdom2.Element; public class StoredAt implements EntityFilterInterface { public static final java.util.regex.Pattern PATTERN = - Pattern.compile("((?:(?:\\\\[\\*\\\\])|[^\\*\\\\])+)?(\\*{2,})?(\\*)?"); - private final String location; + // heading and escaped * and \ removed, then + // (part of directory name: no \, no *)?(**)?(*)? + Pattern.compile("((?:(?:\\\\[\\*\\\\])|[^\\*\\\\])+)?(\\*{2,})?(\\*)?"); + private String location; + private final String likeLocation; private boolean pattern_matching = false; public StoredAt(final String loc) { - final String[] dirs = loc.split("/"); - final StringBuffer sb = new StringBuffer(); - - // if (dirs[0].length() == 0) { - // sb.append("/"); - // } - for (final String dir : dirs) { - final Matcher m = PATTERN.matcher(dir); - - sb.append("/"); - while (m.find()) { - // part of a directory name - if (m.group(1) != null) { - sb.append(m.group(1).replace("%", "\\%").replace("_", "\\_").replaceAll("\\\\\\*", "*")); - } - - // ** - if (m.group(2) != null) { - this.pattern_matching = true; - sb.append("%"); - } + Path locPath = Paths.get(loc); + this.location = + locPath.normalize().toString().replaceFirst("^/", "") + (loc.endsWith("/") ? "/" : ""); + this.pattern_matching = requiresPatternMatching(); - // * - if (m.group(3) != null) { - this.pattern_matching = true; - sb.append("%%"); - } - } + if (this.pattern_matching) { + this.likeLocation = convertLikeLocation(); + } else { + this.likeLocation = null; } + } - if (loc.endsWith("/")) { - sb.append("/"); + /** + * Does some special character escaping for LIKE query + * + * <p>The following rules should take place in the future (for now, only a subset is implemented + * correctly): + * + * <ul> + * <li>\* -> * (No special meaning in SQL, even numbers of \ are ignored.) + * <li>* -> %% (Wildcard, to be converted to a more complicated regex without / later. + * Exception: at the beginning of a search expression, convert to %.) + * <li>** -> % (Wildcard, also ***, ****, ... -> %) + * <li>_ -> \_ (Prevent special meaning in SQL) + * <li>% -> \% (Prevent special meaning in SQL) + * <li>Heading `/` is removed + * </ul> + * + * @return The converted String. + */ + String convertLikeLocation() { + final String evenB = "(^|[^b*])(bb)*"; + final String oddB = evenB + "b"; + final String singleEscapedAst = "b\\*"; + final String findSingleAst = + (evenB + "(" + singleEscapedAst + ")?" + "\\*([^*]|$)").replace("b", "\\\\"); + final String findMultipleAst = + (evenB + "(" + singleEscapedAst + ")?" + "\\*{2,}").replace("b", "\\\\"); + java.util.regex.Pattern singlePat = Pattern.compile(findSingleAst); + java.util.regex.Pattern multiplePat = Pattern.compile(findMultipleAst); + + // Simple SQL escape replacements + String converted = this.location.replace("%", "\\%").replace("_", "\\_"); + // * -> %%, has to run mutliple times, because otherwise the separation between patterns would + // need to be larger than one character + while (singlePat.matcher(converted).find()) { + converted = converted.replaceAll(findSingleAst, "$1$2$3%%$4"); } + // ** -> % + converted = converted.replaceAll(findMultipleAst, "$1$2$3%"); + // All remaining asterisks are now guaranteed to have an odd number of backslashes in front - this.location = - sb.toString().replaceFirst("^/", "").replaceFirst("^%{2,}", "%").replaceFirst("^/", ""); + // So we can now do \* -> * + converted = converted.replaceAll(singleEscapedAst.replace("b", "\\\\"), "*"); + + // Final exceptions + converted = converted.replaceFirst("^%{2,}", "%"); // .replaceFirst("^/", ""); + + return converted; } @Override @@ -99,14 +127,14 @@ public class StoredAt implements EntityFilterInterface { if (this.location == null) { // location callSAT.setNull(3, VARCHAR); } else { - callSAT.setString(3, this.location); + callSAT.setString(3, (this.pattern_matching ? this.likeLocation : this.location)); } callSAT.setString(4, (this.pattern_matching ? "LIKE" : "=")); callSAT.execute(); - // ... and then cancel out the wrong guys via regexp - if (this.pattern_matching && this.location.contains("%%")) { + // ... and then cancel out the wrong guys ('*' matching '/') via regexp + if (this.pattern_matching && this.likeLocation.contains("%%")) { // make a MySQL-conform regexp for this.location: // 1) escape literal dots (. = \.) @@ -116,7 +144,7 @@ public class StoredAt implements EntityFilterInterface { // 5) replace non-escaped %% with [^/]* // 6) replace non-escaped % with .* final String nloc = - Pattern.quote(this.location.replace(".", "\\.")) + Pattern.quote(this.likeLocation.replace(".", "\\.")) .replaceFirst("..$", "\\$") .replaceFirst("^..", "^") .replaceAll("(?<!\\\\)%%", "[^/]*") @@ -139,6 +167,20 @@ public class StoredAt implements EntityFilterInterface { query.addBenchmark(this.getClass().getSimpleName(), System.currentTimeMillis() - t1); } + /** + * Tests if the location String is intended for pattern matching. + * + * @return True if the location requires pattern matching for a LIKE query, false otherwise. + */ + boolean requiresPatternMatching() { + // Looking for *, preceded by no or an even number of backslashes + String requiredPatternStr = "(^|[^b])(bb)*\\*"; + requiredPatternStr = requiredPatternStr.replace("b", "\\\\"); + java.util.regex.Pattern REQPATTERN = Pattern.compile(requiredPatternStr); + final Matcher m = REQPATTERN.matcher(this.location); + return m.find(); + } + @Override public Element toElement() { final Element ret = new Element("StoredAt"); @@ -146,8 +188,13 @@ public class StoredAt implements EntityFilterInterface { return ret; } + /** + * For testing purposes, create a string representing the corresponding query. + * + * @return The String "SAT(<location>)", where "<location>" is the query string. + */ @Override public String toString() { - return "SAT(" + this.location + ")"; + return "SAT(" + (this.pattern_matching ? this.likeLocation : this.location) + ")"; } } diff --git a/src/test/java/caosdb/server/query/TestCQL.java b/src/test/java/caosdb/server/query/TestCQL.java index e44110104cbd827bc7f39e126822afd25973a76e..d902d9001e7d07809d3821577d41f0b68deff4cd 100644 --- a/src/test/java/caosdb/server/query/TestCQL.java +++ b/src/test/java/caosdb/server/query/TestCQL.java @@ -86,6 +86,9 @@ public class TestCQL { String query16a = "FIND FILE WHICH IS STORED AT /bla/bla/bla"; String query16b = "FIND FILE WHICH IS STORED AT /bla/bla/bla/"; String query16c = "FIND FILE WHICH IS STORED AT /bla/bla/bla.html"; + String query16d = "FIND FILE WHICH IS STORED AT //bla///bla.html"; + String query16e = "FIND FILE WHICH IS STORED AT /bla/bla_bla.html"; + String query16f = "FIND FILE WHICH IS STORED AT /bla/blubb/../bla.html"; String query17 = "FIND FILE WHICH IS STORED AT \"/bla/bla/bla\" OR HAS A pname2=val2"; String query18 = "FIND FILE WHICH HAS A pname2=val2 OR IS STORED AT \"/bla/bla/bla\""; String query19 = @@ -215,7 +218,7 @@ public class TestCQL { String query56d = "FIND RECORD WHICH REFERENCES A tom"; @Test - public void TestQuery1() + public void testQuery1() throws InterruptedException, SQLException, ConnectionException, QueryException { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query1)); @@ -267,7 +270,7 @@ public class TestCQL { } @Test - public void TestQuery1a() { + public void testQuery1a() { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query1a)); final CommonTokenStream tokens = new CommonTokenStream(lexer); @@ -314,7 +317,7 @@ public class TestCQL { } @Test - public void TestQuery1b() { + public void testQuery1b() { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query1b)); final CommonTokenStream tokens = new CommonTokenStream(lexer); @@ -362,7 +365,7 @@ public class TestCQL { } @Test - public void TestQuery1c() { + public void testQuery1c() { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query1c)); final CommonTokenStream tokens = new CommonTokenStream(lexer); @@ -410,7 +413,7 @@ public class TestCQL { } @Test - public void TestQuery1d() { + public void testQuery1d() { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query1d)); final CommonTokenStream tokens = new CommonTokenStream(lexer); @@ -468,7 +471,7 @@ public class TestCQL { * String query1e = "FIND ename . pname1"; */ @Test - public void TestQuery1e() { + public void testQuery1e() { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query1e)); final CommonTokenStream tokens = new CommonTokenStream(lexer); @@ -520,7 +523,7 @@ public class TestCQL { } @Test - public void TestQuery2() { + public void testQuery2() { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query2)); final CommonTokenStream tokens = new CommonTokenStream(lexer); @@ -587,7 +590,7 @@ public class TestCQL { } @Test - public void TestQuery3() { + public void testQuery3() { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query3)); final CommonTokenStream tokens = new CommonTokenStream(lexer); @@ -662,7 +665,7 @@ public class TestCQL { } // @Test - // public void TestQuery4() { + // public void testQuery4() { // CQLLexer lexer; // lexer = new CQLLexer(CharStreams.fromString(query4)); // final CommonTokenStream tokens = new CommonTokenStream(lexer); @@ -781,7 +784,7 @@ public class TestCQL { // } @Test - public void TestQuery5() { + public void testQuery5() { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query5)); final CommonTokenStream tokens = new CommonTokenStream(lexer); @@ -885,7 +888,7 @@ public class TestCQL { } @Test - public void TestQuery6() { + public void testQuery6() { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query6)); final CommonTokenStream tokens = new CommonTokenStream(lexer); @@ -931,7 +934,7 @@ public class TestCQL { } @Test - public void TestQuery6a() { + public void testQuery6a() { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query6a)); final CommonTokenStream tokens = new CommonTokenStream(lexer); @@ -983,7 +986,7 @@ public class TestCQL { } @Test - public void TestQuery7() { + public void testQuery7() { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query7)); final CommonTokenStream tokens = new CommonTokenStream(lexer); @@ -1029,7 +1032,7 @@ public class TestCQL { } @Test - public void TestQuery11() { + public void testQuery11() { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query11)); final CommonTokenStream tokens = new CommonTokenStream(lexer); @@ -1075,7 +1078,7 @@ public class TestCQL { } @Test - public void TestQuery12() { + public void testQuery12() { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query12)); final CommonTokenStream tokens = new CommonTokenStream(lexer); @@ -1125,7 +1128,7 @@ public class TestCQL { } @Test - public void TestQuery12a() { + public void testQuery12a() { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query12a)); final CommonTokenStream tokens = new CommonTokenStream(lexer); @@ -1172,7 +1175,7 @@ public class TestCQL { } @Test - public void TestQuery13() { + public void testQuery13() { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query13)); final CommonTokenStream tokens = new CommonTokenStream(lexer); @@ -1224,7 +1227,7 @@ public class TestCQL { } @Test - public void TestQuery13a() { + public void testQuery13a() { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query13a)); final CommonTokenStream tokens = new CommonTokenStream(lexer); @@ -1276,7 +1279,7 @@ public class TestCQL { } @Test - public void TestQuery13b() { + public void testQuery13b() { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query13b)); final CommonTokenStream tokens = new CommonTokenStream(lexer); @@ -1328,7 +1331,7 @@ public class TestCQL { } @Test - public void TestQuery14() { + public void testQuery14() { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query14)); final CommonTokenStream tokens = new CommonTokenStream(lexer); @@ -1387,7 +1390,7 @@ public class TestCQL { } @Test - public void TestQuery14a() { + public void testQuery14a() { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query14a)); final CommonTokenStream tokens = new CommonTokenStream(lexer); @@ -1479,7 +1482,7 @@ public class TestCQL { } @Test - public void TestQuery15() { + public void testQuery15() { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query15)); final CommonTokenStream tokens = new CommonTokenStream(lexer); @@ -1534,7 +1537,7 @@ public class TestCQL { } @Test - public void TestQuery16() { + public void testQuery16() { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query16)); final CommonTokenStream tokens = new CommonTokenStream(lexer); @@ -1582,7 +1585,7 @@ public class TestCQL { } @Test - public void TestQuery16a() { + public void testQuery16a() { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query16a)); final CommonTokenStream tokens = new CommonTokenStream(lexer); @@ -1628,7 +1631,7 @@ public class TestCQL { } @Test - public void TestQuery16b() { + public void testQuery16b() { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query16b)); final CommonTokenStream tokens = new CommonTokenStream(lexer); @@ -1672,8 +1675,13 @@ public class TestCQL { assertEquals("SAT(bla/bla/bla/)", ((StoredAt) sfq.filter).toString()); } + /** + * 16c: Query String with double slash in path. + * + * <p>Query string is: "FIND FILE WHICH IS STORED AT /bla/bla/bla.html" + */ @Test - public void TestQuery16c() { + public void testQuery16c() { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query16c)); final CommonTokenStream tokens = new CommonTokenStream(lexer); @@ -1718,8 +1726,166 @@ public class TestCQL { assertEquals("SAT(bla/bla/bla.html)", ((StoredAt) sfq.filter).toString()); } + /** + * 16d: Query String with double slash in path. + * + * <p>Query string is: "FIND FILE WHICH IS STORED AT //bla///bla.html" + */ + @Test + public void testQuery16d() { + CQLLexer lexer; + lexer = new CQLLexer(CharStreams.fromString(this.query16d)); + final CommonTokenStream tokens = new CommonTokenStream(lexer); + + final CQLParser parser = new CQLParser(tokens); + final CqContext sfq = parser.cq(); + + assertEquals(null, sfq.e); + assertEquals(Query.Role.FILE, sfq.r); + assertNotNull(sfq.filter); + assertEquals(StoredAt.class.getName(), sfq.filter.getClass().getName()); + + // 4 children: FIND, role, entity_filter, EOF + assertEquals(4, sfq.getChildCount()); + assertEquals("FIND", sfq.getChild(0).getText()); + assertEquals("FILE", sfq.getChild(1).getText()); + assertEquals("WHICHIS STORED AT//bla///bla.html", sfq.getChild(2).getText()); + // entity_filter + final ParseTree entity_filter = sfq.getChild(2); + + // 2 children: WHICH_EXP, conjunction + assertEquals(2, entity_filter.getChildCount()); + assertEquals("WHICH", entity_filter.getChild(0).getText()); + assertEquals("IS STORED AT//bla///bla.html", entity_filter.getChild(1).getText()); + final ParseTree conjunction = entity_filter.getChild(1); + + // 1 child: storedAt + assertEquals(1, conjunction.getChildCount()); + assertEquals("IS STORED AT//bla///bla.html", conjunction.getChild(0).getText()); + final ParseTree storedat = conjunction.getChild(0); + + // 2 children: IS_STORED_AT, loc + assertEquals(2, storedat.getChildCount()); + assertEquals("IS STORED AT", storedat.getChild(0).getText()); + assertEquals("//bla///bla.html", storedat.getChild(1).getText()); + + assertEquals(null, sfq.e); + assertEquals(Query.Role.FILE, sfq.r); + assertNotNull(sfq.filter); + assertEquals(StoredAt.class.getName(), sfq.filter.getClass().getName()); + + assertEquals("SAT(bla/bla.html)", ((StoredAt) sfq.filter).toString()); + } + + /** + * 16e: Query String with underscore in path. + * + * <p>Query string is "FIND FILE WHICH IS STORED AT /bla/bla_bla.html" + */ @Test - public void TestQuery17() { + public void testQuery16e() { + CQLLexer lexer; + lexer = new CQLLexer(CharStreams.fromString(this.query16e)); + final CommonTokenStream tokens = new CommonTokenStream(lexer); + + final CQLParser parser = new CQLParser(tokens); + final CqContext sfq = parser.cq(); + + assertEquals(null, sfq.e); + assertEquals(Query.Role.FILE, sfq.r); + assertNotNull(sfq.filter); + assertEquals(StoredAt.class.getName(), sfq.filter.getClass().getName()); + + // 4 children: FIND, role, entity_filter, EOF + assertEquals(4, sfq.getChildCount()); + assertEquals("FIND", sfq.getChild(0).getText()); + assertEquals("FILE", sfq.getChild(1).getText()); + assertEquals("WHICHIS STORED AT/bla/bla_bla.html", sfq.getChild(2).getText()); + // entity_filter + final ParseTree entity_filter = sfq.getChild(2); + + // 2 children: WHICH_EXP, conjunction + assertEquals(2, entity_filter.getChildCount()); + assertEquals("WHICH", entity_filter.getChild(0).getText()); + assertEquals("IS STORED AT/bla/bla_bla.html", entity_filter.getChild(1).getText()); + final ParseTree conjunction = entity_filter.getChild(1); + + // 1 child: storedAt + assertEquals(1, conjunction.getChildCount()); + assertEquals("IS STORED AT/bla/bla_bla.html", conjunction.getChild(0).getText()); + final ParseTree storedat = conjunction.getChild(0); + + // 2 children: IS_STORED_AT, loc + assertEquals(2, storedat.getChildCount()); + assertEquals("IS STORED AT", storedat.getChild(0).getText()); + assertEquals("/bla/bla_bla.html", storedat.getChild(1).getText()); + + assertEquals(null, sfq.e); + assertEquals(Query.Role.FILE, sfq.r); + assertNotNull(sfq.filter); + assertEquals(StoredAt.class.getName(), sfq.filter.getClass().getName()); + + assertEquals("SAT(bla/bla_bla.html)", ((StoredAt) sfq.filter).toString()); + } + + /** + * 16f: Query String with `..` in path. + * + * <p>Query string is "FIND FILE WHICH IS STORED AT /bla/blubb/../bla.html" + */ + @Test + public void testQuery16f() { + CQLLexer lexer; + lexer = new CQLLexer(CharStreams.fromString(this.query16f)); + final String origPath = "/bla/blubb/../bla.html"; + final String absPath = "/bla/bla.html"; + final CommonTokenStream tokens = new CommonTokenStream(lexer); + + final CQLParser parser = new CQLParser(tokens); + final CqContext sfq = parser.cq(); + + assertEquals(null, sfq.e); + assertEquals(Query.Role.FILE, sfq.r); + assertNotNull(sfq.filter); + assertEquals(StoredAt.class.getName(), sfq.filter.getClass().getName()); + + // 4 children: FIND, role, entity_filter, EOF + assertEquals(4, sfq.getChildCount()); + assertEquals("FIND", sfq.getChild(0).getText()); + assertEquals("FILE", sfq.getChild(1).getText()); + assertEquals("WHICHIS STORED AT" + origPath, sfq.getChild(2).getText()); + // entity_filter + final ParseTree entity_filter = sfq.getChild(2); + + // 2 children: WHICH_EXP, conjunction + assertEquals(2, entity_filter.getChildCount()); + assertEquals("WHICH", entity_filter.getChild(0).getText()); + assertEquals("IS STORED AT" + origPath, entity_filter.getChild(1).getText()); + final ParseTree conjunction = entity_filter.getChild(1); + + // 1 child: storedAt + assertEquals(1, conjunction.getChildCount()); + assertEquals("IS STORED AT" + origPath, conjunction.getChild(0).getText()); + final ParseTree storedat = conjunction.getChild(0); + + // 2 children: IS_STORED_AT, loc + assertEquals(2, storedat.getChildCount()); + assertEquals("IS STORED AT", storedat.getChild(0).getText()); + assertEquals(origPath, storedat.getChild(1).getText()); + + assertEquals(null, sfq.e); + assertEquals(Query.Role.FILE, sfq.r); + assertNotNull(sfq.filter); + assertEquals(StoredAt.class.getName(), sfq.filter.getClass().getName()); + + assertFalse(((StoredAt) sfq.filter).requiresPatternMatching()); + assertEquals( + "SAT(" + absPath.toString().replaceFirst("^/", "") + ")", + ((StoredAt) sfq.filter).toString()); + } + + @Test + public void testQuery17() { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query17)); final CommonTokenStream tokens = new CommonTokenStream(lexer); @@ -1780,7 +1946,7 @@ public class TestCQL { } @Test - public void TestQuery18() { + public void testQuery18() { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query18)); final CommonTokenStream tokens = new CommonTokenStream(lexer); @@ -1847,7 +2013,7 @@ public class TestCQL { } @Test - public void TestQuery19() { + public void testQuery19() { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query19)); final CommonTokenStream tokens = new CommonTokenStream(lexer); @@ -1921,7 +2087,7 @@ public class TestCQL { } @Test - public void TestQuery19a() { + public void testQuery19a() { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query19a)); final CommonTokenStream tokens = new CommonTokenStream(lexer); @@ -1990,7 +2156,7 @@ public class TestCQL { } @Test - public void TestQuery19b() { + public void testQuery19b() { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query19b)); final CommonTokenStream tokens = new CommonTokenStream(lexer); @@ -2059,7 +2225,7 @@ public class TestCQL { } @Test - public void TestQuery19c() { + public void testQuery19c() { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query19c)); final CommonTokenStream tokens = new CommonTokenStream(lexer); @@ -2132,7 +2298,7 @@ public class TestCQL { } @Test - public void TestQuery19d() { + public void testQuery19d() { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query19d)); final CommonTokenStream tokens = new CommonTokenStream(lexer); @@ -2201,7 +2367,7 @@ public class TestCQL { } @Test - public void TestQuery20() { + public void testQuery20() { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query20)); final CommonTokenStream tokens = new CommonTokenStream(lexer); @@ -2280,7 +2446,7 @@ public class TestCQL { } @Test - public void TestQuery21() { + public void testQuery21() { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query21)); final CommonTokenStream tokens = new CommonTokenStream(lexer); @@ -2349,7 +2515,7 @@ public class TestCQL { } @Test - public void TestQuery22() { + public void testQuery22() { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query22)); final CommonTokenStream tokens = new CommonTokenStream(lexer); @@ -2409,7 +2575,7 @@ public class TestCQL { } @Test - public void TestQuery22a() { + public void testQuery22a() { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query22a)); final CommonTokenStream tokens = new CommonTokenStream(lexer); @@ -2474,7 +2640,7 @@ public class TestCQL { } @Test - public void TestQuery24() { + public void testQuery24() { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query24)); final CommonTokenStream tokens = new CommonTokenStream(lexer); @@ -2732,7 +2898,7 @@ public class TestCQL { * String query25 = "FIND ename . THE GREATEST pname"; */ @Test - public void TestQuery25() + public void testQuery25() throws InterruptedException, SQLException, ConnectionException, QueryException { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query25)); @@ -2755,7 +2921,7 @@ public class TestCQL { * String query26 = "FIND ename . THE SMALLEST pname"; */ @Test - public void TestQuery26() + public void testQuery26() throws InterruptedException, SQLException, ConnectionException, QueryException { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query26)); @@ -2779,7 +2945,7 @@ public class TestCQL { * "FIND SimpleRecordType WITH THE GREATEST SimpleDoubleProperty>0"; */ @Test - public void TestQuery26a() + public void testQuery26a() throws InterruptedException, SQLException, ConnectionException, QueryException { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query26a)); @@ -3396,7 +3562,7 @@ public class TestCQL { * String query27 = "FIND 'Some name with spaces and 1234 numbers'"; */ @Test - public void TestQuery27() + public void testQuery27() throws InterruptedException, SQLException, ConnectionException, QueryException { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query27)); @@ -3421,7 +3587,7 @@ public class TestCQL { * String query27a = "FIND \"Some name with spaces and 1234 numbers\""; */ @Test - public void TestQuery27a() + public void testQuery27a() throws InterruptedException, SQLException, ConnectionException, QueryException { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query27a)); @@ -3446,7 +3612,7 @@ public class TestCQL { * String query27b = "FIND 'Some name with spaces and 1234 numbers and \"'"; */ @Test - public void TestQuery27b() + public void testQuery27b() throws InterruptedException, SQLException, ConnectionException, QueryException { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query27b)); @@ -3472,7 +3638,7 @@ public class TestCQL { * "FIND 'Some name with spaces and 1234 numbers and \\*'"; */ @Test - public void TestQuery27c() + public void testQuery27c() throws InterruptedException, SQLException, ConnectionException, QueryException { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query27c)); @@ -3497,7 +3663,7 @@ public class TestCQL { * String query27d = "FIND 'Some name with spaces and 1234 numbers and *'"; */ @Test - public void TestQuery27d() + public void testQuery27d() throws InterruptedException, SQLException, ConnectionException, QueryException { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query27d)); @@ -3522,7 +3688,7 @@ public class TestCQL { * String query28 = "FIND ename . pname=2.0"; */ @Test - public void TestQuery28() + public void testQuery28() throws InterruptedException, SQLException, ConnectionException, QueryException { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query28)); @@ -3552,7 +3718,7 @@ public class TestCQL { * String query28a ="FIND ename . pname=2.0prop=test"; */ @Test - public void TestQuery28a() + public void testQuery28a() throws InterruptedException, SQLException, ConnectionException, QueryException { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query28a)); @@ -3828,7 +3994,7 @@ public class TestCQL { } @Test - public void TestQuery29() + public void testQuery29() throws InterruptedException, SQLException, ConnectionException, QueryException { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query29)); @@ -3863,7 +4029,7 @@ public class TestCQL { } @Test - public void TestQuery29a() + public void testQuery29a() throws InterruptedException, SQLException, ConnectionException, QueryException { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query29a)); @@ -4088,7 +4254,7 @@ public class TestCQL { * "FIND RECORD.CREATED BY 'henrik.tomwoerden' AND THE GREATEST ID"; */ @Test - public void TestQuery30() + public void testQuery30() throws InterruptedException, SQLException, ConnectionException, QueryException { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query30)); @@ -4127,7 +4293,7 @@ public class TestCQL { /** String query31 = "FIND PROPERTIES WHICH ARE INSERTED TODAY"; */ @Test - public void TestQuery31() { + public void testQuery31() { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query31)); final CommonTokenStream tokens = new CommonTokenStream(lexer); @@ -4445,7 +4611,7 @@ public class TestCQL { /** String query33 = "FIND ename WITH a date IN 2015"; */ @Test - public void TestQuery33() { + public void testQuery33() { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query33)); final CommonTokenStream tokens = new CommonTokenStream(lexer); @@ -4484,7 +4650,7 @@ public class TestCQL { /** String query34 = "FIND ename WITH a date NOT IN 2015"; */ @Test - public void TestQuery34() { + public void testQuery34() { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query34)); final CommonTokenStream tokens = new CommonTokenStream(lexer); @@ -4524,7 +4690,7 @@ public class TestCQL { /** String query35 = "FIND ename WITH a date IN 2015-01-01"; */ @Test - public void TestQuery35() { + public void testQuery35() { CQLLexer lexer; lexer = new CQLLexer(CharStreams.fromString(this.query35)); final CommonTokenStream tokens = new CommonTokenStream(lexer); @@ -4827,10 +4993,11 @@ public class TestCQL { assertTrue(sfq.filter instanceof StoredAt); final StoredAt storedAt = (StoredAt) sfq.filter; - assertEquals("SAT(%%)", storedAt.toString()); + assertTrue(storedAt.requiresPatternMatching()); + assertEquals("SAT(%)", storedAt.toString()); } - /** String query43 = "FIND FILE WHICH IS STORED AT /* /"; */ + /** String query43 = "FIND FILE WHICH IS STORED AT /* /" (without the space); */ @Test public void testQuery43() { CQLLexer lexer; @@ -4864,7 +5031,8 @@ public class TestCQL { assertTrue(sfq.filter instanceof StoredAt); final StoredAt storedAt = (StoredAt) sfq.filter; - assertEquals("SAT(%%/)", storedAt.toString()); + assertTrue(storedAt.requiresPatternMatching()); + assertEquals("SAT(%/)", storedAt.toString()); } /** String query44 = "FIND FILE WHICH IS STORED AT /** /"; */ @@ -4975,7 +5143,7 @@ public class TestCQL { assertTrue(sfq.filter instanceof StoredAt); final StoredAt storedAt = (StoredAt) sfq.filter; - assertEquals("SAT(%%/%%)", storedAt.toString()); + assertEquals("SAT(%/%%)", storedAt.toString()); } /** String query47 = "FIND FILE WHICH IS STORED AT /* /*.acq"; */ @@ -5012,7 +5180,7 @@ public class TestCQL { assertTrue(sfq.filter instanceof StoredAt); final StoredAt storedAt = (StoredAt) sfq.filter; - assertEquals("SAT(%%/%%.acq)", storedAt.toString()); + assertEquals("SAT(%/%%.acq)", storedAt.toString()); } /** String query48 = "FIND FILE WHICH IS STORED AT /** /*.acq"; */ @@ -5086,7 +5254,7 @@ public class TestCQL { assertTrue(sfq.filter instanceof StoredAt); final StoredAt storedAt = (StoredAt) sfq.filter; - assertEquals("SAT(%%.acq)", storedAt.toString()); + assertEquals("SAT(%.acq)", storedAt.toString()); } /** String query50 = "FIND FILE WHICH IS STORED AT *.acq"; */