Kalle Stenflo
9 years ago
26 changed files with 852 additions and 67 deletions
@ -0,0 +1,33 @@
|
||||
package com.jayway.jsonpath; |
||||
|
||||
import com.jayway.jsonpath.internal.EvaluationContext; |
||||
import com.jayway.jsonpath.internal.PathRef; |
||||
|
||||
/** |
||||
* Defines the pattern by which a function can be executed over the result set in the particular path |
||||
* being grabbed. The Function's input is the content of the data from the json path selector and its output |
||||
* is defined via the functions behavior. Thus transformations in types can take place. Additionally, functions |
||||
* can accept multiple selectors in order to produce their output. |
||||
* |
||||
* Created by matt@mjgreenwood.net on 6/26/15. |
||||
*/ |
||||
public interface Function { |
||||
|
||||
/** |
||||
* Invoke the function and output a JSON object (or scalar) value which will be the result of executing the path |
||||
* |
||||
* @param currentPath |
||||
* The current path location inclusive of the function name |
||||
* @param parent |
||||
* The path location above the current function |
||||
* |
||||
* @param model |
||||
* The JSON model as input to this particular function |
||||
* |
||||
* @param ctx |
||||
* Eval context, state bag used as the path is traversed, maintains the result of executing |
||||
* |
||||
* @return |
||||
*/ |
||||
Object invoke(String currentPath, PathRef parent, Object model, EvaluationContext ctx); |
||||
} |
@ -0,0 +1,71 @@
|
||||
package com.jayway.jsonpath.internal.function; |
||||
|
||||
import com.jayway.jsonpath.Function; |
||||
import com.jayway.jsonpath.InvalidPathException; |
||||
import com.jayway.jsonpath.internal.function.numeric.*; |
||||
|
||||
import java.util.Collections; |
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* Implements a factory that given a name of the function will return the Function implementation, or null |
||||
* if the value is not obtained. |
||||
* |
||||
* Leverages the function's name in order to determine which function to execute which is maintained internally |
||||
* here via a static map |
||||
* |
||||
* Created by mattg on 6/27/15. |
||||
*/ |
||||
public class FunctionFactory { |
||||
|
||||
public static final Map<String, Class> FUNCTIONS; |
||||
|
||||
static { |
||||
// New functions should be added here and ensure the name is not overridden
|
||||
Map<String, Class> map = new HashMap<String, Class>(); |
||||
|
||||
// Math Functions
|
||||
map.put("avg", Average.class); |
||||
map.put("stddev", StandardDeviation.class); |
||||
map.put("sum", Sum.class); |
||||
map.put("min", Min.class); |
||||
map.put("max", Max.class); |
||||
|
||||
// JSON Entity Functions
|
||||
map.put("length", Length.class); |
||||
|
||||
FUNCTIONS = Collections.unmodifiableMap(map); |
||||
} |
||||
|
||||
/** |
||||
* Either provides a pass thru function when the function cannot be properly mapped or otherwise returns the function |
||||
* implementation based on the name using the internal FUNCTION map |
||||
* |
||||
* @see #FUNCTIONS |
||||
* @see Function |
||||
* |
||||
* @param name |
||||
* The name of the function |
||||
* |
||||
* @return |
||||
* The implementation of a function |
||||
* |
||||
* @throws InvalidPathException |
||||
*/ |
||||
public static Function newFunction(String name) throws InvalidPathException { |
||||
Function result = new PassthruFunction(); |
||||
|
||||
if (null != name && FUNCTIONS.containsKey(name) && Function.class.isAssignableFrom(FUNCTIONS.get(name))) { |
||||
try { |
||||
result = (Function)FUNCTIONS.get(name).newInstance(); |
||||
} catch (InstantiationException e) { |
||||
throw new InvalidPathException("Function of name: " + name + " cannot be created", e); |
||||
} catch (IllegalAccessException e) { |
||||
throw new InvalidPathException("Function of name: " + name + " cannot be created", e); |
||||
} |
||||
} |
||||
return result; |
||||
|
||||
} |
||||
} |
@ -0,0 +1,26 @@
|
||||
package com.jayway.jsonpath.internal.function; |
||||
|
||||
import com.jayway.jsonpath.Function; |
||||
import com.jayway.jsonpath.internal.EvaluationContext; |
||||
import com.jayway.jsonpath.internal.PathRef; |
||||
import net.minidev.json.JSONArray; |
||||
|
||||
import java.util.*; |
||||
|
||||
/** |
||||
* Provides the length of a JSONArray Object |
||||
* |
||||
* Created by mattg on 6/26/15. |
||||
*/ |
||||
public class Length implements Function { |
||||
|
||||
@Override |
||||
public Object invoke(String currentPath, PathRef parent, Object model, EvaluationContext ctx) { |
||||
if(ctx.configuration().jsonProvider().isArray(model)){ |
||||
return ctx.configuration().jsonProvider().length(model); |
||||
} else if(ctx.configuration().jsonProvider().isMap(model)){ |
||||
return ctx.configuration().jsonProvider().length(model); |
||||
} |
||||
return null; |
||||
} |
||||
} |
@ -0,0 +1,18 @@
|
||||
package com.jayway.jsonpath.internal.function; |
||||
|
||||
import com.jayway.jsonpath.Function; |
||||
import com.jayway.jsonpath.internal.EvaluationContext; |
||||
import com.jayway.jsonpath.internal.PathRef; |
||||
|
||||
/** |
||||
* Defines the default behavior which is to return the model that is provided as input as output |
||||
* |
||||
* Created by mattg on 6/26/15. |
||||
*/ |
||||
public class PassthruFunction implements Function { |
||||
|
||||
@Override |
||||
public Object invoke(String currentPath, PathRef parent, Object model, EvaluationContext ctx) { |
||||
return model; |
||||
} |
||||
} |
@ -0,0 +1,55 @@
|
||||
package com.jayway.jsonpath.internal.function.numeric; |
||||
|
||||
import com.jayway.jsonpath.Function; |
||||
import com.jayway.jsonpath.internal.EvaluationContext; |
||||
import com.jayway.jsonpath.internal.PathRef; |
||||
import net.minidev.json.JSONArray; |
||||
|
||||
import java.util.Iterator; |
||||
|
||||
/** |
||||
* Defines the pattern for processing numerical values via an abstract implementation that iterates over the collection |
||||
* of JSONArray entities and verifies that each is a numerical value and then passes that along the abstract methods |
||||
* |
||||
* |
||||
* Created by mattg on 6/26/15. |
||||
*/ |
||||
public abstract class AbstractAggregation implements Function { |
||||
|
||||
/** |
||||
* Defines the next value in the array to the mathmatical function |
||||
* |
||||
* @param value |
||||
* The numerical value to process next |
||||
*/ |
||||
protected abstract void next(Number value); |
||||
|
||||
/** |
||||
* Obtains the value generated via the series of next value calls |
||||
* |
||||
* @return |
||||
* A numerical answer based on the input value provided |
||||
*/ |
||||
protected abstract Number getValue(); |
||||
|
||||
@Override |
||||
public Object invoke(String currentPath, PathRef parent, Object model, EvaluationContext ctx) { |
||||
if(ctx.configuration().jsonProvider().isArray(model)){ |
||||
|
||||
Iterable<?> objects = ctx.configuration().jsonProvider().toIterable(model); |
||||
for (Object obj : objects) { |
||||
// Object unwraped = ctx.configuration().jsonProvider().unwrap(obj);
|
||||
// if (unwraped instanceof Number) {
|
||||
// Number value = (Number) unwraped;
|
||||
// next(value);
|
||||
// }
|
||||
if (obj instanceof Number) { |
||||
Number value = (Number) obj; |
||||
next(value); |
||||
} |
||||
} |
||||
return getValue(); |
||||
} |
||||
return null; |
||||
} |
||||
} |
@ -0,0 +1,26 @@
|
||||
package com.jayway.jsonpath.internal.function.numeric; |
||||
|
||||
/** |
||||
* Provides the average of a series of numbers in a JSONArray |
||||
* |
||||
* Created by mattg on 6/26/15. |
||||
*/ |
||||
public class Average extends AbstractAggregation { |
||||
|
||||
private Double summation = 0d; |
||||
private Double count = 0d; |
||||
|
||||
@Override |
||||
protected void next(Number value) { |
||||
count++; |
||||
summation += value.doubleValue(); |
||||
} |
||||
|
||||
@Override |
||||
protected Number getValue() { |
||||
if (count != 0d) { |
||||
return summation / count; |
||||
} |
||||
return 0d; |
||||
} |
||||
} |
@ -0,0 +1,22 @@
|
||||
package com.jayway.jsonpath.internal.function.numeric; |
||||
|
||||
/** |
||||
* Defines the summation of a series of JSONArray numerical values |
||||
* |
||||
* Created by mattg on 6/26/15. |
||||
*/ |
||||
public class Max extends AbstractAggregation { |
||||
private Double max = Double.MIN_VALUE; |
||||
|
||||
@Override |
||||
protected void next(Number value) { |
||||
if (max < value.doubleValue()) { |
||||
max = value.doubleValue(); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
protected Number getValue() { |
||||
return max; |
||||
} |
||||
} |
@ -0,0 +1,22 @@
|
||||
package com.jayway.jsonpath.internal.function.numeric; |
||||
|
||||
/** |
||||
* Defines the summation of a series of JSONArray numerical values |
||||
* |
||||
* Created by mattg on 6/26/15. |
||||
*/ |
||||
public class Min extends AbstractAggregation { |
||||
private Double min = Double.MAX_VALUE; |
||||
|
||||
@Override |
||||
protected void next(Number value) { |
||||
if (min > value.doubleValue()) { |
||||
min = value.doubleValue(); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
protected Number getValue() { |
||||
return min; |
||||
} |
||||
} |
@ -0,0 +1,24 @@
|
||||
package com.jayway.jsonpath.internal.function.numeric; |
||||
|
||||
/** |
||||
* Provides the standard deviation of a series of numbers |
||||
* |
||||
* Created by mattg on 6/27/15. |
||||
*/ |
||||
public class StandardDeviation extends AbstractAggregation { |
||||
private Double sumSq = 0d; |
||||
private Double sum = 0d; |
||||
private Double count = 0d; |
||||
|
||||
@Override |
||||
protected void next(Number value) { |
||||
sum += value.doubleValue(); |
||||
sumSq += value.doubleValue() * value.doubleValue(); |
||||
count++; |
||||
} |
||||
|
||||
@Override |
||||
protected Number getValue() { |
||||
return Math.sqrt(sumSq/count - sum*sum/count/count); |
||||
} |
||||
} |
@ -0,0 +1,20 @@
|
||||
package com.jayway.jsonpath.internal.function.numeric; |
||||
|
||||
/** |
||||
* Defines the summation of a series of JSONArray numerical values |
||||
* |
||||
* Created by mattg on 6/26/15. |
||||
*/ |
||||
public class Sum extends AbstractAggregation { |
||||
private Double summation = 0d; |
||||
|
||||
@Override |
||||
protected void next(Number value) { |
||||
summation += value.doubleValue(); |
||||
} |
||||
|
||||
@Override |
||||
protected Number getValue() { |
||||
return summation; |
||||
} |
||||
} |
@ -0,0 +1,56 @@
|
||||
package com.jayway.jsonpath.internal.token; |
||||
|
||||
import com.jayway.jsonpath.Function; |
||||
import com.jayway.jsonpath.internal.PathRef; |
||||
import com.jayway.jsonpath.internal.function.FunctionFactory; |
||||
|
||||
import java.util.regex.Matcher; |
||||
import java.util.regex.Pattern; |
||||
|
||||
/** |
||||
* Token representing a Function call to one of the functions produced via the FunctionFactory |
||||
* |
||||
* @see FunctionFactory |
||||
* |
||||
* Created by mattg on 6/27/15. |
||||
*/ |
||||
public class FunctionPathToken extends PathToken { |
||||
|
||||
private final String functionName; |
||||
private final String pathFragment; |
||||
|
||||
public FunctionPathToken(String pathFragment) { |
||||
this.pathFragment = pathFragment; |
||||
Matcher matcher = Pattern.compile(".*?\\%(\\w+)\\(.*?").matcher(pathFragment); |
||||
if (matcher.matches()) { |
||||
functionName = matcher.group(1); |
||||
} |
||||
else { |
||||
// We'll end up throwing an error from the factory when we get that far
|
||||
functionName = null; |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void evaluate(String currentPath, PathRef parent, Object model, EvaluationContextImpl ctx) { |
||||
Function function = FunctionFactory.newFunction(functionName); |
||||
Object result = function.invoke(currentPath, parent, model, ctx); |
||||
ctx.addResult(currentPath, parent, result); |
||||
} |
||||
|
||||
/** |
||||
* Return the actual value by indicating true. If this return was false then we'd return the value in an array which |
||||
* isn't what is desired - true indicates the raw value is returned. |
||||
* |
||||
* @return |
||||
*/ |
||||
@Override |
||||
public boolean isTokenDefinite() { |
||||
return true; |
||||
} |
||||
|
||||
@Override |
||||
public String getPathFragment() { |
||||
return pathFragment; |
||||
} |
||||
} |
@ -0,0 +1,56 @@
|
||||
package com.jayway.jsonpath; |
||||
|
||||
import com.jayway.jsonpath.spi.json.GsonJsonProvider; |
||||
import com.jayway.jsonpath.spi.json.JacksonJsonNodeJsonProvider; |
||||
import com.jayway.jsonpath.spi.json.JacksonJsonProvider; |
||||
import com.jayway.jsonpath.spi.json.JsonSmartJsonProvider; |
||||
import com.jayway.jsonpath.spi.mapper.GsonMappingProvider; |
||||
import com.jayway.jsonpath.spi.mapper.JacksonMappingProvider; |
||||
import com.jayway.jsonpath.spi.mapper.JsonSmartMappingProvider; |
||||
|
||||
import java.util.Arrays; |
||||
|
||||
public class Configurations { |
||||
|
||||
public static final Configuration GSON_CONFIGURATION = Configuration |
||||
.builder() |
||||
.mappingProvider(new GsonMappingProvider()) |
||||
.jsonProvider(new GsonJsonProvider()) |
||||
.build(); |
||||
|
||||
public static final Configuration JACKSON_CONFIGURATION = Configuration |
||||
.builder() |
||||
.mappingProvider(new JacksonMappingProvider()) |
||||
.jsonProvider(new JacksonJsonProvider()) |
||||
.build(); |
||||
|
||||
public static final Configuration JACKSON_JSON_NODE_CONFIGURATION = Configuration |
||||
.builder() |
||||
.mappingProvider(new JacksonMappingProvider()) |
||||
.jsonProvider(new JacksonJsonNodeJsonProvider()) |
||||
.build(); |
||||
|
||||
public static final Configuration JSON_SMART_CONFIGURATION = Configuration |
||||
.builder() |
||||
.mappingProvider(new JsonSmartMappingProvider()) |
||||
.jsonProvider(new JsonSmartJsonProvider()) |
||||
.build(); |
||||
|
||||
public static Iterable<Configuration> configurations() { |
||||
return Arrays.asList( |
||||
JSON_SMART_CONFIGURATION |
||||
,GSON_CONFIGURATION |
||||
,JACKSON_CONFIGURATION |
||||
,JACKSON_JSON_NODE_CONFIGURATION |
||||
); |
||||
} |
||||
|
||||
|
||||
public static Iterable<Configuration> objectMappingConfigurations() { |
||||
return Arrays.asList( |
||||
GSON_CONFIGURATION |
||||
,JACKSON_CONFIGURATION |
||||
,JACKSON_JSON_NODE_CONFIGURATION |
||||
); |
||||
} |
||||
} |
@ -0,0 +1,75 @@
|
||||
package com.jayway.jsonpath; |
||||
|
||||
import org.junit.Test; |
||||
import org.junit.runner.RunWith; |
||||
import org.junit.runners.Parameterized; |
||||
|
||||
import java.io.IOException; |
||||
import java.util.List; |
||||
|
||||
import static com.jayway.jsonpath.JsonPath.using; |
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
@RunWith(Parameterized.class) |
||||
public class JsonProviderTestObjectMapping extends BaseTest { |
||||
|
||||
private static final String JSON = |
||||
"[" + |
||||
"{\n" + |
||||
" \"foo\" : \"foo0\",\n" + |
||||
" \"bar\" : 0,\n" + |
||||
" \"baz\" : true,\n" + |
||||
" \"gen\" : {\"prop\" : \"yepp0\"}" + |
||||
"}," + |
||||
"{\n" + |
||||
" \"foo\" : \"foo1\",\n" + |
||||
" \"bar\" : 1,\n" + |
||||
" \"baz\" : true,\n" + |
||||
" \"gen\" : {\"prop\" : \"yepp1\"}" + |
||||
"}," + |
||||
"{\n" + |
||||
" \"foo\" : \"foo2\",\n" + |
||||
" \"bar\" : 2,\n" + |
||||
" \"baz\" : true,\n" + |
||||
" \"gen\" : {\"prop\" : \"yepp2\"}" + |
||||
"}" + |
||||
"]"; |
||||
|
||||
private final Configuration conf; |
||||
|
||||
public JsonProviderTestObjectMapping(Configuration conf) { |
||||
this.conf = conf; |
||||
} |
||||
|
||||
@Parameterized.Parameters |
||||
public static Iterable<Configuration> configurations() { |
||||
return Configurations.objectMappingConfigurations(); |
||||
} |
||||
|
||||
@Test |
||||
public void list_of_numbers() { |
||||
|
||||
TypeRef<List<Double>> typeRef = new TypeRef<List<Double>>() {}; |
||||
|
||||
assertThat(using(conf).parse(JSON_DOCUMENT).read("$.store.book[*].display-price", typeRef)).containsExactly(8.95D, 12.99D, 8.99D, 22.99D); |
||||
} |
||||
|
||||
@Test |
||||
public void test_type_ref() throws IOException { |
||||
TypeRef<List<FooBarBaz<Sub>>> typeRef = new TypeRef<List<FooBarBaz<Sub>>>() {}; |
||||
|
||||
assertThat(using(conf).parse(JSON).read("$", typeRef)).extracting("foo").containsExactly("foo0", "foo1", "foo2"); |
||||
} |
||||
|
||||
|
||||
public static class FooBarBaz<T> { |
||||
public T gen; |
||||
public String foo; |
||||
public Long bar; |
||||
public boolean baz; |
||||
} |
||||
|
||||
public static class Sub { |
||||
public String prop; |
||||
} |
||||
} |
@ -0,0 +1,45 @@
|
||||
package com.jayway.jsonpath.functions; |
||||
|
||||
import com.jayway.jsonpath.Configuration; |
||||
|
||||
import java.io.IOException; |
||||
import java.util.Scanner; |
||||
|
||||
import static com.jayway.jsonpath.JsonPath.using; |
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
/** |
||||
* Created by mattg on 6/27/15. |
||||
*/ |
||||
public class BaseFunctionTest { |
||||
protected static final String NUMBER_SERIES = "{\"numbers\" : [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]}"; |
||||
protected static final String TEXT_SERIES = "{\"text\" : [ \"a\", \"b\", \"c\", \"d\", \"e\", \"f\" ]}"; |
||||
|
||||
|
||||
|
||||
|
||||
/** |
||||
* Verify the function returns the correct result based on the input expectedValue |
||||
* |
||||
* @param pathExpr |
||||
* The path expression to execute |
||||
* |
||||
* @param json |
||||
* The json document (actual content) to parse |
||||
* |
||||
* @param expectedValue |
||||
* The expected value to be returned from the test |
||||
*/ |
||||
protected void verifyFunction(Configuration conf, String pathExpr, String json, Object expectedValue) { |
||||
Object result = using(conf).parse(json).read(pathExpr); |
||||
assertThat(result).isEqualTo(expectedValue); |
||||
} |
||||
|
||||
protected void verifyMathFunction(Configuration conf, String pathExpr, Object expectedValue) { |
||||
verifyFunction(conf, pathExpr, NUMBER_SERIES, expectedValue); |
||||
} |
||||
|
||||
protected String getResourceAsText(String resourceName) throws IOException { |
||||
return new Scanner(BaseFunctionTest.class.getResourceAsStream(resourceName), "UTF-8").useDelimiter("\\A").next(); |
||||
} |
||||
} |
@ -0,0 +1,105 @@
|
||||
package com.jayway.jsonpath.functions; |
||||
|
||||
import com.jayway.jsonpath.Configuration; |
||||
import com.jayway.jsonpath.Configurations; |
||||
import net.minidev.json.JSONArray; |
||||
import org.junit.Test; |
||||
|
||||
/** |
||||
* Verifies methods that are helper implementations of functions for manipulating JSON entities, i.e. |
||||
* length, etc. |
||||
* |
||||
* Created by mattg on 6/27/15. |
||||
*/ |
||||
public class JSONEntityFunctionTest extends BaseFunctionTest { |
||||
|
||||
|
||||
private static final String BATCH_JSON = "{\n" + |
||||
" \"batches\": {\n" + |
||||
" \"minBatchSize\": 10,\n" + |
||||
" \"results\": [\n" + |
||||
" {\n" + |
||||
" \"productId\": 23,\n" + |
||||
" \"values\": [\n" + |
||||
" 2,\n" + |
||||
" 45,\n" + |
||||
" 34,\n" + |
||||
" 23,\n" + |
||||
" 3,\n" + |
||||
" 5,\n" + |
||||
" 4,\n" + |
||||
" 3,\n" + |
||||
" 2,\n" + |
||||
" 1,\n" + |
||||
" ]\n" + |
||||
" },\n" + |
||||
" {\n" + |
||||
" \"productId\": 23,\n" + |
||||
" \"values\": [\n" + |
||||
" 52,\n" + |
||||
" 3,\n" + |
||||
" 12,\n" + |
||||
" 11,\n" + |
||||
" 18,\n" + |
||||
" 22,\n" + |
||||
" 1\n" + |
||||
" ]\n" + |
||||
" }\n" + |
||||
" ]\n" + |
||||
" }\n" + |
||||
"}"; |
||||
|
||||
private Configuration conf = Configurations.JSON_SMART_CONFIGURATION; |
||||
|
||||
@Test |
||||
public void testLengthOfTextArray() { |
||||
// The length of JSONArray is an integer
|
||||
System.out.println(TEXT_SERIES); |
||||
verifyFunction(conf, "$['text'].%length()", TEXT_SERIES, 6); |
||||
} |
||||
@Test |
||||
public void testLengthOfNumberArray() { |
||||
// The length of JSONArray is an integer
|
||||
verifyFunction(conf, "$.numbers.%length()", NUMBER_SERIES, 10); |
||||
} |
||||
|
||||
|
||||
@Test |
||||
public void testLengthOfStructure() { |
||||
verifyFunction(conf, "$.batches.%length()", BATCH_JSON, 2); |
||||
} |
||||
|
||||
/** |
||||
* The fictitious use-case/story - is we have a collection of batches with values indicating some quality metric. |
||||
* We want to determine the average of the values for only the batch's values where the number of items in the batch |
||||
* is greater than the min batch size which is encoded in the JSON document. |
||||
* |
||||
* We use the length function in the predicate to determine the number of values in each batch and then for those |
||||
* batches where the count is greater than min we calculate the average batch value. |
||||
* |
||||
* Its completely contrived example, however, this test exercises functions within predicates. |
||||
*/ |
||||
@Test |
||||
public void testPredicateWithFunctionCallSingleMatch() { |
||||
String path = "$.batches.results[?(@.values.%length() >= $.batches.minBatchSize)].values.%avg()"; |
||||
|
||||
// Its an array because in some use-cases the min size might match more than one batch and thus we'll get
|
||||
// the average out for each collection
|
||||
JSONArray values = new JSONArray(); |
||||
values.add(12.2d); |
||||
verifyFunction(conf, path, BATCH_JSON, values); |
||||
} |
||||
|
||||
@Test |
||||
public void testPredicateWithFunctionCallTwoMatches() { |
||||
String path = "$.batches.results[?(@.values.%length() >= 3)].values.%avg()"; |
||||
|
||||
// Its an array because in some use-cases the min size might match more than one batch and thus we'll get
|
||||
// the average out for each collection
|
||||
JSONArray values = new JSONArray(); |
||||
values.add(12.2d); |
||||
values.add(17d); |
||||
verifyFunction(conf, path, BATCH_JSON, values); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,90 @@
|
||||
package com.jayway.jsonpath.functions; |
||||
|
||||
import com.jayway.jsonpath.Configuration; |
||||
import com.jayway.jsonpath.Configurations; |
||||
import com.jayway.jsonpath.JsonPath; |
||||
import net.minidev.json.JSONArray; |
||||
import org.junit.Ignore; |
||||
import org.junit.Test; |
||||
import org.junit.experimental.theories.DataPoints; |
||||
import org.junit.experimental.theories.Theories; |
||||
import org.junit.experimental.theories.Theory; |
||||
import org.junit.runner.RunWith; |
||||
import org.junit.runners.Parameterized; |
||||
import org.slf4j.Logger; |
||||
import org.slf4j.LoggerFactory; |
||||
|
||||
import java.util.Arrays; |
||||
|
||||
import static com.jayway.jsonpath.Configurations.*; |
||||
import static com.jayway.jsonpath.JsonPath.using; |
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static org.junit.runners.Parameterized.Parameters; |
||||
|
||||
/** |
||||
* Defines functional tests around executing: |
||||
* |
||||
* - sum |
||||
* - avg |
||||
* - stddev |
||||
* |
||||
* for each of the above, executes the test and verifies that the results are as expected based on a static input |
||||
* and static output. |
||||
* |
||||
* Created by mattg on 6/26/15. |
||||
*/ |
||||
@RunWith(Parameterized.class) |
||||
public class NumericFunctionTest extends BaseFunctionTest { |
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(NumericFunctionTest.class); |
||||
|
||||
private Configuration conf = Configurations.GSON_CONFIGURATION; |
||||
|
||||
public NumericFunctionTest(Configuration conf) { |
||||
logger.debug("Testing with configuration {}", conf.getClass().getName()); |
||||
this.conf = conf; |
||||
} |
||||
|
||||
@Parameters |
||||
public static Iterable<Configuration> configurations() { |
||||
return Configurations.configurations(); |
||||
} |
||||
|
||||
|
||||
@Test |
||||
public void testAverageOfDoubles() { |
||||
verifyMathFunction(conf, "$.numbers.%avg()", 5.5); |
||||
} |
||||
|
||||
@Test |
||||
public void testSumOfDouble() { |
||||
verifyMathFunction(conf, "$.numbers.%sum()", (10d * (10d + 1d)) / 2d); |
||||
} |
||||
|
||||
@Test |
||||
public void testMaxOfDouble() { |
||||
verifyMathFunction(conf, "$.numbers.%max()", 10d); |
||||
} |
||||
|
||||
@Test |
||||
public void testMinOfDouble() { |
||||
verifyMathFunction(conf, "$.numbers.%min()", 1d); |
||||
} |
||||
|
||||
@Test |
||||
public void testStdDevOfDouble() { |
||||
verifyMathFunction(conf, "$.numbers.%stddev()", 2.8722813232690143d); |
||||
} |
||||
|
||||
/** |
||||
* Expect that for an invalid function name we'll get back the original input to the function |
||||
*/ |
||||
// @Test
|
||||
// @Ignore
|
||||
// public void testInvalidFunctionNameNegative() {
|
||||
// JSONArray numberSeries = new JSONArray();
|
||||
// numberSeries.addAll(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
|
||||
// assertThat(using(conf).parse(NUMBER_SERIES).read("$.numbers.%foo()")).isEqualTo(numberSeries);
|
||||
// }
|
||||
|
||||
} |
Loading…
Reference in new issue