/*******************************************************************************
* Copyright 2013 SAP AG
*
* Licensed 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 com.sap.core.odata.core.uri.expression;
import org.junit.Test;
import com.sap.core.odata.api.edm.EdmEntityType;
import com.sap.core.odata.api.uri.expression.ExpressionKind;
import com.sap.core.odata.api.uri.expression.ExpressionParserException;
/**
* @author SAP AG
*/
public class TestParserExceptions extends TestBase {
@Test
public void testOPMparseOrderByString() {
EdmEntityType edmEtAllTypes = edmInfo.getTypeEtAllTypes();
//CASE 1
//http://services.odata.org/Northwind/Northwind.svc/Products/?$orderby=UnitPrice%20ascc
//-->Syntax error at position 10.
GetPTO(edmEtAllTypes, "String ascc").aExMsgText("Invalid sort order in OData orderby parser at position 8 in \"String ascc\".");
//CASE 2
//http://services.odata.org/Northwind/Northwind.svc/Products/?$orderby=UnitPrice%20asc,
//-->Expression expected at position 12.
GetPTO(edmEtAllTypes, "String asc,").aExMsgText("Expression expected after position 11 in \"String asc,\".");
//CASE 3
//http://services.odata.org/Northwind/Northwind.svc/Products/?$orderby=UnitPrice%20asc%20d
//-->Syntax error at position 14.
GetPTO(edmEtAllTypes, "String asc a").aExMsgText("Comma or end of expression expected at position 12 in \"String asc a\".");
//CASE 4
//http://services.odata.org/Northwind/Northwind.svc/Products/?$orderby=UnitPrice b
//-->Syntax error at position 10.
GetPTO(edmEtAllTypes, "String b").aExMsgText("Invalid sort order in OData orderby parser at position 8 in \"String b\".");
//CASE 5
//http://services.odata.org/Northwind/Northwind.svc/Products/?$orderby=UnitPrice, UnitPrice b
//-->Syntax error at position 21.
GetPTO(edmEtAllTypes, "String, String b").aExMsgText("Invalid sort order in OData orderby parser at position 16 in \"String, String b\".");
//CASE 6
//http://services.odata.org/Northwind/Northwind.svc/Products/?$orderby=UnitPrice a, UnitPrice desc
//-->Syntax error at position 10.
GetPTO(edmEtAllTypes, "String a, String desc").aExMsgText("Invalid sort order in OData orderby parser at position 8 in \"String a, String desc\".");
//CASE 7
//http://services.odata.org/Northwind/Northwind.svc/Products/?$orderby=UnitPrice asc, UnitPrice b
//-->Syntax error at position 25.
GetPTO(edmEtAllTypes, "String asc, String b").aExMsgText("Invalid sort order in OData orderby parser at position 20 in \"String asc, String b\".");
}
@Test
public void testPMvalidateEdmProperty() {
EdmEntityType edmEtAllTypes = edmInfo.getTypeEtAllTypes();
//OK
GetPTF(edmEtAllTypes, "'text' eq String").aKind(ExpressionKind.BINARY).aSerialized("{'text' eq String}");
//CASE 1
//http://services.odata.org/Northwind/Northwind.svc/Products/?$filter=NotAProperty
//-->No property 'NotAProperty' exists in type 'ODataWeb.Northwind.Model.Product' at position 10.
GetPTF(edmEtAllTypes, "NotAProperty").aExMsgText("No property \"NotAProperty\" exists in type \"TecRefScenario.EtAllTypes\" at position 1 in \"NotAProperty\".");
//CASE 2
//http://services.odata.org/Northwind/Northwind.svc/Products/?$filter='text'%20eq%20NotAProperty
//-->No property 'NotAProperty' exists in type 'ODataWeb.Northwind.Model.Product' at position 10.
GetPTF(edmEtAllTypes, "'text' eq NotAProperty").aExMsgText("No property \"NotAProperty\" exists in type \"TecRefScenario.EtAllTypes\" at position 11 in \"'text' eq NotAProperty\".");
//CASE 3
GetPTF(edmEtAllTypes, "Complex/NotAProperty").aExMsgText("No property \"NotAProperty\" exists in type \"TecRefScenario.CtAllTypes\" at position 9 in \"Complex/NotAProperty\".");
//CASE 4
GetPTF(edmEtAllTypes, "'text' eq Complex/NotAProperty").aExMsgText("No property \"NotAProperty\" exists in type \"TecRefScenario.CtAllTypes\" at position 19 in \"'text' eq Complex/NotAProperty\".");
//CASE 5
GetPTF(edmEtAllTypes, "String/NotAProperty").aExMsgText("No property \"NotAProperty\" exists in type \"Edm.String\" at position 8 in \"String/NotAProperty\".");
//CASE 6
//http://services.odata.org/Northwind/Northwind.svc/Products/?$filter='aText'/NotAProperty
//-->Exception Stack
GetPTF(edmEtAllTypes, "'aText'/NotAProperty").aExMsgText("Leftside of method operator at position 8 is not a property in \"'aText'/NotAProperty\".");
//CASE 7
//http://services.odata.org/Northwind/Northwind.svc/Products/?$filter='Hong Kong' eq ProductName/city
//--> No property 'city' exists in type 'System.String' at position 27.
GetPTF(edmEtAllTypes, "'Hong Kong' eq DateTime/city").aExMsgText("No property \"city\" exists in type \"Edm.DateTime\" at position 25 in \"'Hong Kong' eq DateTime/city\".");
//CASE 8
//http://services.odata.org/Northwind/Northwind.svc/Products/?$filter='Hong Kong' eq ProductName/city
//--> No property 'city' exists in type 'System.String' at position 27.
GetPTF(edmEtAllTypes, "'Hong Kong' eq String/city").aExMsgText("No property \"city\" exists in type \"Edm.String\" at position 23 in \"'Hong Kong' eq String/city\".");
}
@Test
public void testPMreadParameters() {
//OK
GetPTF("concat('A','B')").aSerialized("{concat('A','B')}");
//CASE 12
//http://services.odata.org/Northwind/Northwind.svc/Products(1)/Supplier?$filter=startswith()
//-->No applicable function found for 'startswith' at position 0 with the specified arguments. The functions considered are: startswith(System.String, System.String).
GetPTF("startswith()").aExType(ExpressionParserException.class).aExMsgText("No applicable method found for \"startswith\" at position 1 in \"startswith()\" with the specified arguments. Method \"startswith\" requires exact 2 argument(s).");
//CASE 13
//http://services.odata.org/Northwind/Northwind.svc/Products(1)/Supplier?$filter=startswith('A')
//-->No applicable function found for 'startswith' at position 0 with the specified arguments. The functions considered are: startswith(System.String, System.String).
GetPTF("startswith('A')").aExType(ExpressionParserException.class).aExMsgText("No applicable method found for \"startswith\" at position 1 in \"startswith('A')\" with the specified arguments. Method \"startswith\" requires exact 2 argument(s).");
//CASE 14
//http://services.odata.org/Northwind/Northwind.svc/Products(1)/Supplier?$filter=startswith('A','B')
//-->Resource not found for the segment 'Supplier'.
GetPTF("startswith('A','B')").aSerialized("{startswith('A','B')}");
//CASE 15
//http://services.odata.org/Northwind/Northwind.svc/Products(1)/Supplier?$filter=startswith('A','B','C')
//-->No applicable function found for 'startswith' at position 0 with the specified arguments. The functions considered are: startswith(System.String, System.String).
GetPTF("startswith('A','B','C')").aExType(ExpressionParserException.class).aExMsgText("No applicable method found for \"startswith\" at position 1 in \"startswith('A','B','C')\" with the specified arguments. Method \"startswith\" requires exact 2 argument(s).");
//CASE 16
GetPTF("concat()").aExMsgText("No applicable method found for \"concat\" at position 1 in \"concat()\" with the specified arguments. Method \"concat\" requires 2 or more arguments.");
//CASE 17
GetPTF("concat('A')").aExMsgText("No applicable method found for \"concat\" at position 1 in \"concat('A')\" with the specified arguments. Method \"concat\" requires 2 or more arguments.");
//CASE 18
GetPTF("concat('A','B')").aSerialized("{concat('A','B')}");
//CASE 19
GetPTF("concat('A','B','C')").aSerialized("{concat('A','B','C')}");
//CASE 20
GetPTF("'A' and concat('A')").aExMsgText("No applicable method found for \"concat\" at position 9 in \"'A' and concat('A')\" with the specified arguments. Method \"concat\" requires 2 or more arguments.");
//CASE 1
//http://services.odata.org/Northwind/Northwind.svc/Products(1)/Supplier?$filter=concat(
//-->Expression expected at position 7.
GetPTF("concat(").aExType(ExpressionParserException.class).aExMsgText("Expression expected after position 7 in \"concat(\".");
//CASE 2
//http://services.odata.org/Northwind/Northwind.svc/Products(1)/Supplier?$filter=concat(123
//-->')' or ',' expected at position 10.
GetPTF("concat(123").aExType(ExpressionParserException.class).aExMsgText("\")\" or \",\" expected after position 10 in \"concat(123\".");
//.aExMsgText("Missing closing parenthesis \")\" for opening parenthesis \"(\" at position 7 in \"concat(\".");
//CASE 3
//http://services.odata.org/Northwind/Northwind.svc/Products(1)/Supplier?$filter=concat(,
//Expression expected at position 7.
GetPTF("concat(,").aExType(ExpressionParserException.class).aExMsgText("Expression expected at position 8 in \"concat(,\".");
//CASE 4
//http://services.odata.org/Northwind/Northwind.svc/Products(1)/Supplier?$filter=concat(123,
//-->Expression expected at position 11.
GetPTF("concat(123,").aExType(ExpressionParserException.class).aExMsgText("Expression expected after position 11 in \"concat(123,\".");
//CASE 5
//min = -1, max = -1,
GetPTF("testingMINMAX1()").aSerialized("{concat()}");
GetPTF("testingMINMAX1('A')").aSerialized("{concat('A')}");
GetPTF("testingMINMAX1('A','B')").aSerialized("{concat('A','B')}");
GetPTF("testingMINMAX1('A','B','C')").aSerialized("{concat('A','B','C')}");
//CASE 6
//min = 0, max = -1,
GetPTF("testingMINMAX2()").aSerialized("{concat()}");
GetPTF("testingMINMAX2('A')").aSerialized("{concat('A')}");
GetPTF("testingMINMAX2('A','B')").aSerialized("{concat('A','B')}");
GetPTF("testingMINMAX2('A','B','C')").aSerialized("{concat('A','B','C')}");
//CASE 7
//min = 2, max = -1,
GetPTF("testingMINMAX3()").aExType(ExpressionParserException.class).aExMsgText("No applicable method found for \"concat\" at position 1 in \"testingMINMAX3()\" with the specified arguments. Method \"concat\" requires 2 or more arguments.");
GetPTF("testingMINMAX3('A')").aExType(ExpressionParserException.class).aExMsgText("No applicable method found for \"concat\" at position 1 in \"testingMINMAX3('A')\" with the specified arguments. Method \"concat\" requires 2 or more arguments.");
GetPTF("testingMINMAX3('A','B')").aSerialized("{concat('A','B')}");
GetPTF("testingMINMAX3('A','B','C')").aSerialized("{concat('A','B','C')}");
//CASE 8
//min =-1, max = 0,
GetPTF("testingMINMAX4()").aSerialized("{concat()}");
GetPTF("testingMINMAX4('A')").aExType(ExpressionParserException.class).aExMsgText("No applicable method found for \"concat\" at position 1 in \"testingMINMAX4('A')\" with the specified arguments. Method \"concat\" requires maximal 0 arguments.");
GetPTF("testingMINMAX4('A','B')").aExType(ExpressionParserException.class).aExMsgText("No applicable method found for \"concat\" at position 1 in \"testingMINMAX4('A','B')\" with the specified arguments. Method \"concat\" requires maximal 0 arguments.");
GetPTF("testingMINMAX4('A','B','C')").aExType(ExpressionParserException.class).aExMsgText("No applicable method found for \"concat\" at position 1 in \"testingMINMAX4('A','B','C')\" with the specified arguments. Method \"concat\" requires maximal 0 arguments.");
//CASE 9
//min =-1, max = 2,
GetPTF("testingMINMAX5()").aSerialized("{concat()}");
GetPTF("testingMINMAX5('A')").aSerialized("{concat('A')}");
GetPTF("testingMINMAX5('A','B')").aSerialized("{concat('A','B')}");
GetPTF("testingMINMAX5('A','B','C')").aExType(ExpressionParserException.class).aExMsgText("No applicable method found for \"concat\" at position 1 in \"testingMINMAX5('A','B','C')\" with the specified arguments. Method \"concat\" requires maximal 2 arguments.");
//CASE 10
// min =1, max = 2,
GetPTF("testingMINMAX6()").aExType(ExpressionParserException.class).aExMsgText("No applicable method found for \"concat\" at position 1 in \"testingMINMAX6()\" with the specified arguments. Method \"concat\" requires between 1 and 2 arguments.");
GetPTF("testingMINMAX6('A')").aSerialized("{concat('A')}");
GetPTF("testingMINMAX6('A','B')").aSerialized("{concat('A','B')}");
GetPTF("testingMINMAX6('A','B','C')").aExType(ExpressionParserException.class).aExMsgText("No applicable method found for \"concat\" at position 1 in \"testingMINMAX6('A','B','C')\" with the specified arguments. Method \"concat\" requires between 1 and 2 arguments.");
//CASE 11
// min =1, max = 2,
GetPTF("testingMINMAX7()").aExType(ExpressionParserException.class).aExMsgText("No applicable method found for \"concat\" at position 1 in \"testingMINMAX7()\" with the specified arguments. Method \"concat\" requires exact 1 argument(s).");
GetPTF("testingMINMAX7('A')").aSerialized("{concat('A')}");
GetPTF("testingMINMAX7('A','B')").aExType(ExpressionParserException.class).aExMsgText("No applicable method found for \"concat\" at position 1 in \"testingMINMAX7('A','B')\" with the specified arguments. Method \"concat\" requires exact 1 argument(s).");
GetPTF("testingMINMAX7('A','B','C')").aExType(ExpressionParserException.class).aExMsgText("No applicable method found for \"concat\" at position 1 in \"testingMINMAX7('A','B','C')\" with the specified arguments. Method \"concat\" requires exact 1 argument(s).");
//CASE 12
//http://services.odata.org/Northwind/Northwind.svc/Products(1)/Supplier?$filter=concat('a' 'b')
//-->')' or ',' expected at position 11.
GetPTF("concat('a' 'b')").aExMsgText("\")\" or \",\" expected after position 10 in \"concat('a' 'b')\".");
}
@Test
public void testPMreadParenthesis() {
//http://services.odata.org/Northwind/Northwind.svc/Products(1)/Supplier?$filter=(123
//-->')' or operator expected at position 4.
GetPTF("(123").aExType(ExpressionParserException.class).aExMsgText("Missing closing parenthesis \")\" for opening parenthesis \"(\" at position 1 in \"(123\".");
//http://services.odata.org/Northwind/Northwind.svc/Products(1)/Supplier?$filter=(123 add (456
//-->')' or operator expected at position 13.
GetPTF("(123 add (456").aExType(ExpressionParserException.class).aExMsgText("Missing closing parenthesis \")\" for opening parenthesis \"(\" at position 10 in \"(123 add (456\".");
}
@Test
public void testPMvalidateBinaryOperator() {/*PM = Parsermethod*/
//http://services.odata.org/Northwind/Northwind.svc/Products(1)/Supplier?$filter=123 add 'abc'
//-->Operator 'add' incompatible with operand types 'System.Int32' and 'System.String' at position 4.
GetPTF("123 add 'abc'").aExType(ExpressionParserException.class).aExKey(ExpressionParserException.INVALID_TYPES_FOR_BINARY_OPERATOR).aExMsgText("Operator \"add\" incompatible with operand types \"System.Uint7\" and \"Edm.String\" at position 5 in \"123 add 'abc'\".");
}
@Test
public void testPMvalidateMethodTypes() /*PM = Parsermethod*/{
//CASE 1
//http://services.odata.org/Northwind/Northwind.svc/Products/?$filter=year(327686)
//-->No applicable function found for 'year' at position 0 with the specified arguments. The functions considered are: year(System.DateTime).
String aInt32 = "327686";
GetPTF("year(" + aInt32 + ")").aExMsgText("No applicable method found for \"year\" at position 1 in \"year(327686)\" for the specified argument types.");
}
@Test
public void testPMparseFilterString() { /*PM = Parsermethod*/
//http://services.odata.org/Northwind/Northwind.svc/Products(1)/Supplier?$filter='123
//-->Unterminated string literal at position 4 in ''123'.
GetPTF("'123").aExType(ExpressionParserException.class).aExKey(ExpressionParserException.TOKEN_UNDETERMINATED_STRING).aExMsgText("Unterminated string literal at position 1 in \"'123\".");
//http://services.odata.org/Northwind/Northwind.svc/Products(1)/Supplier?$filter=1%20add%20'123
//-->Unterminated string literal at position 10 in '1 add '123'.
GetPTF("1 add '123").aExType(ExpressionParserException.class).aExKey(ExpressionParserException.TOKEN_UNDETERMINATED_STRING).aExMsgText("Unterminated string literal at position 7 in \"1 add '123\".");
//http://services.odata.org/Northwind/Northwind.svc/Products(1)/Supplier?$filter=datetime'123
//-->Unterminated literal at position 12 in 'datetime'123'.
GetPTF("datetime'123").aExType(ExpressionParserException.class).aExKey(ExpressionParserException.TOKEN_UNDETERMINATED_STRING).aExMsgText("Unterminated string literal at position 9 in \"datetime'123\".");
//http://services.odata.org/Northwind/Northwind.svc/Products(1)/Supplier?$filter=123%20456
//-->Expression of type 'System.Boolean' expected at position 0.
GetPTF("123 456").aExType(ExpressionParserException.class).aExKey(ExpressionParserException.INVALID_TRAILING_TOKEN_DETECTED_AFTER_PARSING).aExMsgText("Invalid token \"456\" detected after parsing at position 5 in \"123 456\".");
//http://services.odata.org/Northwind/Northwind.svc/Products(1)/Supplier?$filter=123%20456
//-->Expression of type 'System.Boolean' expected at position 0.
GetPTF("123 456 789").aExType(ExpressionParserException.class).aExKey(ExpressionParserException.INVALID_TRAILING_TOKEN_DETECTED_AFTER_PARSING).aExMsgText("Invalid token \"456\" detected after parsing at position 5 in \"123 456 789\".");
//http://services.odata.org/Northwind/Northwind.svc/Products(1)/Supplier?$filter=abc%20abc
//-->No property 'abc' exists in type 'ODataWeb.Northwind.Model.Supplier' at position 0.
GetPTF("abc abc").aExType(ExpressionParserException.class).aExKey(ExpressionParserException.INVALID_TRAILING_TOKEN_DETECTED_AFTER_PARSING).aExMsgText("Invalid token \"abc\" detected after parsing at position 5 in \"abc abc\".");
}
@Test
public void testAdditionalStuff() {
GetPTF("( A mul B )/X eq TEST").aSerialized("{{{A mul B}/X} eq TEST}");
GetPTF("( 1 mul 2 )/X eq TEST").aSerialized("{{{1 mul 2}/X} eq TEST}");
//CASE 1
EdmEntityType edmEtAllTypes = edmInfo.getTypeEtAllTypes();
GetPTF(edmEtAllTypes, "( 1 mul 2 )/X eq TEST").aExMsgText("Leftside of method operator at position 12 is not a property in \"( 1 mul 2 )/X eq TEST\".");
//CASE 2
//http://services.odata.org/Northwind/Northwind.svc/Products/?$filter=notsupportedfunction('a')
//-->Unknown function 'notsupportedfunction' at position 0.
GetPTF("notsupportedfunction('a')").aExMsgText("Unknown function \"notsupportedfunction\" at position 1 in \"notsupportedfunction('a')\".");
//CASE 3
//http://services.odata.org/Northwind/Northwind.svc/Products/?$filter=notsupportedfunction('a')
//-->Unknown function 'notsupportedfunction' at position 0.
GetPTF("notsupportedfunction ('a')").aExMsgText("Unknown function \"notsupportedfunction\" at position 1 in \"notsupportedfunction ('a')\".");
//CASE 4
//Use \ instead of /
GetPTF("Address\\NotAProperty").aExMsgText("Error while tokenizing a ODATA expression on token \"\\\" at position 8 in \"Address\\NotAProperty\".");
//CASE 5
GetPTF("-(-(- 2d)))").aExMsgText("Invalid token \")\" detected after parsing at position 11 in \"-(-(- 2d)))\".");
//CASE 6
GetPTF("a b").aExMsgText("Invalid token \"b\" detected after parsing at position 3 in \"a b\".");
//CASE 7
GetPTF("a eq b b").aExMsgText("Invalid token \"b\" detected after parsing at position 8 in \"a eq b b\".");
//CASE 8
GetPTF(edmEtAllTypes, "year(Complex)").aExMsgText("No applicable method found for \"year\" at position 1 in \"year(Complex)\" for the specified argument types.");
//CASE 9
//http://services.odata.org/Northwind/Northwind.svc/Products(1)/Supplier?$filter=1%20add%202
//-->Expression of type 'System.Boolean' expected at position 0.
GetPTF_onlyBinary("1 add 2").aExMsgText("Expression of type \"Edm.Boolean\" expected at position 1 in \"1 add 2\" (actual type is \"Edm.SByte\").");
//CASE 10
//http://services.odata.org/Northwind/Northwind.svc/Products(1)/Supplier?$filter=1%20add
//-->Expression expected at position 5.
GetPTF_onlyBinary("1 add").aExMsgText("Expression expected after position 5 in \"1 add\".");
//CASE 11
//http://services.odata.org/Northwind/Northwind.svc/Products(1)/Supplier?$filter=1%20add
//-->Expression expected at position 5.
GetPTF_onlyBinary("1 add ").aExMsgText("Expression expected after position 5 in \"1 add \".");
}
}