fix StringIndexOutOfBounds when caret is in position 0

This commit is contained in:
2019-10-26 10:30:02 +02:00
parent f28a67a5c1
commit 7636781315
2 changed files with 49 additions and 28 deletions

View File

@@ -175,21 +175,27 @@ public class FindValuesForQueryCompletion extends ExpressionVisitor<SortedSet<St
this.queryCompletionIndex = queryCompletionIndex; this.queryCompletionIndex = queryCompletionIndex;
} }
@Override @Override
public SortedSet<String> visit(final Property property) { public SortedSet<String> visit(final Property property) {
final long start = System.nanoTime(); final long start = System.nanoTime();
final String field = property.getField(); final String field = property.getField();
final String value = property.getValue().getValue(); final String value = property.getValue().getValue();
final SortedSet<String> allValuesForField = queryCompletionIndex.findAllValuesForField(dateRange, field); final SortedSet<String> allValuesForField = queryCompletionIndex.findAllValuesForField(dateRange, field);
final String valuePrefix = value.substring(0, value.indexOf(NewProposerParser.CARET_MARKER)); final String valuePrefix;
final TreeSet<String> result = GloblikePattern.filterValues(allValuesForField, valuePrefix, TreeSet::new); if (value.indexOf(NewProposerParser.CARET_MARKER) >= 0) {
METRIC_LOGGER.debug("{}: {}ms", property, (System.nanoTime() - start) / 1_000_000.0); valuePrefix = value.substring(0, value.indexOf(NewProposerParser.CARET_MARKER));
return result; } else {
} valuePrefix = value;
}
final TreeSet<String> result = GloblikePattern.filterValues(allValuesForField, valuePrefix, TreeSet::new);
METRIC_LOGGER.debug("{}: {}ms", property, (System.nanoTime() - start) / 1_000_000.0);
return result;
}
@Override @Override
public SortedSet<String> visit(final AndCaretExpression expression) { public SortedSet<String> visit(final AndCaretExpression expression) {

View File

@@ -73,7 +73,7 @@ public class ProposerTest {
public void testEmptyQuery() throws Exception { public void testEmptyQuery() throws Exception {
assertProposals("", ResultMode.FULL_VALUES, 0, // assertProposals("|", ResultMode.FULL_VALUES, //
new Proposal("name", "name=*", true, "name=", 5), // new Proposal("name", "name=*", true, "name=", 5), //
new Proposal("bird", "bird=*", true, "bird=", 5), // new Proposal("bird", "bird=*", true, "bird=", 5), //
new Proposal("dog", "dog=*", true, "dog=", 4), // new Proposal("dog", "dog=*", true, "dog=", 4), //
@@ -81,7 +81,7 @@ public class ProposerTest {
new Proposal("source", "source=*", true, "source=", 7)// new Proposal("source", "source=*", true, "source=", 7)//
); );
assertProposals(" ", ResultMode.FULL_VALUES, 1, // assertProposals(" |", ResultMode.FULL_VALUES, //
new Proposal("name", "name=*", true, "name=", 5), // new Proposal("name", "name=*", true, "name=", 5), //
new Proposal("bird", "bird=*", true, "bird=", 5), // new Proposal("bird", "bird=*", true, "bird=", 5), //
new Proposal("dog", "dog=*", true, "dog=", 4), // new Proposal("dog", "dog=*", true, "dog=", 4), //
@@ -91,48 +91,63 @@ public class ProposerTest {
} }
public void testPrefixOfKey() throws Exception { public void testPrefixOfKey() throws Exception {
assertProposals("bi", ResultMode.FULL_VALUES, 2, // assertProposals("bi|", ResultMode.FULL_VALUES, //
new Proposal("bird", "bird=* ", true, "bird=", 5) // new Proposal("bird", "bird=* ", true, "bird=", 5) //
); );
assertProposals("bird", ResultMode.FULL_VALUES, 4, // assertProposals("bird|", ResultMode.FULL_VALUES, //
new Proposal("bird", "bird=* ", true, "bird=", 5) // new Proposal("bird", "bird=* ", true, "bird=", 5) //
); );
assertProposals("bird=eagle and n", ResultMode.FULL_VALUES, 16, // assertProposals("bird=eagle and n|", ResultMode.FULL_VALUES, //
new Proposal("name", "bird=eagle and name=* ", true, "bird=eagle and name=", 20) // new Proposal("name", "bird=eagle and name=* ", true, "bird=eagle and name=", 20) //
); );
assertProposals("|bird", ResultMode.FULL_VALUES, //
new Proposal("bird", "bird=* ", true, "bird=", 5), //
new Proposal("dog", "dog=* ", true, "dog=", 4), //
new Proposal("method", "method=* ", true, "method=", 7), //
new Proposal("name", "name=* ", true, "name=", 5), //
new Proposal("source", "source=* ", true, "source=", 7) //
);
} }
public void testPrefixOfValue() throws Exception { public void testPrefixOfValue() throws Exception {
assertProposals("name =Tim", ResultMode.FULL_VALUES, 9, // assertProposals("name =Tim|", ResultMode.FULL_VALUES, //
new Proposal("Tim", "name =Tim", true, "name =Tim", 9), new Proposal("Tim", "name =Tim", true, "name =Tim", 9),
new Proposal("Timothy", "name =Timothy", true, "name =Timothy", 13)); new Proposal("Timothy", "name =Timothy", true, "name =Timothy", 13));
assertProposals("name =Je", ResultMode.FULL_VALUES, 8, // assertProposals("name =Je|", ResultMode.FULL_VALUES, //
new Proposal("Jennifer", "name =Jennifer", true, "name =Jennifer", 14), // new Proposal("Jennifer", "name =Jennifer", true, "name =Jennifer", 14), //
new Proposal("Jenny", "name =Jenny", true, "name =Jenny", 11) // new Proposal("Jenny", "name =Jenny", true, "name =Jenny", 11) //
); );
assertProposals("name =Tim,Je", ResultMode.FULL_VALUES, 12, // assertProposals("name =Tim,Je|", ResultMode.FULL_VALUES, //
new Proposal("Jennifer", "name =Tim,Jennifer", true, "name =Tim,Jennifer", 18), // new Proposal("Jennifer", "name =Tim,Jennifer", true, "name =Tim,Jennifer", 18), //
new Proposal("Jenny", "name =Tim,Jenny", true, "name =Tim,Jenny", 15) // new Proposal("Jenny", "name =Tim,Jenny", true, "name =Tim,Jenny", 15) //
); );
// TODO this case is currently handled completely wrong - it is handled similar to an empty query
// assertProposals("|bird=eagle and name=Tim", ResultMode.FULL_VALUES, //
// new Proposal("Jennifer", "name =Tim,Jennifer", true, "name =Tim,Jennifer", 18), //
// new Proposal("Jenny", "name =Tim,Jenny", true, "name =Tim,Jenny", 15) //
// );
/* /*
*/ */
} }
@Test(enabled = true) @Test(enabled = true)
public void testInExpressions() throws Exception { public void testInExpressions() throws Exception {
assertProposals("name = (Timothy,)", ResultMode.FULL_VALUES, 16, // assertProposals("name = (Timothy,|)", ResultMode.FULL_VALUES, //
new Proposal("Jennifer", "name = (Timothy,Jennifer)", true, "name = (Timothy,Jennifer)", 24), // new Proposal("Jennifer", "name = (Timothy,Jennifer)", true, "name = (Timothy,Jennifer)", 24), //
new Proposal("Jenny", "name = (Timothy,Jenny)", true, "name = (Timothy,Jenny)", 21), // new Proposal("Jenny", "name = (Timothy,Jenny)", true, "name = (Timothy,Jenny)", 21), //
new Proposal("Tim", "name = (Timothy,Tim)", true, "name = (Timothy,Tim)", 19), // new Proposal("Tim", "name = (Timothy,Tim)", true, "name = (Timothy,Tim)", 19), //
new Proposal("Timothy", "name = (Timothy,Timothy)", true, "name = (Timothy,Timothy)", 23)// new Proposal("Timothy", "name = (Timothy,Timothy)", true, "name = (Timothy,Timothy)", 23)//
); );
assertProposals("name = (Timothy, J)", ResultMode.FULL_VALUES, 18, // assertProposals("name = (Timothy, J|)", ResultMode.FULL_VALUES, //
new Proposal("Jennifer", "name = (Timothy, Jennifer)", true, "name = (Timothy, Jennifer)", 25), // new Proposal("Jennifer", "name = (Timothy, Jennifer)", true, "name = (Timothy, Jennifer)", 25), //
new Proposal("Jenny", "name = (Timothy, Jenny)", true, "name = (Timothy, Jenny)", 22)); new Proposal("Jenny", "name = (Timothy, Jenny)", true, "name = (Timothy, Jenny)", 22));
assertProposals("name = (Tim)", ResultMode.FULL_VALUES, 11, // assertProposals("name = (Tim|)", ResultMode.FULL_VALUES, //
new Proposal("Tim", "name = (Tim)", true, "name = (Tim)", 11), new Proposal("Tim", "name = (Tim)", true, "name = (Tim)", 11),
new Proposal("Timothy", "name = (Timothy)", true, "name = (Timothy)", 15)); new Proposal("Timothy", "name = (Timothy)", true, "name = (Timothy)", 15));
@@ -141,20 +156,20 @@ public class ProposerTest {
} }
public void testProposalOnEmptyValuePrefix() throws Exception { public void testProposalOnEmptyValuePrefix() throws Exception {
assertProposals("name=", ResultMode.FULL_VALUES, 5, // assertProposals("name=|", ResultMode.FULL_VALUES, //
new Proposal("Jennifer", "name=Jennifer", true, "name=Jennifer", 13), // new Proposal("Jennifer", "name=Jennifer", true, "name=Jennifer", 13), //
new Proposal("Jenny", "name=Jenny", true, "name=Jenny", 10), // new Proposal("Jenny", "name=Jenny", true, "name=Jenny", 10), //
new Proposal("Tim", "name=Tim", true, "name=Tim", 8), // new Proposal("Tim", "name=Tim", true, "name=Tim", 8), //
new Proposal("Timothy", "name=Timothy", true, "name=Timothy", 12) // new Proposal("Timothy", "name=Timothy", true, "name=Timothy", 12) //
); );
assertProposals("method=", ResultMode.CUT_AT_DOT, 7, // assertProposals("method=|", ResultMode.CUT_AT_DOT, //
new Proposal("FooController.", "method=FooController.", true, "method=FooController.", 21), // new Proposal("FooController.", "method=FooController.", true, "method=FooController.", 21), //
new Proposal("FooService.", "method=FooService.", true, "method=FooService.", 18), // new Proposal("FooService.", "method=FooService.", true, "method=FooService.", 18), //
new Proposal("BarController.", "method=BarController.", true, "method=BarController.", 21), // new Proposal("BarController.", "method=BarController.", true, "method=BarController.", 21), //
new Proposal("FooBarService.", "method=FooBarService.", true, "method=FooBarService.", 21) // new Proposal("FooBarService.", "method=FooBarService.", true, "method=FooBarService.", 21) //
); );
assertProposals("method=", ResultMode.FULL_VALUES, 7, // assertProposals("method=|", ResultMode.FULL_VALUES, //
new Proposal("FooController.doImportantStuff", "method=FooController.doImportantStuff", true, new Proposal("FooController.doImportantStuff", "method=FooController.doImportantStuff", true,
"method=FooController.doImportantStuff", 37), // "method=FooController.doImportantStuff", 37), //
new Proposal("FooService.doImportantStuff", "method=FooService.doImportantStuff", true, new Proposal("FooService.doImportantStuff", "method=FooService.doImportantStuff", true,
@@ -167,7 +182,7 @@ public class ProposerTest {
} }
public void testProposalOnValueSmartExpression() throws Exception { public void testProposalOnValueSmartExpression() throws Exception {
assertProposals("method=Foo.", ResultMode.CUT_AT_DOT, 11, // assertProposals("method=Foo.|", ResultMode.CUT_AT_DOT, //
new Proposal("FooController.doImportantStuff", "method=FooController.doImportantStuff", true, new Proposal("FooController.doImportantStuff", "method=FooController.doImportantStuff", true,
"method=FooController.doImportantStuff", 37), // "method=FooController.doImportantStuff", 37), //
new Proposal("FooService.doImportantStuff", "method=FooService.doImportantStuff", true, new Proposal("FooService.doImportantStuff", "method=FooService.doImportantStuff", true,
@@ -176,7 +191,7 @@ public class ProposerTest {
"method=FooBarService.doOtherStuff", 33) // "method=FooBarService.doOtherStuff", 33) //
); );
assertProposals("method=Foo.*Stuf", ResultMode.CUT_AT_DOT, 16, // assertProposals("method=Foo.*Stuf|", ResultMode.CUT_AT_DOT, //
new Proposal("FooController.doImportantStuff", "method=FooController.doImportantStuff", true, new Proposal("FooController.doImportantStuff", "method=FooController.doImportantStuff", true,
"method=FooController.doImportantStuff", 37), // "method=FooController.doImportantStuff", 37), //
new Proposal("FooService.doImportantStuff", "method=FooService.doImportantStuff", true, new Proposal("FooService.doImportantStuff", "method=FooService.doImportantStuff", true,
@@ -189,7 +204,7 @@ public class ProposerTest {
// following regex: ^[a-z]*Foo.*\.[a-z]*Stuf // following regex: ^[a-z]*Foo.*\.[a-z]*Stuf
// Maybe I will change that some day and allow upper case characters before // Maybe I will change that some day and allow upper case characters before
// "Stuff". // "Stuff".
assertProposals("method=Foo.Stuf", ResultMode.CUT_AT_DOT, 15); assertProposals("method=Foo.Stuf|", ResultMode.CUT_AT_DOT);
assertProposals("method=Foo.Im", ResultMode.CUT_AT_DOT, 13, // assertProposals("method=Foo.Im", ResultMode.CUT_AT_DOT, 13, //
new Proposal("FooController.doImportantStuff", "method=FooController.doImportantStuff", true, new Proposal("FooController.doImportantStuff", "method=FooController.doImportantStuff", true,