|
|
@ -3,6 +3,8 @@ package com.jayway.jsonpath; |
|
|
|
import com.jayway.jsonpath.internal.Path; |
|
|
|
import com.jayway.jsonpath.internal.Path; |
|
|
|
import com.jayway.jsonpath.internal.PathCompiler; |
|
|
|
import com.jayway.jsonpath.internal.PathCompiler; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import com.jayway.jsonpath.internal.compiler.PredicateContextImpl; |
|
|
|
|
|
|
|
import com.sun.tools.doclets.formats.html.SourceToHTMLConverter; |
|
|
|
import org.slf4j.Logger; |
|
|
|
import org.slf4j.Logger; |
|
|
|
import org.slf4j.LoggerFactory; |
|
|
|
import org.slf4j.LoggerFactory; |
|
|
|
|
|
|
|
|
|
|
@ -34,7 +36,7 @@ public class Criteria implements Predicate { |
|
|
|
private static enum CriteriaType { |
|
|
|
private static enum CriteriaType { |
|
|
|
EQ { |
|
|
|
EQ { |
|
|
|
@Override |
|
|
|
@Override |
|
|
|
boolean eval(Object expected, Object actual, Configuration configuration) { |
|
|
|
boolean eval(Object expected, Object actual, PredicateContext ctx) { |
|
|
|
boolean res = (0 == safeCompare(expected, actual)); |
|
|
|
boolean res = (0 == safeCompare(expected, actual)); |
|
|
|
logger.debug("[{}] {} [{}] => {}", actual, name(), expected, res); |
|
|
|
logger.debug("[{}] {} [{}] => {}", actual, name(), expected, res); |
|
|
|
return res; |
|
|
|
return res; |
|
|
@ -42,7 +44,7 @@ public class Criteria implements Predicate { |
|
|
|
}, |
|
|
|
}, |
|
|
|
NE { |
|
|
|
NE { |
|
|
|
@Override |
|
|
|
@Override |
|
|
|
boolean eval(Object expected, Object actual, Configuration configuration) { |
|
|
|
boolean eval(Object expected, Object actual, PredicateContext ctx) { |
|
|
|
boolean res = (0 != safeCompare(expected, actual)); |
|
|
|
boolean res = (0 != safeCompare(expected, actual)); |
|
|
|
logger.debug("[{}] {} [{}] => {}", actual, name(), expected, res); |
|
|
|
logger.debug("[{}] {} [{}] => {}", actual, name(), expected, res); |
|
|
|
return res; |
|
|
|
return res; |
|
|
@ -50,7 +52,7 @@ public class Criteria implements Predicate { |
|
|
|
}, |
|
|
|
}, |
|
|
|
GT { |
|
|
|
GT { |
|
|
|
@Override |
|
|
|
@Override |
|
|
|
boolean eval(Object expected, Object actual, Configuration configuration) { |
|
|
|
boolean eval(Object expected, Object actual, PredicateContext ctx) { |
|
|
|
if ((expected == null) ^ (actual == null)) { |
|
|
|
if ((expected == null) ^ (actual == null)) { |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
@ -61,7 +63,7 @@ public class Criteria implements Predicate { |
|
|
|
}, |
|
|
|
}, |
|
|
|
GTE { |
|
|
|
GTE { |
|
|
|
@Override |
|
|
|
@Override |
|
|
|
boolean eval(Object expected, Object actual, Configuration configuration) { |
|
|
|
boolean eval(Object expected, Object actual, PredicateContext ctx) { |
|
|
|
if ((expected == null) ^ (actual == null)) { |
|
|
|
if ((expected == null) ^ (actual == null)) { |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
@ -72,7 +74,7 @@ public class Criteria implements Predicate { |
|
|
|
}, |
|
|
|
}, |
|
|
|
LT { |
|
|
|
LT { |
|
|
|
@Override |
|
|
|
@Override |
|
|
|
boolean eval(Object expected, Object actual, Configuration configuration) { |
|
|
|
boolean eval(Object expected, Object actual, PredicateContext ctx) { |
|
|
|
if ((expected == null) ^ (actual == null)) { |
|
|
|
if ((expected == null) ^ (actual == null)) { |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
@ -83,7 +85,7 @@ public class Criteria implements Predicate { |
|
|
|
}, |
|
|
|
}, |
|
|
|
LTE { |
|
|
|
LTE { |
|
|
|
@Override |
|
|
|
@Override |
|
|
|
boolean eval(Object expected, Object actual, Configuration configuration) { |
|
|
|
boolean eval(Object expected, Object actual, PredicateContext ctx) { |
|
|
|
if ((expected == null) ^ (actual == null)) { |
|
|
|
if ((expected == null) ^ (actual == null)) { |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
@ -94,7 +96,7 @@ public class Criteria implements Predicate { |
|
|
|
}, |
|
|
|
}, |
|
|
|
IN { |
|
|
|
IN { |
|
|
|
@Override |
|
|
|
@Override |
|
|
|
boolean eval(Object expected, Object actual, Configuration configuration) { |
|
|
|
boolean eval(Object expected, Object actual, PredicateContext ctx) { |
|
|
|
boolean res = false; |
|
|
|
boolean res = false; |
|
|
|
Collection exps = (Collection) expected; |
|
|
|
Collection exps = (Collection) expected; |
|
|
|
for (Object exp : exps) { |
|
|
|
for (Object exp : exps) { |
|
|
@ -109,7 +111,7 @@ public class Criteria implements Predicate { |
|
|
|
}, |
|
|
|
}, |
|
|
|
NIN { |
|
|
|
NIN { |
|
|
|
@Override |
|
|
|
@Override |
|
|
|
boolean eval(Object expected, Object actual, Configuration configuration) { |
|
|
|
boolean eval(Object expected, Object actual, PredicateContext ctx) { |
|
|
|
Collection nexps = (Collection) expected; |
|
|
|
Collection nexps = (Collection) expected; |
|
|
|
boolean res = !nexps.contains(actual); |
|
|
|
boolean res = !nexps.contains(actual); |
|
|
|
logger.debug("[{}] {} [{}] => {}", actual, name(), join(", ", nexps), res); |
|
|
|
logger.debug("[{}] {} [{}] => {}", actual, name(), join(", ", nexps), res); |
|
|
@ -118,13 +120,13 @@ public class Criteria implements Predicate { |
|
|
|
}, |
|
|
|
}, |
|
|
|
ALL { |
|
|
|
ALL { |
|
|
|
@Override |
|
|
|
@Override |
|
|
|
boolean eval(Object expected, Object actual, Configuration configuration) { |
|
|
|
boolean eval(Object expected, Object actual, PredicateContext ctx) { |
|
|
|
boolean res = true; |
|
|
|
boolean res = true; |
|
|
|
Collection exps = (Collection) expected; |
|
|
|
Collection exps = (Collection) expected; |
|
|
|
if (configuration.jsonProvider().isArray(actual)) { |
|
|
|
if (ctx.configuration().jsonProvider().isArray(actual)) { |
|
|
|
for (Object exp : exps) { |
|
|
|
for (Object exp : exps) { |
|
|
|
boolean found = false; |
|
|
|
boolean found = false; |
|
|
|
for (Object check : configuration.jsonProvider().toIterable(actual)) { |
|
|
|
for (Object check : ctx.configuration().jsonProvider().toIterable(actual)) { |
|
|
|
if (0 == safeCompare(exp, check)) { |
|
|
|
if (0 == safeCompare(exp, check)) { |
|
|
|
found = true; |
|
|
|
found = true; |
|
|
|
break; |
|
|
|
break; |
|
|
@ -135,7 +137,7 @@ public class Criteria implements Predicate { |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
logger.debug("[{}] {} [{}] => {}", join(", ", configuration.jsonProvider().toIterable(actual)), name(), join(", ", exps), res); |
|
|
|
logger.debug("[{}] {} [{}] => {}", join(", ", ctx.configuration().jsonProvider().toIterable(actual)), name(), join(", ", exps), res); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
res = false; |
|
|
|
res = false; |
|
|
|
logger.debug("[{}] {} [{}] => {}", "<NOT AN ARRAY>", name(), join(", ", exps), res); |
|
|
|
logger.debug("[{}] {} [{}] => {}", "<NOT AN ARRAY>", name(), join(", ", exps), res); |
|
|
@ -145,11 +147,11 @@ public class Criteria implements Predicate { |
|
|
|
}, |
|
|
|
}, |
|
|
|
SIZE { |
|
|
|
SIZE { |
|
|
|
@Override |
|
|
|
@Override |
|
|
|
boolean eval(Object expected, Object actual, Configuration configuration) { |
|
|
|
boolean eval(Object expected, Object actual, PredicateContext ctx) { |
|
|
|
int size = (Integer) expected; |
|
|
|
int size = (Integer) expected; |
|
|
|
boolean res; |
|
|
|
boolean res; |
|
|
|
if (configuration.jsonProvider().isArray(actual)) { |
|
|
|
if (ctx.configuration().jsonProvider().isArray(actual)) { |
|
|
|
int length = configuration.jsonProvider().length(actual); |
|
|
|
int length = ctx.configuration().jsonProvider().length(actual); |
|
|
|
res = (length == size); |
|
|
|
res = (length == size); |
|
|
|
logger.debug("Array with size {} {} {} => {}", length, name(), size, res); |
|
|
|
logger.debug("Array with size {} {} {} => {}", length, name(), size, res); |
|
|
|
} else if (actual instanceof String) { |
|
|
|
} else if (actual instanceof String) { |
|
|
@ -165,14 +167,14 @@ public class Criteria implements Predicate { |
|
|
|
}, |
|
|
|
}, |
|
|
|
EXISTS { |
|
|
|
EXISTS { |
|
|
|
@Override |
|
|
|
@Override |
|
|
|
boolean eval(Object expected, Object actual, Configuration configuration) { |
|
|
|
boolean eval(Object expected, Object actual, PredicateContext ctx) { |
|
|
|
//This must be handled outside
|
|
|
|
//This must be handled outside
|
|
|
|
throw new UnsupportedOperationException(); |
|
|
|
throw new UnsupportedOperationException(); |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
}, |
|
|
|
TYPE { |
|
|
|
TYPE { |
|
|
|
@Override |
|
|
|
@Override |
|
|
|
boolean eval(Object expected, Object actual, Configuration configuration) { |
|
|
|
boolean eval(Object expected, Object actual, PredicateContext ctx) { |
|
|
|
final Class<?> expType = (Class<?>) expected; |
|
|
|
final Class<?> expType = (Class<?>) expected; |
|
|
|
final Class<?> actType = actual == null ? null : actual.getClass(); |
|
|
|
final Class<?> actType = actual == null ? null : actual.getClass(); |
|
|
|
|
|
|
|
|
|
|
@ -181,7 +183,7 @@ public class Criteria implements Predicate { |
|
|
|
}, |
|
|
|
}, |
|
|
|
REGEX { |
|
|
|
REGEX { |
|
|
|
@Override |
|
|
|
@Override |
|
|
|
boolean eval(Object expected, Object actual, Configuration configuration) { |
|
|
|
boolean eval(Object expected, Object actual, PredicateContext ctx) { |
|
|
|
boolean res = false; |
|
|
|
boolean res = false; |
|
|
|
final Pattern pattern = (Pattern) expected; |
|
|
|
final Pattern pattern = (Pattern) expected; |
|
|
|
if (actual != null && actual instanceof String) { |
|
|
|
if (actual != null && actual instanceof String) { |
|
|
@ -193,28 +195,18 @@ public class Criteria implements Predicate { |
|
|
|
}, |
|
|
|
}, |
|
|
|
MATCHES { |
|
|
|
MATCHES { |
|
|
|
@Override |
|
|
|
@Override |
|
|
|
boolean eval(Object expected, final Object actual, final Configuration configuration) { |
|
|
|
boolean eval(Object expected, final Object actual, final PredicateContext ctx) { |
|
|
|
Predicate exp = (Predicate) expected; |
|
|
|
Predicate exp = (Predicate) expected; |
|
|
|
return exp.apply(new PredicateContext() { |
|
|
|
return exp.apply(new PredicateContextImpl(actual, ctx.rootDocument(), ctx.configuration())); |
|
|
|
@Override |
|
|
|
|
|
|
|
public Object target() { |
|
|
|
|
|
|
|
return actual; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
|
|
public Configuration configuration() { |
|
|
|
|
|
|
|
return configuration; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
}, |
|
|
|
NOT_EMPTY { |
|
|
|
NOT_EMPTY { |
|
|
|
@Override |
|
|
|
@Override |
|
|
|
boolean eval(Object expected, Object actual, Configuration configuration) { |
|
|
|
boolean eval(Object expected, Object actual, PredicateContext ctx) { |
|
|
|
boolean res = false; |
|
|
|
boolean res = false; |
|
|
|
if (actual != null) { |
|
|
|
if (actual != null) { |
|
|
|
if (configuration.jsonProvider().isArray(actual)) { |
|
|
|
if (ctx.configuration().jsonProvider().isArray(actual)) { |
|
|
|
int len = configuration.jsonProvider().length(actual); |
|
|
|
int len = ctx.configuration().jsonProvider().length(actual); |
|
|
|
res = (0 != len); |
|
|
|
res = (0 != len); |
|
|
|
logger.debug("array length = {} {} => {}", len, name(), res); |
|
|
|
logger.debug("array length = {} {} => {}", len, name(), res); |
|
|
|
} else if (actual instanceof String) { |
|
|
|
} else if (actual instanceof String) { |
|
|
@ -227,7 +219,7 @@ public class Criteria implements Predicate { |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
abstract boolean eval(Object expected, Object actual, Configuration configuration); |
|
|
|
abstract boolean eval(Object expected, Object actual, PredicateContext ctx); |
|
|
|
|
|
|
|
|
|
|
|
public static CriteriaType parse(String str) { |
|
|
|
public static CriteriaType parse(String str) { |
|
|
|
if ("==".equals(str)) { |
|
|
|
if ("==".equals(str)) { |
|
|
@ -283,16 +275,23 @@ public class Criteria implements Predicate { |
|
|
|
boolean exists = ((Boolean) expected); |
|
|
|
boolean exists = ((Boolean) expected); |
|
|
|
try { |
|
|
|
try { |
|
|
|
Configuration c = Configuration.builder().jsonProvider(ctx.configuration().jsonProvider()).options().build(); |
|
|
|
Configuration c = Configuration.builder().jsonProvider(ctx.configuration().jsonProvider()).options().build(); |
|
|
|
path.evaluate(ctx.target(), c).getValue(); |
|
|
|
path.evaluate(ctx.contextDocument(), ctx.rootDocument(), c).getValue(); |
|
|
|
return exists; |
|
|
|
return exists; |
|
|
|
} catch (PathNotFoundException e) { |
|
|
|
} catch (PathNotFoundException e) { |
|
|
|
return !exists; |
|
|
|
return !exists; |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
try { |
|
|
|
try { |
|
|
|
final Object actual = path.evaluate(ctx.target(), ctx.configuration()).getValue(); |
|
|
|
final Object actual = path.evaluate(ctx.contextDocument(), ctx.rootDocument(), ctx.configuration()).getValue(); |
|
|
|
|
|
|
|
|
|
|
|
return criteriaType.eval(expected, actual, ctx.configuration()); |
|
|
|
Object expectedVal = expected; |
|
|
|
|
|
|
|
if(expected instanceof Path){ |
|
|
|
|
|
|
|
Path expectedPath = (Path) expected; |
|
|
|
|
|
|
|
Object doc = expectedPath.isRootPath()?ctx.rootDocument():ctx.contextDocument(); |
|
|
|
|
|
|
|
expectedVal = expectedPath.evaluate(doc, ctx.rootDocument(), ctx.configuration()).getValue(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return criteriaType.eval(expectedVal, actual, ctx); |
|
|
|
} catch (ValueCompareException e) { |
|
|
|
} catch (ValueCompareException e) { |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
} catch (PathNotFoundException e) { |
|
|
|
} catch (PathNotFoundException e) { |
|
|
@ -571,6 +570,10 @@ public class Criteria implements Predicate { |
|
|
|
|
|
|
|
|
|
|
|
private static int safeCompare(Object expected, Object providerParsed) throws ValueCompareException { |
|
|
|
private static int safeCompare(Object expected, Object providerParsed) throws ValueCompareException { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(expected == providerParsed){ |
|
|
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
boolean expNullish = isNullish(expected); |
|
|
|
boolean expNullish = isNullish(expected); |
|
|
|
boolean provNullish = isNullish(providerParsed); |
|
|
|
boolean provNullish = isNullish(providerParsed); |
|
|
|
|
|
|
|
|
|
|
@ -611,12 +614,21 @@ public class Criteria implements Predicate { |
|
|
|
|
|
|
|
|
|
|
|
Path p = PathCompiler.compile(path); |
|
|
|
Path p = PathCompiler.compile(path); |
|
|
|
|
|
|
|
|
|
|
|
if ("$".equals(path) && (operator == null || operator.isEmpty()) && (expected == null || expected.isEmpty())) { |
|
|
|
if (("$".equals(path) || "@".equals(path) )&& (operator == null || operator.isEmpty()) && (expected == null || expected.isEmpty())) { |
|
|
|
return new Criteria(p, CriteriaType.NE, null); |
|
|
|
return new Criteria(p, CriteriaType.NE, null); |
|
|
|
} else if (operator.isEmpty()) { |
|
|
|
} else if (operator.isEmpty()) { |
|
|
|
return Criteria.where(path).exists(true); |
|
|
|
return Criteria.where(path).exists(true); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
return new Criteria(p, CriteriaType.parse(operator), expected); |
|
|
|
if(expected.startsWith("$") || expected.startsWith("@")){ |
|
|
|
|
|
|
|
Path compile = PathCompiler.compile(expected); |
|
|
|
|
|
|
|
if(!compile.isDefinite()){ |
|
|
|
|
|
|
|
throw new InvalidPathException("the predicate path: " + expected + " is not definite"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return new Criteria(p, CriteriaType.parse(operator), compile); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
return new Criteria(p, CriteriaType.parse(operator), expected); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|