[OLINGO-834] URI parser shall not ignore empty path segments
Signed-off-by: Christian Amend <christian.amend@sap.com>
This commit is contained in:
parent
b0866014df
commit
3295bcc062
|
@ -114,7 +114,7 @@ public class BasicHttpITCase extends AbstractBaseTestITCase {
|
|||
|
||||
@Test
|
||||
public void testIEEE754ParameterContentNegotiation() throws Exception {
|
||||
final URL url = new URL(SERVICE_URI + "/ESAllPrim(32767)?$format=application/json;IEEE754Compatible=true");
|
||||
final URL url = new URL(SERVICE_URI + "ESAllPrim(32767)?$format=application/json;IEEE754Compatible=true");
|
||||
final HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||
connection.setRequestMethod(HttpMethod.GET.name());
|
||||
connection.setRequestProperty(HttpHeader.ACCEPT, "application/json;IEEE754Compatible=false");
|
||||
|
@ -131,7 +131,7 @@ public class BasicHttpITCase extends AbstractBaseTestITCase {
|
|||
|
||||
@Test
|
||||
public void testIEEE754ParameterViaAcceptHeader() throws Exception {
|
||||
final URL url = new URL(SERVICE_URI + "/ESAllPrim(32767)");
|
||||
final URL url = new URL(SERVICE_URI + "ESAllPrim(32767)");
|
||||
final HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||
connection.setRequestMethod(HttpMethod.GET.name());
|
||||
connection.setRequestProperty(HttpHeader.ACCEPT, "application/json;IEEE754Compatible=true");
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
package org.apache.olingo.server.core.uri.parser;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Collections;
|
||||
import java.util.Deque;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -60,6 +61,7 @@ public class Parser {
|
|||
private static final String ATOM = "atom";
|
||||
private static final String JSON = "json";
|
||||
private static final String XML = "xml";
|
||||
private static final String DOLLAR = "$";
|
||||
private static final String AT = "@";
|
||||
private static final String NULL = "null";
|
||||
|
||||
|
@ -78,14 +80,19 @@ public class Parser {
|
|||
Deque<EdmType> contextTypes = new ArrayDeque<EdmType>();
|
||||
boolean contextIsCollection = false;
|
||||
|
||||
final List<String> pathSegmentsDecoded = UriDecoder.splitAndDecodePath(path);
|
||||
final int numberOfSegments = pathSegmentsDecoded.size();
|
||||
List<String> pathSegmentsDecoded = UriDecoder.splitAndDecodePath(path);
|
||||
int numberOfSegments = pathSegmentsDecoded.size();
|
||||
// Remove an initial empty segment resulting from the expected '/' at the beginning of the path.
|
||||
if (numberOfSegments > 1 && pathSegmentsDecoded.get(0).isEmpty()) {
|
||||
pathSegmentsDecoded.remove(0);
|
||||
numberOfSegments--;
|
||||
}
|
||||
|
||||
// first, read the decoded path segments
|
||||
final String firstSegment = numberOfSegments == 0 ? "" : pathSegmentsDecoded.get(0);
|
||||
final String firstSegment = pathSegmentsDecoded.get(0);
|
||||
|
||||
if (firstSegment.isEmpty()) {
|
||||
ensureLastSegment(firstSegment, 0, numberOfSegments);
|
||||
ensureLastSegment(firstSegment, 1, numberOfSegments);
|
||||
contextUriInfo.setKind(UriInfoKind.service);
|
||||
|
||||
} else if (firstSegment.equals("$batch")) {
|
||||
|
@ -168,11 +175,12 @@ public class Parser {
|
|||
}
|
||||
|
||||
// second, read the system query options and the custom query options
|
||||
final List<QueryOption> options = UriDecoder.splitAndDecodeOptions(query);
|
||||
final List<QueryOption> options =
|
||||
query == null ? Collections.<QueryOption> emptyList() : UriDecoder.splitAndDecodeOptions(query);
|
||||
for (final QueryOption option : options) {
|
||||
final String optionName = option.getName();
|
||||
final String optionValue = option.getText();
|
||||
if (optionName.startsWith("$")) {
|
||||
if (optionName.startsWith(DOLLAR)) {
|
||||
SystemQueryOption systemOption = null;
|
||||
if (optionName.equals(SystemQueryOptionKind.FILTER.toString())) {
|
||||
UriTokenizer filterTokenizer = new UriTokenizer(optionValue);
|
||||
|
@ -315,7 +323,7 @@ public class Parser {
|
|||
UriParserSyntaxException.MessageKeys.DUPLICATED_ALIAS, optionName);
|
||||
}
|
||||
|
||||
} else {
|
||||
} else if (!optionName.isEmpty()) {
|
||||
contextUriInfo.addCustomQueryOption((CustomQueryOption) option);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -157,7 +157,7 @@ public class ParserHelper {
|
|||
final List<EdmKeyPropertyRef> keyPropertyRefs = edmEntityType.getKeyPropertyRefs();
|
||||
if (tokenizer.next(TokenKind.CLOSE)) {
|
||||
throw new UriParserSemanticException(
|
||||
"Expected " + keyPropertyRefs.size() + " key predicates but none.",
|
||||
"Expected " + keyPropertyRefs.size() + " key predicates but got none.",
|
||||
UriParserSemanticException.MessageKeys.WRONG_NUMBER_OF_KEY_PROPERTIES,
|
||||
Integer.toString(keyPropertyRefs.size()), "0");
|
||||
}
|
||||
|
|
|
@ -19,8 +19,6 @@
|
|||
package org.apache.olingo.server.core.uri.parser;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -33,7 +31,7 @@ public class UriDecoder {
|
|||
/** Splits the path string at '/' characters and percent-decodes the resulting path segments. */
|
||||
protected static List<String> splitAndDecodePath(final String path) throws UriParserSyntaxException {
|
||||
List<String> pathSegmentsDecoded = new ArrayList<String>();
|
||||
for (final String segment : splitSkipEmpty(path, '/')) {
|
||||
for (final String segment : split(path, '/')) {
|
||||
pathSegmentsDecoded.add(decode(segment));
|
||||
}
|
||||
return pathSegmentsDecoded;
|
||||
|
@ -42,58 +40,39 @@ public class UriDecoder {
|
|||
/**
|
||||
* Splits the query-option string at '&' characters, the resulting parts at '=' characters,
|
||||
* and separately percent-decodes names and values of the resulting name-value pairs.
|
||||
* If there is no '=' character in an option, the whole option is considered as name.
|
||||
*/
|
||||
protected static List<QueryOption> splitAndDecodeOptions(final String queryOptionString)
|
||||
throws UriParserSyntaxException {
|
||||
if (queryOptionString == null || queryOptionString.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<QueryOption> queryOptions = new ArrayList<QueryOption>();
|
||||
for (final String option : splitSkipEmpty(queryOptionString, '&')) {
|
||||
final List<String> pair = splitFirst(option, '=');
|
||||
for (final String option : split(queryOptionString, '&')) {
|
||||
final int pos = option.indexOf('=');
|
||||
final String name = pos >= 0 ? option.substring(0, pos) : option;
|
||||
final String text = pos >= 0 ? option.substring(pos + 1) : "";
|
||||
queryOptions.add(new CustomQueryOptionImpl()
|
||||
.setName(decode(pair.get(0)))
|
||||
.setText(decode(pair.get(1))));
|
||||
.setName(decode(name))
|
||||
.setText(decode(text)));
|
||||
}
|
||||
return queryOptions;
|
||||
}
|
||||
|
||||
private static List<String> splitFirst(final String input, final char c) {
|
||||
int pos = input.indexOf(c);
|
||||
if (pos >= 0) {
|
||||
return Arrays.asList(input.substring(0, pos), input.substring(pos + 1));
|
||||
} else {
|
||||
return Arrays.asList(input, "");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits the input string at the given character and drops all empty elements.
|
||||
* Splits the input string at the given character.
|
||||
* @param input string to split
|
||||
* @param c character at which to split
|
||||
* @return list of elements (can be empty)
|
||||
*/
|
||||
private static List<String> splitSkipEmpty(final String input, final char c) {
|
||||
if (input.isEmpty() || input.length() == 1 && input.charAt(0) == c) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private static List<String> split(final String input, final char c) {
|
||||
List<String> list = new LinkedList<String>();
|
||||
|
||||
int start = 0;
|
||||
int end;
|
||||
|
||||
while ((end = input.indexOf(c, start)) >= 0) {
|
||||
if (start != end) {
|
||||
list.add(input.substring(start, end));
|
||||
}
|
||||
list.add(input.substring(start, end));
|
||||
start = end + 1;
|
||||
}
|
||||
|
||||
if (input.charAt(input.length() - 1) != c) {
|
||||
list.add(input.substring(start));
|
||||
}
|
||||
list.add(input.substring(start));
|
||||
|
||||
return list;
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ public class SearchParser {
|
|||
searchExpression = parse(tokenizer.tokenize(searchQuery));
|
||||
} catch (SearchTokenizerException e) {
|
||||
String message = e.getMessage();
|
||||
throw new SearchParserException("Tokenizer exception with message: " + message,
|
||||
throw new SearchParserException("Tokenizer exception with message: " + message, e,
|
||||
SearchParserException.MessageKeys.TOKENIZER_EXCEPTION, message);
|
||||
}
|
||||
final SearchOptionImpl searchOption = new SearchOptionImpl();
|
||||
|
|
|
@ -286,9 +286,9 @@ public class UriValidator {
|
|||
RowIndexForUriType.mediaStream : RowIndexForUriType.propertyPrimitiveValue;
|
||||
break;
|
||||
default:
|
||||
throw new UriValidationException("Unexpected kind in path segment before $value: "
|
||||
+ secondLastPathSegment.getKind(), UriValidationException.MessageKeys.UNALLOWED_KIND_BEFORE_VALUE,
|
||||
secondLastPathSegment.toString());
|
||||
throw new UriValidationException(
|
||||
"Unexpected kind in path segment before $value: " + secondLastPathSegment.getKind(),
|
||||
UriValidationException.MessageKeys.UNALLOWED_KIND_BEFORE_VALUE, secondLastPathSegment.toString());
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
@ -302,9 +302,9 @@ public class UriValidator {
|
|||
return ((UriResourcePartTyped) secondLastPathSegment).isCollection() ?
|
||||
RowIndexForUriType.references : RowIndexForUriType.reference;
|
||||
} else {
|
||||
throw new UriValidationException("secondLastPathSegment not a class of UriResourcePartTyped: "
|
||||
+ lastPathSegment.getClass(), UriValidationException.MessageKeys.LAST_SEGMENT_NOT_TYPED, lastPathSegment
|
||||
.toString());
|
||||
throw new UriValidationException(
|
||||
"secondLastPathSegment not a class of UriResourcePartTyped: " + lastPathSegment.getClass(),
|
||||
UriValidationException.MessageKeys.LAST_SEGMENT_NOT_TYPED, lastPathSegment.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -314,40 +314,36 @@ public class UriValidator {
|
|||
return ((UriResourcePartTyped) lastPathSegment).isCollection() ?
|
||||
RowIndexForUriType.propertyPrimitiveCollection : RowIndexForUriType.propertyPrimitive;
|
||||
} else {
|
||||
throw new UriValidationException("lastPathSegment not a class of UriResourcePartTyped: "
|
||||
+ lastPathSegment.getClass(), UriValidationException.MessageKeys.LAST_SEGMENT_NOT_TYPED, lastPathSegment
|
||||
.toString());
|
||||
throw new UriValidationException(
|
||||
"lastPathSegment not a class of UriResourcePartTyped: " + lastPathSegment.getClass(),
|
||||
UriValidationException.MessageKeys.LAST_SEGMENT_NOT_TYPED, lastPathSegment.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private RowIndexForUriType rowIndexForFunction(final UriResource lastPathSegment) throws UriValidationException {
|
||||
final UriResourceFunction uriFunction = (UriResourceFunction) lastPathSegment;
|
||||
final EdmReturnType returnType = uriFunction.getFunction().getReturnType();
|
||||
|
||||
if (!uriFunction.getFunction().isComposable()) {
|
||||
return RowIndexForUriType.none;
|
||||
}
|
||||
|
||||
final boolean isCollection = uriFunction.isCollection();
|
||||
final EdmTypeKind typeKind = uriFunction.getFunction().getReturnType().getType().getKind();
|
||||
RowIndexForUriType idx;
|
||||
switch (returnType.getType().getKind()) {
|
||||
switch (typeKind) {
|
||||
case ENTITY:
|
||||
idx = returnType.isCollection() && uriFunction.getKeyPredicates().isEmpty() ?
|
||||
RowIndexForUriType.entitySet : RowIndexForUriType.entity;
|
||||
idx = isCollection ? RowIndexForUriType.entitySet : RowIndexForUriType.entity;
|
||||
break;
|
||||
case PRIMITIVE:
|
||||
case ENUM:
|
||||
case DEFINITION:
|
||||
idx = returnType.isCollection() ? RowIndexForUriType.propertyPrimitiveCollection :
|
||||
RowIndexForUriType.propertyPrimitive;
|
||||
idx = isCollection ? RowIndexForUriType.propertyPrimitiveCollection : RowIndexForUriType.propertyPrimitive;
|
||||
break;
|
||||
case COMPLEX:
|
||||
idx = returnType.isCollection() ? RowIndexForUriType.propertyComplexCollection :
|
||||
RowIndexForUriType.propertyComplex;
|
||||
idx = isCollection ? RowIndexForUriType.propertyComplexCollection : RowIndexForUriType.propertyComplex;
|
||||
break;
|
||||
default:
|
||||
throw new UriValidationException("Unsupported function return type: " + returnType.getType().getKind(),
|
||||
UriValidationException.MessageKeys.UNSUPPORTED_FUNCTION_RETURN_TYPE,
|
||||
returnType.getType().getKind().toString());
|
||||
throw new UriValidationException("Unsupported function return type: " + typeKind,
|
||||
UriValidationException.MessageKeys.UNSUPPORTED_FUNCTION_RETURN_TYPE, typeKind.toString());
|
||||
}
|
||||
|
||||
return idx;
|
||||
|
@ -512,18 +508,17 @@ public class UriValidator {
|
|||
for (SystemQueryOption option : uriInfo.getSystemQueryOptions()) {
|
||||
options.append(option.getName()).append(" ");
|
||||
}
|
||||
throw new UriValidationException("System query option " + options.toString() + " not allowed for method "
|
||||
+ httpMethod, UriValidationException.MessageKeys.SYSTEM_QUERY_OPTION_NOT_ALLOWED_FOR_HTTP_METHOD,
|
||||
throw new UriValidationException(
|
||||
"System query option " + options.toString() + " not allowed for method " + httpMethod,
|
||||
UriValidationException.MessageKeys.SYSTEM_QUERY_OPTION_NOT_ALLOWED_FOR_HTTP_METHOD,
|
||||
options.toString(), httpMethod.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isAction(final UriInfo uriInfo) {
|
||||
List<UriResource> uriResourceParts = uriInfo.getUriResourceParts();
|
||||
if (uriResourceParts.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
return UriResourceKind.action == uriResourceParts.get(uriResourceParts.size() - 1).getKind();
|
||||
return !uriResourceParts.isEmpty()
|
||||
&& UriResourceKind.action == uriResourceParts.get(uriResourceParts.size() - 1).getKind();
|
||||
}
|
||||
|
||||
private void validateParameters(final UriInfo uriInfo) throws UriValidationException {
|
||||
|
@ -531,18 +526,18 @@ public class UriValidator {
|
|||
final boolean isFunction = pathSegment.getKind() == UriResourceKind.function;
|
||||
|
||||
if (isFunction) {
|
||||
final UriResourceFunction functionPathSegement = (UriResourceFunction) pathSegment;
|
||||
final EdmFunction edmFuntion = functionPathSegement.getFunction();
|
||||
final UriResourceFunction functionPathSegment = (UriResourceFunction) pathSegment;
|
||||
final EdmFunction edmFunction = functionPathSegment.getFunction();
|
||||
|
||||
final Map<String, UriParameter> parameters = new HashMap<String, UriParameter>();
|
||||
for (final UriParameter parameter : functionPathSegement.getParameters()) {
|
||||
for (final UriParameter parameter : functionPathSegment.getParameters()) {
|
||||
parameters.put(parameter.getName(), parameter);
|
||||
}
|
||||
|
||||
boolean firstParameter = true;
|
||||
for (final String parameterName : edmFuntion.getParameterNames()) {
|
||||
for (final String parameterName : edmFunction.getParameterNames()) {
|
||||
final UriParameter parameter = parameters.get(parameterName);
|
||||
final boolean isNullable = edmFuntion.getParameter(parameterName).isNullable();
|
||||
final boolean isNullable = edmFunction.getParameter(parameterName).isNullable();
|
||||
|
||||
if (parameter != null) {
|
||||
/** No alias, value explicit null */
|
||||
|
@ -560,7 +555,7 @@ public class UriValidator {
|
|||
}
|
||||
|
||||
parameters.remove(parameterName);
|
||||
} else if (!isNullable && !(firstParameter && edmFuntion.isBound())) {
|
||||
} else if (!isNullable && !(firstParameter && edmFunction.isBound())) {
|
||||
// The first parameter of bound functions is implicit provided by the preceding path segment
|
||||
throw new UriValidationException("Missing non nullable parameter " + parameterName,
|
||||
UriValidationException.MessageKeys.MISSING_PARAMETER, parameterName);
|
||||
|
@ -586,11 +581,11 @@ public class UriValidator {
|
|||
if (isEntitySet || pathSegment.getKind() == UriResourceKind.navigationProperty || isEntityColFunction) {
|
||||
final List<UriParameter> keyPredicates = isEntitySet ?
|
||||
((UriResourceEntitySet) pathSegment).getKeyPredicates() :
|
||||
isEntityColFunction ? ((UriResourceFunction) pathSegment).getKeyPredicates()
|
||||
: ((UriResourceNavigation) pathSegment).getKeyPredicates();
|
||||
isEntityColFunction ?
|
||||
((UriResourceFunction) pathSegment).getKeyPredicates() :
|
||||
((UriResourceNavigation) pathSegment).getKeyPredicates();
|
||||
|
||||
if (keyPredicates != null) {
|
||||
|
||||
final EdmEntityType entityType = isEntitySet ?
|
||||
((UriResourceEntitySet) pathSegment).getEntityType() :
|
||||
isEntityColFunction ? (EdmEntityType) ((UriResourceFunction) pathSegment).getType()
|
||||
|
|
|
@ -290,15 +290,13 @@ public class ExpressionParserTest {
|
|||
}
|
||||
expressionString += ')';
|
||||
|
||||
Expression expression = parseExpression(expressionString);
|
||||
assertNotNull(expression);
|
||||
return expression;
|
||||
return parseExpression(expressionString);
|
||||
}
|
||||
|
||||
private Expression parseExpression(final String expressionString)
|
||||
throws UriParserException, UriValidationException {
|
||||
UriTokenizer tokenizer = new UriTokenizer(expressionString);
|
||||
Expression expression = new ExpressionParser(mock(Edm.class), odata).parse(tokenizer, null, null);
|
||||
final Expression expression = new ExpressionParser(mock(Edm.class), odata).parse(tokenizer, null, null);
|
||||
assertNotNull(expression);
|
||||
assertTrue(tokenizer.next(TokenKind.EOF));
|
||||
return expression;
|
||||
|
@ -306,7 +304,7 @@ public class ExpressionParserTest {
|
|||
|
||||
private void wrongExpression(final String expressionString) {
|
||||
try {
|
||||
new ExpressionParser(mock(Edm.class), odata).parse(new UriTokenizer(expressionString), null, null);
|
||||
parseExpression(expressionString);
|
||||
fail("Expected exception not thrown.");
|
||||
} catch (final UriParserException e) {
|
||||
assertNotNull(e);
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.olingo.server.core.uri.antlr;
|
||||
package org.apache.olingo.server.core.uri.parser;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
@ -28,21 +28,9 @@ import org.junit.Test;
|
|||
/**
|
||||
* Tests originally written for the ANTLR lexer.
|
||||
*/
|
||||
public class TestLexer {
|
||||
public class LexerTest {
|
||||
|
||||
private TokenValidator test = null;
|
||||
|
||||
// The last two chars are not in cPCT_ENCODED_UNESCAPED.
|
||||
private static final String cPCT_ENCODED = "%45%46%47" + "%22" + "%5C";
|
||||
private static final String cUNRESERVED = "ABCabc123-._~";
|
||||
private static final String cOTHER_DELIMS = "!()*+,;";
|
||||
private static final String cSUB_DELIMS = "$&'=" + cOTHER_DELIMS;
|
||||
|
||||
private static final String cPCHAR = cUNRESERVED + cPCT_ENCODED + cSUB_DELIMS + ":@";
|
||||
|
||||
public TestLexer() {
|
||||
test = new TokenValidator();
|
||||
}
|
||||
private TokenValidator test = new TokenValidator();
|
||||
|
||||
@Test
|
||||
public void unary() {
|
||||
|
@ -271,7 +259,14 @@ public class TestLexer {
|
|||
|
||||
@Test
|
||||
public void delims() {
|
||||
final String reserved = "/";
|
||||
// The last two chars are not in cPCT_ENCODED_UNESCAPED.
|
||||
// final String cPCT_ENCODED = "%45%46%47" + "%22" + "%5C";
|
||||
// final String cUNRESERVED = "ABCabc123-._~";
|
||||
// final String cOTHER_DELIMS = "!()*+,;";
|
||||
// final String cSUB_DELIMS = "$&'=" + cOTHER_DELIMS;
|
||||
|
||||
// private static final String cPCHAR = cUNRESERVED + cPCT_ENCODED + cSUB_DELIMS + ":@";
|
||||
// final String reserved = "/";
|
||||
// Test lexer rule UNRESERVED
|
||||
// test.run("$format=A/" + cUNRESERVED).has(TokenKind.FORMAT).isInput();
|
||||
// test.run("$format=A/" + cUNRESERVED + reserved).has(TokenKind.FORMAT).isText(cUNRESERVED);
|
|
@ -19,7 +19,6 @@
|
|||
package org.apache.olingo.server.core.uri.parser;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
@ -32,13 +31,14 @@ public class UriDecoderTest {
|
|||
|
||||
@Test
|
||||
public void split() throws Exception {
|
||||
assertTrue(UriDecoder.splitAndDecodePath("").isEmpty());
|
||||
assertTrue(UriDecoder.splitAndDecodePath("/").isEmpty());
|
||||
assertEquals(Arrays.asList(""), UriDecoder.splitAndDecodePath(""));
|
||||
assertEquals(Arrays.asList("", ""), UriDecoder.splitAndDecodePath("/"));
|
||||
assertEquals(Arrays.asList("a"), UriDecoder.splitAndDecodePath("a"));
|
||||
assertEquals(Arrays.asList("a"), UriDecoder.splitAndDecodePath("a/"));
|
||||
assertEquals(Arrays.asList("a"), UriDecoder.splitAndDecodePath("/a"));
|
||||
assertEquals(Arrays.asList("a", "a"), UriDecoder.splitAndDecodePath("a/a"));
|
||||
assertEquals(Arrays.asList("a", "a"), UriDecoder.splitAndDecodePath("/a/a"));
|
||||
assertEquals(Arrays.asList("a", ""), UriDecoder.splitAndDecodePath("a/"));
|
||||
assertEquals(Arrays.asList("", "a"), UriDecoder.splitAndDecodePath("/a"));
|
||||
assertEquals(Arrays.asList("a", "b"), UriDecoder.splitAndDecodePath("a/b"));
|
||||
assertEquals(Arrays.asList("", "a", "b"), UriDecoder.splitAndDecodePath("/a/b"));
|
||||
assertEquals(Arrays.asList("", "a", "", "", "b", ""), UriDecoder.splitAndDecodePath("/a///b/"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -49,7 +49,7 @@ public class UriDecoderTest {
|
|||
|
||||
@Test
|
||||
public void options() throws Exception {
|
||||
assertTrue(UriDecoder.splitAndDecodeOptions("").isEmpty());
|
||||
checkOption("", "", "");
|
||||
|
||||
checkOption("a", "a", "");
|
||||
checkOption("a=b", "a", "b");
|
||||
|
@ -67,6 +67,7 @@ public class UriDecoderTest {
|
|||
|
||||
checkOption("=&=", "", "");
|
||||
assertEquals(2, UriDecoder.splitAndDecodeOptions("=&=").size());
|
||||
assertEquals(13, UriDecoder.splitAndDecodeOptions("&&&&&&&&&&&&").size());
|
||||
|
||||
checkOption("=&c=d", "", "");
|
||||
checkOption("=&c=d", "c", "d");
|
||||
|
|
|
@ -194,7 +194,7 @@ public class SearchParserAndTokenizerTest {
|
|||
}
|
||||
|
||||
private static Validator assertQuery(final String searchQuery) {
|
||||
return Validator.init(searchQuery);
|
||||
return new Validator(searchQuery);
|
||||
}
|
||||
|
||||
private static class Validator {
|
||||
|
@ -204,18 +204,12 @@ public class SearchParserAndTokenizerTest {
|
|||
this.searchQuery = searchQuery;
|
||||
}
|
||||
|
||||
private static Validator init(final String searchQuery) {
|
||||
return new Validator(searchQuery);
|
||||
}
|
||||
|
||||
private void resultsIn(final SearchParserException.MessageKey key)
|
||||
throws SearchTokenizerException {
|
||||
|
||||
private void resultsIn(final SearchParserException.MessageKey key) throws SearchTokenizerException {
|
||||
try {
|
||||
resultsIn(searchQuery);
|
||||
} catch (SearchParserException e) {
|
||||
Assert.assertEquals("SearchParserException with unexpected message '" + e.getMessage() +
|
||||
"' was thrown.", key, e.getMessageKey());
|
||||
} catch (final SearchParserException e) {
|
||||
Assert.assertEquals("SearchParserException with unexpected message '" + e.getMessage() + "' was thrown.",
|
||||
key, e.getMessageKey());
|
||||
return;
|
||||
}
|
||||
Assert.fail("SearchParserException with message key " + key.getKey() + " was not thrown.");
|
||||
|
@ -224,23 +218,22 @@ public class SearchParserAndTokenizerTest {
|
|||
public void resultsInExpectedTerm(final String actualToken) throws SearchTokenizerException {
|
||||
try {
|
||||
resultsIn(searchQuery);
|
||||
} catch (SearchParserException e) {
|
||||
} catch (final SearchParserException e) {
|
||||
Assert.assertEquals(SearchParserException.MessageKeys.EXPECTED_DIFFERENT_TOKEN, e.getMessageKey());
|
||||
Assert.assertEquals("Expected PHRASE||WORD found: " + actualToken, e.getMessage());
|
||||
return;
|
||||
}
|
||||
Assert.fail("SearchParserException with message key "
|
||||
+ SearchParserException.MessageKeys.EXPECTED_DIFFERENT_TOKEN + " was not thrown.");
|
||||
}
|
||||
|
||||
private void resultsIn(String expectedSearchExpression) throws SearchTokenizerException, SearchParserException {
|
||||
final SearchExpression searchExpression = getSearchExpression();
|
||||
Assert.assertEquals(expectedSearchExpression, searchExpression.toString());
|
||||
}
|
||||
|
||||
private SearchExpression getSearchExpression() throws SearchParserException, SearchTokenizerException {
|
||||
SearchOption result = new SearchParser().parse(searchQuery);
|
||||
private void resultsIn(final String expectedSearchExpression)
|
||||
throws SearchTokenizerException, SearchParserException {
|
||||
final SearchOption result = new SearchParser().parse(searchQuery);
|
||||
Assert.assertNotNull(result);
|
||||
final SearchExpression searchExpression = result.getSearchExpression();
|
||||
Assert.assertNotNull(searchExpression);
|
||||
return searchExpression;
|
||||
Assert.assertEquals(expectedSearchExpression, searchExpression.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -224,34 +224,34 @@ public class SearchParserTest extends SearchParser {
|
|||
private void runEx(final MessageKeys key, final Token... tokenArray) {
|
||||
try {
|
||||
run(tokenArray);
|
||||
fail("Expected UriParserSyntaxException with key " + key);
|
||||
fail("Expected SearchParserException with key " + key);
|
||||
} catch (SearchParserException e) {
|
||||
assertEquals(key, e.getMessageKey());
|
||||
}
|
||||
}
|
||||
|
||||
private SearchExpression run(final SearchQueryToken.Token... tokenArray) throws SearchParserException {
|
||||
private SearchExpression run(final Token... tokenArray) throws SearchParserException {
|
||||
List<SearchQueryToken> tokenList = prepareTokens(tokenArray);
|
||||
SearchExpression se = parse(tokenList);
|
||||
assertNotNull(se);
|
||||
return se;
|
||||
}
|
||||
|
||||
public List<SearchQueryToken> prepareTokens(final SearchQueryToken.Token... tokenArray) {
|
||||
public List<SearchQueryToken> prepareTokens(final Token... tokenArray) {
|
||||
ArrayList<SearchQueryToken> tokenList = new ArrayList<SearchQueryToken>();
|
||||
int wordNumber = 1;
|
||||
int phraseNumber = 1;
|
||||
for (Token aTokenArray : tokenArray) {
|
||||
for (Token aToken : tokenArray) {
|
||||
SearchQueryToken token = mock(SearchQueryToken.class);
|
||||
when(token.getToken()).thenReturn(aTokenArray);
|
||||
if (aTokenArray == Token.WORD) {
|
||||
when(token.getToken()).thenReturn(aToken);
|
||||
if (aToken == Token.WORD) {
|
||||
when(token.getLiteral()).thenReturn("word" + wordNumber);
|
||||
wordNumber++;
|
||||
} else if (aTokenArray == Token.PHRASE) {
|
||||
} else if (aToken == Token.PHRASE) {
|
||||
when(token.getLiteral()).thenReturn("\"phrase" + phraseNumber + "\"");
|
||||
phraseNumber++;
|
||||
}
|
||||
when(token.toString()).thenReturn("" + aTokenArray);
|
||||
when(token.toString()).thenReturn("" + aToken);
|
||||
tokenList.add(token);
|
||||
}
|
||||
return tokenList;
|
||||
|
|
|
@ -269,7 +269,7 @@ public class SearchTokenizerTest {
|
|||
assertQuery("\"\"").resultsIn(SearchTokenizerException.MessageKeys.INVALID_TOKEN_STATE);
|
||||
assertQuery("some AND)").resultsIn(SearchTokenizerException.MessageKeys.FORBIDDEN_CHARACTER);
|
||||
assertQuery("some OR)").resultsIn(SearchTokenizerException.MessageKeys.FORBIDDEN_CHARACTER);
|
||||
assertQuery("some NOT)").enableLogging().resultsIn(SearchTokenizerException.MessageKeys.FORBIDDEN_CHARACTER);
|
||||
assertQuery("some NOT)").resultsIn(SearchTokenizerException.MessageKeys.FORBIDDEN_CHARACTER);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -308,7 +308,6 @@ public class SearchTokenizerTest {
|
|||
|
||||
private static class Validator {
|
||||
private List<Tuple> validations = new ArrayList<Tuple>();
|
||||
private boolean log;
|
||||
private final String searchQuery;
|
||||
|
||||
public void resultsIn(final SearchQueryToken.Token... tokens) throws SearchTokenizerException {
|
||||
|
@ -345,11 +344,6 @@ public class SearchTokenizerTest {
|
|||
this.searchQuery = searchQuery;
|
||||
}
|
||||
|
||||
private Validator enableLogging() {
|
||||
log = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
private Validator addExpected(final SearchQueryToken.Token token, final String literal) {
|
||||
validations.add(new Tuple(token, literal));
|
||||
return this;
|
||||
|
@ -368,10 +362,6 @@ public class SearchTokenizerTest {
|
|||
validate();
|
||||
} catch (SearchTokenizerException e) {
|
||||
Assert.assertEquals("SearchTokenizerException with unexpected message was thrown.", key, e.getMessageKey());
|
||||
if (log) {
|
||||
System.out.println("Caught SearchTokenizerException with message key " +
|
||||
e.getMessageKey() + " and message " + e.getMessage());
|
||||
}
|
||||
return;
|
||||
}
|
||||
Assert.fail("No SearchTokenizerException was not thrown.");
|
||||
|
@ -381,9 +371,6 @@ public class SearchTokenizerTest {
|
|||
SearchTokenizer tokenizer = new SearchTokenizer();
|
||||
List<SearchQueryToken> result = tokenizer.tokenize(searchQuery);
|
||||
Assert.assertNotNull(result);
|
||||
if (log) {
|
||||
System.out.println(result);
|
||||
}
|
||||
if (validations.size() != 0) {
|
||||
Assert.assertEquals(validations.size(), result.size());
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.olingo.server.core.uri.antlr;
|
||||
package org.apache.olingo.server.core.uri.parser;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
@ -3011,6 +3011,11 @@ public class TestFullResourcePath {
|
|||
testUri.run("$batch")
|
||||
.isKind(UriInfoKind.batch);
|
||||
|
||||
testUri.runEx("//").isExSyntax(UriParserSyntaxException.MessageKeys.MUST_BE_LAST_SEGMENT);
|
||||
testUri.runEx("$metadata/").isExSyntax(UriParserSyntaxException.MessageKeys.MUST_BE_LAST_SEGMENT);
|
||||
testUri.runEx("//$metadata").isExSyntax(UriParserSyntaxException.MessageKeys.MUST_BE_LAST_SEGMENT);
|
||||
testUri.runEx("ESKeyNav//$count").isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
|
||||
|
||||
testUri.runEx("$metadata/$ref").isExSyntax(UriParserSyntaxException.MessageKeys.MUST_BE_LAST_SEGMENT);
|
||||
testUri.runEx("$batch/$ref").isExSyntax(UriParserSyntaxException.MessageKeys.MUST_BE_LAST_SEGMENT);
|
||||
testUri.runEx("$all/$ref").isExSyntax(UriParserSyntaxException.MessageKeys.MUST_BE_LAST_SEGMENT);
|
|
@ -16,7 +16,7 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.olingo.server.core.uri.antlr;
|
||||
package org.apache.olingo.server.core.uri.parser;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
|
@ -33,11 +33,11 @@ import org.apache.olingo.server.api.uri.queryoption.SystemQueryOption;
|
|||
import org.apache.olingo.server.api.uri.queryoption.SystemQueryOptionKind;
|
||||
import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
|
||||
import org.apache.olingo.server.core.uri.UriInfoImpl;
|
||||
import org.apache.olingo.server.core.uri.parser.search.SearchTermImpl;
|
||||
import org.apache.olingo.server.core.uri.queryoption.expression.AliasImpl;
|
||||
import org.apache.olingo.server.core.uri.queryoption.expression.LiteralImpl;
|
||||
import org.junit.Test;
|
||||
|
||||
//TOOD add getKind check to all
|
||||
public class QueryOptionTest {
|
||||
|
||||
@Test
|
||||
|
@ -196,6 +196,7 @@ public class QueryOptionTest {
|
|||
@Test
|
||||
public void testOrderByOptionImpl() {
|
||||
OrderByOptionImpl option = new OrderByOptionImpl();
|
||||
assertEquals(SystemQueryOptionKind.ORDERBY, option.getKind());
|
||||
|
||||
OrderByItemImpl order0 = new OrderByItemImpl();
|
||||
OrderByItemImpl order1 = new OrderByItemImpl();
|
||||
|
@ -217,14 +218,17 @@ public class QueryOptionTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testSearchOptionImpl() {
|
||||
public void searchOptionImpl() {
|
||||
SearchOptionImpl option = new SearchOptionImpl();
|
||||
assertEquals(SystemQueryOptionKind.SEARCH, option.getKind());
|
||||
// $search is not supported yet
|
||||
|
||||
final SearchTermImpl searchExpression = new SearchTermImpl("A");
|
||||
option.setSearchExpression(searchExpression);
|
||||
assertEquals(searchExpression, option.getSearchExpression());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSelectItemImpl() {
|
||||
public void selectItemImpl() {
|
||||
SelectItemImpl option = new SelectItemImpl();
|
||||
|
||||
// no typed collection else case ( e.g. if not path is added)
|
||||
|
@ -244,7 +248,7 @@ public class QueryOptionTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testSelectOptionImpl() {
|
||||
public void selectOptionImpl() {
|
||||
SelectOptionImpl option = new SelectOptionImpl();
|
||||
assertEquals(SystemQueryOptionKind.SELECT, option.getKind());
|
||||
|
||||
|
|
Loading…
Reference in New Issue