You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by ch...@apache.org on 2016/01/12 14:08:23 UTC
[22/30] olingo-odata4 git commit: [OLINGO-834] $expand parser in Java
+ clean-up
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8925274c/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriTokenizer.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriTokenizer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriTokenizer.java
index f505a21..3b673a6 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriTokenizer.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriTokenizer.java
@@ -40,6 +40,15 @@ public class UriTokenizer {
ROOT,
IT,
+ EXPAND,
+ FILTER,
+ LEVELS,
+ ORDERBY,
+ SEARCH,
+ SELECT,
+ SKIP,
+ TOP,
+
ANY,
ALL,
@@ -53,8 +62,9 @@ public class UriTokenizer {
EQ,
STAR,
PLUS,
- MINUS,
+
NULL,
+ MAX,
// variable-value tokens (convention: mixed case)
ODataIdentifier,
@@ -76,6 +86,13 @@ public class UriTokenizer {
jsonArrayOrObject,
+ Word,
+ Phrase,
+
+ OrOperatorSearch,
+ AndOperatorSearch,
+ NotOperatorSearch,
+
OrOperator,
AndOperator,
EqualsOperator,
@@ -90,6 +107,7 @@ public class UriTokenizer {
MulOperator,
DivOperator,
ModOperator,
+ MinusOperator,
NotOperator,
CastMethod,
@@ -161,6 +179,10 @@ public class UriTokenizer {
boolean found = false;
final int previousIndex = index;
switch (allowedTokenKind) {
+ case EOF:
+ found = index >= parseString.length();
+ break;
+
// Constants
case REF:
found = nextConstant("$ref");
@@ -181,6 +203,31 @@ public class UriTokenizer {
found = nextConstant("$it");
break;
+ case EXPAND:
+ found = nextConstant("$expand");
+ break;
+ case FILTER:
+ found = nextConstant("$filter");
+ break;
+ case LEVELS:
+ found = nextConstant("$levels");
+ break;
+ case ORDERBY:
+ found = nextConstant("$orderby");
+ break;
+ case SEARCH:
+ found = nextConstant("$search");
+ break;
+ case SELECT:
+ found = nextConstant("$select");
+ break;
+ case SKIP:
+ found = nextConstant("$skip");
+ break;
+ case TOP:
+ found = nextConstant("$top");
+ break;
+
case ANY:
found = nextConstant("any");
break;
@@ -218,14 +265,12 @@ public class UriTokenizer {
case PLUS:
found = nextCharacter('+');
break;
- case MINUS:
- found = nextMinus();
- break;
+
case NULL:
found = nextConstant("null");
break;
- case EOF:
- found = index >= parseString.length();
+ case MAX:
+ found = nextConstant("max");
break;
// Identifiers
@@ -282,6 +327,25 @@ public class UriTokenizer {
found = nextJsonArrayOrObject();
break;
+ // Search
+ case Word:
+ found = nextWord();
+ break;
+ case Phrase:
+ found = nextPhrase();
+ break;
+
+ // Operators in Search Expressions
+ case OrOperatorSearch:
+ found = nextBinaryOperator("OR");
+ break;
+ case AndOperatorSearch:
+ found = nextAndOperatorSearch();
+ break;
+ case NotOperatorSearch:
+ found = nextUnaryOperator("NOT");
+ break;
+
// Operators
case OrOperator:
found = nextBinaryOperator("or");
@@ -325,8 +389,12 @@ public class UriTokenizer {
case ModOperator:
found = nextBinaryOperator("mod");
break;
+ case MinusOperator:
+ // To avoid unnecessary minus operators for negative numbers, we have to check what follows the minus sign.
+ found = nextCharacter('-') && !nextDigit() && !nextConstant("INF");
+ break;
case NotOperator:
- found = nextConstant("not") && nextWhitespace();
+ found = nextUnaryOperator("not");
break;
// Methods
@@ -444,27 +512,6 @@ public class UriTokenizer {
return found;
}
- private boolean nextMinus() {
- if(parseString.startsWith("-", index)) {
- final int lastGoodIndex = index;
-
- if(nextDoubleValue()) {
- index = lastGoodIndex;
- return false;
- } else if(nextDecimalValue()) {
- index = lastGoodIndex;
- return false;
- } else if(nextIntegerValue(true)) {
- index = lastGoodIndex;
- return false;
- } else {
- index++;
- return true;
- }
- }
- return false;
- }
-
/**
* Moves past the given string constant if found; otherwise leaves the index unchanged.
* @return whether the constant has been found at the current index
@@ -569,34 +616,6 @@ public class UriTokenizer {
}
return count > 0;
}
-
- /**
- * Moves past the given whitespace-surrounded operator constant if found;
- * otherwise leaves the index unchanged.
- * @return whether the operator has been found at the current index
- */
- private boolean nextBinaryOperator(final String operator) {
- return nextWhitespace() && nextConstant(operator) && nextWhitespace();
- }
-
- /**
- * Moves past the given method name and its immediately following opening parenthesis if found;
- * otherwise leaves the index unchanged.
- * @return whether the method has been found at the current index
- */
- private boolean nextMethod(final String methodName) {
- return nextConstant(methodName) && nextCharacter('(');
- }
-
- /**
- * Moves past (required) whitespace and the given suffix name if found;
- * otherwise leaves the index unchanged.
- * @return whether the suffix has been found at the current index
- */
- private boolean nextSuffix(final String suffixName) {
- return nextWhitespace() && nextConstant(suffixName);
- }
-
/**
* Moves past an OData identifier if found; otherwise leaves the index unchanged.
* @return whether an OData identifier has been found at the current index
@@ -650,6 +669,38 @@ public class UriTokenizer {
}
}
+ /**
+ * Moves past the given whitespace-surrounded operator constant if found.
+ * @return whether the operator has been found at the current index
+ */
+ private boolean nextBinaryOperator(final String operator) {
+ return nextWhitespace() && nextConstant(operator) && nextWhitespace();
+ }
+
+ /**
+ * Moves past the given whitespace-suffixed operator constant if found.
+ * @return whether the operator has been found at the current index
+ */
+ private boolean nextUnaryOperator(final String operator) {
+ return nextConstant(operator) && nextWhitespace();
+ }
+
+ /**
+ * Moves past the given method name and its immediately following opening parenthesis if found.
+ * @return whether the method has been found at the current index
+ */
+ private boolean nextMethod(final String methodName) {
+ return nextConstant(methodName) && nextCharacter('(');
+ }
+
+ /**
+ * Moves past (required) whitespace and the given suffix name if found.
+ * @return whether the suffix has been found at the current index
+ */
+ private boolean nextSuffix(final String suffixName) {
+ return nextWhitespace() && nextConstant(suffixName);
+ }
+
private boolean nextParameterAliasName() {
return nextCharacter('@') && nextODataIdentifier();
}
@@ -978,4 +1029,52 @@ public class UriTokenizer {
return false;
}
}
+
+ private boolean nextAndOperatorSearch() {
+ if (nextWhitespace()) {
+ final int lastGoodIndex = index;
+ if (nextUnaryOperator("OR")) {
+ return false;
+ } else if (!(nextUnaryOperator("AND"))) {
+ index = lastGoodIndex;
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ private boolean nextWord() {
+ int count = 0;
+ while (index < parseString.length()) {
+ final int code = parseString.codePointAt(index);
+ if (Character.isUnicodeIdentifierStart(code)) {
+ count++;
+ // Unicode characters outside of the Basic Multilingual Plane are represented as two Java characters.
+ index += Character.isSupplementaryCodePoint(code) ? 2 : 1;
+ } else {
+ break;
+ }
+ }
+ final String word = parseString.substring(index - count, index);
+ return count > 0 && !("OR".equals(word) || "AND".equals(word) || "NOT".equals(word));
+ }
+
+ private boolean nextPhrase() {
+ if (nextCharacter('"')) {
+ do {
+ if (nextCharacter('\\')) {
+ if (!(nextCharacter('\\') || nextCharacter('"'))) {
+ return false;
+ }
+ } else if (nextCharacter('"')) {
+ return true;
+ } else {
+ index++;
+ }
+ } while (index < parseString.length());
+ return false;
+ }
+ return false;
+ }
}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8925274c/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/AliasImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/AliasImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/AliasImpl.java
index c7d7c20..8c8dab9 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/AliasImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/AliasImpl.java
@@ -41,4 +41,8 @@ public class AliasImpl implements Alias {
return visitor.visitAlias(parameterName);
}
+ @Override
+ public String toString() {
+ return parameterName;
+ }
}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8925274c/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/EnumerationImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/EnumerationImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/EnumerationImpl.java
index 256b8d1..a238104 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/EnumerationImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/EnumerationImpl.java
@@ -53,4 +53,10 @@ public class EnumerationImpl implements Enumeration {
public <T> T accept(final ExpressionVisitor<T> visitor) throws ExpressionVisitException, ODataApplicationException {
return visitor.visitEnum(type, values);
}
+
+ @Override
+ public String toString() {
+ return type == null ? null :
+ type.getFullQualifiedName().getFullQualifiedNameAsString() + getValues();
+ }
}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8925274c/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/LambdaRefImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/LambdaRefImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/LambdaRefImpl.java
index 824943a..16232b8 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/LambdaRefImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/LambdaRefImpl.java
@@ -40,4 +40,9 @@ public class LambdaRefImpl implements LambdaRef {
public <T> T accept(final ExpressionVisitor<T> visitor) throws ExpressionVisitException, ODataApplicationException {
return visitor.visitLambdaReference(variableText);
}
+
+ @Override
+ public String toString() {
+ return variableText;
+ }
}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8925274c/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/TypeLiteralImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/TypeLiteralImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/TypeLiteralImpl.java
index 336c203..6a2a1c6 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/TypeLiteralImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/TypeLiteralImpl.java
@@ -41,4 +41,9 @@ public class TypeLiteralImpl implements TypeLiteral {
public <T> T accept(final ExpressionVisitor<T> visitor) throws ExpressionVisitException, ODataApplicationException {
return visitor.visitTypeLiteral(type);
}
+
+ @Override
+ public String toString() {
+ return type == null ? null : type.getFullQualifiedName().getFullQualifiedNameAsString();
+ }
}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8925274c/lib/server-core/src/main/resources/server-core-exceptions-i18n.properties
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/resources/server-core-exceptions-i18n.properties b/lib/server-core/src/main/resources/server-core-exceptions-i18n.properties
index 0b43f70..e178fed 100644
--- a/lib/server-core/src/main/resources/server-core-exceptions-i18n.properties
+++ b/lib/server-core/src/main/resources/server-core-exceptions-i18n.properties
@@ -81,11 +81,11 @@ UriParserSemanticException.COMPLEX_PROPERTY_OF_ENTITY_TYPE_EXPECTED=A complex pr
UriParserSemanticException.NOT_FOR_ENTITY_TYPE=Not allowed for entity type.
UriParserSemanticException.PREVIOUS_PART_TYPED=The previous part is typed.
UriParserSemanticException.RESOURCE_NOT_FOUND=Cannot find EntitySet, Singleton, ActionImport or FunctionImport with name '%1$s'.
-UriParserSemanticException.NOT_IMPLEMENTED=%1$s is not implemented!
-UriParserSemanticException.NAMESPACE_NOT_ALLOWED_AT_FIRST_ELEMENT=Namespace is not allowed for Entity Sets, Singeltons, Action Imports and Function Imports. Found '%1$s'.
-UriParserSemanticException.COMPLEX_PARAMETER_IN_RESOURCE_PATH=Complex parameters must not appear in resource path segments. Found: '%1$s'.
+UriParserSemanticException.NOT_IMPLEMENTED='%1$s' is not implemented!
+UriParserSemanticException.NAMESPACE_NOT_ALLOWED_AT_FIRST_ELEMENT=Namespace is not allowed for Entity Sets, Singletons, Action Imports and Function Imports; found '%1$s'.
+UriParserSemanticException.COMPLEX_PARAMETER_IN_RESOURCE_PATH=Complex parameters must not appear in resource path segments; found: '%1$s'.
UriParserSemanticException.FUNCTION_IMPORT_NOT_ALLOWED=Function Imports are not allowed in $filter or $orderby. Found: '%1$s'.
-UriParserSemanticException.TYPES_NOT_COMPATIBLE=Types are not compatible. Left type: '%1$s', right type: '%1$s'.
+UriParserSemanticException.TYPES_NOT_COMPATIBLE=The types '%1$s' and '%2$s' are not compatible.
UriValidationException.UNSUPPORTED_QUERY_OPTION=The query option '%1$s' is not supported.
UriValidationException.UNSUPPORTED_URI_KIND=The URI kind '%1$s' is not supported.
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8925274c/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/ExpressionParserTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/ExpressionParserTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/ExpressionParserTest.java
index 4ab7fce..94d5373 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/ExpressionParserTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/ExpressionParserTest.java
@@ -22,9 +22,11 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
import java.util.Locale;
+import org.apache.olingo.commons.api.edm.Edm;
import org.apache.olingo.server.api.OData;
import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
import org.apache.olingo.server.core.uri.parser.UriTokenizer.TokenKind;
@@ -260,9 +262,17 @@ public class ExpressionParserTest {
expression = parseMethod(TokenKind.SubstringMethod, "'abc'", "1");
assertEquals("{substring ['abc', 1]}", expression.toString());
+ assertEquals("{cast [Edm.SByte]}", parseMethod(TokenKind.CastMethod, "Edm.SByte").toString());
+ assertEquals("{cast [42, Edm.SByte]}", parseMethod(TokenKind.CastMethod, "42", "Edm.SByte").toString());
+
+ assertEquals("{isof [Edm.SByte]}", parseMethod(TokenKind.IsofMethod, "Edm.SByte").toString());
+ assertEquals("{isof [42, Edm.SByte]}", parseMethod(TokenKind.IsofMethod, "42", "Edm.SByte").toString());
+
wrongExpression("substring('abc')");
wrongExpression("substring('abc',1,2,3)");
wrongExpression("substring(1,2)");
+ wrongExpression("cast(1,2)");
+ wrongExpression("isof(Edm.Int16,2)");
}
private Expression parseMethod(TokenKind kind, String... parameters)
@@ -288,7 +298,7 @@ public class ExpressionParserTest {
private Expression parseExpression(final String expressionString)
throws UriParserException, UriValidationException {
UriTokenizer tokenizer = new UriTokenizer(expressionString);
- Expression expression = new ExpressionParser(null, odata).parse(tokenizer, null, null);
+ Expression expression = new ExpressionParser(mock(Edm.class), odata).parse(tokenizer, null, null);
assertNotNull(expression);
assertTrue(tokenizer.next(TokenKind.EOF));
return expression;
@@ -296,7 +306,7 @@ public class ExpressionParserTest {
private void wrongExpression(final String expressionString) {
try {
- new ExpressionParser(null, odata).parse(new UriTokenizer(expressionString), null, null);
+ new ExpressionParser(mock(Edm.class), odata).parse(new UriTokenizer(expressionString), null, null);
fail("Expected exception not thrown.");
} catch (final UriParserException e) {
assertNotNull(e);
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8925274c/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/UriTokenizerTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/UriTokenizerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/UriTokenizerTest.java
index af45e80..e130457 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/UriTokenizerTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/UriTokenizerTest.java
@@ -76,7 +76,7 @@ public class UriTokenizerTest {
assertTrue(tokenizer.next(TokenKind.STAR));
assertTrue(tokenizer.next(TokenKind.SLASH));
assertTrue(tokenizer.next(TokenKind.PLUS));
- assertTrue(tokenizer.next(TokenKind.MINUS));
+ assertTrue(tokenizer.next(TokenKind.MinusOperator));
assertTrue(tokenizer.next(TokenKind.EOF));
tokenizer = new UriTokenizer("any(a:true) or all(b:false)");
@@ -97,6 +97,45 @@ public class UriTokenizerTest {
}
@Test
+ public void systemQueryOptions() {
+ UriTokenizer tokenizer = new UriTokenizer("$expand=*;$filter=true;$levels=max;$orderby=false");
+ assertTrue(tokenizer.next(TokenKind.EXPAND));
+ assertTrue(tokenizer.next(TokenKind.EQ));
+ assertTrue(tokenizer.next(TokenKind.STAR));
+ assertTrue(tokenizer.next(TokenKind.SEMI));
+ assertTrue(tokenizer.next(TokenKind.FILTER));
+ assertTrue(tokenizer.next(TokenKind.EQ));
+ assertTrue(tokenizer.next(TokenKind.BooleanValue));
+ assertTrue(tokenizer.next(TokenKind.SEMI));
+ assertTrue(tokenizer.next(TokenKind.LEVELS));
+ assertTrue(tokenizer.next(TokenKind.EQ));
+ assertTrue(tokenizer.next(TokenKind.MAX));
+ assertTrue(tokenizer.next(TokenKind.SEMI));
+ assertTrue(tokenizer.next(TokenKind.ORDERBY));
+ assertTrue(tokenizer.next(TokenKind.EQ));
+ assertTrue(tokenizer.next(TokenKind.BooleanValue));
+ assertTrue(tokenizer.next(TokenKind.EOF));
+
+ tokenizer = new UriTokenizer("$search=A;$select=*;$skip=1;$top=2");
+ assertTrue(tokenizer.next(TokenKind.SEARCH));
+ assertTrue(tokenizer.next(TokenKind.EQ));
+ assertTrue(tokenizer.next(TokenKind.ODataIdentifier));
+ assertTrue(tokenizer.next(TokenKind.SEMI));
+ assertTrue(tokenizer.next(TokenKind.SELECT));
+ assertTrue(tokenizer.next(TokenKind.EQ));
+ assertTrue(tokenizer.next(TokenKind.STAR));
+ assertTrue(tokenizer.next(TokenKind.SEMI));
+ assertTrue(tokenizer.next(TokenKind.SKIP));
+ assertTrue(tokenizer.next(TokenKind.EQ));
+ assertTrue(tokenizer.next(TokenKind.IntegerValue));
+ assertTrue(tokenizer.next(TokenKind.SEMI));
+ assertTrue(tokenizer.next(TokenKind.TOP));
+ assertTrue(tokenizer.next(TokenKind.EQ));
+ assertTrue(tokenizer.next(TokenKind.IntegerValue));
+ assertTrue(tokenizer.next(TokenKind.EOF));
+ }
+
+ @Test
public void identifier() {
assertTrue(new UriTokenizer("name").next(TokenKind.ODataIdentifier));
assertTrue(new UriTokenizer("_name").next(TokenKind.ODataIdentifier));
@@ -390,11 +429,11 @@ public class UriTokenizerTest {
assertTrue(tokenizer.next(TokenKind.IntegerValue));
assertTrue(tokenizer.next(TokenKind.EOF));
- tokenizer = new UriTokenizer("1ne 2");
+ tokenizer = new UriTokenizer("-1ne 2");
assertTrue(tokenizer.next(TokenKind.IntegerValue));
assertFalse(tokenizer.next(TokenKind.NotEqualsOperator));
- tokenizer = new UriTokenizer("1 ne2");
+ tokenizer = new UriTokenizer("1 ne-2");
assertTrue(tokenizer.next(TokenKind.IntegerValue));
assertFalse(tokenizer.next(TokenKind.NotEqualsOperator));
@@ -404,6 +443,11 @@ public class UriTokenizerTest {
assertTrue(tokenizer.next(TokenKind.IntegerValue));
assertTrue(tokenizer.next(TokenKind.EOF));
+ assertTrue(new UriTokenizer("-x").next(TokenKind.MinusOperator));
+ assertFalse(new UriTokenizer("-1").next(TokenKind.MinusOperator));
+ assertFalse(new UriTokenizer("-INF").next(TokenKind.MinusOperator));
+ assertFalse(new UriTokenizer("+").next(TokenKind.MinusOperator));
+
assertFalse(new UriTokenizer("nottrue").next(TokenKind.NotOperator));
assertFalse(new UriTokenizer("no true").next(TokenKind.NotOperator));
@@ -484,6 +528,38 @@ public class UriTokenizerTest {
wrongToken(TokenKind.DescSuffix, " desc", 'D');
}
+ @Test
+ public void search() {
+ UriTokenizer tokenizer = new UriTokenizer("a AND b OR NOT \"c\" d");
+ assertTrue(tokenizer.next(TokenKind.Word));
+ assertTrue(tokenizer.next(TokenKind.AndOperatorSearch));
+ assertTrue(tokenizer.next(TokenKind.Word));
+ assertFalse(tokenizer.next(TokenKind.AndOperatorSearch));
+ assertTrue(tokenizer.next(TokenKind.OrOperatorSearch));
+ assertTrue(tokenizer.next(TokenKind.NotOperatorSearch));
+ assertTrue(tokenizer.next(TokenKind.Phrase));
+ assertTrue(tokenizer.next(TokenKind.AndOperatorSearch));
+ assertTrue(tokenizer.next(TokenKind.Word));
+ assertFalse(tokenizer.next(TokenKind.AndOperatorSearch));
+ assertFalse(tokenizer.next(TokenKind.Word));
+ assertFalse(tokenizer.next(TokenKind.Phrase));
+ assertTrue(tokenizer.next(TokenKind.EOF));
+
+ assertTrue(new UriTokenizer("\"a\\\\x\\\"\"").next(TokenKind.Phrase));
+ assertFalse(new UriTokenizer("\"a\\\"").next(TokenKind.Phrase));
+ assertFalse(new UriTokenizer("\"a\\x\"").next(TokenKind.Phrase));
+ wrongToken(TokenKind.Phrase, "\"a\"", '\\');
+
+ final String outsideBmpLetter = String.valueOf(Character.toChars(0x10330));
+ assertTrue(new UriTokenizer("\"" + outsideBmpLetter + "\"").next(TokenKind.Phrase));
+
+ assertTrue(new UriTokenizer(outsideBmpLetter).next(TokenKind.Word));
+ assertFalse(new UriTokenizer("1").next(TokenKind.Word));
+ assertFalse(new UriTokenizer("AND").next(TokenKind.Word));
+ assertFalse(new UriTokenizer("OR").next(TokenKind.Word));
+ assertFalse(new UriTokenizer("NOT").next(TokenKind.Word));
+ }
+
private void wrongToken(final TokenKind kind, final String value, final char disturbCharacter) {
assertFalse(new UriTokenizer(disturbCharacter + value).next(kind));
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8925274c/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java
index e028cfe..f3e50a2 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java
@@ -35,7 +35,7 @@ public class SearchParserAndTokenizerTest {
assertQuery("a AND b AND c").resultsIn("{{'a' AND 'b'} AND 'c'}");
assertQuery("a OR b").resultsIn("{'a' OR 'b'}");
assertQuery("a OR b OR c").resultsIn("{{'a' OR 'b'} OR 'c'}");
-
+
assertQuery("NOT a NOT b").resultsIn("{{NOT 'a'} AND {NOT 'b'}}");
assertQuery("NOT a AND NOT b").resultsIn("{{NOT 'a'} AND {NOT 'b'}}");
assertQuery("NOT a OR NOT b").resultsIn("{{NOT 'a'} OR {NOT 'b'}}");
@@ -59,16 +59,16 @@ public class SearchParserAndTokenizerTest {
assertQuery("a AND (b OR c)").resultsIn("{'a' AND {'b' OR 'c'}}");
assertQuery("(a OR b) AND NOT c").resultsIn("{{'a' OR 'b'} AND {NOT 'c'}}");
assertQuery("(a OR B) AND (c OR d AND NOT e OR (f))")
- .resultsIn("{{'a' OR 'B'} AND {{'c' OR {'d' AND {NOT 'e'}}} OR 'f'}}");
+ .resultsIn("{{'a' OR 'B'} AND {{'c' OR {'d' AND {NOT 'e'}}} OR 'f'}}");
assertQuery("(a OR B) (c OR d NOT e OR (f))")
- .resultsIn("{{'a' OR 'B'} AND {{'c' OR {'d' AND {NOT 'e'}}} OR 'f'}}");
+ .resultsIn("{{'a' OR 'B'} AND {{'c' OR {'d' AND {NOT 'e'}}} OR 'f'}}");
assertQuery("((((a))))").resultsIn("'a'");
assertQuery("((((a)))) ((((a))))").resultsIn("{'a' AND 'a'}");
assertQuery("((((a)))) OR ((((a))))").resultsIn("{'a' OR 'a'}");
assertQuery("((((((a)))) ((((c))) OR (((C)))) ((((a))))))").resultsIn("{{'a' AND {'c' OR 'C'}} AND 'a'}");
assertQuery("((((\"a\")))) OR ((((\"a\"))))").resultsIn("{'a' OR 'a'}");
}
-
+
@Test
public void parseImplicitAnd() throws Exception {
assertQuery("a b").resultsIn("{'a' AND 'b'}");
@@ -103,7 +103,7 @@ public class SearchParserAndTokenizerTest {
assertQuery("((a AND b OR c)").resultsIn(SearchParserException.MessageKeys.MISSING_CLOSE);
assertQuery("a AND (b OR c").resultsIn(SearchParserException.MessageKeys.MISSING_CLOSE);
assertQuery("(a AND ((b OR c)").resultsIn(SearchParserException.MessageKeys.MISSING_CLOSE);
-
+
assertQuery("NOT NOT a").resultsIn(SearchParserException.MessageKeys.INVALID_NOT_OPERAND);
assertQuery("NOT (a)").resultsIn(SearchParserException.MessageKeys.TOKENIZER_EXCEPTION);
}
@@ -186,7 +186,6 @@ public class SearchParserAndTokenizerTest {
// <Input>http://serviceRoot/Products?$search=blue</Input>
assertQuery("blue").resultsIn("'blue'");
-
// below cases can not be tested here
// <TestCase Name="5.1.7 Search - on entity container" Rule="odataUri">
// <Input>http://serviceRoot/Model.Container/$all?$search=blue</Input>
@@ -194,68 +193,47 @@ public class SearchParserAndTokenizerTest {
// <Input>http://serviceRoot/$all?$search=blue</Input>
}
-
private static Validator assertQuery(String searchQuery) {
- return Validator.init(searchQuery);
+ return new Validator(searchQuery);
}
private static class Validator {
- private boolean log;
private final String searchQuery;
private Validator(String searchQuery) {
this.searchQuery = searchQuery;
}
- private static Validator init(String searchQuery) {
- return new Validator(searchQuery);
- }
-
- @SuppressWarnings("unused")
- private Validator withLogging() {
- log = true;
- return this;
- }
-
- private void resultsIn(SearchParserException.MessageKey key)
- throws SearchTokenizerException {
+ private void resultsIn(SearchParserException.MessageKey key) throws SearchTokenizerException {
try {
resultsIn(searchQuery);
} catch (SearchParserException e) {
Assert.assertEquals("SearchParserException with unexpected message '" + e.getMessage() +
"' was thrown.", key, e.getMessageKey());
- if(log) {
- System.out.println("Caught SearchParserException with message key " +
- e.getMessageKey() + " and message " + e.getMessage());
- }
return;
}
Assert.fail("SearchParserException with message key " + key.getKey() + " was not thrown.");
}
-
+
public void resultsInExpectedTerm(final String actualToken) throws SearchTokenizerException {
try {
resultsIn(searchQuery);
- } catch(SearchParserException e) {
+ } catch (SearchParserException e) {
Assert.assertEquals(SearchParserException.MessageKeys.EXPECTED_DIFFERENT_TOKEN, e.getMessageKey());
Assert.assertEquals("Expected PHRASE||WORD found: " + actualToken, e.getMessage());
}
}
-
+
private void resultsIn(String expectedSearchExpression) throws SearchTokenizerException, SearchParserException {
final SearchExpression searchExpression = getSearchExpression();
Assert.assertEquals(expectedSearchExpression, searchExpression.toString());
}
private SearchExpression getSearchExpression() throws SearchParserException, SearchTokenizerException {
- SearchParser tokenizer = new SearchParser();
- SearchOption result = tokenizer.parse(searchQuery);
+ SearchOption result = new SearchParser().parse(searchQuery);
Assert.assertNotNull(result);
final SearchExpression searchExpression = result.getSearchExpression();
Assert.assertNotNull(searchExpression);
- if (log) {
- System.out.println(searchExpression);
- }
return searchExpression;
}
}