diff --git a/build.gradle b/build.gradle index 9317f91..ef424d9 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ plugins { } group "io.github.jamsesso" -version "1.0.10-SNAPSHOT" +version "1.1.0-SNAPSHOT" sourceCompatibility = 1.8 targetCompatibility = 1.8 diff --git a/src/main/java/io/github/jamsesso/jsonlogic/JsonLogic.java b/src/main/java/io/github/jamsesso/jsonlogic/JsonLogic.java index 47add88..fa25f2f 100644 --- a/src/main/java/io/github/jamsesso/jsonlogic/JsonLogic.java +++ b/src/main/java/io/github/jamsesso/jsonlogic/JsonLogic.java @@ -57,7 +57,7 @@ public JsonLogic() { public JsonLogic addOperation(String name, Function function) { return addOperation(new PreEvaluatedArgumentsExpression() { @Override - public Object evaluate(List arguments, Object data) { + public Object evaluate(List arguments, Object data, String jsonPath) { return function.apply(arguments.toArray()); } @@ -84,7 +84,7 @@ public Object apply(String json, Object data) throws JsonLogicException { evaluator = new JsonLogicEvaluator(expressions); } - return evaluator.evaluate(parseCache.get(json), data); + return evaluator.evaluate(parseCache.get(json), data, "$"); } public static boolean truthy(Object value) { diff --git a/src/main/java/io/github/jamsesso/jsonlogic/JsonLogicException.java b/src/main/java/io/github/jamsesso/jsonlogic/JsonLogicException.java index 0c03d25..71b961f 100644 --- a/src/main/java/io/github/jamsesso/jsonlogic/JsonLogicException.java +++ b/src/main/java/io/github/jamsesso/jsonlogic/JsonLogicException.java @@ -1,19 +1,24 @@ package io.github.jamsesso.jsonlogic; public class JsonLogicException extends Exception { + + private String jsonPath; + private JsonLogicException() { // The default constructor should not be called for exceptions. A reason must be provided. } - public JsonLogicException(String msg) { + public JsonLogicException(String msg, String jsonPath) { super(msg); + this.jsonPath = jsonPath; } - public JsonLogicException(Throwable cause) { + public JsonLogicException(Throwable cause, String jsonPath) { super(cause); + this.jsonPath = jsonPath; } - public JsonLogicException(String msg, Throwable cause) { - super(msg, cause); + public String getJsonPath() { + return jsonPath; } } diff --git a/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicParseException.java b/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicParseException.java index ff43164..1df20ec 100644 --- a/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicParseException.java +++ b/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicParseException.java @@ -3,15 +3,11 @@ import io.github.jamsesso.jsonlogic.JsonLogicException; public class JsonLogicParseException extends JsonLogicException { - public JsonLogicParseException(String msg) { - super(msg); + public JsonLogicParseException(String msg, String jsonPath) { + super(msg, jsonPath); } - public JsonLogicParseException(Throwable cause) { - super(cause); - } - - public JsonLogicParseException(String msg, Throwable cause) { - super(msg, cause); + public JsonLogicParseException(Throwable cause, String jsonPath) { + super(cause, jsonPath); } } diff --git a/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicParser.java b/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicParser.java index 21cfba7..bf442b8 100644 --- a/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicParser.java +++ b/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicParser.java @@ -18,11 +18,14 @@ public static JsonLogicNode parse(String json) throws JsonLogicParseException { return parse(PARSER.parse(json)); } catch (JsonSyntaxException e) { - throw new JsonLogicParseException(e); + throw new JsonLogicParseException(e, "$"); } } private static JsonLogicNode parse(JsonElement root) throws JsonLogicParseException { + return parse(root, "$"); + } + private static JsonLogicNode parse(JsonElement root, String jsonPath) throws JsonLogicParseException { // Handle null if (root.isJsonNull()) { return JsonLogicNull.NULL; @@ -53,8 +56,9 @@ private static JsonLogicNode parse(JsonElement root) throws JsonLogicParseExcept JsonArray array = root.getAsJsonArray(); List elements = new ArrayList<>(array.size()); + int index = 0; for (JsonElement element : array) { - elements.add(parse(element)); + elements.add(parse(element, String.format("%s[%d]", jsonPath, index++))); } return new JsonLogicArray(elements); @@ -64,11 +68,11 @@ private static JsonLogicNode parse(JsonElement root) throws JsonLogicParseExcept JsonObject object = root.getAsJsonObject(); if (object.keySet().size() != 1) { - throw new JsonLogicParseException("objects must have exactly 1 key defined, found " + object.keySet().size()); + throw new JsonLogicParseException("objects must have exactly 1 key defined, found " + object.keySet().size(), jsonPath); } String key = object.keySet().stream().findAny().get(); - JsonLogicNode argumentNode = parse(object.get(key)); + JsonLogicNode argumentNode = parse(object.get(key), String.format("%s.%s", jsonPath, key)); JsonLogicArray arguments; // Always coerce single-argument operations into a JsonLogicArray with a single element. diff --git a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/JsonLogicEvaluationException.java b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/JsonLogicEvaluationException.java index 20394f9..2fcf35d 100644 --- a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/JsonLogicEvaluationException.java +++ b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/JsonLogicEvaluationException.java @@ -3,15 +3,11 @@ import io.github.jamsesso.jsonlogic.JsonLogicException; public class JsonLogicEvaluationException extends JsonLogicException { - public JsonLogicEvaluationException(String msg) { - super(msg); + public JsonLogicEvaluationException(String msg, String jsonPath) { + super(msg, jsonPath); } - public JsonLogicEvaluationException(Throwable cause) { - super(cause); - } - - public JsonLogicEvaluationException(String msg, Throwable cause) { - super(msg, cause); + public JsonLogicEvaluationException(Throwable cause, String jsonPath) { + super(cause, jsonPath); } } diff --git a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/JsonLogicEvaluator.java b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/JsonLogicEvaluator.java index 804ee1e..d78892b 100644 --- a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/JsonLogicEvaluator.java +++ b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/JsonLogicEvaluator.java @@ -20,12 +20,12 @@ public JsonLogicEvaluator(Map expressions) { this.expressions = Collections.unmodifiableMap(expressions); } - public Object evaluate(JsonLogicNode node, Object data) throws JsonLogicEvaluationException { + public Object evaluate(JsonLogicNode node, Object data, String jsonPath) throws JsonLogicEvaluationException { switch (node.getType()) { case PRIMITIVE: return evaluate((JsonLogicPrimitive) node); - case VARIABLE: return evaluate((JsonLogicVariable) node, data); - case ARRAY: return evaluate((JsonLogicArray) node, data); - default: return evaluate((JsonLogicOperation) node, data); + case VARIABLE: return evaluate((JsonLogicVariable) node, data, jsonPath + ".var"); + case ARRAY: return evaluate((JsonLogicArray) node, data, jsonPath); + default: return evaluate((JsonLogicOperation) node, data, jsonPath); } } @@ -38,19 +38,20 @@ public Object evaluate(JsonLogicPrimitive primitive) { } } - public Object evaluate(JsonLogicVariable variable, Object data) throws JsonLogicEvaluationException { - Object defaultValue = evaluate(variable.getDefaultValue(), null); + public Object evaluate(JsonLogicVariable variable, Object data, String jsonPath) + throws JsonLogicEvaluationException { + Object defaultValue = evaluate(variable.getDefaultValue(), null, jsonPath + "[1]"); if (data == null) { return defaultValue; } - Object key = evaluate(variable.getKey(), data); + Object key = evaluate(variable.getKey(), data, jsonPath + "[0]"); if (key == null) { return Optional.of(data) .map(JsonLogicEvaluator::transform) - .orElse(evaluate(variable.getDefaultValue(), null)); + .orElse(evaluate(variable.getDefaultValue(), null, jsonPath + "[1]")); } if (key instanceof Number) { @@ -78,10 +79,10 @@ public Object evaluate(JsonLogicVariable variable, Object data) throws JsonLogic String[] keys = name.split("\\."); Object result = data; - for(String partial : keys) { - result = evaluatePartialVariable(partial, result); + for (String partial : keys) { + result = evaluatePartialVariable(partial, result, jsonPath + "[0]"); - if(result == null) { + if (result == null) { return defaultValue; } } @@ -89,10 +90,10 @@ public Object evaluate(JsonLogicVariable variable, Object data) throws JsonLogic return result; } - throw new JsonLogicEvaluationException("var first argument must be null, number, or string"); + throw new JsonLogicEvaluationException("var first argument must be null, number, or string", jsonPath + "[0]"); } - private Object evaluatePartialVariable(String key, Object data) throws JsonLogicEvaluationException { + private Object evaluatePartialVariable(String key, Object data, String jsonPath) throws JsonLogicEvaluationException { if (ArrayLike.isEligible(data)) { ArrayLike list = new ArrayLike(data); int index; @@ -101,7 +102,7 @@ private Object evaluatePartialVariable(String key, Object data) throws JsonLogic index = Integer.parseInt(key); } catch (NumberFormatException e) { - throw new JsonLogicEvaluationException(e); + throw new JsonLogicEvaluationException(e, jsonPath); } if (index < 0 || index >= list.size()) { @@ -118,24 +119,25 @@ private Object evaluatePartialVariable(String key, Object data) throws JsonLogic return null; } - public List evaluate(JsonLogicArray array, Object data) throws JsonLogicEvaluationException { + public List evaluate(JsonLogicArray array, Object data, String jsonPath) throws JsonLogicEvaluationException { List values = new ArrayList<>(array.size()); + int index = 0; for(JsonLogicNode element : array) { - values.add(evaluate(element, data)); + values.add(evaluate(element, data, String.format("%s[%d]", jsonPath, index++))); } return values; } - public Object evaluate(JsonLogicOperation operation, Object data) throws JsonLogicEvaluationException { + public Object evaluate(JsonLogicOperation operation, Object data, String jsonPath) throws JsonLogicEvaluationException { JsonLogicExpression handler = expressions.get(operation.getOperator()); if (handler == null) { - throw new JsonLogicEvaluationException("Undefined operation '" + operation.getOperator() + "'"); + throw new JsonLogicEvaluationException("Undefined operation '" + operation.getOperator() + "'", jsonPath); } - return handler.evaluate(this, operation.getArguments(), data); + return handler.evaluate(this, operation.getArguments(), data, String.format("%s.%s", jsonPath, operation.getOperator())); } public static Object transform(Object value) { @@ -145,4 +147,4 @@ public static Object transform(Object value) { return value; } -} \ No newline at end of file +} diff --git a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/JsonLogicExpression.java b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/JsonLogicExpression.java index 7c267bb..0f1381b 100644 --- a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/JsonLogicExpression.java +++ b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/JsonLogicExpression.java @@ -5,6 +5,6 @@ public interface JsonLogicExpression { String key(); - Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data) + Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data, String jsonPath) throws JsonLogicEvaluationException; } diff --git a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/AllExpression.java b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/AllExpression.java index 711387a..2e9350f 100644 --- a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/AllExpression.java +++ b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/AllExpression.java @@ -20,20 +20,20 @@ public String key() { } @Override - public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data) + public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data, String jsonPath) throws JsonLogicEvaluationException { if (arguments.size() != 2) { - throw new JsonLogicEvaluationException("all expects exactly 2 arguments"); + throw new JsonLogicEvaluationException("all expects exactly 2 arguments", jsonPath); } - Object maybeArray = evaluator.evaluate(arguments.get(0), data); + Object maybeArray = evaluator.evaluate(arguments.get(0), data, jsonPath + "[0]"); if (maybeArray == null) { return false; } if (!ArrayLike.isEligible(maybeArray)) { - throw new JsonLogicEvaluationException("first argument to all must be a valid array"); + throw new JsonLogicEvaluationException("first argument to all must be a valid array", jsonPath); } ArrayLike array = new ArrayLike(maybeArray); @@ -42,8 +42,9 @@ public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, O return false; } + int index = 1; for (Object item : array) { - if(!JsonLogic.truthy(evaluator.evaluate(arguments.get(1), item))) { + if(!JsonLogic.truthy(evaluator.evaluate(arguments.get(1), item, String.format("%s[%d]", jsonPath, index)))) { return false; } } diff --git a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/ArrayHasExpression.java b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/ArrayHasExpression.java index 44d3bb5..7d9bb14 100644 --- a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/ArrayHasExpression.java +++ b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/ArrayHasExpression.java @@ -23,13 +23,13 @@ public String key() { } @Override - public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data) + public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data, String jsonPath) throws JsonLogicEvaluationException { if (arguments.size() != 2) { - throw new JsonLogicEvaluationException("some expects exactly 2 arguments"); + throw new JsonLogicEvaluationException(key() + " expects exactly 2 arguments", jsonPath); } - Object maybeArray = evaluator.evaluate(arguments.get(0), data); + Object maybeArray = evaluator.evaluate(arguments.get(0), data, jsonPath + "[0]"); // Array objects can have null values according to http://jsonlogic.com/ if (maybeArray == null) { @@ -41,15 +41,15 @@ public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, O } if (!ArrayLike.isEligible(maybeArray)) { - throw new JsonLogicEvaluationException("first argument to some must be a valid array"); + throw new JsonLogicEvaluationException("first argument to " + key() + " must be a valid array", jsonPath + "[0]"); } for (Object item : new ArrayLike(maybeArray)) { - if(JsonLogic.truthy(evaluator.evaluate(arguments.get(1), item))) { + if(JsonLogic.truthy(evaluator.evaluate(arguments.get(1), item, jsonPath + "[1]"))) { return isSome; } } return !isSome; } -} \ No newline at end of file +} diff --git a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/ConcatenateExpression.java b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/ConcatenateExpression.java index 81dd180..1ef7651 100644 --- a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/ConcatenateExpression.java +++ b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/ConcatenateExpression.java @@ -18,7 +18,7 @@ public String key() { } @Override - public Object evaluate(List arguments, Object data) throws JsonLogicEvaluationException { + public Object evaluate(List arguments, Object data, String jsonPath) throws JsonLogicEvaluationException { return arguments.stream() .map(obj -> { if (obj instanceof Double && obj.toString().endsWith(".0")) { diff --git a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/EqualityExpression.java b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/EqualityExpression.java index efde9ef..0262ba1 100644 --- a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/EqualityExpression.java +++ b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/EqualityExpression.java @@ -18,9 +18,9 @@ public String key() { } @Override - public Object evaluate(List arguments, Object data) throws JsonLogicEvaluationException { + public Object evaluate(List arguments, Object data, String jsonPath) throws JsonLogicEvaluationException { if (arguments.size() != 2) { - throw new JsonLogicEvaluationException("equality expressions expect exactly 2 arguments"); + throw new JsonLogicEvaluationException("equality expressions expect exactly 2 arguments", jsonPath); } Object left = arguments.get(0); diff --git a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/FilterExpression.java b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/FilterExpression.java index 520c06e..79364e9 100644 --- a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/FilterExpression.java +++ b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/FilterExpression.java @@ -23,22 +23,22 @@ public String key() { } @Override - public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data) + public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data, String jsonPath) throws JsonLogicEvaluationException { if (arguments.size() != 2) { - throw new JsonLogicEvaluationException("filter expects exactly 2 arguments"); + throw new JsonLogicEvaluationException("filter expects exactly 2 arguments", jsonPath); } - Object maybeArray = evaluator.evaluate(arguments.get(0), data); + Object maybeArray = evaluator.evaluate(arguments.get(0), data, jsonPath + "[0]"); if (!ArrayLike.isEligible(maybeArray)) { - throw new JsonLogicEvaluationException("first argument to filter must be a valid array"); + throw new JsonLogicEvaluationException("first argument to filter must be a valid array", jsonPath + "[0]"); } List result = new ArrayList<>(); for (Object item : new ArrayLike(maybeArray)) { - if(JsonLogic.truthy(evaluator.evaluate(arguments.get(1), item))) { + if(JsonLogic.truthy(evaluator.evaluate(arguments.get(1), item, jsonPath + "[1]"))) { result.add(item); } } diff --git a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/IfExpression.java b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/IfExpression.java index 165c6b7..230a636 100644 --- a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/IfExpression.java +++ b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/IfExpression.java @@ -23,7 +23,8 @@ public String key() { } @Override - public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data) + public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data, + String jsonPath) throws JsonLogicEvaluationException { if (arguments.size() < 1) { return null; @@ -31,13 +32,13 @@ public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, O // If there is only a single argument, simply evaluate & return that argument. if (arguments.size() == 1) { - return evaluator.evaluate(arguments.get(0), data); + return evaluator.evaluate(arguments.get(0), data, jsonPath + "[0]"); } // If there is 2 arguments, only evaluate the second argument if the first argument is truthy. if (arguments.size() == 2) { - return JsonLogic.truthy(evaluator.evaluate(arguments.get(0), data)) - ? evaluator.evaluate(arguments.get(1), data) + return JsonLogic.truthy(evaluator.evaluate(arguments.get(0), data, jsonPath + "[0]")) + ? evaluator.evaluate(arguments.get(1), data, jsonPath + "[1]") : null; } @@ -45,8 +46,8 @@ public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, O JsonLogicNode condition = arguments.get(i); JsonLogicNode resultIfTrue = arguments.get(i + 1); - if (JsonLogic.truthy(evaluator.evaluate(condition, data))) { - return evaluator.evaluate(resultIfTrue, data); + if (JsonLogic.truthy(evaluator.evaluate(condition, data, String.format("%s[%d]", jsonPath, i)))) { + return evaluator.evaluate(resultIfTrue, data, String.format("%s[%d]", jsonPath, i + 1)); } } @@ -54,6 +55,6 @@ public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, O return null; } - return evaluator.evaluate(arguments.get(arguments.size() - 1), data); + return evaluator.evaluate(arguments.get(arguments.size() - 1), data, String.format("%s[%d]", jsonPath, arguments.size() - 1)); } } diff --git a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/InExpression.java b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/InExpression.java index 848adf0..e5f6d0b 100644 --- a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/InExpression.java +++ b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/InExpression.java @@ -18,7 +18,7 @@ public String key() { } @Override - public Object evaluate(List arguments, Object data) throws JsonLogicEvaluationException { + public Object evaluate(List arguments, Object data, String jsonPath) throws JsonLogicEvaluationException { if (arguments.size() < 2) { return false; } diff --git a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/InequalityExpression.java b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/InequalityExpression.java index a0ae49a..747afb0 100644 --- a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/InequalityExpression.java +++ b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/InequalityExpression.java @@ -20,9 +20,9 @@ public String key() { } @Override - public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data) + public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data, String jsonPath) throws JsonLogicEvaluationException { - boolean result = (boolean) delegate.evaluate(evaluator, arguments, data); + boolean result = (boolean) delegate.evaluate(evaluator, arguments, data, jsonPath); return !result; } diff --git a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/LogExpression.java b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/LogExpression.java index e82c261..43332c5 100644 --- a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/LogExpression.java +++ b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/LogExpression.java @@ -20,9 +20,9 @@ public String key() { } @Override - public Object evaluate(List arguments, Object data) throws JsonLogicEvaluationException { + public Object evaluate(List arguments, Object data, String jsonPath) throws JsonLogicEvaluationException { if (arguments.isEmpty()) { - throw new JsonLogicEvaluationException("log operator requires exactly 1 argument"); + throw new JsonLogicEvaluationException("log operator requires exactly 1 argument", jsonPath); } Object value = arguments.get(0); diff --git a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/LogicExpression.java b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/LogicExpression.java index 0397b14..8412168 100644 --- a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/LogicExpression.java +++ b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/LogicExpression.java @@ -23,16 +23,17 @@ public String key() { } @Override - public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data) + public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data, String jsonPath) throws JsonLogicEvaluationException { if (arguments.size() < 1) { - throw new JsonLogicEvaluationException("and operator expects at least 1 argument"); + throw new JsonLogicEvaluationException(key() + " operator expects at least 1 argument", jsonPath); } Object result = null; + int index = 0; for (JsonLogicNode element : arguments) { - result = evaluator.evaluate(element, data); + result = evaluator.evaluate(element, data, String.format("%s[%d]", jsonPath, index++)); if ((isAnd && !JsonLogic.truthy(result)) || (!isAnd && JsonLogic.truthy(result))) { return result; diff --git a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/MapExpression.java b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/MapExpression.java index f046ede..9c3a863 100644 --- a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/MapExpression.java +++ b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/MapExpression.java @@ -23,13 +23,13 @@ public String key() { } @Override - public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data) + public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data, String jsonPath) throws JsonLogicEvaluationException { if (arguments.size() != 2) { - throw new JsonLogicEvaluationException("map expects exactly 2 arguments"); + throw new JsonLogicEvaluationException("map expects exactly 2 arguments", jsonPath); } - Object maybeArray = evaluator.evaluate(arguments.get(0), data); + Object maybeArray = evaluator.evaluate(arguments.get(0), data, jsonPath + "[0]"); if (!ArrayLike.isEligible(maybeArray)) { return Collections.emptyList(); @@ -38,7 +38,7 @@ public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, O List result = new ArrayList<>(); for (Object item : new ArrayLike(maybeArray)) { - result.add(evaluator.evaluate(arguments.get(1), item)); + result.add(evaluator.evaluate(arguments.get(1), item, jsonPath + "[1]")); } return result; diff --git a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/MathExpression.java b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/MathExpression.java index a077a54..4703715 100644 --- a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/MathExpression.java +++ b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/MathExpression.java @@ -1,6 +1,7 @@ package io.github.jamsesso.jsonlogic.evaluator.expressions; import io.github.jamsesso.jsonlogic.evaluator.JsonLogicEvaluationException; +import io.github.jamsesso.jsonlogic.utils.ArrayLike; import java.util.List; import java.util.function.BiFunction; @@ -34,36 +35,22 @@ public String key() { } @Override - public Object evaluate(List arguments, Object data) throws JsonLogicEvaluationException { + public Object evaluate(List arguments, Object data, String jsonPath) throws JsonLogicEvaluationException { if (arguments.isEmpty()) { return null; } - if (arguments.size() == 1) { - if (key.equals("+") && arguments.get(0) instanceof String) { - try { - return Double.parseDouble((String) arguments.get(0)); - } - catch (NumberFormatException e) { - throw new JsonLogicEvaluationException(e); - } - } - - if (key.equals("-") && arguments.get(0) instanceof Number) { - return -1 * ((Number) arguments.get(0)).doubleValue(); - } - - if (key.equals("/")) { - return null; - } - } - // Collect all of the arguments double[] values = new double[arguments.size()]; for (int i = 0; i < arguments.size(); i++) { Object value = arguments.get(i); + if (key.equals("*") || key.equals("+")) { + while (ArrayLike.isEligible(value)) { + value = new ArrayLike(value).get(0); + } + } if (value instanceof String) { try { values[i] = Double.parseDouble((String) value); @@ -80,6 +67,16 @@ else if (!(value instanceof Number)) { } } + if (values.length == 1) { + if (key.equals("-")) { + return -values[0]; + } + + if (key.equals("/")) { + return null; + } + } + // Reduce the values into a single result double accumulator = values[0]; diff --git a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/MergeExpression.java b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/MergeExpression.java index ba34d9b..a07d005 100644 --- a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/MergeExpression.java +++ b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/MergeExpression.java @@ -22,11 +22,10 @@ public String key() { } @Override - public Object evaluate(List arguments, Object data) throws JsonLogicEvaluationException { + public Object evaluate(List arguments, Object data, String jsonPath) throws JsonLogicEvaluationException { return ((List) arguments).stream() .map(obj -> ArrayLike.isEligible(obj) ? new ArrayLike(obj) : Collections.singleton(obj)) - .map(Collection::stream) - .flatMap(Function.identity()) + .flatMap(Collection::stream) .collect(Collectors.toList()); } } diff --git a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/MissingExpression.java b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/MissingExpression.java index 2e073bd..a03a616 100644 --- a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/MissingExpression.java +++ b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/MissingExpression.java @@ -22,10 +22,10 @@ public String key() { } @Override - public Object evaluate(List arguments, Object data) throws JsonLogicEvaluationException { - if (isSome && (!ArrayLike.isEligible(arguments.get(1)) || !(arguments.get(0) instanceof Double))) { + public Object evaluate(List arguments, Object data, String jsonPath) throws JsonLogicEvaluationException { + if (isSome && (arguments.size() < 2 || !ArrayLike.isEligible(arguments.get(1)) || !(arguments.get(0) instanceof Double))) { throw new JsonLogicEvaluationException("missing_some expects first argument to be an integer and the second " + - "argument to be an array"); + "argument to be an array", jsonPath); } if (!MapLike.isEligible(data)) { diff --git a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/NotExpression.java b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/NotExpression.java index 2fa0e72..e653129 100644 --- a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/NotExpression.java +++ b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/NotExpression.java @@ -20,7 +20,7 @@ public String key() { } @Override - public Object evaluate(List arguments, Object data) { + public Object evaluate(List arguments, Object data, String jsonPath) { boolean result; if (arguments.isEmpty()) { diff --git a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/NumericComparisonExpression.java b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/NumericComparisonExpression.java index 897817d..98c98a4 100644 --- a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/NumericComparisonExpression.java +++ b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/NumericComparisonExpression.java @@ -22,12 +22,12 @@ public String key() { } @Override - public Object evaluate(List arguments, Object data) throws JsonLogicEvaluationException { + public Object evaluate(List arguments, Object data, String jsonPath) throws JsonLogicEvaluationException { // Convert the arguments to doubles int n = Math.min(arguments.size(), 3); if (n < 2) { - throw new JsonLogicEvaluationException("'" + key + "' requires at least 2 arguments"); + throw new JsonLogicEvaluationException("'" + key + "' requires at least 2 arguments", jsonPath); } double[] values = new double[n]; @@ -51,8 +51,8 @@ else if (!(value instanceof Number)) { } } - // Handle between comparisons (supported for < and <=) - if (arguments.size() == 3) { + // Handle between comparisons + if (arguments.size() >= 3) { switch (key) { case "<": return values[0] < values[1] && values[1] < values[2]; @@ -60,8 +60,14 @@ else if (!(value instanceof Number)) { case "<=": return values[0] <= values[1] && values[1] <= values[2]; + case ">": + return values[0] > values[1] && values[1] > values[2]; + + case ">=": + return values[0] >= values[1] && values[1] >= values[2]; + default: - throw new JsonLogicEvaluationException("'" + key + "' does not support between comparisons"); + throw new JsonLogicEvaluationException("'" + key + "' does not support between comparisons", jsonPath); } } @@ -80,7 +86,7 @@ else if (!(value instanceof Number)) { return values[0] >= values[1]; default: - throw new JsonLogicEvaluationException("'" + key + "' is not a comparison expression"); + throw new JsonLogicEvaluationException("'" + key + "' is not a comparison expression", jsonPath); } } } diff --git a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/PreEvaluatedArgumentsExpression.java b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/PreEvaluatedArgumentsExpression.java index 4c53896..26adfe4 100644 --- a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/PreEvaluatedArgumentsExpression.java +++ b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/PreEvaluatedArgumentsExpression.java @@ -9,17 +9,17 @@ import java.util.List; public interface PreEvaluatedArgumentsExpression extends JsonLogicExpression { - Object evaluate(List arguments, Object data) throws JsonLogicEvaluationException; + Object evaluate(List arguments, Object data, String jsonPath) throws JsonLogicEvaluationException; @Override - default Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data) + default Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data, String jsonPath) throws JsonLogicEvaluationException { - List values = evaluator.evaluate(arguments, data); + List values = evaluator.evaluate(arguments, data, jsonPath); if (values.size() == 1 && ArrayLike.isEligible(values.get(0))) { values = new ArrayLike(values.get(0)); } - return evaluate(values, data); + return evaluate(values, data, jsonPath); } } diff --git a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/ReduceExpression.java b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/ReduceExpression.java index 7864cc5..35bb882 100644 --- a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/ReduceExpression.java +++ b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/ReduceExpression.java @@ -22,14 +22,14 @@ public String key() { } @Override - public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data) + public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data, String jsonPath) throws JsonLogicEvaluationException { if (arguments.size() != 3) { - throw new JsonLogicEvaluationException("reduce expects exactly 3 arguments"); + throw new JsonLogicEvaluationException("reduce expects exactly 3 arguments", jsonPath); } - Object maybeArray = evaluator.evaluate(arguments.get(0), data); - Object accumulator = evaluator.evaluate(arguments.get(2), data); + Object maybeArray = evaluator.evaluate(arguments.get(0), data, jsonPath + "[0]"); + Object accumulator = evaluator.evaluate(arguments.get(2), data, jsonPath + "[2]"); if (!ArrayLike.isEligible(maybeArray)) { return accumulator; @@ -40,7 +40,7 @@ public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, O for (Object item : new ArrayLike(maybeArray)) { context.put("current", item); - context.put("accumulator", evaluator.evaluate(arguments.get(1), context)); + context.put("accumulator", evaluator.evaluate(arguments.get(1), context, jsonPath + "[1]")); } return context.get("accumulator"); diff --git a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/StrictEqualityExpression.java b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/StrictEqualityExpression.java index fcf2325..8cbfc04 100644 --- a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/StrictEqualityExpression.java +++ b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/StrictEqualityExpression.java @@ -17,9 +17,9 @@ public String key() { } @Override - public Object evaluate(List arguments, Object data) throws JsonLogicEvaluationException { + public Object evaluate(List arguments, Object data, String jsonPath) throws JsonLogicEvaluationException { if (arguments.size() != 2) { - throw new JsonLogicEvaluationException("equality expressions expect exactly 2 arguments"); + throw new JsonLogicEvaluationException("equality expressions expect exactly 2 arguments", jsonPath); } Object left = arguments.get(0); diff --git a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/StrictInequalityExpression.java b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/StrictInequalityExpression.java index 41d71ee..68e257c 100644 --- a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/StrictInequalityExpression.java +++ b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/StrictInequalityExpression.java @@ -21,9 +21,9 @@ public String key() { } @Override - public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data) + public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data, String jsonPath) throws JsonLogicEvaluationException { - boolean result = (boolean) delegate.evaluate(evaluator, arguments, data); + boolean result = (boolean) delegate.evaluate(evaluator, arguments, data, jsonPath); return !result; } diff --git a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/SubstringExpression.java b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/SubstringExpression.java index f9f844f..6fc8b7b 100644 --- a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/SubstringExpression.java +++ b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/SubstringExpression.java @@ -17,13 +17,13 @@ public String key() { } @Override - public Object evaluate(List arguments, Object data) throws JsonLogicEvaluationException { + public Object evaluate(List arguments, Object data, String jsonPath) throws JsonLogicEvaluationException { if (arguments.size() < 2 || arguments.size() > 3) { - throw new JsonLogicEvaluationException("substr expects 2 or 3 arguments"); + throw new JsonLogicEvaluationException("substr expects 2 or 3 arguments", jsonPath); } if (!(arguments.get(1) instanceof Double)) { - throw new JsonLogicEvaluationException("first argument to substr must be a number"); + throw new JsonLogicEvaluationException("second argument to substr must be a number", jsonPath + "[1]"); } String value = arguments.get(0).toString(); @@ -44,7 +44,7 @@ public Object evaluate(List arguments, Object data) throws JsonLogicEvaluationEx } else { if (!(arguments.get(2) instanceof Double)) { - throw new JsonLogicEvaluationException("second argument to substr must be an integer"); + throw new JsonLogicEvaluationException("third argument to substr must be an integer", jsonPath + "[2]"); } startIndex = ((Double) arguments.get(1)).intValue(); diff --git a/src/test/java/io/github/jamsesso/jsonlogic/ErrorFixtureTests.java b/src/test/java/io/github/jamsesso/jsonlogic/ErrorFixtureTests.java new file mode 100644 index 0000000..9e8cef0 --- /dev/null +++ b/src/test/java/io/github/jamsesso/jsonlogic/ErrorFixtureTests.java @@ -0,0 +1,96 @@ +package io.github.jamsesso.jsonlogic; + +import java.util.ArrayList; +import java.util.List; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import org.junit.Assert; +import org.junit.Test; +import io.github.jamsesso.jsonlogic.utils.JsonValueExtractor; + +import static io.github.jamsesso.jsonlogic.FixtureTests.readFixtures; + +public class ErrorFixtureTests { + private static final List FIXTURES = readFixtures("error-fixtures.json", ErrorFixture::fromArray); + + @Test + public void testAllFixtures() { + JsonLogic jsonLogic = new JsonLogic(); + List failures = new ArrayList<>(); + + for (ErrorFixture fixture : FIXTURES) { + try { + jsonLogic.apply(fixture.getJson(), fixture.getData()); + failures.add(new TestResult(fixture, new JsonLogicException("Expected an exception at " + fixture.getExpectedJsonPath(), ""))); + } catch (JsonLogicException e) { + if (!fixture.getExpectedJsonPath().equals(e.getJsonPath()) || + !fixture.getExpectedError().equals(e.getMessage())) { + failures.add(new TestResult(fixture, e)); + } + } + } + + for (TestResult testResult : failures) { + JsonLogicException exception = testResult.getException(); + ErrorFixture fixture = testResult.getFixture(); + + System.out.printf("FAIL: %s\n\t%s\n\tExpected: %s at %s Got: \"%s\" at \"%s\"\n%n", fixture.getJson(), fixture.getData(), + fixture.getExpectedError(), fixture.getExpectedJsonPath(), + exception.getMessage(), exception.getJsonPath()); + } + + Assert.assertEquals(String.format("%d/%d test failures!", failures.size(), FIXTURES.size()), 0, failures.size()); + } + + private static class ErrorFixture { + private final String json; + private final Object data; + private final String expectedPath; + private final String expectedError; + + private ErrorFixture(String json, JsonElement data, String expectedPath, String expectedError) { + this.json = json; + this.data = JsonValueExtractor.extract(data); + this.expectedPath = expectedPath; + this.expectedError = expectedError; + } + + public static ErrorFixture fromArray(JsonArray array) { + return new ErrorFixture(array.get(0).toString(), array.get(1), array.get(2).getAsString(), array.get(3).getAsString()); + } + + String getJson() { + return json; + } + + Object getData() { + return data; + } + + String getExpectedJsonPath() { + return expectedPath; + } + + String getExpectedError() { + return expectedError; + } + } + + private static class TestResult { + private final ErrorFixture fixture; + private final JsonLogicException exception; + + private TestResult(ErrorFixture fixture, JsonLogicException exception) { + this.fixture = fixture; + this.exception = exception; + } + + ErrorFixture getFixture() { + return fixture; + } + + JsonLogicException getException() { + return exception; + } + } +} diff --git a/src/test/java/io/github/jamsesso/jsonlogic/FixtureTests.java b/src/test/java/io/github/jamsesso/jsonlogic/FixtureTests.java index 085129d..d75efe9 100644 --- a/src/test/java/io/github/jamsesso/jsonlogic/FixtureTests.java +++ b/src/test/java/io/github/jamsesso/jsonlogic/FixtureTests.java @@ -3,22 +3,22 @@ import com.google.gson.*; import io.github.jamsesso.jsonlogic.utils.JsonValueExtractor; import org.junit.Assert; -import org.junit.BeforeClass; import org.junit.Test; import java.io.InputStream; import java.io.InputStreamReader; import java.util.*; +import java.util.function.Function; public class FixtureTests { - private static final List FIXTURES = new ArrayList<>(); + private static final List FIXTURES = readFixtures("fixtures.json", Fixture::fromArray); - @BeforeClass - public static void beforeAll() { - InputStream inputStream = FixtureTests.class.getClassLoader().getResourceAsStream("fixtures.json"); + public static List readFixtures(String fileName, Function makeFixture) { + InputStream inputStream = ErrorFixtureTests.class.getClassLoader().getResourceAsStream(fileName); JsonParser parser = new JsonParser(); JsonArray json = parser.parse(new InputStreamReader(inputStream)).getAsJsonArray(); + List fixtures = new ArrayList<>(); // Pull out each fixture from the array. for (JsonElement element : json) { if (!element.isJsonArray()) { @@ -26,8 +26,9 @@ public static void beforeAll() { } JsonArray array = element.getAsJsonArray(); - FIXTURES.add(new Fixture(array.get(0).toString(), array.get(1), array.get(2))); + fixtures.add(makeFixture.apply(array)); } + return fixtures; } @Test @@ -60,6 +61,10 @@ public void testAllFixtures() { } private static class Fixture { + public static Fixture fromArray(JsonArray array) { + return new Fixture(array.get(0).toString(), array.get(1), array.get(2)); + } + private final String json; private final Object data; private final Object expectedValue; diff --git a/src/test/java/io/github/jamsesso/jsonlogic/MathExpressionTests.java b/src/test/java/io/github/jamsesso/jsonlogic/MathExpressionTests.java index 8d6ea8d..b7a356b 100644 --- a/src/test/java/io/github/jamsesso/jsonlogic/MathExpressionTests.java +++ b/src/test/java/io/github/jamsesso/jsonlogic/MathExpressionTests.java @@ -3,6 +3,7 @@ import org.junit.Test; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; public class MathExpressionTests { private static final JsonLogic jsonLogic = new JsonLogic(); @@ -31,6 +32,21 @@ public void testSingleAdd() throws JsonLogicException { assertEquals(3.14, result); } + @Test + public void testAddWithArray() throws JsonLogicException { + String json = "{\"+\":[2,[[3,4],5]]}"; + Object result = jsonLogic.apply(json, null); + + assertEquals(5.0, result); // This matches reference impl at jsonlogic.com + } + + @Test + public void testStringAdd() throws JsonLogicException { + assertNull(jsonLogic.apply("{\"+\" : \"foo\"}", null)); + assertNull(jsonLogic.apply("{\"+\" : [\"foo\"]}", null)); + assertNull(jsonLogic.apply("{\"+\" : [1, \"foo\"]}", null)); + } + @Test public void testSubtract() throws JsonLogicException { String json = "{\"-\":[4,2]}"; @@ -47,6 +63,14 @@ public void testSingleSubtract() throws JsonLogicException { assertEquals(-2.0, result); } + @Test + public void testSingleSubtractString() throws JsonLogicException { + String json = "{\"-\": \"2\" }"; + Object result = jsonLogic.apply(json, null); + + assertEquals(-2.0, result); + } + @Test public void testMultiply() throws JsonLogicException { String json = "{\"*\":[4,2]}"; @@ -63,6 +87,14 @@ public void testMultiMultiply() throws JsonLogicException { assertEquals(32.0, result); } + @Test + public void testMultiplyWithArray() throws JsonLogicException { + String json = "{\"*\":[2,[[3, 4], 5]]}"; + Object result = jsonLogic.apply(json, null); + + assertEquals(6.0, result); // This matches reference impl at jsonlogic.com + } + @Test public void testDivide() throws JsonLogicException { String json = "{\"/\":[4,2]}"; diff --git a/src/test/java/io/github/jamsesso/jsonlogic/NumericComparisonExpressionTests.java b/src/test/java/io/github/jamsesso/jsonlogic/NumericComparisonExpressionTests.java index f1cbf0a..d4633b1 100644 --- a/src/test/java/io/github/jamsesso/jsonlogic/NumericComparisonExpressionTests.java +++ b/src/test/java/io/github/jamsesso/jsonlogic/NumericComparisonExpressionTests.java @@ -54,4 +54,26 @@ public void testBetweenInclusive() throws JsonLogicException { assertEquals(true, result); } + + @Test + public void testGtBetweenExclusive() throws JsonLogicException { + String json = "{\">\" : [3, 2, 1]}"; + Object result = jsonLogic.apply(json, null); + + assertEquals(true, result); + } + + @Test + public void testGtBetweenInclusive() throws JsonLogicException { + String json = "{\">=\" : [3, 1, 1]}"; + Object result = jsonLogic.apply(json, null); + + assertEquals(true, result); + } + + @Test + public void testEdgeCases() throws JsonLogicException { + assertEquals(true, jsonLogic.apply("{\">=\" : [3, 1, 1, 1]}", null)); + assertEquals(false, jsonLogic.apply("{\">=\" : [3, 1, 3, 1]}", null)); + } } diff --git a/src/test/resources/error-fixtures.json b/src/test/resources/error-fixtures.json new file mode 100644 index 0000000..ab5f3b4 --- /dev/null +++ b/src/test/resources/error-fixtures.json @@ -0,0 +1,278 @@ +[ + [ + {}, + {}, + "$", + "objects must have exactly 1 key defined, found 0" + ], + [ + {"all":[1]}, + {}, + "$.all", + "all expects exactly 2 arguments" + ], + [ + {"all":[{"some":[]}, 1]}, + {}, + "$.all[0].some", + "some expects exactly 2 arguments" + ], + [ + {"all":[[1], {"none":[]}]}, + {}, + "$.all[1].none", + "none expects exactly 2 arguments" + ], + [ + {"some":[0, 1]}, + {}, + "$.some[0]", + "first argument to some must be a valid array" + ], + [ + {"none":[1, 2]}, + {}, + "$.none[0]", + "first argument to none must be a valid array" + ], + [ + {"cat":["foo", {}]}, + {}, + "$.cat[1]", + "objects must have exactly 1 key defined, found 0" + ], + [ + {"==":[0]}, + {}, + "$.==", + "equality expressions expect exactly 2 arguments" + ], + [ + {"filter":[0]}, + {}, + "$.filter", + "filter expects exactly 2 arguments" + ], + [ + {"filter":[1, 2]}, + {}, + "$.filter[0]", + "first argument to filter must be a valid array" + ], + [ + {"filter":["foo", {}]}, + {}, + "$.filter[1]", + "objects must have exactly 1 key defined, found 0" + ], + [ + {"if":[{}]}, + {}, + "$.if[0]", + "objects must have exactly 1 key defined, found 0" + ], + [ + {"if":[true,{}]}, + {}, + "$.if[1]", + "objects must have exactly 1 key defined, found 0" + ], + [ + {"if":[false,1,{"filter":[1]}]}, + {}, + "$.if[2].filter", + "filter expects exactly 2 arguments" + ], + [ + {"if":[false,1,true,{"filter":[1]}]}, + {}, + "$.if[3].filter", + "filter expects exactly 2 arguments" + ], + [ + {"!=":[0]}, + {}, + "$.!=", + "equality expressions expect exactly 2 arguments" + ], + [ + {"log":[]}, + {}, + "$.log", + "log operator requires exactly 1 argument" + ], + [ + {"and":[]}, + {}, + "$.and", + "and operator expects at least 1 argument" + ], + [ + {"and":[true,{"log":[]}]}, + {}, + "$.and[1].log", + "log operator requires exactly 1 argument" + ], + [ + {"or":[]}, + {}, + "$.or", + "or operator expects at least 1 argument" + ], + [ + {"map":[1]}, + {}, + "$.map", + "map expects exactly 2 arguments" + ], + [ + {"+":[1, {"-": [2, {"*": [3, {"/": [4, {"log":[]}]}]}]}]}, + {}, + "$.+[1].-[1].*[1]./[1].log", + "log operator requires exactly 1 argument" + ], + [ + {"%":[1, {"min": [2, {"max": [3, {"log":[]}]}]}]}, + {}, + "$.%[1].min[1].max[1].log", + "log operator requires exactly 1 argument" + ], + [ + {"merge":[1, 2, {"log":[]}]}, + {}, + "$.merge[2].log", + "log operator requires exactly 1 argument" + ], + [ + {"missing_some":[1]}, + {}, + "$.missing_some", + "missing_some expects first argument to be an integer and the second argument to be an array" + ], + [ + {"missing_some":[1, 2]}, + {}, + "$.missing_some", + "missing_some expects first argument to be an integer and the second argument to be an array" + ], + [ + {"missing":[1, {"log":[]}]}, + {}, + "$.missing[1].log", + "log operator requires exactly 1 argument" + ], + [ + {"!":[1, {"log":[]}]}, + {}, + "$.![1].log", + "log operator requires exactly 1 argument" + ], + [ + {"!!":[{"log":[]}]}, + {}, + "$.!![0].log", + "log operator requires exactly 1 argument" + ], + [ + {"<":[1]}, + {}, + "$.<", + "'<' requires at least 2 arguments" + ], + [ + {">":[1]}, + {}, + "$.>", + "'>' requires at least 2 arguments" + ], + [ + {"<=":[1]}, + {}, + "$.<=", + "'<=' requires at least 2 arguments" + ], + [ + {">=":[1]}, + {}, + "$.>=", + "'>=' requires at least 2 arguments" + ], + [ + {">":[1, {"log":[]}]}, + {}, + "$.>[1].log", + "log operator requires exactly 1 argument" + ], + [ + {">":[0, 1, 2, "three", 4, 5, {"log":[]}]}, + {}, + "$.>[6].log", + "log operator requires exactly 1 argument" + ], + [ + {"reduce":[1]}, + {}, + "$.reduce", + "reduce expects exactly 3 arguments" + ], + [ + {"reduce":[{"log":[]}, 2, 3]}, + {}, + "$.reduce[0].log", + "log operator requires exactly 1 argument" + ], + [ + {"reduce":[[1], {"log":[]}, 3]}, + {}, + "$.reduce[1].log", + "log operator requires exactly 1 argument" + ], + [ + {"reduce":[1, 2, {"log":[]}]}, + {}, + "$.reduce[2].log", + "log operator requires exactly 1 argument" + ], + [ + {"===":[1]}, + {}, + "$.===", + "equality expressions expect exactly 2 arguments" + ], + [ + {"!==":[1]}, + {}, + "$.!==", + "equality expressions expect exactly 2 arguments" + ], + [ + {"substr":["jsonlogic"]}, + {}, + "$.substr", + "substr expects 2 or 3 arguments" + ], + [ + {"substr":["jsonlogic", "one"]}, + {}, + "$.substr[1]", + "second argument to substr must be a number" + ], + [ + {"substr":["jsonlogic", 1, "two"]}, + {}, + "$.substr[2]", + "third argument to substr must be an integer" + ], + [ + {"var":[[1, 2]]}, + {}, + "$.var[0]", + "var first argument must be null, number, or string" + ], + [ + {"var":"key.foo"}, + {"key": [1, 2]}, + "$.var[0]", + "java.lang.NumberFormatException: For input string: \"foo\"" + ] +]