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/09/29 14:32:12 UTC
[7/7] olingo-odata4 git commit: [OLINGO-1028] stricter multiplicity
tests in expression parser + clean-up
[OLINGO-1028] stricter multiplicity tests in expression parser + clean-up
Signed-off-by: Christian Amend <ch...@sap.com>
Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo
Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/72fcaa1a
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/72fcaa1a
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/72fcaa1a
Branch: refs/heads/master
Commit: 72fcaa1a54a3607ee2b94f66414677ab6f9c8e92
Parents: b9a71ff
Author: Klaus Straubinger <kl...@sap.com>
Authored: Thu Sep 29 16:25:33 2016 +0200
Committer: Christian Amend <ch...@sap.com>
Committed: Thu Sep 29 16:31:24 2016 +0200
----------------------------------------------------------------------
.../core/uri/parser/ExpressionParser.java | 59 +-
.../uri/parser/UriParserSemanticException.java | 3 +-
.../uri/queryoption/expression/MemberImpl.java | 14 +-
.../server-core-exceptions-i18n.properties | 1 +
.../core/uri/parser/ExpandParserTest.java | 561 ++
.../core/uri/parser/ExpressionParserTest.java | 2389 +++++++
.../core/uri/parser/ResourcePathParserTest.java | 2100 ++++++
.../core/uri/parser/SearchParserTest.java | 187 +
.../core/uri/parser/SelectParserTest.java | 177 +
.../core/uri/parser/TestFullResourcePath.java | 6003 ------------------
.../core/uri/parser/TestUriParserImpl.java | 1047 ---
.../server/core/uri/parser/UriParserTest.java | 843 +++
.../core/uri/testutil/ResourceValidator.java | 221 +-
13 files changed, 6388 insertions(+), 7217 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/72fcaa1a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpressionParser.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpressionParser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpressionParser.java
index 23fd8a4..7a34095 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpressionParser.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpressionParser.java
@@ -180,15 +180,19 @@ public class ExpressionParser {
this.crossjoinEntitySetNames = crossjoinEntitySetNames;
this.aliases = aliases;
- return parseExpression();
+ final Expression expression = parseExpression();
+ checkNoCollection(expression);
+ return expression;
}
private Expression parseExpression() throws UriParserException, UriValidationException {
Expression left = parseAnd();
while (tokenizer.next(TokenKind.OrOperator)) {
- final Expression right = parseAnd();
checkType(left, EdmPrimitiveTypeKind.Boolean);
+ checkNoCollection(left);
+ final Expression right = parseAnd();
checkType(right, EdmPrimitiveTypeKind.Boolean);
+ checkNoCollection(right);
left = new BinaryImpl(left, BinaryOperatorKind.OR, right,
odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Boolean));
}
@@ -198,9 +202,11 @@ public class ExpressionParser {
private Expression parseAnd() throws UriParserException, UriValidationException {
Expression left = parseExprEquality();
while (tokenizer.next(TokenKind.AndOperator)) {
- final Expression right = parseExprEquality();
checkType(left, EdmPrimitiveTypeKind.Boolean);
+ checkNoCollection(left);
+ final Expression right = parseExprEquality();
checkType(right, EdmPrimitiveTypeKind.Boolean);
+ checkNoCollection(right);
left = new BinaryImpl(left, BinaryOperatorKind.AND, right,
odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Boolean));
}
@@ -285,8 +291,8 @@ public class ExpressionParser {
TokenKind.MulOperator, TokenKind.DivOperator, TokenKind.ModOperator);
// Null for everything other than MUL or DIV or MOD
while (operatorTokenKind != null) {
- final Expression right = parseExprUnary();
checkNumericType(left);
+ final Expression right = parseExprUnary();
checkNumericType(right);
left = new BinaryImpl(left, tokenToBinaryOperator.get(operatorTokenKind), right,
odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Double));
@@ -306,6 +312,7 @@ public class ExpressionParser {
} else if (tokenizer.next(TokenKind.NotOperator)) {
final Expression expression = parseExprPrimary();
checkType(expression, EdmPrimitiveTypeKind.Boolean);
+ checkNoCollection(expression);
return new UnaryImpl(UnaryOperatorKind.NOT, expression, getType(expression));
} else if (tokenizer.next(TokenKind.CastMethod)) {
return parseIsOfOrCastMethod(MethodKind.CAST);
@@ -443,6 +450,7 @@ public class ExpressionParser {
case TRIM:
final Expression stringParameter = parseExpression();
checkType(stringParameter, EdmPrimitiveTypeKind.String);
+ checkNoCollection(stringParameter);
parameters.add(stringParameter);
break;
case YEAR:
@@ -450,6 +458,7 @@ public class ExpressionParser {
case DAY:
final Expression dateParameter = parseExpression();
checkType(dateParameter, EdmPrimitiveTypeKind.Date, EdmPrimitiveTypeKind.DateTimeOffset);
+ checkNoCollection(dateParameter);
parameters.add(dateParameter);
break;
case HOUR:
@@ -458,6 +467,7 @@ public class ExpressionParser {
case FRACTIONALSECONDS:
final Expression timeParameter = parseExpression();
checkType(timeParameter, EdmPrimitiveTypeKind.TimeOfDay, EdmPrimitiveTypeKind.DateTimeOffset);
+ checkNoCollection(timeParameter);
parameters.add(timeParameter);
break;
case DATE:
@@ -465,11 +475,13 @@ public class ExpressionParser {
case TOTALOFFSETMINUTES:
final Expression dateTimeParameter = parseExpression();
checkType(dateTimeParameter, EdmPrimitiveTypeKind.DateTimeOffset);
+ checkNoCollection(dateTimeParameter);
parameters.add(dateTimeParameter);
break;
case TOTALSECONDS:
final Expression durationParameter = parseExpression();
checkType(durationParameter, EdmPrimitiveTypeKind.Duration);
+ checkNoCollection(durationParameter);
parameters.add(durationParameter);
break;
case ROUND:
@@ -478,12 +490,14 @@ public class ExpressionParser {
final Expression decimalParameter = parseExpression();
checkType(decimalParameter,
EdmPrimitiveTypeKind.Decimal, EdmPrimitiveTypeKind.Single, EdmPrimitiveTypeKind.Double);
+ checkNoCollection(decimalParameter);
parameters.add(decimalParameter);
break;
case GEOLENGTH:
final Expression geoParameter = parseExpression();
checkType(geoParameter,
EdmPrimitiveTypeKind.GeographyLineString, EdmPrimitiveTypeKind.GeometryLineString);
+ checkNoCollection(geoParameter);
parameters.add(geoParameter);
break;
@@ -495,30 +509,36 @@ public class ExpressionParser {
case CONCAT:
final Expression stringParameter1 = parseExpression();
checkType(stringParameter1, EdmPrimitiveTypeKind.String);
+ checkNoCollection(stringParameter1);
parameters.add(stringParameter1);
ParserHelper.requireNext(tokenizer, TokenKind.COMMA);
final Expression stringParameter2 = parseExpression();
checkType(stringParameter2, EdmPrimitiveTypeKind.String);
+ checkNoCollection(stringParameter2);
parameters.add(stringParameter2);
break;
case GEODISTANCE:
final Expression geoParameter1 = parseExpression();
checkType(geoParameter1, EdmPrimitiveTypeKind.GeographyPoint, EdmPrimitiveTypeKind.GeometryPoint);
+ checkNoCollection(geoParameter1);
parameters.add(geoParameter1);
ParserHelper.requireNext(tokenizer, TokenKind.COMMA);
final Expression geoParameter2 = parseExpression();
checkType(geoParameter2, EdmPrimitiveTypeKind.GeographyPoint, EdmPrimitiveTypeKind.GeometryPoint);
+ checkNoCollection(geoParameter2);
parameters.add(geoParameter2);
break;
case GEOINTERSECTS:
final Expression geoPointParameter = parseExpression();
checkType(geoPointParameter,
EdmPrimitiveTypeKind.GeographyPoint, EdmPrimitiveTypeKind.GeometryPoint);
+ checkNoCollection(geoPointParameter);
parameters.add(geoPointParameter);
ParserHelper.requireNext(tokenizer, TokenKind.COMMA);
final Expression geoPolygonParameter = parseExpression();
checkType(geoPolygonParameter,
EdmPrimitiveTypeKind.GeographyPolygon, EdmPrimitiveTypeKind.GeometryPolygon);
+ checkNoCollection(geoPolygonParameter);
parameters.add(geoPolygonParameter);
break;
@@ -526,6 +546,7 @@ public class ExpressionParser {
case SUBSTRING:
final Expression parameterFirst = parseExpression();
checkType(parameterFirst, EdmPrimitiveTypeKind.String);
+ checkNoCollection(parameterFirst);
parameters.add(parameterFirst);
ParserHelper.requireNext(tokenizer, TokenKind.COMMA);
final Expression parameterSecond = parseExpression();
@@ -905,8 +926,9 @@ public class ExpressionParser {
} else if (tokenizer.next(TokenKind.ALL)) {
uriInfo.addResourcePart(parseLambdaRest(TokenKind.ALL, lastResource));
} else if (tokenizer.next(TokenKind.QualifiedName)) {
- final FullQualifiedName fullQualifiedName = new FullQualifiedName(tokenizer.getText());
- parseBoundFunction(fullQualifiedName, uriInfo, lastResource);
+ parseBoundFunction(new FullQualifiedName(tokenizer.getText()), uriInfo, lastResource);
+ } else {
+ throw new UriParserSyntaxException("Unexpected token.", UriParserSyntaxException.MessageKeys.SYNTAX);
}
}
@@ -1071,13 +1093,22 @@ public class ExpressionParser {
}
}
+ private void checkNoCollection(final Expression expression) throws UriParserException {
+ if (expression instanceof Member && ((Member) expression).isCollection()) {
+ throw new UriParserSemanticException("Collection not allowed.",
+ UriParserSemanticException.MessageKeys.COLLECTION_NOT_ALLOWED);
+ }
+ }
+
protected void checkIntegerType(final Expression expression) throws UriParserException {
+ checkNoCollection(expression);
checkType(expression,
EdmPrimitiveTypeKind.Int64, EdmPrimitiveTypeKind.Int32, EdmPrimitiveTypeKind.Int16,
EdmPrimitiveTypeKind.Byte, EdmPrimitiveTypeKind.SByte);
}
protected void checkNumericType(final Expression expression) throws UriParserException {
+ checkNoCollection(expression);
checkType(expression,
EdmPrimitiveTypeKind.Int64, EdmPrimitiveTypeKind.Int32, EdmPrimitiveTypeKind.Int16,
EdmPrimitiveTypeKind.Byte, EdmPrimitiveTypeKind.SByte,
@@ -1085,6 +1116,9 @@ public class ExpressionParser {
}
private void checkEqualityTypes(final Expression left, final Expression right) throws UriParserException {
+ checkNoCollection(left);
+ checkNoCollection(right);
+
final EdmType leftType = getType(left);
final EdmType rightType = getType(right);
if (leftType == null || rightType == null || leftType.equals(rightType)) {
@@ -1141,11 +1175,10 @@ public class ExpressionParser {
}
private void checkRelationTypes(final Expression left, final Expression right) throws UriParserException {
+ checkNoCollection(left);
+ checkNoCollection(right);
final EdmType leftType = getType(left);
final EdmType rightType = getType(right);
- if (leftType == null || rightType == null) {
- return;
- }
checkType(left,
EdmPrimitiveTypeKind.Int16, EdmPrimitiveTypeKind.Int32, EdmPrimitiveTypeKind.Int64,
EdmPrimitiveTypeKind.Byte, EdmPrimitiveTypeKind.SByte,
@@ -1160,6 +1193,9 @@ public class ExpressionParser {
EdmPrimitiveTypeKind.Boolean, EdmPrimitiveTypeKind.Guid, EdmPrimitiveTypeKind.String,
EdmPrimitiveTypeKind.Date, EdmPrimitiveTypeKind.TimeOfDay,
EdmPrimitiveTypeKind.DateTimeOffset, EdmPrimitiveTypeKind.Duration);
+ if (leftType == null || rightType == null) {
+ return;
+ }
if (!(((EdmPrimitiveType) leftType).isCompatible((EdmPrimitiveType) rightType)
|| ((EdmPrimitiveType) rightType).isCompatible((EdmPrimitiveType) leftType))) {
throw new UriParserSemanticException("Incompatible types.",
@@ -1171,11 +1207,10 @@ public class ExpressionParser {
private EdmType getAddSubTypeAndCheckLeftAndRight(final Expression left, final Expression right, final boolean isSub)
throws UriParserException {
+ checkNoCollection(left);
+ checkNoCollection(right);
final EdmType leftType = getType(left);
final EdmType rightType = getType(right);
- if (leftType == null || rightType == null) {
- return null;
- }
if (isType(leftType,
EdmPrimitiveTypeKind.Int16, EdmPrimitiveTypeKind.Int32, EdmPrimitiveTypeKind.Int64,
EdmPrimitiveTypeKind.Byte, EdmPrimitiveTypeKind.SByte,
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/72fcaa1a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParserSemanticException.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParserSemanticException.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParserSemanticException.java
index f2c4634..8260af7 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParserSemanticException.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParserSemanticException.java
@@ -74,7 +74,8 @@ public class UriParserSemanticException extends UriParserException {
/** parameter: expression */
ONLY_FOR_PRIMITIVE_TYPES,
/** parameter: function name */
- FUNCTION_MUST_USE_COLLECTIONS;
+ FUNCTION_MUST_USE_COLLECTIONS,
+ COLLECTION_NOT_ALLOWED;
@Override
public String getKey() {
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/72fcaa1a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/MemberImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/MemberImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/MemberImpl.java
index 3306565..4a67231 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/MemberImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/MemberImpl.java
@@ -21,6 +21,8 @@ package org.apache.olingo.server.core.uri.queryoption.expression;
import org.apache.olingo.commons.api.edm.EdmType;
import org.apache.olingo.server.api.ODataApplicationException;
import org.apache.olingo.server.api.uri.UriInfoResource;
+import org.apache.olingo.server.api.uri.UriResource;
+import org.apache.olingo.server.api.uri.UriResourcePartTyped;
import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitException;
import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitor;
import org.apache.olingo.server.api.uri.queryoption.expression.Member;
@@ -85,14 +87,10 @@ public class MemberImpl implements Member {
@Override
public boolean isCollection() {
UriInfoImpl uriInfo = (UriInfoImpl) path;
- UriResourceImpl lastResourcePart = (UriResourceImpl) uriInfo.getLastResourcePart();
- if (lastResourcePart instanceof UriResourceTypedImpl) {
- UriResourceTypedImpl lastTyped = (UriResourceTypedImpl) lastResourcePart;
- return lastTyped.isCollection();
- } else if (lastResourcePart instanceof UriResourceActionImpl) {
- return ((UriResourceActionImpl) lastResourcePart).isCollection();
- }
- return false;
+ UriResource lastResourcePart = uriInfo.getLastResourcePart();
+ return lastResourcePart instanceof UriResourcePartTyped ?
+ ((UriResourcePartTyped) lastResourcePart).isCollection() :
+ false;
}
@Override
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/72fcaa1a/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 831fe37..5768565 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
@@ -76,6 +76,7 @@ UriParserSemanticException.NOT_A_MEDIA_RESOURCE=The resource '%1$s' is not a med
UriParserSemanticException.IS_PROPERTY=The identifier '%1$s' is already used as a property.
UriParserSemanticException.ONLY_FOR_PRIMITIVE_TYPES='%1$s' is only allowed for primitive-type expressions.
UriParserSemanticException.FUNCTION_MUST_USE_COLLECTIONS=Only bound functions with collections of structural types as binding parameter and as return type are allowed; '%1$s' is not such a function.
+UriParserSemanticException.COLLECTION_NOT_ALLOWED=A collection expression is not allowed.
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/72fcaa1a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/parser/ExpandParserTest.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/parser/ExpandParserTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/parser/ExpandParserTest.java
new file mode 100644
index 0000000..ebc4cc6
--- /dev/null
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/parser/ExpandParserTest.java
@@ -0,0 +1,561 @@
+/*
+ * 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.apache.olingo.server.core.uri.parser;
+
+import java.util.Collections;
+
+import org.apache.olingo.commons.api.edm.Edm;
+import org.apache.olingo.commons.api.edmx.EdmxReference;
+import org.apache.olingo.server.api.OData;
+import org.apache.olingo.server.api.uri.UriInfoKind;
+import org.apache.olingo.server.core.uri.parser.UriParserSemanticException.MessageKeys;
+import org.apache.olingo.server.core.uri.testutil.TestUriValidator;
+import org.apache.olingo.server.tecsvc.provider.ComplexTypeProvider;
+import org.apache.olingo.server.tecsvc.provider.EdmTechProvider;
+import org.apache.olingo.server.tecsvc.provider.EntityTypeProvider;
+import org.apache.olingo.server.tecsvc.provider.PropertyProvider;
+import org.junit.Test;
+
+/** Tests of the parts of the URI parser that parse the sytem query option $expand. */
+public class ExpandParserTest {
+
+ private static final Edm edm = OData.newInstance().createServiceMetadata(
+ new EdmTechProvider(), Collections.<EdmxReference> emptyList()).getEdm();
+
+ private final TestUriValidator testUri = new TestUriValidator().setEdm(edm);
+
+ @Test
+ public void expandStar() throws Exception {
+ testUri.run("ESKeyNav(1)", "$expand=*")
+ .isKind(UriInfoKind.resource).goExpand()
+ .first()
+ .isSegmentStar();
+
+ testUri.run("ESKeyNav(1)", "$expand=*/$ref")
+ .isKind(UriInfoKind.resource).goExpand()
+ .first()
+ .isSegmentStar()
+ .isSegmentRef();
+
+ testUri.run("ESKeyNav(1)", "$expand=*/$ref,NavPropertyETKeyNavMany")
+ .isKind(UriInfoKind.resource).goExpand()
+ .first()
+ .isSegmentStar().isSegmentRef()
+ .next()
+ .goPath().first()
+ .isNavProperty("NavPropertyETKeyNavMany", EntityTypeProvider.nameETKeyNav, true);
+
+ testUri.run("ESKeyNav(1)", "$expand=*($levels=3)")
+ .isKind(UriInfoKind.resource).goExpand()
+ .first()
+ .isSegmentStar()
+ .isLevelText("3");
+
+ testUri.run("ESKeyNav(1)", "$expand=*($levels=max)")
+ .isKind(UriInfoKind.resource).goExpand()
+ .first()
+ .isSegmentStar()
+ .isLevelText("max");
+ }
+
+ @Test
+ public void expandNavigationRef() throws Exception {
+ testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavMany/$ref")
+ .isKind(UriInfoKind.resource).goExpand()
+ .first()
+ .goPath().first()
+ .isNavProperty("NavPropertyETKeyNavMany", EntityTypeProvider.nameETKeyNav, true)
+ .isType(EntityTypeProvider.nameETKeyNav, true)
+ .n().isRef();
+
+ testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavOne/$ref")
+ .isKind(UriInfoKind.resource).goExpand()
+ .first()
+ .goPath().first()
+ .isNavProperty("NavPropertyETKeyNavOne", EntityTypeProvider.nameETKeyNav, false)
+ .isType(EntityTypeProvider.nameETKeyNav, false)
+ .n().isRef();
+
+ testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavMany/$ref($filter=PropertyInt16 eq 1)")
+ .isKind(UriInfoKind.resource).goExpand()
+ .first()
+ .goPath().first()
+ .isNavProperty("NavPropertyETKeyNavMany", EntityTypeProvider.nameETKeyNav, true)
+ .isType(EntityTypeProvider.nameETKeyNav, true)
+ .n().isRef()
+ .goUpExpandValidator().goFilter().is("<<PropertyInt16> eq <1>>");
+
+ testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavMany/$ref($orderby=PropertyInt16)")
+ .isKind(UriInfoKind.resource).goExpand()
+ .first()
+ .goPath().first()
+ .isNavProperty("NavPropertyETKeyNavMany", EntityTypeProvider.nameETKeyNav, true)
+ .isType(EntityTypeProvider.nameETKeyNav, true)
+ .n().isRef()
+ .goUpExpandValidator()
+ .isSortOrder(0, false)
+ .goOrder(0).goPath().isPrimitiveProperty("PropertyInt16", PropertyProvider.nameInt16, false);
+
+ testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavMany/$ref($skip=1)")
+ .isKind(UriInfoKind.resource).goExpand()
+ .first()
+ .goPath().first()
+ .isNavProperty("NavPropertyETKeyNavMany", EntityTypeProvider.nameETKeyNav, true)
+ .isType(EntityTypeProvider.nameETKeyNav, true)
+ .n().isRef()
+ .goUpExpandValidator()
+ .isSkipText("1");
+
+ testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavMany/$ref($top=2)")
+ .isKind(UriInfoKind.resource).goExpand()
+ .first()
+ .goPath().first()
+ .isNavProperty("NavPropertyETKeyNavMany", EntityTypeProvider.nameETKeyNav, true)
+ .isType(EntityTypeProvider.nameETKeyNav, true)
+ .n().isRef()
+ .goUpExpandValidator()
+ .isTopText("2");
+
+ testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavMany/$ref($count=true)")
+ .isKind(UriInfoKind.resource).goExpand()
+ .first()
+ .goPath().first()
+ .isNavProperty("NavPropertyETKeyNavMany", EntityTypeProvider.nameETKeyNav, true)
+ .isType(EntityTypeProvider.nameETKeyNav, true)
+ .n().isRef()
+ .goUpExpandValidator()
+ .isInlineCountText("true");
+
+ testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavMany/$ref($skip=1;$top=3)")
+ .isKind(UriInfoKind.resource).goExpand()
+ .first()
+ .goPath().first()
+ .isNavProperty("NavPropertyETKeyNavMany", EntityTypeProvider.nameETKeyNav, true)
+ .isType(EntityTypeProvider.nameETKeyNav, true)
+ .n().isRef()
+ .goUpExpandValidator()
+ .isSkipText("1")
+ .isTopText("3");
+
+ testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavMany/$ref($skip=1%3b$top=3)")
+ .isKind(UriInfoKind.resource).goExpand()
+ .first()
+ .goPath().first()
+ .isNavProperty("NavPropertyETKeyNavMany", EntityTypeProvider.nameETKeyNav, true)
+ .isType(EntityTypeProvider.nameETKeyNav, true)
+ .n().isRef()
+ .goUpExpandValidator()
+ .isSkipText("1")
+ .isTopText("3");
+ }
+
+ @Test
+ public void expandNavigationCount() throws Exception {
+ testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavMany/$count")
+ .isKind(UriInfoKind.resource).goExpand()
+ .first()
+ .goPath().first()
+ .isNavProperty("NavPropertyETKeyNavMany", EntityTypeProvider.nameETKeyNav, true)
+ .isType(EntityTypeProvider.nameETKeyNav, true)
+ .n().isCount();
+
+ testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavOne/$count")
+ .isKind(UriInfoKind.resource).goExpand()
+ .first()
+ .goPath().first()
+ .isNavProperty("NavPropertyETKeyNavOne", EntityTypeProvider.nameETKeyNav, false)
+ .isType(EntityTypeProvider.nameETKeyNav, false)
+ .n().isCount();
+
+ testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavMany/$count($filter=PropertyInt16 gt 1)")
+ .isKind(UriInfoKind.resource).goExpand()
+ .first()
+ .goPath().first()
+ .isNavProperty("NavPropertyETKeyNavMany", EntityTypeProvider.nameETKeyNav, true)
+ .isType(EntityTypeProvider.nameETKeyNav, true)
+ .n().isCount()
+ .goUpExpandValidator()
+ .goFilter().is("<<PropertyInt16> gt <1>>");
+ }
+
+ @Test
+ public void expandNavigationOptions() throws Exception {
+ testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavMany($filter=PropertyInt16 eq 1)")
+ .isKind(UriInfoKind.resource).goExpand()
+ .first()
+ .goPath().first()
+ .isNavProperty("NavPropertyETKeyNavMany", EntityTypeProvider.nameETKeyNav, true)
+ .isType(EntityTypeProvider.nameETKeyNav, true)
+ .goUpExpandValidator().goFilter().is("<<PropertyInt16> eq <1>>");
+
+ testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavMany($orderby=PropertyInt16)")
+ .isKind(UriInfoKind.resource).goExpand()
+ .first()
+ .goPath().first()
+ .isNavProperty("NavPropertyETKeyNavMany", EntityTypeProvider.nameETKeyNav, true)
+ .isType(EntityTypeProvider.nameETKeyNav, true)
+ .goUpExpandValidator()
+ .isSortOrder(0, false)
+ .goOrder(0).goPath().isPrimitiveProperty("PropertyInt16", PropertyProvider.nameInt16, false);
+
+ testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavMany($skip=1)")
+ .isKind(UriInfoKind.resource).goExpand()
+ .first()
+ .goPath().first()
+ .isNavProperty("NavPropertyETKeyNavMany", EntityTypeProvider.nameETKeyNav, true)
+ .isType(EntityTypeProvider.nameETKeyNav, true)
+ .goUpExpandValidator()
+ .isSkipText("1");
+
+ testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavMany($top=2)")
+ .isKind(UriInfoKind.resource).goExpand()
+ .first()
+ .goPath().first()
+ .isNavProperty("NavPropertyETKeyNavMany", EntityTypeProvider.nameETKeyNav, true)
+ .isType(EntityTypeProvider.nameETKeyNav, true)
+ .goUpExpandValidator()
+ .isTopText("2");
+
+ testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavMany($count=true)")
+ .isKind(UriInfoKind.resource).goExpand()
+ .first()
+ .goPath().first()
+ .isNavProperty("NavPropertyETKeyNavMany", EntityTypeProvider.nameETKeyNav, true)
+ .isType(EntityTypeProvider.nameETKeyNav, true)
+ .goUpExpandValidator()
+ .isInlineCountText("true");
+
+ testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavMany($select=PropertyString)")
+ .isKind(UriInfoKind.resource).goExpand()
+ .first()
+ .goPath().first()
+ .isNavProperty("NavPropertyETKeyNavMany", EntityTypeProvider.nameETKeyNav, true)
+ .isType(EntityTypeProvider.nameETKeyNav, true)
+ .goUpExpandValidator()
+ .goSelectItem(0).isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false);
+
+ testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavMany($expand=NavPropertyETTwoKeyNavOne)")
+ .isKind(UriInfoKind.resource).goExpand()
+ .first()
+ .goPath().first()
+ .isNavProperty("NavPropertyETKeyNavMany", EntityTypeProvider.nameETKeyNav, true)
+ .isType(EntityTypeProvider.nameETKeyNav, true)
+ .goUpExpandValidator()
+ .goExpand()
+ .goPath().first()
+ .isNavProperty("NavPropertyETTwoKeyNavOne", EntityTypeProvider.nameETTwoKeyNav, false);
+
+ testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavMany($expand=NavPropertyETKeyNavMany)")
+ .isKind(UriInfoKind.resource).goExpand()
+ .first()
+ .goPath().first()
+ .isNavProperty("NavPropertyETKeyNavMany", EntityTypeProvider.nameETKeyNav, true)
+ .isType(EntityTypeProvider.nameETKeyNav, true)
+ .goUpExpandValidator()
+ .goExpand()
+ .goPath().first()
+ .isNavProperty("NavPropertyETKeyNavMany", EntityTypeProvider.nameETKeyNav, true);
+
+ testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavOne($levels=5)")
+ .isKind(UriInfoKind.resource).goExpand()
+ .first()
+ .goPath().first()
+ .isNavProperty("NavPropertyETKeyNavOne", EntityTypeProvider.nameETKeyNav, false)
+ .isType(EntityTypeProvider.nameETKeyNav, false)
+ .goUpExpandValidator()
+ .isLevelText("5");
+
+ testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavMany($select=PropertyString)")
+ .isKind(UriInfoKind.resource).goExpand()
+ .first()
+ .goPath().first()
+ .isNavProperty("NavPropertyETKeyNavMany", EntityTypeProvider.nameETKeyNav, true)
+ .isType(EntityTypeProvider.nameETKeyNav, true)
+ .goUpExpandValidator()
+ .goSelectItem(0).isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false);
+
+ testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavOne($levels=max)")
+ .isKind(UriInfoKind.resource).goExpand()
+ .first()
+ .goPath().first()
+ .isNavProperty("NavPropertyETKeyNavOne", EntityTypeProvider.nameETKeyNav, false)
+ .isType(EntityTypeProvider.nameETKeyNav, false)
+ .goUpExpandValidator()
+ .isLevelText("max");
+
+ testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavMany($skip=1;$top=2)")
+ .isKind(UriInfoKind.resource).goExpand()
+ .first()
+ .goPath().first()
+ .isNavProperty("NavPropertyETKeyNavMany", EntityTypeProvider.nameETKeyNav, true)
+ .isType(EntityTypeProvider.nameETKeyNav, true)
+ .goUpExpandValidator()
+ .isSkipText("1")
+ .isTopText("2");
+
+ testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavMany($skip=1%3b$top=2)")
+ .isKind(UriInfoKind.resource).goExpand()
+ .first()
+ .goPath().first()
+ .isNavProperty("NavPropertyETKeyNavMany", EntityTypeProvider.nameETKeyNav, true)
+ .isType(EntityTypeProvider.nameETKeyNav, true)
+ .goUpExpandValidator()
+ .isSkipText("1")
+ .isTopText("2");
+
+ testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavMany($search=Country AND Western)")
+ .isKind(UriInfoKind.resource).goExpand()
+ .first().goPath().first().isNavProperty("NavPropertyETKeyNavMany", EntityTypeProvider.nameETKeyNav, true)
+ .goUpExpandValidator()
+ .isSearchSerialized("{'Country' AND 'Western'}");
+
+ testUri.run("ESTwoKeyNav(PropertyInt16=1,PropertyString='Hugo')", "$expand=NavPropertyETKeyNavMany")
+ .isKind(UriInfoKind.resource).goPath()
+ .first()
+ .isKeyPredicate(0, "PropertyInt16", "1")
+ .isKeyPredicate(1, "PropertyString", "'Hugo'")
+ .goUpUriValidator().goExpand()
+ .first()
+ .goPath().first()
+ .isNavProperty("NavPropertyETKeyNavMany", EntityTypeProvider.nameETKeyNav, true)
+ .isType(EntityTypeProvider.nameETKeyNav, true);
+ }
+
+ @Test
+ public void expandTypeCasts() throws Exception {
+ testUri.run("ESTwoKeyNav", "$expand=olingo.odata.test1.ETBaseTwoKeyNav/NavPropertyETKeyNavMany")
+ .isKind(UriInfoKind.resource)
+ .goExpand().first()
+ .isExpandStartType(EntityTypeProvider.nameETBaseTwoKeyNav)
+ .goPath().first()
+ .isNavProperty("NavPropertyETKeyNavMany", EntityTypeProvider.nameETKeyNav, true);
+
+ testUri.run("ESTwoKeyNav(PropertyInt16=1,PropertyString='Hugo')",
+ "$expand=olingo.odata.test1.ETBaseTwoKeyNav/NavPropertyETKeyNavMany")
+ .isKind(UriInfoKind.resource).goPath().first()
+ .isKeyPredicate(0, "PropertyInt16", "1")
+ .isKeyPredicate(1, "PropertyString", "'Hugo'")
+ .goUpUriValidator().goExpand().first()
+ .isExpandStartType(EntityTypeProvider.nameETBaseTwoKeyNav)
+ .goPath().first()
+ .isType(EntityTypeProvider.nameETKeyNav)
+ .isNavProperty("NavPropertyETKeyNavMany", EntityTypeProvider.nameETKeyNav, true);
+
+ testUri.run("ESTwoKeyNav(PropertyInt16=1,PropertyString='2')",
+ "$expand=olingo.odata.test1.ETBaseTwoKeyNav/NavPropertyETTwoKeyNavMany")
+ .isKind(UriInfoKind.resource).goPath().first()
+ .isKeyPredicate(0, "PropertyInt16", "1")
+ .isKeyPredicate(1, "PropertyString", "'2'")
+ .goUpUriValidator().goExpand().first()
+ .isExpandStartType(EntityTypeProvider.nameETBaseTwoKeyNav)
+ .goPath().first()
+ .isType(EntityTypeProvider.nameETTwoKeyNav)
+ .isNavProperty("NavPropertyETTwoKeyNavMany", EntityTypeProvider.nameETTwoKeyNav, true);
+
+ testUri.run("ESTwoKeyNav(PropertyInt16=1,PropertyString='2')",
+ "$expand=olingo.odata.test1.ETBaseTwoKeyNav/NavPropertyETTwoKeyNavMany/olingo.odata.test1.ETTwoBaseTwoKeyNav")
+ .isKind(UriInfoKind.resource).goPath().first()
+ .isKeyPredicate(0, "PropertyInt16", "1")
+ .isKeyPredicate(1, "PropertyString", "'2'")
+ .goUpUriValidator().goExpand().first()
+ .isExpandStartType(EntityTypeProvider.nameETBaseTwoKeyNav)
+ .goPath().first()
+ .isNavProperty("NavPropertyETTwoKeyNavMany", EntityTypeProvider.nameETTwoKeyNav, true)
+ .isTypeFilterOnCollection(EntityTypeProvider.nameETTwoBaseTwoKeyNav);
+
+ testUri.run("ESTwoKeyNav", "$expand=olingo.odata.test1.ETBaseTwoKeyNav/PropertyCompNav/NavPropertyETTwoKeyNavOne")
+ .isKind(UriInfoKind.resource)
+ .goExpand().first()
+ .isExpandStartType(EntityTypeProvider.nameETBaseTwoKeyNav)
+ .goPath().first()
+ .isComplexProperty("PropertyCompNav", ComplexTypeProvider.nameCTBasePrimCompNav, false)
+ .n()
+ .isNavProperty("NavPropertyETTwoKeyNavOne", EntityTypeProvider.nameETTwoKeyNav, false);
+
+ testUri.run("ESTwoKeyNav", "$expand=olingo.odata.test1.ETBaseTwoKeyNav/PropertyCompNav/*")
+ .isKind(UriInfoKind.resource)
+ .goExpand().first()
+ .isExpandStartType(EntityTypeProvider.nameETBaseTwoKeyNav)
+ .isSegmentStar()
+ .goPath().first().isComplexProperty("PropertyCompNav", ComplexTypeProvider.nameCTBasePrimCompNav, false);
+
+ testUri.run("ESTwoKeyNav", "$expand=olingo.odata.test1.ETBaseTwoKeyNav/PropertyCompNav"
+ + "/olingo.odata.test1.CTTwoBasePrimCompNav/NavPropertyETTwoKeyNavOne")
+ .isKind(UriInfoKind.resource)
+ .goExpand().first()
+ .isExpandStartType(EntityTypeProvider.nameETBaseTwoKeyNav)
+ .goPath().first()
+ .isComplexProperty("PropertyCompNav", ComplexTypeProvider.nameCTBasePrimCompNav, false)
+ .isTypeFilter(ComplexTypeProvider.nameCTTwoBasePrimCompNav)
+ .n()
+ .isNavProperty("NavPropertyETTwoKeyNavOne", EntityTypeProvider.nameETTwoKeyNav, false);
+
+ testUri.run("ESKeyNav", "$expand=NavPropertyETTwoKeyNavMany/Namespace1_Alias.ETBaseTwoKeyNav"
+ + "($expand=NavPropertyETBaseTwoKeyNavOne)")
+ .isKind(UriInfoKind.resource)
+ .goExpand().goPath().first()
+ .isNavProperty("NavPropertyETTwoKeyNavMany", EntityTypeProvider.nameETTwoKeyNav, true)
+ .isType(EntityTypeProvider.nameETTwoKeyNav, true)
+ .isTypeFilterOnCollection(EntityTypeProvider.nameETBaseTwoKeyNav)
+ .goUpExpandValidator()
+ // go to the expand options of the current expand
+ .goExpand()
+ .goPath().first()
+ .isNavProperty("NavPropertyETBaseTwoKeyNavOne", EntityTypeProvider.nameETBaseTwoKeyNav, false);
+
+ testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavMany/$ref,NavPropertyETTwoKeyNavMany($skip=2;$top=1)")
+ .isKind(UriInfoKind.resource)
+ .goExpand().first()
+ .goPath()
+ .first()
+ .isNavProperty("NavPropertyETKeyNavMany", EntityTypeProvider.nameETKeyNav, true)
+ .n().isRef()
+ .goUpExpandValidator()
+ .next()
+ .goPath()
+ .first().isNavProperty("NavPropertyETTwoKeyNavMany", EntityTypeProvider.nameETTwoKeyNav, true)
+ .goUpExpandValidator()
+ .isSkipText("2")
+ .isTopText("1");
+
+ testUri.run("ESTwoKeyNav(PropertyInt16=1,PropertyString='2')", "$expand=olingo.odata.test1.ETBaseTwoKeyNav"
+ + "/NavPropertyETTwoKeyNavMany/olingo.odata.test1.ETTwoBaseTwoKeyNav($select=PropertyString)")
+ .isKind(UriInfoKind.resource).goPath()
+ .first()
+ .isKeyPredicate(0, "PropertyInt16", "1")
+ .isKeyPredicate(1, "PropertyString", "'2'")
+ .goUpUriValidator().goExpand().first()
+ .isExpandStartType(EntityTypeProvider.nameETBaseTwoKeyNav)
+ .goPath().first()
+ .isNavProperty("NavPropertyETTwoKeyNavMany", EntityTypeProvider.nameETTwoKeyNav, true)
+ .isType(EntityTypeProvider.nameETTwoKeyNav)
+ .isTypeFilterOnCollection(EntityTypeProvider.nameETTwoBaseTwoKeyNav)
+ .goUpExpandValidator()
+ .goSelectItem(0).isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false);
+
+ testUri.run("ESKeyNav", "$expand=NavPropertyETKeyNavOne($expand=NavPropertyETKeyNavMany("
+ + "$expand=NavPropertyETKeyNavOne))")
+ .isKind(UriInfoKind.resource)
+ .goExpand().first()
+ .goPath().first()
+ .isNavProperty("NavPropertyETKeyNavOne", EntityTypeProvider.nameETKeyNav, false)
+ .isType(EntityTypeProvider.nameETKeyNav)
+ .goUpExpandValidator()
+ .goExpand().first()
+ .goPath().first()
+ .isNavProperty("NavPropertyETKeyNavMany", EntityTypeProvider.nameETKeyNav, true)
+ .isType(EntityTypeProvider.nameETKeyNav)
+ .goUpExpandValidator()
+ .goExpand().first()
+ .goPath().first()
+ .isNavProperty("NavPropertyETKeyNavOne", EntityTypeProvider.nameETKeyNav, false)
+ .isType(EntityTypeProvider.nameETKeyNav);
+
+ testUri.run("ESKeyNav", "$expand=NavPropertyETKeyNavOne($select=PropertyInt16)")
+ .isKind(UriInfoKind.resource)
+ .goExpand().first()
+ .goPath().first()
+ .isNavProperty("NavPropertyETKeyNavOne", EntityTypeProvider.nameETKeyNav, false)
+ .isType(EntityTypeProvider.nameETKeyNav)
+ .goUpExpandValidator()
+ .goSelectItem(0).isPrimitiveProperty("PropertyInt16", PropertyProvider.nameInt16, false);
+
+ testUri.run("ESKeyNav", "$expand=NavPropertyETKeyNavOne($select=PropertyCompNav/PropertyInt16)")
+ .isKind(UriInfoKind.resource)
+ .goExpand().first()
+ .goPath().first()
+ .isNavProperty("NavPropertyETKeyNavOne", EntityTypeProvider.nameETKeyNav, false)
+ .isType(EntityTypeProvider.nameETKeyNav)
+ .goUpExpandValidator()
+ .goSelectItem(0)
+ .first().isComplexProperty("PropertyCompNav", ComplexTypeProvider.nameCTNavFiveProp, false)
+ .n().isPrimitiveProperty("PropertyInt16", PropertyProvider.nameInt16, false);
+
+ testUri.runEx("ESKeyNav", "$expand=undefined")
+ .isExSemantic(MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE);
+ testUri.runEx("ESTwoKeyNav", "$expand=PropertyCompNav/undefined")
+ .isExSemantic(MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE);
+ testUri.runEx("ESTwoKeyNav", "$expand=PropertyCompNav/*+")
+ .isExSyntax(UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION);
+ }
+
+ @Test
+ public void duplicatedSystemQueryOptionsInExpand() throws Exception {
+ testUri.runEx("ESKeyNav", "$expand=NavPropertyETKeyNavOne($select=PropertyInt16;$select=PropertyInt16)")
+ .isExSyntax(UriParserSyntaxException.MessageKeys.DOUBLE_SYSTEM_QUERY_OPTION);
+
+ testUri.runEx("ESKeyNav", "$expand=NavPropertyETKeyNavOne($filter=true;$filter=true)")
+ .isExSyntax(UriParserSyntaxException.MessageKeys.DOUBLE_SYSTEM_QUERY_OPTION);
+
+ testUri.runEx("ESKeyNav", "$expand=NavPropertyETKeyNavOne($orderby=PropertyInt16;$orderby=PropertyInt16)")
+ .isExSyntax(UriParserSyntaxException.MessageKeys.DOUBLE_SYSTEM_QUERY_OPTION);
+
+ testUri.runEx("ESKeyNav", "$expand=NavPropertyETKeyNavOne($levels=2;$levels=3)")
+ .isExSyntax(UriParserSyntaxException.MessageKeys.DOUBLE_SYSTEM_QUERY_OPTION);
+
+ testUri.runEx("ESKeyNav", "$expand=NavPropertyETKeyNavOne($expand=*;$expand=*)")
+ .isExSyntax(UriParserSyntaxException.MessageKeys.DOUBLE_SYSTEM_QUERY_OPTION);
+
+ testUri.runEx("ESKeyNav", "$expand=NavPropertyETKeyNavOne($count=true;$count=true)")
+ .isExSyntax(UriParserSyntaxException.MessageKeys.DOUBLE_SYSTEM_QUERY_OPTION);
+
+ testUri.runEx("ESKeyNav", "$expand=NavPropertyETKeyNavOne($top=1;$top=1)")
+ .isExSyntax(UriParserSyntaxException.MessageKeys.DOUBLE_SYSTEM_QUERY_OPTION);
+
+ testUri.runEx("ESKeyNav", "$expand=NavPropertyETKeyNavOne($skip=2;$skip=2)")
+ .isExSyntax(UriParserSyntaxException.MessageKeys.DOUBLE_SYSTEM_QUERY_OPTION);
+
+ testUri.runEx("ESKeyNav", "$expand=NavPropertyETKeyNavOne($search=Test;$search=Test)")
+ .isExSyntax(UriParserSyntaxException.MessageKeys.DOUBLE_SYSTEM_QUERY_OPTION);
+ }
+
+ @Test
+ public void simpleKeyInExpandSystemQueryOption() throws Exception {
+ testUri.runEx("ESAllPrim(0)", "$expand=NavPropertyETTwoPrimMany(-365)($filter=PropertyString eq 'Test String1')")
+ .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
+ }
+
+ @Test
+ public void compoundKeyInExpandSystemQueryOption() throws Exception {
+ testUri.runEx("ESAllPrim(0)", "$expand=NavPropertyETTwoPrimMany(PropertyInt16=1,PropertyString=2)"
+ + "($filter=PropertyString eq 'Test String1')")
+ .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
+ }
+
+ @Test
+ public void keyPredicatesInExpandFilter() throws Exception {
+ testUri.run("ESKeyNav(0)", "$expand=NavPropertyETTwoKeyNavMany($filter=NavPropertyETTwoKeyNavMany"
+ + "(PropertyInt16=1,PropertyString='2')/PropertyInt16 eq 1)").goExpand()
+ .first().goPath().isNavProperty("NavPropertyETTwoKeyNavMany", EntityTypeProvider.nameETTwoKeyNav, true)
+ .goUpExpandValidator().goFilter()
+ .is("<<NavPropertyETTwoKeyNavMany/PropertyInt16> eq <1>>");
+ }
+
+ @Test
+ public void keyPredicatesInDoubleExpandedFilter() throws Exception {
+ testUri.run("ESKeyNav(0)", "$expand=NavPropertyETTwoKeyNavMany($expand=NavPropertyETTwoKeyNavMany"
+ + "($filter=NavPropertyETTwoKeyNavMany(PropertyInt16=1,PropertyString='2')/PropertyInt16 eq 1))")
+ .goExpand()
+ .first().goPath().isNavProperty("NavPropertyETTwoKeyNavMany", EntityTypeProvider.nameETTwoKeyNav, true)
+ .goUpExpandValidator().goExpand()
+ .first().goPath().isNavProperty("NavPropertyETTwoKeyNavMany", EntityTypeProvider.nameETTwoKeyNav, true)
+ .goUpExpandValidator().goFilter()
+ .is("<<NavPropertyETTwoKeyNavMany/PropertyInt16> eq <1>>");
+ }
+}