Browse Source

added negative test cases - removed readPosition from function parameter parser, ready for review

pull/167/head
Matthew J Greenwood 9 years ago
parent
commit
5e2ef13c64
  1. 39
      json-path/src/main/java/com/jayway/jsonpath/internal/path/PathCompiler.java
  2. 45
      json-path/src/test/java/com/jayway/jsonpath/internal/function/NestedFunctionTest.java

39
json-path/src/main/java/com/jayway/jsonpath/internal/path/PathCompiler.java

@ -204,8 +204,10 @@ public class PathCompiler {
// read the next token to determine if we have a simple no-args function call // read the next token to determine if we have a simple no-args function call
char c = path.charAt(readPosition + 1); char c = path.charAt(readPosition + 1);
if (c != CLOSE_PARENTHESIS) { if (c != CLOSE_PARENTHESIS) {
path.setPosition(endPosition+1);
// parse the arguments of the function - arguments that are inner queries or JSON document(s) // parse the arguments of the function - arguments that are inner queries or JSON document(s)
functionParameters = parseFunctionParameters(readPosition); String functionName = path.subSequence(startPosition, endPosition).toString();
functionParameters = parseFunctionParameters(functionName);
} else { } else {
path.setPosition(readPosition + 1); path.setPosition(readPosition + 1);
} }
@ -252,14 +254,12 @@ public class PathCompiler {
* *
* The above is a valid function call, we're first summing 10 + avg of 1...10 (5.5) so the total should be 15.5 * The above is a valid function call, we're first summing 10 + avg of 1...10 (5.5) so the total should be 15.5
* *
* @param readPosition
* The current position within the stream we've advanced - TODO remove the need for this...
* @return * @return
* An ordered list of parameters that are to processed via the function. Typically functions either process * An ordered list of parameters that are to processed via the function. Typically functions either process
* an array of values and/or can consume parameters in addition to the values provided from the consumption of * an array of values and/or can consume parameters in addition to the values provided from the consumption of
* an array. * an array.
*/ */
private List<Parameter> parseFunctionParameters(int readPosition) { private List<Parameter> parseFunctionParameters(String funcName) {
PathToken currentToken; PathToken currentToken;
ParamType type = null; ParamType type = null;
@ -270,8 +270,9 @@ public class PathCompiler {
char priorChar = 0; char priorChar = 0;
List<Parameter> parameters = new ArrayList<Parameter>(); List<Parameter> parameters = new ArrayList<Parameter>();
StringBuffer parameter = new StringBuffer(); StringBuffer parameter = new StringBuffer();
while (path.inBounds(readPosition) && !endOfStream) { while (path.inBounds() && !endOfStream) {
char c = path.charAt(readPosition++); char c = path.currentChar();
path.incrementPosition(1);
// we're at the start of the stream, and don't know what type of parameter we have // we're at the start of the stream, and don't know what type of parameter we have
if (type == null) { if (type == null) {
@ -290,6 +291,9 @@ public class PathCompiler {
switch (c) { switch (c) {
case DOUBLE_QUOTE: case DOUBLE_QUOTE:
if (priorChar != '\\' && groupQuote > 0) { if (priorChar != '\\' && groupQuote > 0) {
if (groupQuote == 0) {
throw new InvalidPathException("Unexpected quote '\"' at character position: " + path.position());
}
groupQuote--; groupQuote--;
} }
else { else {
@ -307,9 +311,15 @@ public class PathCompiler {
break; break;
case CLOSE_BRACE: case CLOSE_BRACE:
if (0 == groupBrace) {
throw new InvalidPathException("Unexpected close brace '}' at character position: " + path.position());
}
groupBrace--; groupBrace--;
break; break;
case CLOSE_SQUARE_BRACKET: case CLOSE_SQUARE_BRACKET:
if (0 == groupBracket) {
throw new InvalidPathException("Unexpected close bracket ']' at character position: " + path.position());
}
groupBracket--; groupBracket--;
break; break;
@ -323,26 +333,27 @@ public class PathCompiler {
case COMMA: case COMMA:
// In this state we've reach the end of a function parameter and we can pass along the parameter string // In this state we've reach the end of a function parameter and we can pass along the parameter string
// to the parser // to the parser
if ((0 == groupQuote && 0 == groupBrace && 0 == groupBracket && ((0 == groupParen && CLOSE_PARENTHESIS == c) || 1 == groupParen))) { if ((0 == groupQuote && 0 == groupBrace && 0 == groupBracket
&& ((0 == groupParen && CLOSE_PARENTHESIS == c) || 1 == groupParen))) {
endOfStream = (0 == groupParen); endOfStream = (0 == groupParen);
if (null != type) { if (null != type) {
Parameter param = null; Parameter param = null;
if (type == ParamType.JSON) { switch (type) {
case JSON:
// parse the json and set the value // parse the json and set the value
param = new Parameter(parameter.toString()); param = new Parameter(parameter.toString());
} else if (type == ParamType.PATH) { break;
case PATH:
LinkedList<Predicate> predicates = new LinkedList<Predicate>(); LinkedList<Predicate> predicates = new LinkedList<Predicate>();
PathCompiler compiler = new PathCompiler(parameter.toString(), predicates); PathCompiler compiler = new PathCompiler(parameter.toString(), predicates);
param = new Parameter(compiler.compile()); param = new Parameter(compiler.compile());
break;
} }
if (null != param) { if (null != param) {
parameters.add(param); parameters.add(param);
} else {
// TODO: raise error...
} }
parameter.delete(0, parameter.length()); parameter.delete(0, parameter.length());
type = null; type = null;
} }
} }
@ -354,7 +365,9 @@ public class PathCompiler {
} }
priorChar = c; priorChar = c;
} }
path.setPosition(readPosition); if (0 != groupBrace || 0 != groupParen || 0 != groupBracket) {
throw new InvalidPathException("Arguments to function: '" + funcName + "' are not closed properly.");
}
return parameters; return parameters;
} }

45
json-path/src/test/java/com/jayway/jsonpath/internal/function/NestedFunctionTest.java

@ -8,6 +8,9 @@ import org.junit.runners.Parameterized;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import static com.jayway.jsonpath.JsonPath.using;
import static org.junit.Assert.assertTrue;
/** /**
* Created by matt@mjgreenwood.net on 12/10/15. * Created by matt@mjgreenwood.net on 12/10/15.
*/ */
@ -74,4 +77,46 @@ public class NestedFunctionTest extends BaseFunctionTest {
public void testAppendNumber() { public void testAppendNumber() {
verifyMathFunction(conf, "$.numbers.append(11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 0).avg()", 10.0); verifyMathFunction(conf, "$.numbers.append(11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 0).avg()", 10.0);
} }
/**
* Aggregation function should ignore text values
*/
@Test
public void testAppendTextAndNumberThenSum() {
verifyMathFunction(conf, "$.numbers.append(\"0\", \"11\").sum()", 55.0);
}
@Test
public void testErrantCloseBraceNegative() {
try {
using(conf).parse(this.NUMBER_SERIES).read("$.numbers.append(0, 1, 2}).avg()");
assert(false);
}
catch (Exception e) {
assertTrue(e.getMessage().startsWith("Unexpected close brace"));
}
}
@Test
public void testErrantCloseBracketNegative() {
try {
using(conf).parse(this.NUMBER_SERIES).read("$.numbers.append(0, 1, 2]).avg()");
assert(false);
}
catch (Exception e) {
assertTrue(e.getMessage().startsWith("Unexpected close bracket"));
}
}
@Test
public void testUnclosedFunctionCallNegative() {
try {
using(conf).parse(this.NUMBER_SERIES).read("$.numbers.append(0, 1, 2");
assert(false);
}
catch (Exception e) {
assertTrue(e.getMessage().startsWith("Arguments to function: 'append'"));
}
}
} }

Loading…
Cancel
Save