From a4f8add950244eebbca5a541b3b581ab51931253 Mon Sep 17 00:00:00 2001 From: Andras Markos Date: Fri, 15 Aug 2025 17:09:38 +1200 Subject: [PATCH] [LT-1633] LT-1633 enabled Checkstyle and reformatted code, minor refactorings to satisfy all enabled Checkstyle rules --- README.md | 71 +++- build.gradle | 1 - .../github/jamsesso/jsonlogic/JsonLogic.java | 234 ++++++----- .../jsonlogic/JsonLogicException.java | 38 +- .../jsonlogic/ast/JsonLogicArray.java | 250 +++++------ .../jsonlogic/ast/JsonLogicBoolean.java | 28 +- .../jamsesso/jsonlogic/ast/JsonLogicNode.java | 2 +- .../jsonlogic/ast/JsonLogicNodeType.java | 8 +- .../jamsesso/jsonlogic/ast/JsonLogicNull.java | 24 +- .../jsonlogic/ast/JsonLogicNumber.java | 24 +- .../jsonlogic/ast/JsonLogicOperation.java | 32 +- .../ast/JsonLogicParseException.java | 18 +- .../jsonlogic/ast/JsonLogicParser.java | 160 ++++---- .../jsonlogic/ast/JsonLogicPrimitive.java | 12 +- .../jsonlogic/ast/JsonLogicPrimitiveType.java | 8 +- .../jsonlogic/ast/JsonLogicString.java | 24 +- .../jsonlogic/ast/JsonLogicVariable.java | 32 +- .../JsonLogicEvaluationException.java | 18 +- .../evaluator/JsonLogicEvaluator.java | 243 ++++++----- .../evaluator/JsonLogicExpression.java | 6 +- .../evaluator/expressions/AllExpression.java | 74 ++-- .../expressions/ArrayHasExpression.java | 69 ++-- .../expressions/ConcatenateExpression.java | 40 +- .../expressions/EqualityExpression.java | 166 ++++---- .../expressions/FilterExpression.java | 58 +-- .../evaluator/expressions/IfExpression.java | 88 ++-- .../evaluator/expressions/InExpression.java | 50 +-- .../expressions/InequalityExpression.java | 30 +- .../evaluator/expressions/LogExpression.java | 36 +- .../expressions/LogicExpression.java | 50 +-- .../evaluator/expressions/MapExpression.java | 52 +-- .../evaluator/expressions/MathExpression.java | 141 ++++--- .../expressions/MergeExpression.java | 31 +- .../expressions/MissingExpression.java | 125 +++--- .../evaluator/expressions/NotExpression.java | 47 ++- .../NumericComparisonExpression.java | 128 +++--- .../PreEvaluatedArgumentsExpression.java | 22 +- .../expressions/ReduceExpression.java | 60 +-- .../expressions/StrictEqualityExpression.java | 46 +-- .../StrictInequalityExpression.java | 32 +- .../expressions/SubstringExpression.java | 98 +++-- .../jamsesso/jsonlogic/utils/ArrayLike.java | 366 +++++++++-------- .../jsonlogic/utils/JsonValueExtractor.java | 72 ++-- .../jamsesso/jsonlogic/utils/MapLike.java | 146 ++++--- .../jsonlogic/AllExpressionTests.java | 20 +- .../jsonlogic/ArrayHasExpressionTests.java | 72 ++-- .../jsonlogic/ConcatenateExpressionTests.java | 12 +- .../jsonlogic/CustomOperationTests.java | 22 +- .../jsonlogic/EqualityExpressionTests.java | 34 +- .../jamsesso/jsonlogic/ErrorFixtureTests.java | 149 +++---- .../jsonlogic/FilterExpressionTests.java | 28 +- .../jamsesso/jsonlogic/FixtureTests.java | 162 ++++---- .../jamsesso/jsonlogic/IfExpressionTests.java | 58 +-- .../jamsesso/jsonlogic/InExpressionTests.java | 98 ++--- .../jsonlogic/InequalityExpressionTests.java | 18 +- .../jsonlogic/LogExpressionTests.java | 10 +- .../jsonlogic/LogicExpressionTests.java | 18 +- .../jsonlogic/MapExpressionTests.java | 28 +- .../jsonlogic/MathExpressionTests.java | 264 ++++++------ .../jsonlogic/MergeExpressionTests.java | 46 +-- .../jsonlogic/MissingExpressionTests.java | 144 +++---- .../jsonlogic/NotExpressionTests.java | 82 ++-- .../jamsesso/jsonlogic/NumberTests.java | 32 +- .../NumericComparisonExpressionTests.java | 108 ++--- .../jsonlogic/ReduceExpressionTests.java | 24 +- .../StrictEqualityExpressionTests.java | 18 +- .../StrictInequalityExpressionTests.java | 18 +- .../jsonlogic/SubstringExpressionTests.java | 62 +-- .../jamsesso/jsonlogic/TruthyTests.java | 70 ++-- .../jamsesso/jsonlogic/VariableTests.java | 388 +++++++++--------- src/test/resources/error-fixtures.json | 374 ++++++++++++++--- src/test/resources/fixtures.json | 83 +++- 72 files changed, 3068 insertions(+), 2634 deletions(-) diff --git a/README.md b/README.md index 0fe339a..5346508 100644 --- a/README.md +++ b/README.md @@ -2,24 +2,30 @@ This parser accepts [JsonLogic](http://jsonlogic.com) rules and executes them in Java without Nashorn. -The JsonLogic format is designed to allow you to share rules (logic) between front-end and back-end code (regardless of language difference), even to store logic along with a record in a database. -JsonLogic is documented extensively at [JsonLogic.com](http://jsonlogic.com), including examples of every [supported operation](http://jsonlogic.com/operations.html) and a place to [try out rules in your browser](http://jsonlogic.com/play.html). +The JsonLogic format is designed to allow you to share rules (logic) between front-end and back-end code (regardless of +language difference), even to store logic along with a record in a database. +JsonLogic is documented extensively at [JsonLogic.com](http://jsonlogic.com), including examples of +every [supported operation](http://jsonlogic.com/operations.html) and a place +to [try out rules in your browser](http://jsonlogic.com/play.html). ## Installation ```xml + - com.sailthru - json-logic-java - 2.0.0 + com.sailthru + json-logic-java + 2.0.0 ``` ## Examples -The public API for json-logic-java attempts to mimic the public API of the original Javascript implementation as close as possible. +The public API for json-logic-java attempts to mimic the public API of the original Javascript implementation as close +as possible. For this reason, the API is loosely typed in many places. -This implementation relies on duck-typing for maps/dictionaries and arrays: if it looks and feels like an array, we treat it like an array. +This implementation relies on duck-typing for maps/dictionaries and arrays: if it looks and feels like an array, we +treat it like an array. ```java // Create a new JsonLogic instance. JsonLogic is thread safe. @@ -28,31 +34,41 @@ JsonLogic jsonLogic = new JsonLogic(); // Set up some JSON and some data. String expression = "{\"*\": [{\"var\": \"x\"}, 2]}"; Map data = new HashMap<>(); -data.put("x", 10); +data. + +put("x",10); // Evaluate the result. double result = (double) jsonLogic.apply(expression, data); -assert result == 20.0; +assert result ==20.0; ``` You can add your own operations like so: ```java // Register an operation. -jsonLogic.addOperation("greet", (args) -> "Hello, " + args[0] + "!"); +jsonLogic.addOperation("greet",(args) ->"Hello, "+args[0]+"!"); // Evaluate the result. String result = (String) jsonLogic.apply("{\"greet\": [\"Sam\"]}", null); -assert "Hello, Sam!".equals(result); +assert"Hello, Sam!". + +equals(result); ``` There is a `truthy` static method that mimics the truthy-ness rules of Javascript: ```java -assert JsonLogic.truthy(0) == false; -assert JsonLogic.truthy(1) == true; -assert JsonLogic.truthy("") == false; -assert JsonLogic.truthy("Hello world!") == true; +assert JsonLogic.truthy(0) ==false; + assert JsonLogic. + +truthy(1) ==true; + assert JsonLogic. + +truthy("") ==false; + assert JsonLogic. + +truthy("Hello world!") ==true; // etc... ``` @@ -60,12 +76,15 @@ assert JsonLogic.truthy("Hello world!") == true; ## Usage: ### Update dependencies: + ```bash ./gradlew dependencies --write-locks ``` ### Local testing + To "publish" a version locally for testing run: + ```bash ./gradlew publishToMavenLocal ``` @@ -75,6 +94,7 @@ This will publish a copy of the library to maven local that will be accessible w Inside your other project update the version of the dependency to `vSANDBOX` to access the library. For example: + ``` implementation("com.sailthru:json-logic-java:v2.0.0") // Becomes @@ -82,21 +102,30 @@ implementation("com.sailthru:json-logic-java:vSANDBOX") ``` ## Contents: + This template contains the bare minimal requirements to create and publish a Java library. ### CI/CD -CI/CD is provided by CircleCI. Specifically the [Sailthru JVM orb](https://circleci.com/developer/orbs/orb/sailthru/jvm). + +CI/CD is provided by CircleCI. Specifically +the [Sailthru JVM orb](https://circleci.com/developer/orbs/orb/sailthru/jvm). Every branch is tested using the `./gradlew check` command. -To publish a release you must [create a GitHub Release](https://docs.github.com/en/repositories/releasing-projects-on-github/managing-releases-in-a-repository#creating-a-release). -Within this release you will need to create a semantic version tag in the format `vMAJOR.MINOR.PATCH` for example `v1.0.1`. +To publish a release you +must [create a GitHub Release](https://docs.github.com/en/repositories/releasing-projects-on-github/managing-releases-in-a-repository#creating-a-release). +Within this release you will need to create a semantic version tag in the format `vMAJOR.MINOR.PATCH` for example +`v1.0.1`. -Once a tag is created CircleCI will automatically detect this and publish the JAR to [CodeArtifact](https://us-east-1.console.aws.amazon.com/codesuite/codeartifact/d/680305091011/sailthru/r/maven). +Once a tag is created CircleCI will automatically detect this and publish the JAR +to [CodeArtifact](https://us-east-1.console.aws.amazon.com/codesuite/codeartifact/d/680305091011/sailthru/r/maven). ### Gradle -Most Gradle logic will be contained within our [Sailthru gradle plugin (gradle-config)](https://github.com/sailthru/gradle-config). -All projects require dependency locking, connecting to CodeArtifact as a source, and to use Checkstyle (this can be disabled if required). +Most Gradle logic will be contained within +our [Sailthru gradle plugin (gradle-config)](https://github.com/sailthru/gradle-config). + +All projects require dependency locking, connecting to CodeArtifact as a source, and to use Checkstyle (this can be +disabled if required). Library projects also include support to publish to CodeArtifact. diff --git a/build.gradle b/build.gradle index 85358d4..f4ab967 100644 --- a/build.gradle +++ b/build.gradle @@ -15,5 +15,4 @@ dependencies { sailthru { type = ProjectType.LIBRARY javaVersion = JavaVersion.VERSION_1_8 - checkstyleEnabled = false } diff --git a/src/main/java/io/github/jamsesso/jsonlogic/JsonLogic.java b/src/main/java/io/github/jamsesso/jsonlogic/JsonLogic.java index fa25f2f..58412cf 100644 --- a/src/main/java/io/github/jamsesso/jsonlogic/JsonLogic.java +++ b/src/main/java/io/github/jamsesso/jsonlogic/JsonLogic.java @@ -4,136 +4,156 @@ import io.github.jamsesso.jsonlogic.ast.JsonLogicParser; import io.github.jamsesso.jsonlogic.evaluator.JsonLogicEvaluator; import io.github.jamsesso.jsonlogic.evaluator.JsonLogicExpression; -import io.github.jamsesso.jsonlogic.evaluator.expressions.*; +import io.github.jamsesso.jsonlogic.evaluator.expressions.AllExpression; +import io.github.jamsesso.jsonlogic.evaluator.expressions.ArrayHasExpression; +import io.github.jamsesso.jsonlogic.evaluator.expressions.ConcatenateExpression; +import io.github.jamsesso.jsonlogic.evaluator.expressions.EqualityExpression; +import io.github.jamsesso.jsonlogic.evaluator.expressions.FilterExpression; +import io.github.jamsesso.jsonlogic.evaluator.expressions.IfExpression; +import io.github.jamsesso.jsonlogic.evaluator.expressions.InExpression; +import io.github.jamsesso.jsonlogic.evaluator.expressions.InequalityExpression; +import io.github.jamsesso.jsonlogic.evaluator.expressions.LogExpression; +import io.github.jamsesso.jsonlogic.evaluator.expressions.LogicExpression; +import io.github.jamsesso.jsonlogic.evaluator.expressions.MapExpression; +import io.github.jamsesso.jsonlogic.evaluator.expressions.MathExpression; +import io.github.jamsesso.jsonlogic.evaluator.expressions.MergeExpression; +import io.github.jamsesso.jsonlogic.evaluator.expressions.MissingExpression; +import io.github.jamsesso.jsonlogic.evaluator.expressions.NotExpression; +import io.github.jamsesso.jsonlogic.evaluator.expressions.NumericComparisonExpression; +import io.github.jamsesso.jsonlogic.evaluator.expressions.PreEvaluatedArgumentsExpression; +import io.github.jamsesso.jsonlogic.evaluator.expressions.ReduceExpression; +import io.github.jamsesso.jsonlogic.evaluator.expressions.StrictEqualityExpression; +import io.github.jamsesso.jsonlogic.evaluator.expressions.StrictInequalityExpression; +import io.github.jamsesso.jsonlogic.evaluator.expressions.SubstringExpression; import java.lang.reflect.Array; -import java.util.*; +import java.util.Collection; +import java.util.List; +import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; public final class JsonLogic { - private final Map parseCache = new ConcurrentHashMap<>(); - private final Map expressions = new ConcurrentHashMap<>(); - private JsonLogicEvaluator evaluator; - - public JsonLogic() { - // Add default operations - addOperation(MathExpression.ADD); - addOperation(MathExpression.SUBTRACT); - addOperation(MathExpression.MULTIPLY); - addOperation(MathExpression.DIVIDE); - addOperation(MathExpression.MODULO); - addOperation(MathExpression.MIN); - addOperation(MathExpression.MAX); - addOperation(NumericComparisonExpression.GT); - addOperation(NumericComparisonExpression.GTE); - addOperation(NumericComparisonExpression.LT); - addOperation(NumericComparisonExpression.LTE); - addOperation(IfExpression.IF); - addOperation(IfExpression.TERNARY); - addOperation(EqualityExpression.INSTANCE); - addOperation(InequalityExpression.INSTANCE); - addOperation(StrictEqualityExpression.INSTANCE); - addOperation(StrictInequalityExpression.INSTANCE); - addOperation(NotExpression.SINGLE); - addOperation(NotExpression.DOUBLE); - addOperation(LogicExpression.AND); - addOperation(LogicExpression.OR); - addOperation(LogExpression.STDOUT); - addOperation(MapExpression.INSTANCE); - addOperation(FilterExpression.INSTANCE); - addOperation(ReduceExpression.INSTANCE); - addOperation(AllExpression.INSTANCE); - addOperation(ArrayHasExpression.SOME); - addOperation(ArrayHasExpression.NONE); - addOperation(MergeExpression.INSTANCE); - addOperation(InExpression.INSTANCE); - addOperation(ConcatenateExpression.INSTANCE); - addOperation(SubstringExpression.INSTANCE); - addOperation(MissingExpression.ALL); - addOperation(MissingExpression.SOME); - } - - public JsonLogic addOperation(String name, Function function) { - return addOperation(new PreEvaluatedArgumentsExpression() { - @Override - public Object evaluate(List arguments, Object data, String jsonPath) { - return function.apply(arguments.toArray()); - } - - @Override - public String key() { - return name; - } - }); - } - - public JsonLogic addOperation(JsonLogicExpression expression) { - expressions.put(expression.key(), expression); - evaluator = null; - - return this; - } - - public Object apply(String json, Object data) throws JsonLogicException { - if (!parseCache.containsKey(json)) { - parseCache.put(json, JsonLogicParser.parse(json)); + private final Map parseCache = new ConcurrentHashMap<>(); + private final Map expressions = new ConcurrentHashMap<>(); + private JsonLogicEvaluator evaluator; + + public JsonLogic() { + // Add default operations + addOperation(MathExpression.ADD); + addOperation(MathExpression.SUBTRACT); + addOperation(MathExpression.MULTIPLY); + addOperation(MathExpression.DIVIDE); + addOperation(MathExpression.MODULO); + addOperation(MathExpression.MIN); + addOperation(MathExpression.MAX); + addOperation(NumericComparisonExpression.GT); + addOperation(NumericComparisonExpression.GTE); + addOperation(NumericComparisonExpression.LT); + addOperation(NumericComparisonExpression.LTE); + addOperation(IfExpression.IF); + addOperation(IfExpression.TERNARY); + addOperation(EqualityExpression.INSTANCE); + addOperation(InequalityExpression.INSTANCE); + addOperation(StrictEqualityExpression.INSTANCE); + addOperation(StrictInequalityExpression.INSTANCE); + addOperation(NotExpression.SINGLE); + addOperation(NotExpression.DOUBLE); + addOperation(LogicExpression.AND); + addOperation(LogicExpression.OR); + addOperation(LogExpression.STDOUT); + addOperation(MapExpression.INSTANCE); + addOperation(FilterExpression.INSTANCE); + addOperation(ReduceExpression.INSTANCE); + addOperation(AllExpression.INSTANCE); + addOperation(ArrayHasExpression.SOME); + addOperation(ArrayHasExpression.NONE); + addOperation(MergeExpression.INSTANCE); + addOperation(InExpression.INSTANCE); + addOperation(ConcatenateExpression.INSTANCE); + addOperation(SubstringExpression.INSTANCE); + addOperation(MissingExpression.ALL); + addOperation(MissingExpression.SOME); } - if (evaluator == null) { - evaluator = new JsonLogicEvaluator(expressions); + public JsonLogic addOperation(String name, Function function) { + return addOperation(new PreEvaluatedArgumentsExpression() { + @Override + public Object evaluate(List arguments, Object data, String jsonPath) { + return function.apply(arguments.toArray()); + } + + @Override + public String key() { + return name; + } + }); } - return evaluator.evaluate(parseCache.get(json), data, "$"); - } + public JsonLogic addOperation(JsonLogicExpression expression) { + expressions.put(expression.key(), expression); + evaluator = null; - public static boolean truthy(Object value) { - if (value == null) { - return false; + return this; } - if (value instanceof Boolean) { - return (boolean) value; - } + public Object apply(String json, Object data) throws JsonLogicException { + if (!parseCache.containsKey(json)) { + parseCache.put(json, JsonLogicParser.parse(json)); + } - if (value instanceof Number) { - if (value instanceof Double) { - Double d = (Double) value; + if (evaluator == null) { + evaluator = new JsonLogicEvaluator(expressions); + } + + return evaluator.evaluate(parseCache.get(json), data, "$"); + } - if (d.isNaN()) { - return false; + public static boolean truthy(Object value) { + if (value == null) { + return false; } - else if (d.isInfinite()) { - return true; + + if (value instanceof Boolean) { + return (boolean) value; } - } - if (value instanceof Float) { - Float f = (Float) value; + if (value instanceof Number) { + if (value instanceof Double) { + Double d = (Double) value; - if (f.isNaN()) { - return false; - } - else if (f.isInfinite()) { - return true; + if (d.isNaN()) { + return false; + } else if (d.isInfinite()) { + return true; + } + } + + if (value instanceof Float) { + Float f = (Float) value; + + if (f.isNaN()) { + return false; + } else if (f.isInfinite()) { + return true; + } + } + + return ((Number) value).doubleValue() != 0.0; } - } - return ((Number) value).doubleValue() != 0.0; - } + if (value instanceof String) { + return !((String) value).isEmpty(); + } - if (value instanceof String) { - return !((String) value).isEmpty(); - } + if (value instanceof Collection) { + return !((Collection) value).isEmpty(); + } - if (value instanceof Collection) { - return !((Collection) value).isEmpty(); - } + if (value.getClass().isArray()) { + return Array.getLength(value) > 0; + } - if (value.getClass().isArray()) { - return Array.getLength(value) > 0; + return true; } - - return true; - } } diff --git a/src/main/java/io/github/jamsesso/jsonlogic/JsonLogicException.java b/src/main/java/io/github/jamsesso/jsonlogic/JsonLogicException.java index 0e34710..c6cb5e3 100644 --- a/src/main/java/io/github/jamsesso/jsonlogic/JsonLogicException.java +++ b/src/main/java/io/github/jamsesso/jsonlogic/JsonLogicException.java @@ -2,28 +2,28 @@ public class JsonLogicException extends Exception { - private String jsonPath; + private String jsonPath; - private JsonLogicException() { - // The default constructor should not be called for exceptions. A reason must be provided. - } + private JsonLogicException() { + // The default constructor should not be called for exceptions. A reason must be provided. + } - public JsonLogicException(String msg, String jsonPath) { - super(msg); - this.jsonPath = jsonPath; - } + public JsonLogicException(String msg, String jsonPath) { + super(msg); + this.jsonPath = jsonPath; + } - public JsonLogicException(Throwable cause, String jsonPath) { - super(cause); - this.jsonPath = jsonPath; - } + public JsonLogicException(Throwable cause, String jsonPath) { + super(cause); + this.jsonPath = jsonPath; + } - public JsonLogicException(String msg, Throwable cause, String jsonPath) { - super(msg, cause); - this.jsonPath = jsonPath; - } + public JsonLogicException(String msg, Throwable cause, String jsonPath) { + super(msg, cause); + this.jsonPath = jsonPath; + } - public String getJsonPath() { - return jsonPath; - } + public String getJsonPath() { + return jsonPath; + } } diff --git a/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicArray.java b/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicArray.java index cdb7949..2e47e40 100644 --- a/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicArray.java +++ b/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicArray.java @@ -6,129 +6,129 @@ import java.util.ListIterator; public class JsonLogicArray implements JsonLogicNode, List { - private final List delegate; - - public JsonLogicArray(List delegate) { - this.delegate = delegate; - } - - @Override - public JsonLogicNodeType getType() { - return JsonLogicNodeType.ARRAY; - } - - @Override - public int size() { - return delegate.size(); - } - - @Override - public boolean isEmpty() { - return delegate.isEmpty(); - } - - @Override - public boolean contains(Object o) { - return delegate.contains(o); - } - - @Override - public Iterator iterator() { - return delegate.iterator(); - } - - @Override - public Object[] toArray() { - return delegate.toArray(); - } - - @Override - public T[] toArray(T[] a) { - return delegate.toArray(a); - } - - @Override - public boolean add(JsonLogicNode node) { - throw new UnsupportedOperationException("json-logic arrays are immutable"); - } - - @Override - public boolean remove(Object o) { - throw new UnsupportedOperationException("json-logic arrays are immutable"); - } - - @Override - public boolean containsAll(Collection c) { - return delegate.containsAll(c); - } - - @Override - public boolean addAll(Collection c) { - throw new UnsupportedOperationException("json-logic arrays are immutable"); - } - - @Override - public boolean addAll(int index, Collection c) { - throw new UnsupportedOperationException("json-logic arrays are immutable"); - } - - @Override - public boolean removeAll(Collection c) { - throw new UnsupportedOperationException("json-logic arrays are immutable"); - } - - @Override - public boolean retainAll(Collection c) { - throw new UnsupportedOperationException("json-logic arrays are immutable"); - } - - @Override - public void clear() { - throw new UnsupportedOperationException("json-logic arrays are immutable"); - } - - @Override - public JsonLogicNode get(int index) { - return delegate.get(index); - } - - @Override - public JsonLogicNode set(int index, JsonLogicNode element) { - throw new UnsupportedOperationException("json-logic arrays are immutable"); - } - - @Override - public void add(int index, JsonLogicNode element) { - throw new UnsupportedOperationException("json-logic arrays are immutable"); - } - - @Override - public JsonLogicNode remove(int index) { - throw new UnsupportedOperationException("json-logic arrays are immutable"); - } - - @Override - public int indexOf(Object o) { - return delegate.indexOf(o); - } - - @Override - public int lastIndexOf(Object o) { - return delegate.lastIndexOf(o); - } - - @Override - public ListIterator listIterator() { - return delegate.listIterator(); - } - - @Override - public ListIterator listIterator(int index) { - return delegate.listIterator(index); - } - - @Override - public List subList(int fromIndex, int toIndex) { - return delegate.subList(fromIndex, toIndex); - } + private final List delegate; + + public JsonLogicArray(List delegate) { + this.delegate = delegate; + } + + @Override + public JsonLogicNodeType getType() { + return JsonLogicNodeType.ARRAY; + } + + @Override + public int size() { + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public boolean contains(Object o) { + return delegate.contains(o); + } + + @Override + public Iterator iterator() { + return delegate.iterator(); + } + + @Override + public Object[] toArray() { + return delegate.toArray(); + } + + @Override + public T[] toArray(T[] a) { + return delegate.toArray(a); + } + + @Override + public boolean add(JsonLogicNode node) { + throw new UnsupportedOperationException("json-logic arrays are immutable"); + } + + @Override + public boolean remove(Object o) { + throw new UnsupportedOperationException("json-logic arrays are immutable"); + } + + @Override + public boolean containsAll(Collection c) { + return delegate.containsAll(c); + } + + @Override + public boolean addAll(Collection c) { + throw new UnsupportedOperationException("json-logic arrays are immutable"); + } + + @Override + public boolean addAll(int index, Collection c) { + throw new UnsupportedOperationException("json-logic arrays are immutable"); + } + + @Override + public boolean removeAll(Collection c) { + throw new UnsupportedOperationException("json-logic arrays are immutable"); + } + + @Override + public boolean retainAll(Collection c) { + throw new UnsupportedOperationException("json-logic arrays are immutable"); + } + + @Override + public void clear() { + throw new UnsupportedOperationException("json-logic arrays are immutable"); + } + + @Override + public JsonLogicNode get(int index) { + return delegate.get(index); + } + + @Override + public JsonLogicNode set(int index, JsonLogicNode element) { + throw new UnsupportedOperationException("json-logic arrays are immutable"); + } + + @Override + public void add(int index, JsonLogicNode element) { + throw new UnsupportedOperationException("json-logic arrays are immutable"); + } + + @Override + public JsonLogicNode remove(int index) { + throw new UnsupportedOperationException("json-logic arrays are immutable"); + } + + @Override + public int indexOf(Object o) { + return delegate.indexOf(o); + } + + @Override + public int lastIndexOf(Object o) { + return delegate.lastIndexOf(o); + } + + @Override + public ListIterator listIterator() { + return delegate.listIterator(); + } + + @Override + public ListIterator listIterator(int index) { + return delegate.listIterator(index); + } + + @Override + public List subList(int fromIndex, int toIndex) { + return delegate.subList(fromIndex, toIndex); + } } diff --git a/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicBoolean.java b/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicBoolean.java index 34ccd8f..d6cf3dd 100644 --- a/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicBoolean.java +++ b/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicBoolean.java @@ -1,22 +1,22 @@ package io.github.jamsesso.jsonlogic.ast; public class JsonLogicBoolean implements JsonLogicPrimitive { - public static final JsonLogicBoolean TRUE = new JsonLogicBoolean(true); - public static final JsonLogicBoolean FALSE = new JsonLogicBoolean(false); + public static final JsonLogicBoolean TRUE = new JsonLogicBoolean(true); + public static final JsonLogicBoolean FALSE = new JsonLogicBoolean(false); - private final boolean value; + private final boolean value; - public JsonLogicBoolean(boolean value) { - this.value = value; - } + public JsonLogicBoolean(boolean value) { + this.value = value; + } - @Override - public Boolean getValue() { - return value; - } + @Override + public Boolean getValue() { + return value; + } - @Override - public JsonLogicPrimitiveType getPrimitiveType() { - return JsonLogicPrimitiveType.BOOLEAN; - } + @Override + public JsonLogicPrimitiveType getPrimitiveType() { + return JsonLogicPrimitiveType.BOOLEAN; + } } diff --git a/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicNode.java b/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicNode.java index 563750c..4fe701e 100644 --- a/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicNode.java +++ b/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicNode.java @@ -1,5 +1,5 @@ package io.github.jamsesso.jsonlogic.ast; public interface JsonLogicNode { - JsonLogicNodeType getType(); + JsonLogicNodeType getType(); } diff --git a/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicNodeType.java b/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicNodeType.java index 46f8716..00b429c 100644 --- a/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicNodeType.java +++ b/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicNodeType.java @@ -1,8 +1,8 @@ package io.github.jamsesso.jsonlogic.ast; public enum JsonLogicNodeType { - PRIMITIVE, - VARIABLE, - ARRAY, - OPERATION + PRIMITIVE, + VARIABLE, + ARRAY, + OPERATION } diff --git a/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicNull.java b/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicNull.java index 5951580..4334ca0 100644 --- a/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicNull.java +++ b/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicNull.java @@ -1,19 +1,19 @@ package io.github.jamsesso.jsonlogic.ast; public class JsonLogicNull implements JsonLogicPrimitive { - public static final JsonLogicNull NULL = new JsonLogicNull(); + public static final JsonLogicNull NULL = new JsonLogicNull(); - private JsonLogicNull() { - // Consumers should use the NULL static instance. - } + private JsonLogicNull() { + // Consumers should use the NULL static instance. + } - @Override - public Object getValue() { - return null; - } + @Override + public Object getValue() { + return null; + } - @Override - public JsonLogicPrimitiveType getPrimitiveType() { - return JsonLogicPrimitiveType.NULL; - } + @Override + public JsonLogicPrimitiveType getPrimitiveType() { + return JsonLogicPrimitiveType.NULL; + } } diff --git a/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicNumber.java b/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicNumber.java index 7ea3bc3..768cba1 100644 --- a/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicNumber.java +++ b/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicNumber.java @@ -1,19 +1,19 @@ package io.github.jamsesso.jsonlogic.ast; public class JsonLogicNumber implements JsonLogicPrimitive { - private final Number value; + private final Number value; - public JsonLogicNumber(Number value) { - this.value = value; - } + public JsonLogicNumber(Number value) { + this.value = value; + } - @Override - public Double getValue() { - return value.doubleValue(); - } + @Override + public Double getValue() { + return value.doubleValue(); + } - @Override - public JsonLogicPrimitiveType getPrimitiveType() { - return JsonLogicPrimitiveType.NUMBER; - } + @Override + public JsonLogicPrimitiveType getPrimitiveType() { + return JsonLogicPrimitiveType.NUMBER; + } } diff --git a/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicOperation.java b/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicOperation.java index e2bedf6..4a43014 100644 --- a/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicOperation.java +++ b/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicOperation.java @@ -1,24 +1,24 @@ package io.github.jamsesso.jsonlogic.ast; public class JsonLogicOperation implements JsonLogicNode { - private final String operator; - private final JsonLogicArray arguments; + private final String operator; + private final JsonLogicArray arguments; - public JsonLogicOperation(String operator, JsonLogicArray arguments) { - this.operator = operator; - this.arguments = arguments; - } + public JsonLogicOperation(String operator, JsonLogicArray arguments) { + this.operator = operator; + this.arguments = arguments; + } - @Override - public JsonLogicNodeType getType() { - return JsonLogicNodeType.OPERATION; - } + @Override + public JsonLogicNodeType getType() { + return JsonLogicNodeType.OPERATION; + } - public String getOperator() { - return operator; - } + public String getOperator() { + return operator; + } - public JsonLogicArray getArguments() { - return arguments; - } + public JsonLogicArray getArguments() { + return arguments; + } } 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 8bc5873..4c13106 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,15 @@ import io.github.jamsesso.jsonlogic.JsonLogicException; public class JsonLogicParseException extends JsonLogicException { - public JsonLogicParseException(String msg, String jsonPath) { - super(msg, jsonPath); - } + public JsonLogicParseException(String msg, String jsonPath) { + super(msg, jsonPath); + } - public JsonLogicParseException(Throwable cause, String jsonPath) { - super(cause, jsonPath); - } + public JsonLogicParseException(Throwable cause, String jsonPath) { + super(cause, jsonPath); + } - public JsonLogicParseException(String msg, Throwable cause, String jsonPath) { - super(msg, cause, jsonPath); - } + public JsonLogicParseException(String msg, Throwable cause, String jsonPath) { + super(msg, 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 bf442b8..d6f60b8 100644 --- a/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicParser.java +++ b/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicParser.java @@ -1,95 +1,99 @@ package io.github.jamsesso.jsonlogic.ast; -import com.google.gson.*; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.JsonPrimitive; +import com.google.gson.JsonSyntaxException; import java.util.ArrayList; import java.util.Collections; import java.util.List; public final class JsonLogicParser { - private static final JsonParser PARSER = new JsonParser(); + private static final JsonParser PARSER = new JsonParser(); - private JsonLogicParser() { - // Utility class has no public constructor. - } - - public static JsonLogicNode parse(String json) throws JsonLogicParseException { - try { - return parse(PARSER.parse(json)); - } - catch (JsonSyntaxException 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; - } - - // Handle primitives - if (root.isJsonPrimitive()) { - JsonPrimitive primitive = root.getAsJsonPrimitive(); - - if (primitive.isString()) { - return new JsonLogicString(primitive.getAsString()); - } - - if (primitive.isNumber()) { - return new JsonLogicNumber(primitive.getAsNumber()); - } - - if (primitive.isBoolean() && primitive.getAsBoolean()) { - return JsonLogicBoolean.TRUE; - } - else { - return JsonLogicBoolean.FALSE; - } + private JsonLogicParser() { + // Utility class has no public constructor. } - // Handle arrays - if (root.isJsonArray()) { - JsonArray array = root.getAsJsonArray(); - List elements = new ArrayList<>(array.size()); - - int index = 0; - for (JsonElement element : array) { - elements.add(parse(element, String.format("%s[%d]", jsonPath, index++))); - } - - return new JsonLogicArray(elements); - } - - // Handle objects & variables - JsonObject object = root.getAsJsonObject(); - - if (object.keySet().size() != 1) { - throw new JsonLogicParseException("objects must have exactly 1 key defined, found " + object.keySet().size(), jsonPath); + public static JsonLogicNode parse(String json) throws JsonLogicParseException { + try { + return parse(PARSER.parse(json)); + } catch (JsonSyntaxException e) { + throw new JsonLogicParseException(e, "$"); + } } - String key = object.keySet().stream().findAny().get(); - 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. - if (argumentNode instanceof JsonLogicArray) { - arguments = (JsonLogicArray) argumentNode; - } - else { - arguments = new JsonLogicArray(Collections.singletonList(argumentNode)); + private static JsonLogicNode parse(JsonElement root) throws JsonLogicParseException { + return parse(root, "$"); } - // Special case for variable handling - if ("var".equals(key)) { - JsonLogicNode defaultValue = arguments.size() > 1 ? arguments.get(1) : JsonLogicNull.NULL; - return new JsonLogicVariable(arguments.size() < 1 ? JsonLogicNull.NULL : arguments.get(0), defaultValue); + private static JsonLogicNode parse(JsonElement root, String jsonPath) throws JsonLogicParseException { + // Handle null + if (root.isJsonNull()) { + return JsonLogicNull.NULL; + } + + // Handle primitives + if (root.isJsonPrimitive()) { + JsonPrimitive primitive = root.getAsJsonPrimitive(); + + if (primitive.isString()) { + return new JsonLogicString(primitive.getAsString()); + } + + if (primitive.isNumber()) { + return new JsonLogicNumber(primitive.getAsNumber()); + } + + if (primitive.isBoolean() && primitive.getAsBoolean()) { + return JsonLogicBoolean.TRUE; + } else { + return JsonLogicBoolean.FALSE; + } + } + + // Handle arrays + if (root.isJsonArray()) { + JsonArray array = root.getAsJsonArray(); + List elements = new ArrayList<>(array.size()); + + int index = 0; + for (JsonElement element : array) { + elements.add(parse(element, String.format("%s[%d]", jsonPath, index++))); + } + + return new JsonLogicArray(elements); + } + + // Handle objects & variables + JsonObject object = root.getAsJsonObject(); + + if (object.keySet().size() != 1) { + 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), String.format("%s.%s", jsonPath, key)); + JsonLogicArray arguments; + + // Always coerce single-argument operations into a JsonLogicArray with a single element. + if (argumentNode instanceof JsonLogicArray) { + arguments = (JsonLogicArray) argumentNode; + } else { + arguments = new JsonLogicArray(Collections.singletonList(argumentNode)); + } + + // Special case for variable handling + if ("var".equals(key)) { + JsonLogicNode defaultValue = arguments.size() > 1 ? arguments.get(1) : JsonLogicNull.NULL; + return new JsonLogicVariable(arguments.size() < 1 ? JsonLogicNull.NULL : arguments.get(0), defaultValue); + } + + // Handle regular operations + return new JsonLogicOperation(key, arguments); } - - // Handle regular operations - return new JsonLogicOperation(key, arguments); - } } diff --git a/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicPrimitive.java b/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicPrimitive.java index 26ae717..01625d2 100644 --- a/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicPrimitive.java +++ b/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicPrimitive.java @@ -1,12 +1,12 @@ package io.github.jamsesso.jsonlogic.ast; public interface JsonLogicPrimitive extends JsonLogicNode { - T getValue(); + T getValue(); - JsonLogicPrimitiveType getPrimitiveType(); + JsonLogicPrimitiveType getPrimitiveType(); - @Override - default JsonLogicNodeType getType() { - return JsonLogicNodeType.PRIMITIVE; - } + @Override + default JsonLogicNodeType getType() { + return JsonLogicNodeType.PRIMITIVE; + } } diff --git a/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicPrimitiveType.java b/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicPrimitiveType.java index 0a23719..2cd6e9e 100644 --- a/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicPrimitiveType.java +++ b/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicPrimitiveType.java @@ -1,8 +1,8 @@ package io.github.jamsesso.jsonlogic.ast; public enum JsonLogicPrimitiveType { - STRING, - NUMBER, - BOOLEAN, - NULL + STRING, + NUMBER, + BOOLEAN, + NULL } diff --git a/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicString.java b/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicString.java index bd3009b..d51109f 100644 --- a/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicString.java +++ b/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicString.java @@ -1,19 +1,19 @@ package io.github.jamsesso.jsonlogic.ast; public class JsonLogicString implements JsonLogicPrimitive { - private final String value; + private final String value; - public JsonLogicString(String value) { - this.value = value; - } + public JsonLogicString(String value) { + this.value = value; + } - @Override - public String getValue() { - return value; - } + @Override + public String getValue() { + return value; + } - @Override - public JsonLogicPrimitiveType getPrimitiveType() { - return JsonLogicPrimitiveType.STRING; - } + @Override + public JsonLogicPrimitiveType getPrimitiveType() { + return JsonLogicPrimitiveType.STRING; + } } diff --git a/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicVariable.java b/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicVariable.java index 181c5b6..6619819 100644 --- a/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicVariable.java +++ b/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicVariable.java @@ -1,24 +1,24 @@ package io.github.jamsesso.jsonlogic.ast; public class JsonLogicVariable implements JsonLogicNode { - private final JsonLogicNode key; - private final JsonLogicNode defaultValue; + private final JsonLogicNode key; + private final JsonLogicNode defaultValue; - public JsonLogicVariable(JsonLogicNode key, JsonLogicNode defaultValue) { - this.key = key; - this.defaultValue = defaultValue; - } + public JsonLogicVariable(JsonLogicNode key, JsonLogicNode defaultValue) { + this.key = key; + this.defaultValue = defaultValue; + } - @Override - public JsonLogicNodeType getType() { - return JsonLogicNodeType.VARIABLE; - } + @Override + public JsonLogicNodeType getType() { + return JsonLogicNodeType.VARIABLE; + } - public JsonLogicNode getKey() { - return key; - } + public JsonLogicNode getKey() { + return key; + } - public JsonLogicNode getDefaultValue() { - return defaultValue; - } + public JsonLogicNode getDefaultValue() { + return defaultValue; + } } 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 b35d2bc..511270e 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,15 @@ import io.github.jamsesso.jsonlogic.JsonLogicException; public class JsonLogicEvaluationException extends JsonLogicException { - public JsonLogicEvaluationException(String msg, String jsonPath) { - super(msg, jsonPath); - } + public JsonLogicEvaluationException(String msg, String jsonPath) { + super(msg, jsonPath); + } - public JsonLogicEvaluationException(Throwable cause, String jsonPath) { - super(cause, jsonPath); - } + public JsonLogicEvaluationException(Throwable cause, String jsonPath) { + super(cause, jsonPath); + } - public JsonLogicEvaluationException(String msg, Throwable cause, String jsonPath) { - super(msg, cause, jsonPath); - } + public JsonLogicEvaluationException(String msg, Throwable cause, String jsonPath) { + super(msg, 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 e15fbb0..78cb5b8 100644 --- a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/JsonLogicEvaluator.java +++ b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/JsonLogicEvaluator.java @@ -1,161 +1,184 @@ package io.github.jamsesso.jsonlogic.evaluator; -import io.github.jamsesso.jsonlogic.ast.*; +import io.github.jamsesso.jsonlogic.ast.JsonLogicArray; +import io.github.jamsesso.jsonlogic.ast.JsonLogicNode; +import io.github.jamsesso.jsonlogic.ast.JsonLogicNumber; +import io.github.jamsesso.jsonlogic.ast.JsonLogicOperation; +import io.github.jamsesso.jsonlogic.ast.JsonLogicPrimitive; +import io.github.jamsesso.jsonlogic.ast.JsonLogicVariable; import io.github.jamsesso.jsonlogic.utils.ArrayLike; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; public class JsonLogicEvaluator { - /** Sentinel object to represent a missing value (for internal use only). */ - private static final Object MISSING = new Object(); + /** + * Sentinel object to represent a missing value (for internal use only). + */ + private static final Object MISSING = new Object(); - private final Map expressions; + private final Map expressions; - public JsonLogicEvaluator(Collection expressions) { - this.expressions = new HashMap<>(); + public JsonLogicEvaluator(Collection expressions) { + this.expressions = new HashMap<>(); - for (JsonLogicExpression expression : expressions) { - this.expressions.put(expression.key(), expression); - } - } - - public JsonLogicEvaluator(Map expressions) { - this.expressions = Collections.unmodifiableMap(expressions); - } - - 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, jsonPath + ".var"); - case ARRAY: return evaluate((JsonLogicArray) node, data, jsonPath); - default: return evaluate((JsonLogicOperation) node, data, jsonPath); + for (JsonLogicExpression expression : expressions) { + this.expressions.put(expression.key(), expression); + } } - } - public Object evaluate(JsonLogicPrimitive primitive) { - switch (primitive.getPrimitiveType()) { - case NUMBER: return ((JsonLogicNumber) primitive).getValue(); + public JsonLogicEvaluator(Map expressions) { + this.expressions = Collections.unmodifiableMap(expressions); + } - default: - return primitive.getValue(); + 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, jsonPath + ".var"); + case ARRAY: + return evaluate((JsonLogicArray) node, data, jsonPath); + default: + return evaluate((JsonLogicOperation) node, data, jsonPath); + } } - } - public Object evaluate(JsonLogicVariable variable, Object data, String jsonPath) - throws JsonLogicEvaluationException { - Object defaultValue = evaluate(variable.getDefaultValue(), null, jsonPath + "[1]"); + public Object evaluate(JsonLogicPrimitive primitive) { + switch (primitive.getPrimitiveType()) { + case NUMBER: + return ((JsonLogicNumber) primitive).getValue(); - if (data == null) { - return defaultValue; + default: + return primitive.getValue(); + } } - Object key = evaluate(variable.getKey(), data, jsonPath + "[0]"); + public Object evaluate(JsonLogicVariable variable, Object data, String jsonPath) + throws JsonLogicEvaluationException { + Object defaultValue = evaluate(variable.getDefaultValue(), null, jsonPath + "[1]"); - if (key == null) { - return Optional.of(data) - .map(JsonLogicEvaluator::transform) - .orElse(evaluate(variable.getDefaultValue(), null, jsonPath + "[1]")); - } + if (data == null) { + return defaultValue; + } + + Object key = evaluate(variable.getKey(), data, jsonPath + "[0]"); + + if (key == null) { + return Optional.of(data) + .map(JsonLogicEvaluator::transform) + .orElse(evaluate(variable.getDefaultValue(), null, jsonPath + "[1]")); + } - if (key instanceof Number) { - int index = ((Number) key).intValue(); + if (key instanceof Number) { + int index = ((Number) key).intValue(); - if (ArrayLike.isEligible(data)) { - ArrayLike list = new ArrayLike(data); + if (ArrayLike.isEligible(data)) { + ArrayLike list = new ArrayLike(data); - if (index >= 0 && index < list.size()) { - return transform(list.get(index)); + if (index >= 0 && index < list.size()) { + return transform(list.get(index)); + } + } + + return defaultValue; } - } - return defaultValue; - } + // Handle the case when the key is a string, potentially referencing an infinitely-deep map: x.y.z + if (key instanceof String) { + String name = (String) key; - // Handle the case when the key is a string, potentially referencing an infinitely-deep map: x.y.z - if (key instanceof String) { - String name = (String) key; + if (name.isEmpty()) { + return data; + } - if (name.isEmpty()) { - return data; - } + String[] keys = name.split("\\."); + Object result = data; - String[] keys = name.split("\\."); - Object result = data; + for (String partial : keys) { + result = evaluatePartialVariable(partial, result, jsonPath + "[0]"); - for (String partial : keys) { - result = evaluatePartialVariable(partial, result, jsonPath + "[0]"); + if (result == MISSING) { + return defaultValue; + } else if (result == null) { + return null; + } + } - if (result == MISSING) { - return defaultValue; - } else if (result == null) { - return null; + return result; } - } - return result; + throw new JsonLogicEvaluationException("var first argument must be null, number, or string", jsonPath + "[0]"); } - throw new JsonLogicEvaluationException("var first argument must be null, number, or string", jsonPath + "[0]"); - } + private Object evaluatePartialVariable(String key, Object data, String jsonPath) + throws JsonLogicEvaluationException { + if (ArrayLike.isEligible(data)) { + ArrayLike list = new ArrayLike(data); + int index; - private Object evaluatePartialVariable(String key, Object data, String jsonPath) throws JsonLogicEvaluationException { - if (ArrayLike.isEligible(data)) { - ArrayLike list = new ArrayLike(data); - int index; + try { + index = Integer.parseInt(key); + } catch (NumberFormatException e) { + throw new JsonLogicEvaluationException(e, jsonPath); + } - try { - index = Integer.parseInt(key); - } - catch (NumberFormatException e) { - throw new JsonLogicEvaluationException(e, jsonPath); - } + if (index < 0 || index >= list.size()) { + return MISSING; + } - if (index < 0 || index >= list.size()) { - return MISSING; - } + return transform(list.get(index)); + } - return transform(list.get(index)); - } + if (data instanceof Map) { + Map map = (Map) data; + if (map.containsKey(key)) { + return transform(map.get(key)); + } else { + return MISSING; + } + } - if (data instanceof Map) { - Map map = (Map) data; - if (map.containsKey(key)) { - return transform(map.get(key)); - } else { - return MISSING; - } + return null; } - return null; - } + public List evaluate(JsonLogicArray array, Object data, String jsonPath) + throws JsonLogicEvaluationException { + List values = new ArrayList<>(array.size()); - 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, String.format("%s[%d]", jsonPath, index++))); + } - int index = 0; - for(JsonLogicNode element : array) { - values.add(evaluate(element, data, String.format("%s[%d]", jsonPath, index++))); + return values; } - return values; - } + public Object evaluate(JsonLogicOperation operation, Object data, String jsonPath) + throws JsonLogicEvaluationException { + JsonLogicExpression handler = expressions.get(operation.getOperator()); - 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() + "'", jsonPath); + } - if (handler == null) { - throw new JsonLogicEvaluationException("Undefined operation '" + operation.getOperator() + "'", jsonPath); + return handler.evaluate(this, + operation.getArguments(), + data, + String.format("%s.%s", jsonPath, operation.getOperator())); } - return handler.evaluate(this, operation.getArguments(), data, String.format("%s.%s", jsonPath, operation.getOperator())); - } + public static Object transform(Object value) { + if (value instanceof Number) { + return ((Number) value).doubleValue(); + } - public static Object transform(Object value) { - if (value instanceof Number) { - return ((Number) value).doubleValue(); + return value; } - - return value; - } } 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 0f1381b..d6c0526 100644 --- a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/JsonLogicExpression.java +++ b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/JsonLogicExpression.java @@ -3,8 +3,8 @@ import io.github.jamsesso.jsonlogic.ast.JsonLogicArray; public interface JsonLogicExpression { - String key(); + String key(); - Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data, String jsonPath) - throws JsonLogicEvaluationException; + 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 2e9350f..269aac7 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 @@ -1,54 +1,56 @@ package io.github.jamsesso.jsonlogic.evaluator.expressions; +import io.github.jamsesso.jsonlogic.JsonLogic; import io.github.jamsesso.jsonlogic.ast.JsonLogicArray; import io.github.jamsesso.jsonlogic.evaluator.JsonLogicEvaluationException; import io.github.jamsesso.jsonlogic.evaluator.JsonLogicEvaluator; import io.github.jamsesso.jsonlogic.evaluator.JsonLogicExpression; import io.github.jamsesso.jsonlogic.utils.ArrayLike; -import io.github.jamsesso.jsonlogic.JsonLogic; public class AllExpression implements JsonLogicExpression { - public static final AllExpression INSTANCE = new AllExpression(); - - private AllExpression() { - // Use INSTANCE instead. - } - - @Override - public String key() { - return "all"; - } - - @Override - 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", jsonPath); - } + public static final AllExpression INSTANCE = new AllExpression(); - Object maybeArray = evaluator.evaluate(arguments.get(0), data, jsonPath + "[0]"); - - if (maybeArray == null) { - return false; + private AllExpression() { + // Use INSTANCE instead. } - if (!ArrayLike.isEligible(maybeArray)) { - throw new JsonLogicEvaluationException("first argument to all must be a valid array", jsonPath); + @Override + public String key() { + return "all"; } - ArrayLike array = new ArrayLike(maybeArray); + @Override + 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", jsonPath); + } - if (array.size() < 1) { - return false; - } + Object maybeArray = evaluator.evaluate(arguments.get(0), data, jsonPath + "[0]"); - int index = 1; - for (Object item : array) { - if(!JsonLogic.truthy(evaluator.evaluate(arguments.get(1), item, String.format("%s[%d]", jsonPath, index)))) { - return false; - } - } + if (maybeArray == null) { + return false; + } - return true; - } + if (!ArrayLike.isEligible(maybeArray)) { + throw new JsonLogicEvaluationException("first argument to all must be a valid array", jsonPath); + } + + ArrayLike array = new ArrayLike(maybeArray); + + if (array.size() < 1) { + return false; + } + + int index = 1; + for (Object item : array) { + if (!JsonLogic.truthy(evaluator.evaluate(arguments.get(1), + item, + String.format("%s[%d]", jsonPath, index)))) { + return false; + } + } + + return true; + } } 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 7d9bb14..4646ec7 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 @@ -1,55 +1,52 @@ package io.github.jamsesso.jsonlogic.evaluator.expressions; +import io.github.jamsesso.jsonlogic.JsonLogic; import io.github.jamsesso.jsonlogic.ast.JsonLogicArray; import io.github.jamsesso.jsonlogic.evaluator.JsonLogicEvaluationException; import io.github.jamsesso.jsonlogic.evaluator.JsonLogicEvaluator; import io.github.jamsesso.jsonlogic.evaluator.JsonLogicExpression; import io.github.jamsesso.jsonlogic.utils.ArrayLike; -import io.github.jamsesso.jsonlogic.JsonLogic; public class ArrayHasExpression implements JsonLogicExpression { - public static final ArrayHasExpression SOME = new ArrayHasExpression(true); - public static final ArrayHasExpression NONE = new ArrayHasExpression(false); - - private final boolean isSome; + public static final ArrayHasExpression SOME = new ArrayHasExpression(true); + public static final ArrayHasExpression NONE = new ArrayHasExpression(false); - private ArrayHasExpression(boolean isSome) { - this.isSome = isSome; - } + private final boolean isSome; - @Override - public String key() { - return isSome ? "some" : "none"; - } + private ArrayHasExpression(boolean isSome) { + this.isSome = isSome; + } - @Override - public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data, String jsonPath) - throws JsonLogicEvaluationException { - if (arguments.size() != 2) { - throw new JsonLogicEvaluationException(key() + " expects exactly 2 arguments", jsonPath); + @Override + public String key() { + return isSome ? "some" : "none"; } - Object maybeArray = evaluator.evaluate(arguments.get(0), data, jsonPath + "[0]"); + @Override + public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data, String jsonPath) + throws JsonLogicEvaluationException { + if (arguments.size() != 2) { + throw new JsonLogicEvaluationException(key() + " expects exactly 2 arguments", jsonPath); + } - // Array objects can have null values according to http://jsonlogic.com/ - if (maybeArray == null) { - if (isSome) { - return false; - } else { - return true; - } - } + Object maybeArray = evaluator.evaluate(arguments.get(0), data, jsonPath + "[0]"); - if (!ArrayLike.isEligible(maybeArray)) { - throw new JsonLogicEvaluationException("first argument to " + key() + " must be a valid array", jsonPath + "[0]"); - } + // Array objects can have null values according to http://jsonlogic.com/ + if (maybeArray == null) { + return !isSome; + } - for (Object item : new ArrayLike(maybeArray)) { - if(JsonLogic.truthy(evaluator.evaluate(arguments.get(1), item, jsonPath + "[1]"))) { - return isSome; - } - } + if (!ArrayLike.isEligible(maybeArray)) { + throw new JsonLogicEvaluationException("first argument to " + key() + " must be a valid array", + jsonPath + "[0]"); + } - return !isSome; - } + for (Object item : new ArrayLike(maybeArray)) { + if (JsonLogic.truthy(evaluator.evaluate(arguments.get(1), item, jsonPath + "[1]"))) { + return isSome; + } + } + + return !isSome; + } } 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 1ef7651..f272749 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 @@ -6,28 +6,28 @@ import java.util.stream.Collectors; public class ConcatenateExpression implements PreEvaluatedArgumentsExpression { - public static final ConcatenateExpression INSTANCE = new ConcatenateExpression(); + public static final ConcatenateExpression INSTANCE = new ConcatenateExpression(); - private ConcatenateExpression() { - // Use INSTANCE instead. - } + private ConcatenateExpression() { + // Use INSTANCE instead. + } - @Override - public String key() { - return "cat"; - } + @Override + public String key() { + return "cat"; + } - @Override - public Object evaluate(List arguments, Object data, String jsonPath) throws JsonLogicEvaluationException { - return arguments.stream() - .map(obj -> { - if (obj instanceof Double && obj.toString().endsWith(".0")) { - return ((Double) obj).intValue(); - } + @Override + public Object evaluate(List arguments, Object data, String jsonPath) throws JsonLogicEvaluationException { + return arguments.stream() + .map(obj -> { + if (obj instanceof Double && obj.toString().endsWith(".0")) { + return ((Double) obj).intValue(); + } - return obj; - }) - .map(Object::toString) - .collect(Collectors.joining()); - } + return obj; + }) + .map(Object::toString) + .collect(Collectors.joining()); + } } 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 0262ba1..a284ee9 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 @@ -6,102 +6,100 @@ import java.util.List; public class EqualityExpression implements PreEvaluatedArgumentsExpression { - public static final EqualityExpression INSTANCE = new EqualityExpression(); + public static final EqualityExpression INSTANCE = new EqualityExpression(); - private EqualityExpression() { - // Only one instance can be constructed. Use EqualityExpression.INSTANCE - } - - @Override - public String key() { - return "=="; - } - - @Override - public Object evaluate(List arguments, Object data, String jsonPath) throws JsonLogicEvaluationException { - if (arguments.size() != 2) { - throw new JsonLogicEvaluationException("equality expressions expect exactly 2 arguments", jsonPath); - } - - Object left = arguments.get(0); - Object right = arguments.get(1); - - // Use the loose equality matrix - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness#Loose_equality_using - if (left == null && right == null) { - return true; - } - - if (left == null || right == null) { - return false; - } - - // Check numeric loose equality - if (left instanceof Number && right instanceof Number) { - return Double.valueOf(((Number) left).doubleValue()).equals(((Number) right).doubleValue()); + private EqualityExpression() { + // Only one instance can be constructed. Use EqualityExpression.INSTANCE } - if (left instanceof Number && right instanceof String) { - return compareNumberToString((Number) left, (String) right); + @Override + public String key() { + return "=="; } - if (left instanceof Number && right instanceof Boolean) { - return compareNumberToBoolean((Number) left, (Boolean) right); + @Override + public Object evaluate(List arguments, Object data, String jsonPath) throws JsonLogicEvaluationException { + if (arguments.size() != 2) { + throw new JsonLogicEvaluationException("equality expressions expect exactly 2 arguments", jsonPath); + } + + Object left = arguments.get(0); + Object right = arguments.get(1); + + // Use the loose equality matrix + //https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness#Loose_equality_using + if (left == null && right == null) { + return true; + } + + if (left == null || right == null) { + return false; + } + + // Check numeric loose equality + if (left instanceof Number && right instanceof Number) { + return Double.valueOf(((Number) left).doubleValue()).equals(((Number) right).doubleValue()); + } + + if (left instanceof Number && right instanceof String) { + return compareNumberToString((Number) left, (String) right); + } + + if (left instanceof Number && right instanceof Boolean) { + return compareNumberToBoolean((Number) left, (Boolean) right); + } + + // Check string loose equality + if (left instanceof String && right instanceof String) { + return left.equals(right); + } + + if (left instanceof String && right instanceof Number) { + return compareNumberToString((Number) right, (String) left); + } + + if (left instanceof String && right instanceof Boolean) { + return compareStringToBoolean((String) left, (Boolean) right); + } + + // Check boolean loose equality + if (left instanceof Boolean && right instanceof Boolean) { + return ((Boolean) left).booleanValue() == ((Boolean) right).booleanValue(); + } + + if (left instanceof Boolean && right instanceof Number) { + return compareNumberToBoolean((Number) right, (Boolean) left); + } + + if (left instanceof Boolean && right instanceof String) { + return compareStringToBoolean((String) right, (Boolean) left); + } + + // Check non-truthy values + return !JsonLogic.truthy(left) && !JsonLogic.truthy(right); } - // Check string loose equality - if (left instanceof String && right instanceof String) { - return left.equals(right); - } + private boolean compareNumberToString(Number left, String right) { + try { + if (right.trim().isEmpty()) { + right = "0"; + } - if (left instanceof String && right instanceof Number) { - return compareNumberToString((Number) right, (String) left); + return Double.parseDouble(right) == left.doubleValue(); + } catch (NumberFormatException e) { + return false; + } } - if (left instanceof String && right instanceof Boolean) { - return compareStringToBoolean((String) left, (Boolean) right); - } + private boolean compareNumberToBoolean(Number left, Boolean right) { + if (right) { + return left.doubleValue() == 1.0; + } - // Check boolean loose equality - if (left instanceof Boolean && right instanceof Boolean) { - return ((Boolean) left).booleanValue() == ((Boolean) right).booleanValue(); + return left.doubleValue() == 0.0; } - if (left instanceof Boolean && right instanceof Number) { - return compareNumberToBoolean((Number) right, (Boolean) left); + private boolean compareStringToBoolean(String left, Boolean right) { + return JsonLogic.truthy(left) == right; } - - if (left instanceof Boolean && right instanceof String) { - return compareStringToBoolean((String) right, (Boolean) left); - } - - // Check non-truthy values - return !JsonLogic.truthy(left) && !JsonLogic.truthy(right); - - } - - private boolean compareNumberToString(Number left, String right) { - try { - if (right.trim().isEmpty()) { - right = "0"; - } - - return Double.parseDouble(right) == left.doubleValue(); - } - catch (NumberFormatException e) { - return false; - } - } - - private boolean compareNumberToBoolean(Number left, Boolean right) { - if (right) { - return left.doubleValue() == 1.0; - } - - return left.doubleValue() == 0.0; - } - - private boolean compareStringToBoolean(String left, Boolean right) { - return JsonLogic.truthy(left) == right; - } } 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 79364e9..1357b2f 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 @@ -1,48 +1,48 @@ package io.github.jamsesso.jsonlogic.evaluator.expressions; -import io.github.jamsesso.jsonlogic.utils.ArrayLike; import io.github.jamsesso.jsonlogic.JsonLogic; import io.github.jamsesso.jsonlogic.ast.JsonLogicArray; import io.github.jamsesso.jsonlogic.evaluator.JsonLogicEvaluationException; import io.github.jamsesso.jsonlogic.evaluator.JsonLogicEvaluator; import io.github.jamsesso.jsonlogic.evaluator.JsonLogicExpression; +import io.github.jamsesso.jsonlogic.utils.ArrayLike; import java.util.ArrayList; import java.util.List; public class FilterExpression implements JsonLogicExpression { - public static final FilterExpression INSTANCE = new FilterExpression(); - - private FilterExpression() { - // Use INSTANCE instead. - } - - @Override - public String key() { - return "filter"; - } - - @Override - 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", jsonPath); - } + public static final FilterExpression INSTANCE = new FilterExpression(); - Object maybeArray = evaluator.evaluate(arguments.get(0), data, jsonPath + "[0]"); + private FilterExpression() { + // Use INSTANCE instead. + } - if (!ArrayLike.isEligible(maybeArray)) { - throw new JsonLogicEvaluationException("first argument to filter must be a valid array", jsonPath + "[0]"); + @Override + public String key() { + return "filter"; } - List result = new ArrayList<>(); + @Override + 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", jsonPath); + } - for (Object item : new ArrayLike(maybeArray)) { - if(JsonLogic.truthy(evaluator.evaluate(arguments.get(1), item, jsonPath + "[1]"))) { - result.add(item); - } - } + Object maybeArray = evaluator.evaluate(arguments.get(0), data, jsonPath + "[0]"); - return result; - } + if (!ArrayLike.isEligible(maybeArray)) { + 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, jsonPath + "[1]"))) { + result.add(item); + } + } + + return result; + } } 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 230a636..d62a44c 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 @@ -1,60 +1,62 @@ package io.github.jamsesso.jsonlogic.evaluator.expressions; -import io.github.jamsesso.jsonlogic.evaluator.JsonLogicExpression; import io.github.jamsesso.jsonlogic.JsonLogic; import io.github.jamsesso.jsonlogic.ast.JsonLogicArray; import io.github.jamsesso.jsonlogic.ast.JsonLogicNode; import io.github.jamsesso.jsonlogic.evaluator.JsonLogicEvaluationException; import io.github.jamsesso.jsonlogic.evaluator.JsonLogicEvaluator; +import io.github.jamsesso.jsonlogic.evaluator.JsonLogicExpression; public class IfExpression implements JsonLogicExpression { - public static final IfExpression IF = new IfExpression("if"); - public static final IfExpression TERNARY = new IfExpression("?:"); - - private final String operator; - - private IfExpression(String operator) { - this.operator = operator; - } - - @Override - public String key() { - return operator; - } - - @Override - public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data, - String jsonPath) - throws JsonLogicEvaluationException { - if (arguments.size() < 1) { - return null; - } + public static final IfExpression IF = new IfExpression("if"); + public static final IfExpression TERNARY = new IfExpression("?:"); - // If there is only a single argument, simply evaluate & return that argument. - if (arguments.size() == 1) { - return evaluator.evaluate(arguments.get(0), data, jsonPath + "[0]"); - } + private final String operator; - // 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, jsonPath + "[0]")) - ? evaluator.evaluate(arguments.get(1), data, jsonPath + "[1]") - : null; + private IfExpression(String operator) { + this.operator = operator; } - for (int i = 0; i < arguments.size() - 1; i += 2) { - JsonLogicNode condition = arguments.get(i); - JsonLogicNode resultIfTrue = arguments.get(i + 1); - - 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)); - } + @Override + public String key() { + return operator; } - if ((arguments.size() & 1) == 0) { - return null; + @Override + public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data, + String jsonPath) + throws JsonLogicEvaluationException { + if (arguments.size() < 1) { + return null; + } + + // If there is only a single argument, simply evaluate & return that argument. + if (arguments.size() == 1) { + 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, jsonPath + "[0]")) + ? evaluator.evaluate(arguments.get(1), data, jsonPath + "[1]") + : null; + } + + for (int i = 0; i < arguments.size() - 1; i += 2) { + JsonLogicNode condition = arguments.get(i); + JsonLogicNode resultIfTrue = arguments.get(i + 1); + + 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)); + } + } + + if ((arguments.size() & 1) == 0) { + return null; + } + + return evaluator.evaluate(arguments.get(arguments.size() - 1), + data, + String.format("%s[%d]", jsonPath, arguments.size() - 1)); } - - 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 e5f6d0b..8298ca0 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 @@ -6,35 +6,35 @@ import java.util.List; public class InExpression implements PreEvaluatedArgumentsExpression { - public static final InExpression INSTANCE = new InExpression(); + public static final InExpression INSTANCE = new InExpression(); - private InExpression() { - // Use INSTANCE instead. - } - - @Override - public String key() { - return "in"; - } - - @Override - public Object evaluate(List arguments, Object data, String jsonPath) throws JsonLogicEvaluationException { - if (arguments.size() < 2) { - return false; + private InExpression() { + // Use INSTANCE instead. } - // Handle string in (substring) - if (arguments.get(1) instanceof String) { - if (arguments.get(0) == null) { - return false; - } - return ((String) arguments.get(1)).contains(arguments.get(0).toString()); + @Override + public String key() { + return "in"; } - if (ArrayLike.isEligible(arguments.get(1))) { - return new ArrayLike(arguments.get(1)).contains(arguments.get(0)); - } + @Override + public Object evaluate(List arguments, Object data, String jsonPath) throws JsonLogicEvaluationException { + if (arguments.size() < 2) { + return false; + } - return false; - } + // Handle string in (substring) + if (arguments.get(1) instanceof String) { + if (arguments.get(0) == null) { + return false; + } + return ((String) arguments.get(1)).contains(arguments.get(0).toString()); + } + + if (ArrayLike.isEligible(arguments.get(1))) { + return new ArrayLike(arguments.get(1)).contains(arguments.get(0)); + } + + 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 747afb0..0774323 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 @@ -6,24 +6,24 @@ import io.github.jamsesso.jsonlogic.evaluator.JsonLogicExpression; public class InequalityExpression implements JsonLogicExpression { - public static final InequalityExpression INSTANCE = new InequalityExpression(EqualityExpression.INSTANCE); + public static final InequalityExpression INSTANCE = new InequalityExpression(EqualityExpression.INSTANCE); - private final EqualityExpression delegate; + private final EqualityExpression delegate; - private InequalityExpression(EqualityExpression delegate) { - this.delegate = delegate; - } + private InequalityExpression(EqualityExpression delegate) { + this.delegate = delegate; + } - @Override - public String key() { - return "!="; - } + @Override + public String key() { + return "!="; + } - @Override - public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data, String jsonPath) - throws JsonLogicEvaluationException { - boolean result = (boolean) delegate.evaluate(evaluator, arguments, data, jsonPath); + @Override + public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data, String jsonPath) + throws JsonLogicEvaluationException { + boolean result = (boolean) delegate.evaluate(evaluator, arguments, data, jsonPath); - return !result; - } + 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 43332c5..b76ad35 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 @@ -6,28 +6,28 @@ import java.util.List; public class LogExpression implements PreEvaluatedArgumentsExpression { - public static final LogExpression STDOUT = new LogExpression(System.out); + public static final LogExpression STDOUT = new LogExpression(System.out); - private final PrintStream printer; + private final PrintStream printer; - public LogExpression(PrintStream printer) { - this.printer = printer; - } - - @Override - public String key() { - return "log"; - } + public LogExpression(PrintStream printer) { + this.printer = printer; + } - @Override - public Object evaluate(List arguments, Object data, String jsonPath) throws JsonLogicEvaluationException { - if (arguments.isEmpty()) { - throw new JsonLogicEvaluationException("log operator requires exactly 1 argument", jsonPath); + @Override + public String key() { + return "log"; } - Object value = arguments.get(0); - printer.println("JsonLogic: " + value); + @Override + public Object evaluate(List arguments, Object data, String jsonPath) throws JsonLogicEvaluationException { + if (arguments.isEmpty()) { + throw new JsonLogicEvaluationException("log operator requires exactly 1 argument", jsonPath); + } - return value; - } + Object value = arguments.get(0); + printer.println("JsonLogic: " + value); + + return value; + } } 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 8412168..b68145b 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 @@ -8,38 +8,38 @@ import io.github.jamsesso.jsonlogic.evaluator.JsonLogicExpression; public class LogicExpression implements JsonLogicExpression { - public static final LogicExpression AND = new LogicExpression(true); - public static final LogicExpression OR = new LogicExpression(false); + public static final LogicExpression AND = new LogicExpression(true); + public static final LogicExpression OR = new LogicExpression(false); - private final boolean isAnd; + private final boolean isAnd; - private LogicExpression(boolean isAnd) { - this.isAnd = isAnd; - } - - @Override - public String key() { - return isAnd ? "and" : "or"; - } + private LogicExpression(boolean isAnd) { + this.isAnd = isAnd; + } - @Override - public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data, String jsonPath) - throws JsonLogicEvaluationException { - if (arguments.size() < 1) { - throw new JsonLogicEvaluationException(key() + " operator expects at least 1 argument", jsonPath); + @Override + public String key() { + return isAnd ? "and" : "or"; } - Object result = null; + @Override + public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data, String jsonPath) + throws JsonLogicEvaluationException { + if (arguments.size() < 1) { + 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, String.format("%s[%d]", jsonPath, index++)); + int index = 0; + for (JsonLogicNode element : arguments) { + result = evaluator.evaluate(element, data, String.format("%s[%d]", jsonPath, index++)); + + if (isAnd && !JsonLogic.truthy(result) || !isAnd && JsonLogic.truthy(result)) { + return result; + } + } - if ((isAnd && !JsonLogic.truthy(result)) || (!isAnd && JsonLogic.truthy(result))) { return 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 9c3a863..834238c 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 @@ -11,36 +11,36 @@ import java.util.List; public class MapExpression implements JsonLogicExpression { - public static final MapExpression INSTANCE = new MapExpression(); - - private MapExpression() { - // Use INSTANCE instead. - } - - @Override - public String key() { - return "map"; - } - - @Override - 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", jsonPath); - } + public static final MapExpression INSTANCE = new MapExpression(); - Object maybeArray = evaluator.evaluate(arguments.get(0), data, jsonPath + "[0]"); + private MapExpression() { + // Use INSTANCE instead. + } - if (!ArrayLike.isEligible(maybeArray)) { - return Collections.emptyList(); + @Override + public String key() { + return "map"; } - List result = new ArrayList<>(); + @Override + 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", jsonPath); + } - for (Object item : new ArrayLike(maybeArray)) { - result.add(evaluator.evaluate(arguments.get(1), item, jsonPath + "[1]")); - } + Object maybeArray = evaluator.evaluate(arguments.get(0), data, jsonPath + "[0]"); + + if (!ArrayLike.isEligible(maybeArray)) { + return Collections.emptyList(); + } - return result; - } + List result = new ArrayList<>(); + + for (Object item : new ArrayLike(maybeArray)) { + 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 e1d656b..dba6138 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 @@ -7,87 +7,84 @@ import java.util.function.BiFunction; public class MathExpression implements PreEvaluatedArgumentsExpression { - public static final MathExpression ADD = new MathExpression("+", Double::sum); - public static final MathExpression SUBTRACT = new MathExpression("-", (a, b) -> a - b, 2); - public static final MathExpression MULTIPLY = new MathExpression("*", (a, b) -> a * b); - public static final MathExpression DIVIDE = new MathExpression("/", (a, b) -> a / b, 2); - public static final MathExpression MODULO = new MathExpression("%", (a, b) -> a % b, 2); - public static final MathExpression MIN = new MathExpression("min", Math::min); - public static final MathExpression MAX = new MathExpression("max", Math::max); - - private final String key; - private final BiFunction reducer; - private final int maxArguments; - - public MathExpression(String key, BiFunction reducer) { - this(key, reducer, 0); - } - - public MathExpression(String key, BiFunction reducer, int maxArguments) { - this.key = key; - this.reducer = reducer; - this.maxArguments = maxArguments; - } - - @Override - public String key() { - return key; - } - - @Override - public Object evaluate(List arguments, Object data, String jsonPath) throws JsonLogicEvaluationException { - if (arguments.isEmpty()) { - return null; + public static final MathExpression ADD = new MathExpression("+", Double::sum); + public static final MathExpression SUBTRACT = new MathExpression("-", (a, b) -> a - b, 2); + public static final MathExpression MULTIPLY = new MathExpression("*", (a, b) -> a * b); + public static final MathExpression DIVIDE = new MathExpression("/", (a, b) -> a / b, 2); + public static final MathExpression MODULO = new MathExpression("%", (a, b) -> a % b, 2); + public static final MathExpression MIN = new MathExpression("min", Math::min); + public static final MathExpression MAX = new MathExpression("max", Math::max); + + private final String key; + private final BiFunction reducer; + private final int maxArguments; + + public MathExpression(String key, BiFunction reducer) { + this(key, reducer, 0); } - // Collect all of the arguments - double[] values = new double[arguments.size()]; + public MathExpression(String key, BiFunction reducer, int maxArguments) { + this.key = key; + this.reducer = reducer; + this.maxArguments = maxArguments; + } - for (int i = 0; i < arguments.size(); i++) { - Object value = arguments.get(i); + @Override + public String key() { + return key; + } - if (key.equals("*") || key.equals("+")) { - while (ArrayLike.isEligible(value)) { - ArrayLike array = new ArrayLike(value); - if (array.isEmpty()) { - break; - } - value = array.get(0); - } - } - if (value instanceof String) { - try { - values[i] = Double.parseDouble((String) value); + @Override + public Object evaluate(List arguments, Object data, String jsonPath) throws JsonLogicEvaluationException { + if (arguments.isEmpty()) { + return null; } - catch (NumberFormatException e) { - 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)) { + ArrayLike array = new ArrayLike(value); + if (array.isEmpty()) { + break; + } + value = array.get(0); + } + } + if (value instanceof String) { + try { + values[i] = Double.parseDouble((String) value); + } catch (NumberFormatException e) { + return null; + } + } else if (!(value instanceof Number)) { + return null; + } else { + values[i] = ((Number) value).doubleValue(); + } } - } - else if (!(value instanceof Number)) { - return null; - } - else { - values[i] = ((Number) value).doubleValue(); - } - } - if (values.length == 1) { - if (key.equals("-")) { - return -values[0]; - } + if (values.length == 1) { + if (key.equals("-")) { + return -values[0]; + } - if (key.equals("/")) { - return null; - } - } + if (key.equals("/")) { + return null; + } + } - // Reduce the values into a single result - double accumulator = values[0]; + // Reduce the values into a single result + double accumulator = values[0]; - for (int i = 1; i < values.length && (i < maxArguments || maxArguments == 0); i++) { - accumulator = reducer.apply(accumulator, values[i]); - } + for (int i = 1; i < values.length && (i < maxArguments || maxArguments == 0); i++) { + accumulator = reducer.apply(accumulator, values[i]); + } - return accumulator; - } + return accumulator; + } } 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 a07d005..488017b 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 @@ -6,26 +6,25 @@ import java.util.Collection; import java.util.Collections; import java.util.List; -import java.util.function.Function; import java.util.stream.Collectors; public class MergeExpression implements PreEvaluatedArgumentsExpression { - public static final MergeExpression INSTANCE = new MergeExpression(); + public static final MergeExpression INSTANCE = new MergeExpression(); - private MergeExpression() { - // Use INSTANCE instead. - } + private MergeExpression() { + // Use INSTANCE instead. + } - @Override - public String key() { - return "merge"; - } + @Override + public String key() { + return "merge"; + } - @Override - 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)) - .flatMap(Collection::stream) - .collect(Collectors.toList()); - } + @Override + 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)) + .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 a03a616..da626ee 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 @@ -4,79 +4,84 @@ import io.github.jamsesso.jsonlogic.utils.ArrayLike; import io.github.jamsesso.jsonlogic.utils.MapLike; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; public class MissingExpression implements PreEvaluatedArgumentsExpression { - public static final MissingExpression ALL = new MissingExpression(false); - public static final MissingExpression SOME = new MissingExpression(true); + public static final MissingExpression ALL = new MissingExpression(false); + public static final MissingExpression SOME = new MissingExpression(true); - private final boolean isSome; + private final boolean isSome; - private MissingExpression(boolean isSome) { - this.isSome = isSome; - } - - @Override - public String key() { - return isSome ? "missing_some" : "missing"; - } + private MissingExpression(boolean isSome) { + this.isSome = isSome; + } - @Override - 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", jsonPath); + @Override + public String key() { + return isSome ? "missing_some" : "missing"; } - if (!MapLike.isEligible(data)) { - if (isSome) { - if (((Double) arguments.get(0)).intValue() <= 0) { - return Collections.EMPTY_LIST; + @Override + 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", + jsonPath); } - return arguments.get(1); - } - return arguments; - } - Map map = new MapLike(data); - List options = isSome ? new ArrayLike(arguments.get(1)) : arguments; - Set providedKeys = getFlatKeys(map); - Set requiredKeys = new LinkedHashSet(options); + if (!MapLike.isEligible(data)) { + if (isSome) { + if (((Double) arguments.get(0)).intValue() <= 0) { + return Collections.EMPTY_LIST; + } + return arguments.get(1); + } + return arguments; + } + + Map map = new MapLike(data); + List options = isSome ? new ArrayLike(arguments.get(1)) : arguments; + Set providedKeys = getFlatKeys(map); + Set requiredKeys = new LinkedHashSet(options); + + requiredKeys.removeAll(providedKeys); // Keys that I need but do not have - requiredKeys.removeAll(providedKeys); // Keys that I need but do not have + if (isSome && options.size() - requiredKeys.size() >= ((Double) arguments.get(0)).intValue()) { + return Collections.EMPTY_LIST; + } - if (isSome && options.size() - requiredKeys.size() >= ((Double) arguments.get(0)).intValue()) { - return Collections.EMPTY_LIST; + return new ArrayList<>(requiredKeys); } - return new ArrayList<>(requiredKeys); - } - - /** - * Given a map structure such as: - * {a: {b: 1}, c: 2} - * - * This method will return the following set: - * ["a.b", "c"] - */ - private static Set getFlatKeys(Map map) { - return getFlatKeys(map, ""); - } - - private static Set getFlatKeys(Map map, String prefix) { - Set keys = new LinkedHashSet(); - - for (Object pair : map.entrySet()) { - Map.Entry entry = (Map.Entry) pair; - - if (MapLike.isEligible(entry.getValue())) { - keys.addAll(getFlatKeys(new MapLike(entry.getValue()), prefix + entry.getKey() + ".")); - } - else { - keys.add(prefix + entry.getKey()); - } + /** + * Given a map structure such as: {a: {b: 1}, c: 2} + *

+ * This method will return the following set: ["a.b", "c"] + */ + private static Set getFlatKeys(Map map) { + return getFlatKeys(map, ""); } - return keys; - } + private static Set getFlatKeys(Map map, String prefix) { + Set keys = new LinkedHashSet(); + + for (Object pair : map.entrySet()) { + Map.Entry entry = (Map.Entry) pair; + + if (MapLike.isEligible(entry.getValue())) { + keys.addAll(getFlatKeys(new MapLike(entry.getValue()), prefix + entry.getKey() + ".")); + } else { + keys.add(prefix + entry.getKey()); + } + } + + return keys; + } } 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 e653129..0c289ec 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 @@ -5,35 +5,34 @@ import java.util.List; public class NotExpression implements PreEvaluatedArgumentsExpression { - public static final NotExpression SINGLE = new NotExpression(false); - public static final NotExpression DOUBLE = new NotExpression(true); + public static final NotExpression SINGLE = new NotExpression(false); + public static final NotExpression DOUBLE = new NotExpression(true); - private final boolean isDoubleBang; + private final boolean isDoubleBang; - private NotExpression(boolean isDoubleBang) { - this.isDoubleBang = isDoubleBang; - } + private NotExpression(boolean isDoubleBang) { + this.isDoubleBang = isDoubleBang; + } - @Override - public String key() { - return isDoubleBang ? "!!" : "!"; - } + @Override + public String key() { + return isDoubleBang ? "!!" : "!"; + } - @Override - public Object evaluate(List arguments, Object data, String jsonPath) { - boolean result; + @Override + public Object evaluate(List arguments, Object data, String jsonPath) { + boolean result; - if (arguments.isEmpty()) { - result = false; - } - else { - result = JsonLogic.truthy(arguments.get(0)); - } + if (arguments.isEmpty()) { + result = false; + } else { + result = JsonLogic.truthy(arguments.get(0)); + } - if (isDoubleBang) { - return result; - } + if (isDoubleBang) { + return result; + } - return !result; - } + return !result; + } } 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 98c98a4..3ba75b7 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 @@ -5,88 +5,86 @@ import java.util.List; public class NumericComparisonExpression implements PreEvaluatedArgumentsExpression { - public static final NumericComparisonExpression GT = new NumericComparisonExpression(">"); - public static final NumericComparisonExpression GTE = new NumericComparisonExpression(">="); - public static final NumericComparisonExpression LT = new NumericComparisonExpression("<"); - public static final NumericComparisonExpression LTE = new NumericComparisonExpression("<="); + public static final NumericComparisonExpression GT = new NumericComparisonExpression(">"); + public static final NumericComparisonExpression GTE = new NumericComparisonExpression(">="); + public static final NumericComparisonExpression LT = new NumericComparisonExpression("<"); + public static final NumericComparisonExpression LTE = new NumericComparisonExpression("<="); - private final String key; + private final String key; - private NumericComparisonExpression(String key) { - this.key = key; - } - - @Override - public String key() { - return key; - } - - @Override - 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", jsonPath); + private NumericComparisonExpression(String key) { + this.key = key; } - double[] values = new double[n]; + @Override + public String key() { + return key; + } - for (int i = 0; i < n; i++) { - Object value = arguments.get(i); + @Override + public Object evaluate(List arguments, Object data, String jsonPath) throws JsonLogicEvaluationException { + // Convert the arguments to doubles + int n = Math.min(arguments.size(), 3); - if (value instanceof String) { - try { - values[i] = Double.parseDouble((String) value); + if (n < 2) { + throw new JsonLogicEvaluationException("'" + key + "' requires at least 2 arguments", jsonPath); } - catch (NumberFormatException e) { - return false; + + double[] values = new double[n]; + + for (int i = 0; i < n; i++) { + Object value = arguments.get(i); + + if (value instanceof String) { + try { + values[i] = Double.parseDouble((String) value); + } catch (NumberFormatException e) { + return false; + } + } else if (!(value instanceof Number)) { + return false; + } else { + values[i] = ((Number) value).doubleValue(); + } } - } - else if (!(value instanceof Number)) { - return false; - } - else { - values[i] = ((Number) value).doubleValue(); - } - } - // Handle between comparisons - if (arguments.size() >= 3) { - switch (key) { - case "<": - return values[0] < values[1] && values[1] < values[2]; + // Handle between comparisons + if (arguments.size() >= 3) { + switch (key) { + 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]; - 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]; + case ">=": + return values[0] >= values[1] && values[1] >= values[2]; - default: - throw new JsonLogicEvaluationException("'" + key + "' does not support between comparisons", jsonPath); - } - } + default: + throw new JsonLogicEvaluationException("'" + key + "' does not support between comparisons", + jsonPath); + } + } - // Handle regular comparisons - switch (key) { - case "<": - return values[0] < values[1]; + // Handle regular comparisons + switch (key) { + case "<": + return values[0] < values[1]; - case "<=": - return values[0] <= values[1]; + case "<=": + return values[0] <= values[1]; - case ">": - return values[0] > values[1]; + case ">": + return values[0] > values[1]; - case ">=": - return values[0] >= values[1]; + case ">=": + return values[0] >= values[1]; - default: - throw new JsonLogicEvaluationException("'" + key + "' is not a comparison expression", jsonPath); + default: + 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 26adfe4..4da752e 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 @@ -1,25 +1,25 @@ package io.github.jamsesso.jsonlogic.evaluator.expressions; -import io.github.jamsesso.jsonlogic.utils.ArrayLike; import io.github.jamsesso.jsonlogic.ast.JsonLogicArray; import io.github.jamsesso.jsonlogic.evaluator.JsonLogicEvaluationException; import io.github.jamsesso.jsonlogic.evaluator.JsonLogicEvaluator; import io.github.jamsesso.jsonlogic.evaluator.JsonLogicExpression; +import io.github.jamsesso.jsonlogic.utils.ArrayLike; import java.util.List; public interface PreEvaluatedArgumentsExpression extends JsonLogicExpression { - Object evaluate(List arguments, Object data, String jsonPath) throws JsonLogicEvaluationException; + Object evaluate(List arguments, Object data, String jsonPath) throws JsonLogicEvaluationException; - @Override - default Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data, String jsonPath) - throws JsonLogicEvaluationException { - List values = evaluator.evaluate(arguments, data, jsonPath); + @Override + default Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data, String jsonPath) + throws JsonLogicEvaluationException { + List values = evaluator.evaluate(arguments, data, jsonPath); - if (values.size() == 1 && ArrayLike.isEligible(values.get(0))) { - values = new ArrayLike(values.get(0)); - } + if (values.size() == 1 && ArrayLike.isEligible(values.get(0))) { + values = new ArrayLike(values.get(0)); + } - return evaluate(values, data, jsonPath); - } + 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 35bb882..40ffeab 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 @@ -1,48 +1,48 @@ package io.github.jamsesso.jsonlogic.evaluator.expressions; -import io.github.jamsesso.jsonlogic.utils.ArrayLike; import io.github.jamsesso.jsonlogic.ast.JsonLogicArray; import io.github.jamsesso.jsonlogic.evaluator.JsonLogicEvaluationException; import io.github.jamsesso.jsonlogic.evaluator.JsonLogicEvaluator; import io.github.jamsesso.jsonlogic.evaluator.JsonLogicExpression; +import io.github.jamsesso.jsonlogic.utils.ArrayLike; import java.util.HashMap; import java.util.Map; public class ReduceExpression implements JsonLogicExpression { - public static final ReduceExpression INSTANCE = new ReduceExpression(); - - private ReduceExpression() { - // Use INSTANCE instead. - } - - @Override - public String key() { - return "reduce"; - } - - @Override - 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", jsonPath); - } + public static final ReduceExpression INSTANCE = new ReduceExpression(); - Object maybeArray = evaluator.evaluate(arguments.get(0), data, jsonPath + "[0]"); - Object accumulator = evaluator.evaluate(arguments.get(2), data, jsonPath + "[2]"); + private ReduceExpression() { + // Use INSTANCE instead. + } - if (!ArrayLike.isEligible(maybeArray)) { - return accumulator; + @Override + public String key() { + return "reduce"; } - Map context = new HashMap<>(); - context.put("accumulator", accumulator); + @Override + 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", jsonPath); + } - for (Object item : new ArrayLike(maybeArray)) { - context.put("current", item); - context.put("accumulator", evaluator.evaluate(arguments.get(1), context, jsonPath + "[1]")); - } + Object maybeArray = evaluator.evaluate(arguments.get(0), data, jsonPath + "[0]"); + Object accumulator = evaluator.evaluate(arguments.get(2), data, jsonPath + "[2]"); - return context.get("accumulator"); - } + if (!ArrayLike.isEligible(maybeArray)) { + return accumulator; + } + + Map context = new HashMap<>(); + context.put("accumulator", accumulator); + + for (Object item : new ArrayLike(maybeArray)) { + context.put("current", item); + 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 8cbfc04..113f064 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 @@ -5,34 +5,34 @@ import java.util.List; public class StrictEqualityExpression implements PreEvaluatedArgumentsExpression { - public static final StrictEqualityExpression INSTANCE = new StrictEqualityExpression(); + public static final StrictEqualityExpression INSTANCE = new StrictEqualityExpression(); - private StrictEqualityExpression() { - // Only one instance can be constructed. Use StrictEqualityExpression.INSTANCE - } - - @Override - public String key() { - return "==="; - } + private StrictEqualityExpression() { + // Only one instance can be constructed. Use StrictEqualityExpression.INSTANCE + } - @Override - public Object evaluate(List arguments, Object data, String jsonPath) throws JsonLogicEvaluationException { - if (arguments.size() != 2) { - throw new JsonLogicEvaluationException("equality expressions expect exactly 2 arguments", jsonPath); + @Override + public String key() { + return "==="; } - Object left = arguments.get(0); - Object right = arguments.get(1); + @Override + public Object evaluate(List arguments, Object data, String jsonPath) throws JsonLogicEvaluationException { + if (arguments.size() != 2) { + throw new JsonLogicEvaluationException("equality expressions expect exactly 2 arguments", jsonPath); + } - if (left instanceof Number && right instanceof Number) { - return ((Number) left).doubleValue() == ((Number) right).doubleValue(); - } + Object left = arguments.get(0); + Object right = arguments.get(1); - if (left == right) { - return true; - } + if (left instanceof Number && right instanceof Number) { + return ((Number) left).doubleValue() == ((Number) right).doubleValue(); + } + + if (left == right) { + return true; + } - return left != null && left.equals(right); - } + return left != null && left.equals(right); + } } 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 68e257c..d42475f 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 @@ -6,25 +6,25 @@ import io.github.jamsesso.jsonlogic.evaluator.JsonLogicExpression; public class StrictInequalityExpression implements JsonLogicExpression { - public static final StrictInequalityExpression INSTANCE = - new StrictInequalityExpression(StrictEqualityExpression.INSTANCE); + public static final StrictInequalityExpression INSTANCE = + new StrictInequalityExpression(StrictEqualityExpression.INSTANCE); - private final StrictEqualityExpression delegate; + private final StrictEqualityExpression delegate; - private StrictInequalityExpression(StrictEqualityExpression delegate) { - this.delegate = delegate; - } + private StrictInequalityExpression(StrictEqualityExpression delegate) { + this.delegate = delegate; + } - @Override - public String key() { - return "!=="; - } + @Override + public String key() { + return "!=="; + } - @Override - public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data, String jsonPath) - throws JsonLogicEvaluationException { - boolean result = (boolean) delegate.evaluate(evaluator, arguments, data, jsonPath); + @Override + public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data, String jsonPath) + throws JsonLogicEvaluationException { + boolean result = (boolean) delegate.evaluate(evaluator, arguments, data, jsonPath); - return !result; - } + 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 6fc8b7b..6a4934c 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 @@ -5,68 +5,66 @@ import java.util.List; public class SubstringExpression implements PreEvaluatedArgumentsExpression { - public static final SubstringExpression INSTANCE = new SubstringExpression(); + public static final SubstringExpression INSTANCE = new SubstringExpression(); - private SubstringExpression() { - // Use INSTANCE instead. - } - - @Override - public String key() { - return "substr"; - } - - @Override - 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", jsonPath); + private SubstringExpression() { + // Use INSTANCE instead. } - if (!(arguments.get(1) instanceof Double)) { - throw new JsonLogicEvaluationException("second argument to substr must be a number", jsonPath + "[1]"); + @Override + public String key() { + return "substr"; } - String value = arguments.get(0).toString(); - int startIndex; - int endIndex; + @Override + 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", jsonPath); + } - if (arguments.size() == 2) { - startIndex = ((Double) arguments.get(1)).intValue(); - endIndex = value.length(); + if (!(arguments.get(1) instanceof Double)) { + throw new JsonLogicEvaluationException("second argument to substr must be a number", jsonPath + "[1]"); + } - if (startIndex < 0) { - startIndex = endIndex + startIndex; - } + String value = arguments.get(0).toString(); + int startIndex; + int endIndex; - if (startIndex < 0) { - return ""; - } - } - else { - if (!(arguments.get(2) instanceof Double)) { - throw new JsonLogicEvaluationException("third argument to substr must be an integer", jsonPath + "[2]"); - } + if (arguments.size() == 2) { + startIndex = ((Double) arguments.get(1)).intValue(); + endIndex = value.length(); - startIndex = ((Double) arguments.get(1)).intValue(); + if (startIndex < 0) { + startIndex = endIndex + startIndex; + } - if (startIndex < 0) { - startIndex = value.length() + startIndex; - } + if (startIndex < 0) { + return ""; + } + } else { + if (!(arguments.get(2) instanceof Double)) { + throw new JsonLogicEvaluationException("third argument to substr must be an integer", jsonPath + "[2]"); + } - endIndex = ((Double) arguments.get(2)).intValue(); + startIndex = ((Double) arguments.get(1)).intValue(); - if (endIndex < 0) { - endIndex = value.length() + endIndex; - } - else { - endIndex += startIndex; - } + if (startIndex < 0) { + startIndex = value.length() + startIndex; + } - if (startIndex > endIndex || endIndex > value.length()) { - return ""; - } - } + endIndex = ((Double) arguments.get(2)).intValue(); - return value.substring(startIndex, endIndex); - } + if (endIndex < 0) { + endIndex = value.length() + endIndex; + } else { + endIndex += startIndex; + } + + if (startIndex > endIndex || endIndex > value.length()) { + return ""; + } + } + + return value.substring(startIndex, endIndex); + } } diff --git a/src/main/java/io/github/jamsesso/jsonlogic/utils/ArrayLike.java b/src/main/java/io/github/jamsesso/jsonlogic/utils/ArrayLike.java index a980431..2baeae7 100644 --- a/src/main/java/io/github/jamsesso/jsonlogic/utils/ArrayLike.java +++ b/src/main/java/io/github/jamsesso/jsonlogic/utils/ArrayLike.java @@ -4,193 +4,203 @@ import io.github.jamsesso.jsonlogic.evaluator.JsonLogicEvaluator; import java.lang.reflect.Array; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Objects; import java.util.stream.Collectors; public class ArrayLike implements List { - private final List delegate; - - @SuppressWarnings("unchecked") - public ArrayLike(Object data) { - if (data instanceof List) { - delegate = ((List) data) - .stream() - .map(JsonLogicEvaluator::transform) - .collect(Collectors.toList()); - } - else if (data != null && data.getClass().isArray()) { - delegate = new ArrayList<>(); - - for (int i = 0; i < Array.getLength(data); i++) { - delegate.add(i, JsonLogicEvaluator.transform(Array.get(data, i))); - } - } - else if (data instanceof JsonArray) { - delegate = (List) JsonValueExtractor.extract((JsonArray) data); - } - else if (data instanceof Iterable) { - delegate = new ArrayList<>(); - - for (Object item : (Iterable) data) { - delegate.add(JsonLogicEvaluator.transform(item)); - } - } - else { - throw new IllegalArgumentException("ArrayLike only works with lists, iterables, arrays, or JsonArray"); - } - } - - @Override - public int size() { - return delegate.size(); - } - - @Override - public boolean isEmpty() { - return delegate.isEmpty(); - } - - @Override - public boolean contains(Object o) { - return delegate.contains(o); - } - - @Override - public Iterator iterator() { - return delegate.iterator(); - } - - @Override - public Object[] toArray() { - return delegate.toArray(); - } - - @Override - public T[] toArray(T[] a) { - return delegate.toArray(a); - } - - @Override - public boolean add(Object o) { - throw new UnsupportedOperationException("ArrayLike is immutable"); - } - - @Override - public boolean remove(Object o) { - throw new UnsupportedOperationException("ArrayLike is immutable"); - } - - @Override - public boolean containsAll(Collection c) { - return delegate.containsAll(c); - } - - @Override - public boolean addAll(Collection c) { - throw new UnsupportedOperationException("ArrayLike is immutable"); - } - - @Override - public boolean addAll(int index, Collection c) { - throw new UnsupportedOperationException("ArrayLike is immutable"); - } - - @Override - public boolean removeAll(Collection c) { - throw new UnsupportedOperationException("ArrayLike is immutable"); - } - - @Override - public boolean retainAll(Collection c) { - throw new UnsupportedOperationException("ArrayLike is immutable"); - } - - @Override - public void clear() { - throw new UnsupportedOperationException("ArrayLike is immutable"); - } - - @Override - public Object get(int index) { - return delegate.get(index); - } - - @Override - public Object set(int index, Object element) { - throw new UnsupportedOperationException("ArrayLike is immutable"); - } - - @Override - public void add(int index, Object element) { - throw new UnsupportedOperationException("ArrayLike is immutable"); - } - - @Override - public Object remove(int index) { - throw new UnsupportedOperationException("ArrayLike is immutable"); - } - - @Override - public int indexOf(Object o) { - return delegate.indexOf(o); - } - - @Override - public int lastIndexOf(Object o) { - return delegate.lastIndexOf(o); - } - - @Override - public ListIterator listIterator() { - return delegate.listIterator(); - } - - @Override - public ListIterator listIterator(int index) { - return delegate.listIterator(index); - } - - @Override - public List subList(int fromIndex, int toIndex) { - return delegate.subList(fromIndex, toIndex); - } - - @Override - public String toString() { - return Arrays.toString(delegate.toArray()); - } - - @Override - public boolean equals(Object other) { - if (this == other) { - return true; - } - - if (other instanceof Iterable) { - int i = 0; - - for (Object item : (Iterable) other) { - if (i >= delegate.size()) { - return false; + private final List delegate; + + @SuppressWarnings("unchecked") + public ArrayLike(Object data) { + if (data instanceof List) { + delegate = ((List) data) + .stream() + .map(JsonLogicEvaluator::transform) + .collect(Collectors.toList()); + } else if (data != null && data.getClass().isArray()) { + delegate = new ArrayList<>(); + + for (int i = 0; i < Array.getLength(data); i++) { + delegate.add(i, JsonLogicEvaluator.transform(Array.get(data, i))); + } + } else if (data instanceof JsonArray) { + delegate = (List) JsonValueExtractor.extract((JsonArray) data); + } else if (data instanceof Iterable) { + delegate = new ArrayList<>(); + + for (Object item : (Iterable) data) { + delegate.add(JsonLogicEvaluator.transform(item)); + } + } else { + throw new IllegalArgumentException("ArrayLike only works with lists, iterables, arrays, or JsonArray"); } - else if (!Objects.equals(item, delegate.get(i))) { - return false; + } + + @Override + public int size() { + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public boolean contains(Object o) { + return delegate.contains(o); + } + + @Override + public Iterator iterator() { + return delegate.iterator(); + } + + @Override + public Object[] toArray() { + return delegate.toArray(); + } + + @Override + public T[] toArray(T[] a) { + return delegate.toArray(a); + } + + @Override + public boolean add(Object o) { + throw new UnsupportedOperationException("ArrayLike is immutable"); + } + + @Override + public boolean remove(Object o) { + throw new UnsupportedOperationException("ArrayLike is immutable"); + } + + @Override + public boolean containsAll(Collection c) { + return delegate.containsAll(c); + } + + @Override + public boolean addAll(Collection c) { + throw new UnsupportedOperationException("ArrayLike is immutable"); + } + + @Override + public boolean addAll(int index, Collection c) { + throw new UnsupportedOperationException("ArrayLike is immutable"); + } + + @Override + public boolean removeAll(Collection c) { + throw new UnsupportedOperationException("ArrayLike is immutable"); + } + + @Override + public boolean retainAll(Collection c) { + throw new UnsupportedOperationException("ArrayLike is immutable"); + } + + @Override + public void clear() { + throw new UnsupportedOperationException("ArrayLike is immutable"); + } + + @Override + public Object get(int index) { + return delegate.get(index); + } + + @Override + public Object set(int index, Object element) { + throw new UnsupportedOperationException("ArrayLike is immutable"); + } + + @Override + public void add(int index, Object element) { + throw new UnsupportedOperationException("ArrayLike is immutable"); + } + + @Override + public Object remove(int index) { + throw new UnsupportedOperationException("ArrayLike is immutable"); + } + + @Override + public int indexOf(Object o) { + return delegate.indexOf(o); + } + + @Override + public int lastIndexOf(Object o) { + return delegate.lastIndexOf(o); + } + + @Override + public ListIterator listIterator() { + return delegate.listIterator(); + } + + @Override + public ListIterator listIterator(int index) { + return delegate.listIterator(index); + } + + @Override + public List subList(int fromIndex, int toIndex) { + return delegate.subList(fromIndex, toIndex); + } + + @Override + public String toString() { + return Arrays.toString(delegate.toArray()); + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; } - i++; - } + if (other instanceof Iterable) { + int i = 0; - if (i != delegate.size()) { - return false; - } + for (Object item : (Iterable) other) { + if (i >= delegate.size()) { + return false; + } else if (!Objects.equals(item, delegate.get(i))) { + return false; + } + + i++; + } - return false; + if (i != delegate.size()) { + return false; + } + + return false; + } + + return false; } - return false; - } + @Override + public int hashCode() { + int hash = 1; + for (Object e : delegate) { + hash = 31 * hash + (e == null ? 0 : e.hashCode()); + } + return hash; + } - public static boolean isEligible(Object data) { - return data != null && (data instanceof Iterable || data.getClass().isArray()); - } + public static boolean isEligible(Object data) { + return data != null && (data instanceof Iterable || data.getClass().isArray()); + } } diff --git a/src/main/java/io/github/jamsesso/jsonlogic/utils/JsonValueExtractor.java b/src/main/java/io/github/jamsesso/jsonlogic/utils/JsonValueExtractor.java index d85e129..062a871 100644 --- a/src/main/java/io/github/jamsesso/jsonlogic/utils/JsonValueExtractor.java +++ b/src/main/java/io/github/jamsesso/jsonlogic/utils/JsonValueExtractor.java @@ -10,45 +10,41 @@ import java.util.Map; public final class JsonValueExtractor { - private JsonValueExtractor() { } - - public static Object extract(JsonElement element) { - if (element.isJsonObject()) { - Map map = new HashMap<>(); - JsonObject object = element.getAsJsonObject(); - - for (String key : object.keySet()) { - map.put(key, extract(object.get(key))); - } - - return map; + private JsonValueExtractor() { } - else if (element.isJsonArray()) { - List values = new ArrayList<>(); - - for (JsonElement item : element.getAsJsonArray()) { - values.add(extract(item)); - } - return values; + public static Object extract(JsonElement element) { + if (element.isJsonObject()) { + Map map = new HashMap<>(); + JsonObject object = element.getAsJsonObject(); + + for (String key : object.keySet()) { + map.put(key, extract(object.get(key))); + } + + return map; + } else if (element.isJsonArray()) { + List values = new ArrayList<>(); + + for (JsonElement item : element.getAsJsonArray()) { + values.add(extract(item)); + } + + return values; + } else if (element.isJsonNull()) { + return null; + } else if (element.isJsonPrimitive()) { + JsonPrimitive primitive = element.getAsJsonPrimitive(); + + if (primitive.isBoolean()) { + return primitive.getAsBoolean(); + } else if (primitive.isNumber()) { + return primitive.getAsNumber().doubleValue(); + } else { + return primitive.getAsString(); + } + } + + return element.toString(); } - else if (element.isJsonNull()) { - return null; - } - else if (element.isJsonPrimitive()) { - JsonPrimitive primitive = element.getAsJsonPrimitive(); - - if (primitive.isBoolean()) { - return primitive.getAsBoolean(); - } - else if (primitive.isNumber()) { - return primitive.getAsNumber().doubleValue(); - } - else { - return primitive.getAsString(); - } - } - - return element.toString(); - } } diff --git a/src/main/java/io/github/jamsesso/jsonlogic/utils/MapLike.java b/src/main/java/io/github/jamsesso/jsonlogic/utils/MapLike.java index 02ffe2f..60aebee 100644 --- a/src/main/java/io/github/jamsesso/jsonlogic/utils/MapLike.java +++ b/src/main/java/io/github/jamsesso/jsonlogic/utils/MapLike.java @@ -7,82 +7,80 @@ import java.util.Set; public class MapLike implements Map { - private final Map delegate; + private final Map delegate; + + @SuppressWarnings("unchecked") + public MapLike(Object data) { + if (data instanceof Map) { + delegate = (Map) data; + } else if (data instanceof JsonObject) { + delegate = (Map) JsonValueExtractor.extract((JsonObject) data); + } else { + throw new IllegalArgumentException("MapLike only works with maps and JsonObject"); + } + } + + @Override + public int size() { + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public boolean containsKey(Object key) { + return delegate.containsKey(key); + } + + @Override + public boolean containsValue(Object value) { + return delegate.containsKey(value); + } - @SuppressWarnings("unchecked") - public MapLike(Object data) { - if (data instanceof Map) { - delegate = (Map) data; + @Override + public Object get(Object key) { + return delegate.get(key); } - else if (data instanceof JsonObject) { - delegate = (Map) JsonValueExtractor.extract((JsonObject) data); + + @Override + public Object put(Object key, Object value) { + throw new UnsupportedOperationException("MapLike is immutable"); + } + + @Override + public Object remove(Object key) { + throw new UnsupportedOperationException("MapLike is immutable"); } - else { - throw new IllegalArgumentException("MapLike only works with maps and JsonObject"); + + @Override + public void putAll(Map m) { + throw new UnsupportedOperationException("MapLike is immutable"); + } + + @Override + public void clear() { + throw new UnsupportedOperationException("MapLike is immutable"); + } + + @Override + public Set keySet() { + return delegate.keySet(); + } + + @Override + public Collection values() { + return delegate.values(); + } + + @Override + public Set> entrySet() { + return delegate.entrySet(); + } + + public static boolean isEligible(Object data) { + return data instanceof Map || data instanceof JsonObject; } - } - - @Override - public int size() { - return delegate.size(); - } - - @Override - public boolean isEmpty() { - return delegate.isEmpty(); - } - - @Override - public boolean containsKey(Object key) { - return delegate.containsKey(key); - } - - @Override - public boolean containsValue(Object value) { - return delegate.containsKey(value); - } - - @Override - public Object get(Object key) { - return delegate.get(key); - } - - @Override - public Object put(Object key, Object value) { - throw new UnsupportedOperationException("MapLike is immutable"); - } - - @Override - public Object remove(Object key) { - throw new UnsupportedOperationException("MapLike is immutable"); - } - - @Override - public void putAll(Map m) { - throw new UnsupportedOperationException("MapLike is immutable"); - } - - @Override - public void clear() { - throw new UnsupportedOperationException("MapLike is immutable"); - } - - @Override - public Set keySet() { - return delegate.keySet(); - } - - @Override - public Collection values() { - return delegate.values(); - } - - @Override - public Set> entrySet() { - return delegate.entrySet(); - } - - public static boolean isEligible(Object data) { - return data instanceof Map || data instanceof JsonObject; - } } diff --git a/src/test/java/io/github/jamsesso/jsonlogic/AllExpressionTests.java b/src/test/java/io/github/jamsesso/jsonlogic/AllExpressionTests.java index b264d5b..eaaf547 100644 --- a/src/test/java/io/github/jamsesso/jsonlogic/AllExpressionTests.java +++ b/src/test/java/io/github/jamsesso/jsonlogic/AllExpressionTests.java @@ -5,16 +5,16 @@ import static org.junit.Assert.assertEquals; public class AllExpressionTests { - private static final JsonLogic jsonLogic = new JsonLogic(); + private static final JsonLogic jsonLogic = new JsonLogic(); - @Test - public void testEmptyArray() throws JsonLogicException { - assertEquals(false, jsonLogic.apply("{\"all\": [[], {\">\": [{\"var\": \"\"}, 0]}]}", null)); - } + @Test + public void testEmptyArray() throws JsonLogicException { + assertEquals(false, jsonLogic.apply("{\"all\": [[], {\">\": [{\"var\": \"\"}, 0]}]}", null)); + } - @Test - public void testAll() throws JsonLogicException { - assertEquals(true, jsonLogic.apply("{\"all\": [[1, 2, 3], {\">\": [{\"var\": \"\"}, 0]}]}", null)); - assertEquals(false, jsonLogic.apply("{\"all\": [[1, 2, 3], {\">\": [{\"var\": \"\"}, 1]}]}", null)); - } + @Test + public void testAll() throws JsonLogicException { + assertEquals(true, jsonLogic.apply("{\"all\": [[1, 2, 3], {\">\": [{\"var\": \"\"}, 0]}]}", null)); + assertEquals(false, jsonLogic.apply("{\"all\": [[1, 2, 3], {\">\": [{\"var\": \"\"}, 1]}]}", null)); + } } diff --git a/src/test/java/io/github/jamsesso/jsonlogic/ArrayHasExpressionTests.java b/src/test/java/io/github/jamsesso/jsonlogic/ArrayHasExpressionTests.java index 26f815e..5f68447 100644 --- a/src/test/java/io/github/jamsesso/jsonlogic/ArrayHasExpressionTests.java +++ b/src/test/java/io/github/jamsesso/jsonlogic/ArrayHasExpressionTests.java @@ -5,37 +5,41 @@ import static org.junit.Assert.assertEquals; public class ArrayHasExpressionTests { - private static final JsonLogic jsonLogic = new JsonLogic(); - - @Test - public void testSomeWithNull() throws JsonLogicException { - assertEquals(false, jsonLogic.apply("{\"and\":[{\"some\":[{\"var\":\"fruits\"},{\"in\":[{\"var\":\"\"},[\"apple\"]]}]}]}", "{\"fruits\":null}")); - } - - @Test - public void testSomeEmptyArray() throws JsonLogicException { - assertEquals(false, jsonLogic.apply("{\"some\": [[], {\">\": [{\"var\": \"\"}, 0]}]}", null)); - } - - @Test - public void testSomeAll() throws JsonLogicException { - assertEquals(false, jsonLogic.apply("{\"some\": [[1, 2, 3], {\">\": [{\"var\": \"\"}, 3]}]}", null)); - assertEquals(true, jsonLogic.apply("{\"some\": [[1, 2, 3], {\">\": [{\"var\": \"\"}, 1]}]}", null)); - } - - @Test - public void testNoneWithNull() throws JsonLogicException { - assertEquals(true, jsonLogic.apply("{\"and\":[{\"none\":[{\"var\":\"fruits\"},{\"in\":[{\"var\":\"\"},[\"apple\"]]}]}]}", "{\"fruits\":null}")); - } - - @Test - public void testNoneEmptyArray() throws JsonLogicException { - assertEquals(false, jsonLogic.apply("{\"some\": [[], {\">\": [{\"var\": \"\"}, 0]}]}", null)); - } - - @Test - public void testNoneAll() throws JsonLogicException { - assertEquals(true, jsonLogic.apply("{\"none\": [[1, 2, 3], {\">\": [{\"var\": \"\"}, 3]}]}", null)); - assertEquals(false, jsonLogic.apply("{\"none\": [[1, 2, 3], {\">\": [{\"var\": \"\"}, 2]}]}", null)); - } -} \ No newline at end of file + private static final JsonLogic jsonLogic = new JsonLogic(); + + @Test + public void testSomeWithNull() throws JsonLogicException { + assertEquals(false, + jsonLogic.apply("{\"and\":[{\"some\":[{\"var\":\"fruits\"},{\"in\":[{\"var\":\"\"},[\"apple\"]]}]}]}", + "{\"fruits\":null}")); + } + + @Test + public void testSomeEmptyArray() throws JsonLogicException { + assertEquals(false, jsonLogic.apply("{\"some\": [[], {\">\": [{\"var\": \"\"}, 0]}]}", null)); + } + + @Test + public void testSomeAll() throws JsonLogicException { + assertEquals(false, jsonLogic.apply("{\"some\": [[1, 2, 3], {\">\": [{\"var\": \"\"}, 3]}]}", null)); + assertEquals(true, jsonLogic.apply("{\"some\": [[1, 2, 3], {\">\": [{\"var\": \"\"}, 1]}]}", null)); + } + + @Test + public void testNoneWithNull() throws JsonLogicException { + assertEquals(true, + jsonLogic.apply("{\"and\":[{\"none\":[{\"var\":\"fruits\"},{\"in\":[{\"var\":\"\"},[\"apple\"]]}]}]}", + "{\"fruits\":null}")); + } + + @Test + public void testNoneEmptyArray() throws JsonLogicException { + assertEquals(false, jsonLogic.apply("{\"some\": [[], {\">\": [{\"var\": \"\"}, 0]}]}", null)); + } + + @Test + public void testNoneAll() throws JsonLogicException { + assertEquals(true, jsonLogic.apply("{\"none\": [[1, 2, 3], {\">\": [{\"var\": \"\"}, 3]}]}", null)); + assertEquals(false, jsonLogic.apply("{\"none\": [[1, 2, 3], {\">\": [{\"var\": \"\"}, 2]}]}", null)); + } +} diff --git a/src/test/java/io/github/jamsesso/jsonlogic/ConcatenateExpressionTests.java b/src/test/java/io/github/jamsesso/jsonlogic/ConcatenateExpressionTests.java index f1005cb..e1e65c3 100644 --- a/src/test/java/io/github/jamsesso/jsonlogic/ConcatenateExpressionTests.java +++ b/src/test/java/io/github/jamsesso/jsonlogic/ConcatenateExpressionTests.java @@ -5,11 +5,11 @@ import static org.junit.Assert.assertEquals; public class ConcatenateExpressionTests { - private static final JsonLogic jsonLogic = new JsonLogic(); + private static final JsonLogic jsonLogic = new JsonLogic(); - @Test - public void testCat() throws JsonLogicException { - assertEquals("hello world 2!", jsonLogic.apply("{\"cat\": [\"hello\", \" world \", 2, \"!\"]}", null)); - assertEquals("pi is 3.14159", jsonLogic.apply("{\"cat\": [\"pi is \", 3.14159]}", null)); - } + @Test + public void testCat() throws JsonLogicException { + assertEquals("hello world 2!", jsonLogic.apply("{\"cat\": [\"hello\", \" world \", 2, \"!\"]}", null)); + assertEquals("pi is 3.14159", jsonLogic.apply("{\"cat\": [\"pi is \", 3.14159]}", null)); + } } diff --git a/src/test/java/io/github/jamsesso/jsonlogic/CustomOperationTests.java b/src/test/java/io/github/jamsesso/jsonlogic/CustomOperationTests.java index 6653d66..5248b40 100644 --- a/src/test/java/io/github/jamsesso/jsonlogic/CustomOperationTests.java +++ b/src/test/java/io/github/jamsesso/jsonlogic/CustomOperationTests.java @@ -4,17 +4,17 @@ import org.junit.Test; public class CustomOperationTests { - private static final JsonLogic jsonLogic = new JsonLogic(); + private static final JsonLogic jsonLogic = new JsonLogic(); - @Test - public void testCustomOp() throws JsonLogicException { - jsonLogic.addOperation("greet", args -> String.format("Hello %s!", args[0])); - Assert.assertEquals("Hello json-logic!", jsonLogic.apply("{\"greet\": [\"json-logic\"]}", null)); - } + @Test + public void testCustomOp() throws JsonLogicException { + jsonLogic.addOperation("greet", args -> String.format("Hello %s!", args[0])); + Assert.assertEquals("Hello json-logic!", jsonLogic.apply("{\"greet\": [\"json-logic\"]}", null)); + } - @Test - public void testCustomOpWithUppercaseLetter() throws JsonLogicException { - jsonLogic.addOperation("Greet", args -> String.format("Hello %s!", args[0])); - Assert.assertEquals("Hello json-logic!", jsonLogic.apply("{\"Greet\": [\"json-logic\"]}", null)); - } + @Test + public void testCustomOpWithUppercaseLetter() throws JsonLogicException { + jsonLogic.addOperation("Greet", args -> String.format("Hello %s!", args[0])); + Assert.assertEquals("Hello json-logic!", jsonLogic.apply("{\"Greet\": [\"json-logic\"]}", null)); + } } diff --git a/src/test/java/io/github/jamsesso/jsonlogic/EqualityExpressionTests.java b/src/test/java/io/github/jamsesso/jsonlogic/EqualityExpressionTests.java index 907248f..28329a9 100644 --- a/src/test/java/io/github/jamsesso/jsonlogic/EqualityExpressionTests.java +++ b/src/test/java/io/github/jamsesso/jsonlogic/EqualityExpressionTests.java @@ -5,25 +5,25 @@ import static org.junit.Assert.assertEquals; public class EqualityExpressionTests { - private static final JsonLogic jsonLogic = new JsonLogic(); + private static final JsonLogic jsonLogic = new JsonLogic(); - @Test - public void testSameValueSameType() throws JsonLogicException { - assertEquals(true, jsonLogic.apply("{\"==\": [1, 1]}", null)); - } + @Test + public void testSameValueSameType() throws JsonLogicException { + assertEquals(true, jsonLogic.apply("{\"==\": [1, 1]}", null)); + } - @Test - public void testSameValueDifferentType() throws JsonLogicException { - assertEquals(true, jsonLogic.apply("{\"==\": [1, 1]}", null)); - } + @Test + public void testSameValueDifferentType() throws JsonLogicException { + assertEquals(true, jsonLogic.apply("{\"==\": [1, 1]}", null)); + } - @Test - public void testDifferentValueDifferentType() throws JsonLogicException { - assertEquals(true, jsonLogic.apply("{\"==\": [[], false]}", null)); - } + @Test + public void testDifferentValueDifferentType() throws JsonLogicException { + assertEquals(true, jsonLogic.apply("{\"==\": [[], false]}", null)); + } - @Test - public void testEmptyStringAndZeroComparison() throws JsonLogicException { - assertEquals(true, jsonLogic.apply("{\"==\": [\" \", 0]}", null)); - } + @Test + public void testEmptyStringAndZeroComparison() throws JsonLogicException { + assertEquals(true, jsonLogic.apply("{\"==\": [\" \", 0]}", null)); + } } diff --git a/src/test/java/io/github/jamsesso/jsonlogic/ErrorFixtureTests.java b/src/test/java/io/github/jamsesso/jsonlogic/ErrorFixtureTests.java index 9e8cef0..50b6c37 100644 --- a/src/test/java/io/github/jamsesso/jsonlogic/ErrorFixtureTests.java +++ b/src/test/java/io/github/jamsesso/jsonlogic/ErrorFixtureTests.java @@ -1,96 +1,107 @@ package io.github.jamsesso.jsonlogic; -import java.util.ArrayList; -import java.util.List; import com.google.gson.JsonArray; import com.google.gson.JsonElement; +import io.github.jamsesso.jsonlogic.utils.JsonValueExtractor; import org.junit.Assert; import org.junit.Test; -import io.github.jamsesso.jsonlogic.utils.JsonValueExtractor; + +import java.util.ArrayList; +import java.util.List; 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)); + 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(); + 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()); + } - 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()); } - 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; - } + 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()); - } + 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; - } + String getJson() { + return json; + } - Object getData() { - return data; - } + Object getData() { + return data; + } - String getExpectedJsonPath() { - return expectedPath; - } + String getExpectedJsonPath() { + return expectedPath; + } - String getExpectedError() { - return expectedError; + String getExpectedError() { + return expectedError; + } } - } - private static class TestResult { - private final ErrorFixture fixture; - private final JsonLogicException exception; + private static class TestResult { + private final ErrorFixture fixture; + private final JsonLogicException exception; - private TestResult(ErrorFixture fixture, JsonLogicException exception) { - this.fixture = fixture; - this.exception = exception; - } + private TestResult(ErrorFixture fixture, JsonLogicException exception) { + this.fixture = fixture; + this.exception = exception; + } - ErrorFixture getFixture() { - return fixture; - } + ErrorFixture getFixture() { + return fixture; + } - JsonLogicException getException() { - return exception; + JsonLogicException getException() { + return exception; + } } - } } diff --git a/src/test/java/io/github/jamsesso/jsonlogic/FilterExpressionTests.java b/src/test/java/io/github/jamsesso/jsonlogic/FilterExpressionTests.java index 3a7dae7..3ded217 100644 --- a/src/test/java/io/github/jamsesso/jsonlogic/FilterExpressionTests.java +++ b/src/test/java/io/github/jamsesso/jsonlogic/FilterExpressionTests.java @@ -7,20 +7,20 @@ import static org.junit.Assert.assertEquals; public class FilterExpressionTests { - private static final JsonLogic jsonLogic = new JsonLogic(); + private static final JsonLogic jsonLogic = new JsonLogic(); - @Test - public void testMap() throws JsonLogicException { - String json = "{\"filter\": [\n" + - " {\"var\": \"\"},\n" + - " {\"==\": [{\"%\": [{\"var\": \"\"}, 2]}, 0]}\n" + - "]}"; - int[] data = new int[] {1, 2, 3, 4, 5, 6}; - Object result = jsonLogic.apply(json, data); + @Test + public void testMap() throws JsonLogicException { + String json = "{\"filter\": [\n" + + " {\"var\": \"\"},\n" + + " {\"==\": [{\"%\": [{\"var\": \"\"}, 2]}, 0]}\n" + + "]}"; + int[] data = new int[]{1, 2, 3, 4, 5, 6}; + Object result = jsonLogic.apply(json, data); - assertEquals(3, ((List) result).size()); - assertEquals(2.0, ((List) result).get(0)); - assertEquals(4.0, ((List) result).get(1)); - assertEquals(6.0, ((List) result).get(2)); - } + assertEquals(3, ((List) result).size()); + assertEquals(2.0, ((List) result).get(0)); + assertEquals(4.0, ((List) result).get(1)); + assertEquals(6.0, ((List) result).get(2)); + } } diff --git a/src/test/java/io/github/jamsesso/jsonlogic/FixtureTests.java b/src/test/java/io/github/jamsesso/jsonlogic/FixtureTests.java index d75efe9..cc2be62 100644 --- a/src/test/java/io/github/jamsesso/jsonlogic/FixtureTests.java +++ b/src/test/java/io/github/jamsesso/jsonlogic/FixtureTests.java @@ -1,108 +1,116 @@ package io.github.jamsesso.jsonlogic; -import com.google.gson.*; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; import io.github.jamsesso.jsonlogic.utils.JsonValueExtractor; import org.junit.Assert; import org.junit.Test; import java.io.InputStream; import java.io.InputStreamReader; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; import java.util.function.Function; public class FixtureTests { - private static final List FIXTURES = readFixtures("fixtures.json", Fixture::fromArray); - - 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()) { - continue; - } - - JsonArray array = element.getAsJsonArray(); - fixtures.add(makeFixture.apply(array)); + private static final List FIXTURES = readFixtures("fixtures.json", Fixture::fromArray); + + 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()) { + continue; + } + + JsonArray array = element.getAsJsonArray(); + fixtures.add(makeFixture.apply(array)); + } + return fixtures; } - return fixtures; - } - @Test - public void testAllFixtures() { - JsonLogic jsonLogic = new JsonLogic(); - List failures = new ArrayList<>(); + @Test + public void testAllFixtures() { + JsonLogic jsonLogic = new JsonLogic(); + List failures = new ArrayList<>(); + + for (Fixture fixture : FIXTURES) { + try { + Object result = jsonLogic.apply(fixture.getJson(), fixture.getData()); + + if (!Objects.equals(result, fixture.getExpectedValue())) { + failures.add(new TestResult(fixture, result)); + } + } catch (JsonLogicException e) { + failures.add(new TestResult(fixture, e)); + } + } - for (Fixture fixture : FIXTURES) { - try { - Object result = jsonLogic.apply(fixture.getJson(), fixture.getData()); + for (TestResult testResult : failures) { + Object actual = testResult.getResult(); + Fixture fixture = testResult.getFixture(); - if (!Objects.equals(result, fixture.getExpectedValue())) { - failures.add(new TestResult(fixture, result)); + System.out.println(String.format("FAIL: %s\n\t%s\n\tExpected: %s Got: %s\n", + fixture.getJson(), + fixture.getData(), + fixture.getExpectedValue(), + actual instanceof Exception ? ((Exception) actual).getMessage() : actual)); } - } - catch (JsonLogicException e) { - failures.add(new TestResult(fixture, e)); - } - } - for (TestResult testResult : failures) { - Object actual = testResult.getResult(); - Fixture fixture = testResult.getFixture(); - - System.out.println(String.format("FAIL: %s\n\t%s\n\tExpected: %s Got: %s\n", fixture.getJson(), fixture.getData(), - fixture.getExpectedValue(), actual instanceof Exception ? ((Exception) actual).getMessage() : actual)); + Assert.assertEquals(String.format("%d/%d test failures!", failures.size(), FIXTURES.size()), + 0, + failures.size()); } - Assert.assertEquals(String.format("%d/%d test failures!", failures.size(), FIXTURES.size()), 0, failures.size()); - } - - private static class Fixture { - public static Fixture fromArray(JsonArray array) { - return new Fixture(array.get(0).toString(), array.get(1), array.get(2)); - } + 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; + private final String json; + private final Object data; + private final Object expectedValue; - private Fixture(String json, JsonElement data, JsonElement expectedValue) { - this.json = json; - this.data = JsonValueExtractor.extract(data); - this.expectedValue = JsonValueExtractor.extract(expectedValue); - } + private Fixture(String json, JsonElement data, JsonElement expectedValue) { + this.json = json; + this.data = JsonValueExtractor.extract(data); + this.expectedValue = JsonValueExtractor.extract(expectedValue); + } - String getJson() { - return json; - } + String getJson() { + return json; + } - Object getData() { - return data; - } + Object getData() { + return data; + } - Object getExpectedValue() { - return expectedValue; + Object getExpectedValue() { + return expectedValue; + } } - } - private static class TestResult { - private final Fixture fixture; - private final Object result; + private static class TestResult { + private final Fixture fixture; + private final Object result; - private TestResult(Fixture fixture, Object result) { - this.fixture = fixture; - this.result = result; - } + private TestResult(Fixture fixture, Object result) { + this.fixture = fixture; + this.result = result; + } - Fixture getFixture() { - return fixture; - } + Fixture getFixture() { + return fixture; + } - Object getResult() { - return result; + Object getResult() { + return result; + } } - } } diff --git a/src/test/java/io/github/jamsesso/jsonlogic/IfExpressionTests.java b/src/test/java/io/github/jamsesso/jsonlogic/IfExpressionTests.java index eb33ff6..d41bac4 100644 --- a/src/test/java/io/github/jamsesso/jsonlogic/IfExpressionTests.java +++ b/src/test/java/io/github/jamsesso/jsonlogic/IfExpressionTests.java @@ -5,33 +5,33 @@ import static org.junit.Assert.assertEquals; public class IfExpressionTests { - private static final JsonLogic jsonLogic = new JsonLogic(); - - @Test - public void testIfTrue() throws JsonLogicException { - String json = "{\"if\" : [true, \"yes\", \"no\"]}"; - Object result = jsonLogic.apply(json, null); - - assertEquals("yes", result); - } - - @Test - public void testIfFalse() throws JsonLogicException { - String json = "{\"if\" : [false, \"yes\", \"no\"]}"; - Object result = jsonLogic.apply(json, null); - - assertEquals("no", result); - } - - @Test - public void testIfElseIfElse() throws JsonLogicException { - String json = "{\"if\" : [\n" + - " {\"<\": [50, 0]}, \"freezing\",\n" + - " {\"<\": [50, 100]}, \"liquid\",\n" + - " \"gas\"\n" + - "]}"; - Object result = jsonLogic.apply(json, null); - - assertEquals("liquid", result); - } + private static final JsonLogic jsonLogic = new JsonLogic(); + + @Test + public void testIfTrue() throws JsonLogicException { + String json = "{\"if\" : [true, \"yes\", \"no\"]}"; + Object result = jsonLogic.apply(json, null); + + assertEquals("yes", result); + } + + @Test + public void testIfFalse() throws JsonLogicException { + String json = "{\"if\" : [false, \"yes\", \"no\"]}"; + Object result = jsonLogic.apply(json, null); + + assertEquals("no", result); + } + + @Test + public void testIfElseIfElse() throws JsonLogicException { + String json = "{\"if\" : [\n" + + " {\"<\": [50, 0]}, \"freezing\",\n" + + " {\"<\": [50, 100]}, \"liquid\",\n" + + " \"gas\"\n" + + "]}"; + Object result = jsonLogic.apply(json, null); + + assertEquals("liquid", result); + } } diff --git a/src/test/java/io/github/jamsesso/jsonlogic/InExpressionTests.java b/src/test/java/io/github/jamsesso/jsonlogic/InExpressionTests.java index 8d5107b..61273dc 100644 --- a/src/test/java/io/github/jamsesso/jsonlogic/InExpressionTests.java +++ b/src/test/java/io/github/jamsesso/jsonlogic/InExpressionTests.java @@ -12,63 +12,63 @@ import static org.junit.Assert.assertFalse; public class InExpressionTests { - private static final JsonLogic jsonLogic = new JsonLogic(); + private static final JsonLogic jsonLogic = new JsonLogic(); - @Test - public void testStringIn() throws JsonLogicException { - assertEquals(true, jsonLogic.apply("{\"in\": [\"race\", \"racecar\"]}", null)); - } + @Test + public void testStringIn() throws JsonLogicException { + assertEquals(true, jsonLogic.apply("{\"in\": [\"race\", \"racecar\"]}", null)); + } - @Test - public void testStringNotIn() throws JsonLogicException { - assertEquals(false, jsonLogic.apply("{\"in\": [\"race\", \"clouds\"]}", null)); - assertEquals(false, jsonLogic.apply("{\"in\": [null, \"clouds\"]}", null)); - } + @Test + public void testStringNotIn() throws JsonLogicException { + assertEquals(false, jsonLogic.apply("{\"in\": [\"race\", \"clouds\"]}", null)); + assertEquals(false, jsonLogic.apply("{\"in\": [null, \"clouds\"]}", null)); + } - @Test - public void testArrayIn() throws JsonLogicException { - assertEquals(true, jsonLogic.apply("{\"in\": [1, [1, 2, 3]]}", null)); - assertEquals(true, jsonLogic.apply("{\"in\": [4.56, [1, 2, 3, 4.56]]}", null)); - assertEquals(true, jsonLogic.apply("{\"in\": [null, [1, 2, 3, null]]}", null)); - } + @Test + public void testArrayIn() throws JsonLogicException { + assertEquals(true, jsonLogic.apply("{\"in\": [1, [1, 2, 3]]}", null)); + assertEquals(true, jsonLogic.apply("{\"in\": [4.56, [1, 2, 3, 4.56]]}", null)); + assertEquals(true, jsonLogic.apply("{\"in\": [null, [1, 2, 3, null]]}", null)); + } - @Test - public void testArrayNotIn() throws JsonLogicException { - assertEquals(false, jsonLogic.apply("{\"in\": [5, [1, 2, 3]]}", null)); - assertEquals(false, jsonLogic.apply("{\"in\": [null, [1, 2, 3]]}", null)); - } + @Test + public void testArrayNotIn() throws JsonLogicException { + assertEquals(false, jsonLogic.apply("{\"in\": [5, [1, 2, 3]]}", null)); + assertEquals(false, jsonLogic.apply("{\"in\": [null, [1, 2, 3]]}", null)); + } - @Test - public void testInVariableInt() throws JsonLogicException { - Map data = Collections.singletonMap("list", Arrays.asList(1, 2, 3)); - assertEquals(true, jsonLogic.apply("{\"in\": [2, {\"var\": \"list\"}]}", data)); - } + @Test + public void testInVariableInt() throws JsonLogicException { + Map data = Collections.singletonMap("list", Arrays.asList(1, 2, 3)); + assertEquals(true, jsonLogic.apply("{\"in\": [2, {\"var\": \"list\"}]}", data)); + } - @Test - public void testNotInVariableInt() throws JsonLogicException { - Map data = Collections.singletonMap("list", Arrays.asList(1, 2, 3)); - assertEquals(false, jsonLogic.apply("{\"in\": [4, {\"var\": \"list\"}]}", data)); - assertEquals(false, jsonLogic.apply("{\"in\": [4, {\"var\": \"list\"}]}", null)); - } + @Test + public void testNotInVariableInt() throws JsonLogicException { + Map data = Collections.singletonMap("list", Arrays.asList(1, 2, 3)); + assertEquals(false, jsonLogic.apply("{\"in\": [4, {\"var\": \"list\"}]}", data)); + assertEquals(false, jsonLogic.apply("{\"in\": [4, {\"var\": \"list\"}]}", null)); + } - @Test - public void testAllVariables() throws JsonLogicException { - Map data = Stream.of(new Object[][] { - new Object[] {"list", Arrays.asList(1, 2, 3)}, - new Object[] {"value", 3} - }).collect(Collectors.toMap(o -> o[0], o -> o[1])); + @Test + public void testAllVariables() throws JsonLogicException { + Map data = Stream.of(new Object[][]{ + new Object[]{"list", Arrays.asList(1, 2, 3)}, + new Object[]{"value", 3} + }).collect(Collectors.toMap(o -> o[0], o -> o[1])); - assertEquals(true, jsonLogic.apply("{\"in\": [{\"var\": \"value\"}, {\"var\": \"list\"}]}", data)); - assertEquals(false, jsonLogic.apply("{\"in\": [{\"var\": \"value\"}, {\"var\": \"list\"}]}", null)); - } + assertEquals(true, jsonLogic.apply("{\"in\": [{\"var\": \"value\"}, {\"var\": \"list\"}]}", data)); + assertEquals(false, jsonLogic.apply("{\"in\": [{\"var\": \"value\"}, {\"var\": \"list\"}]}", null)); + } - @Test - public void testSingleArgument() throws JsonLogicException { - assertFalse((boolean) jsonLogic.apply("{\"in\": [\"Spring\"]}", null)); - } + @Test + public void testSingleArgument() throws JsonLogicException { + assertFalse((boolean) jsonLogic.apply("{\"in\": [\"Spring\"]}", null)); + } - @Test - public void testBadSecondArgument() throws JsonLogicException { - assertFalse((boolean) jsonLogic.apply("{\"in\": [\"Spring\", 3]}", null)); - } + @Test + public void testBadSecondArgument() throws JsonLogicException { + assertFalse((boolean) jsonLogic.apply("{\"in\": [\"Spring\", 3]}", null)); + } } diff --git a/src/test/java/io/github/jamsesso/jsonlogic/InequalityExpressionTests.java b/src/test/java/io/github/jamsesso/jsonlogic/InequalityExpressionTests.java index abd27fa..d20c0ce 100644 --- a/src/test/java/io/github/jamsesso/jsonlogic/InequalityExpressionTests.java +++ b/src/test/java/io/github/jamsesso/jsonlogic/InequalityExpressionTests.java @@ -5,15 +5,15 @@ import static org.junit.Assert.assertEquals; public class InequalityExpressionTests { - private static final JsonLogic jsonLogic = new JsonLogic(); + private static final JsonLogic jsonLogic = new JsonLogic(); - @Test - public void testDifferentValueSameType() throws JsonLogicException { - assertEquals(true, jsonLogic.apply("{\"!=\": [1, 2]}", null)); - } + @Test + public void testDifferentValueSameType() throws JsonLogicException { + assertEquals(true, jsonLogic.apply("{\"!=\": [1, 2]}", null)); + } - @Test - public void testSameValueDifferentType() throws JsonLogicException { - assertEquals(false, jsonLogic.apply("{\"!=\": [1.0, \"1\"]}", null)); - } + @Test + public void testSameValueDifferentType() throws JsonLogicException { + assertEquals(false, jsonLogic.apply("{\"!=\": [1.0, \"1\"]}", null)); + } } diff --git a/src/test/java/io/github/jamsesso/jsonlogic/LogExpressionTests.java b/src/test/java/io/github/jamsesso/jsonlogic/LogExpressionTests.java index d9119a8..9eba514 100644 --- a/src/test/java/io/github/jamsesso/jsonlogic/LogExpressionTests.java +++ b/src/test/java/io/github/jamsesso/jsonlogic/LogExpressionTests.java @@ -5,10 +5,10 @@ import static org.junit.Assert.assertEquals; public class LogExpressionTests { - private static final JsonLogic jsonLogic = new JsonLogic(); + private static final JsonLogic jsonLogic = new JsonLogic(); - @Test - public void testDoesLog() throws JsonLogicException { - assertEquals("hello world", jsonLogic.apply("{\"log\": \"hello world\"}", null)); - } + @Test + public void testDoesLog() throws JsonLogicException { + assertEquals("hello world", jsonLogic.apply("{\"log\": \"hello world\"}", null)); + } } diff --git a/src/test/java/io/github/jamsesso/jsonlogic/LogicExpressionTests.java b/src/test/java/io/github/jamsesso/jsonlogic/LogicExpressionTests.java index 27e5510..18655d6 100644 --- a/src/test/java/io/github/jamsesso/jsonlogic/LogicExpressionTests.java +++ b/src/test/java/io/github/jamsesso/jsonlogic/LogicExpressionTests.java @@ -5,15 +5,15 @@ import static org.junit.Assert.assertEquals; public class LogicExpressionTests { - private static final JsonLogic jsonLogic = new JsonLogic(); + private static final JsonLogic jsonLogic = new JsonLogic(); - @Test - public void testOr() throws JsonLogicException { - assertEquals("a", jsonLogic.apply("{\"or\": [0, false, \"a\"]}", null)); - } + @Test + public void testOr() throws JsonLogicException { + assertEquals("a", jsonLogic.apply("{\"or\": [0, false, \"a\"]}", null)); + } - @Test - public void testAnd() throws JsonLogicException { - assertEquals("", jsonLogic.apply("{\"and\": [true, \"\", 3]}", null)); - } + @Test + public void testAnd() throws JsonLogicException { + assertEquals("", jsonLogic.apply("{\"and\": [true, \"\", 3]}", null)); + } } diff --git a/src/test/java/io/github/jamsesso/jsonlogic/MapExpressionTests.java b/src/test/java/io/github/jamsesso/jsonlogic/MapExpressionTests.java index ae176e6..0034b64 100644 --- a/src/test/java/io/github/jamsesso/jsonlogic/MapExpressionTests.java +++ b/src/test/java/io/github/jamsesso/jsonlogic/MapExpressionTests.java @@ -7,20 +7,20 @@ import static org.junit.Assert.assertEquals; public class MapExpressionTests { - private static final JsonLogic jsonLogic = new JsonLogic(); + private static final JsonLogic jsonLogic = new JsonLogic(); - @Test - public void testMap() throws JsonLogicException { - String json = "{\"map\": [\n" + - " {\"var\": \"\"},\n" + - " {\"*\": [{\"var\": \"\"}, 2]}\n" + - "]}"; - int[] data = new int[] {1, 2, 3}; - Object result = jsonLogic.apply(json, data); + @Test + public void testMap() throws JsonLogicException { + String json = "{\"map\": [\n" + + " {\"var\": \"\"},\n" + + " {\"*\": [{\"var\": \"\"}, 2]}\n" + + "]}"; + int[] data = new int[]{1, 2, 3}; + Object result = jsonLogic.apply(json, data); - assertEquals(3, ((List) result).size()); - assertEquals(2.0, ((List) result).get(0)); - assertEquals(4.0, ((List) result).get(1)); - assertEquals(6.0, ((List) result).get(2)); - } + assertEquals(3, ((List) result).size()); + assertEquals(2.0, ((List) result).get(0)); + assertEquals(4.0, ((List) result).get(1)); + assertEquals(6.0, ((List) result).get(2)); + } } diff --git a/src/test/java/io/github/jamsesso/jsonlogic/MathExpressionTests.java b/src/test/java/io/github/jamsesso/jsonlogic/MathExpressionTests.java index 773f706..99aaf95 100644 --- a/src/test/java/io/github/jamsesso/jsonlogic/MathExpressionTests.java +++ b/src/test/java/io/github/jamsesso/jsonlogic/MathExpressionTests.java @@ -6,145 +6,145 @@ import static org.junit.Assert.assertNull; public class MathExpressionTests { - private static final JsonLogic jsonLogic = new JsonLogic(); + private static final JsonLogic jsonLogic = new JsonLogic(); - @Test - public void testAdd() throws JsonLogicException { - String json = "{\"+\":[4,2]}"; - Object result = jsonLogic.apply(json, null); + @Test + public void testAdd() throws JsonLogicException { + String json = "{\"+\":[4,2]}"; + Object result = jsonLogic.apply(json, null); - assertEquals(6.0, result); - } + assertEquals(6.0, result); + } - @Test - public void testMultiAdd() throws JsonLogicException { - String json = "{\"+\":[2,2,2,2,2]}"; - Object result = jsonLogic.apply(json, null); + @Test + public void testMultiAdd() throws JsonLogicException { + String json = "{\"+\":[2,2,2,2,2]}"; + Object result = jsonLogic.apply(json, null); - assertEquals(10.0, result); - } + assertEquals(10.0, result); + } - @Test - public void testSingleAdd() throws JsonLogicException { - String json = "{\"+\" : \"3.14\"}"; - Object result = jsonLogic.apply(json, null); + @Test + public void testSingleAdd() throws JsonLogicException { + String json = "{\"+\" : \"3.14\"}"; + Object result = jsonLogic.apply(json, null); - assertEquals(3.14, result); - } + assertEquals(3.14, result); + } - @Test - public void testAddWithArray() throws JsonLogicException { - String json = "{\"+\":[2,[[3,4],5]]}"; - Object result = jsonLogic.apply(json, null); + @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 - } + 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]}"; - Object result = jsonLogic.apply(json, null); - - assertEquals(2.0, result); - } - - @Test - public void testSingleSubtract() throws JsonLogicException { - String json = "{\"-\": 2 }"; - Object result = jsonLogic.apply(json, null); - - 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]}"; - Object result = jsonLogic.apply(json, null); - - assertEquals(8.0, result); - } - - @Test - public void testMultiMultiply() throws JsonLogicException { - String json = "{\"*\":[2,2,2,2,2]}"; - Object result = jsonLogic.apply(json, null); - - 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 testMultiplyWithEmptyArray() throws JsonLogicException { - String json = "{\"*\":[2,[]]}"; - Object result = jsonLogic.apply(json, null); - - assertEquals(null, result); // This matches reference impl at jsonlogic.com - } - - @Test - public void testDivide() throws JsonLogicException { - String json = "{\"/\":[4,2]}"; - Object result = jsonLogic.apply(json, null); - - assertEquals(2.0, result); - } - - @Test - public void testDivideBy0() throws JsonLogicException { - String json = "{\"/\":[4,0]}"; - Object result = jsonLogic.apply(json, null); - - assertEquals(Double.POSITIVE_INFINITY, result); - } - - @Test - public void testModulo() throws JsonLogicException { - String json = "{\"%\": [101,2]}"; - Object result = jsonLogic.apply(json, null); - - assertEquals(1.0, result); - } - - @Test - public void testMin() throws JsonLogicException { - String json = "{\"min\":[1,2,3]}"; - Object result = jsonLogic.apply(json, null); - - assertEquals(1.0, result); - } - - @Test - public void testMax() throws JsonLogicException { - String json = "{\"max\":[1,2,3]}"; - Object result = jsonLogic.apply(json, null); - - assertEquals(3.0, result); - } - - @Test - public void testDivideSingleNumber() throws JsonLogicException { - assertEquals(null, jsonLogic.apply("{\"/\": [0]}", null)); - } + @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]}"; + Object result = jsonLogic.apply(json, null); + + assertEquals(2.0, result); + } + + @Test + public void testSingleSubtract() throws JsonLogicException { + String json = "{\"-\": 2 }"; + Object result = jsonLogic.apply(json, null); + + 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]}"; + Object result = jsonLogic.apply(json, null); + + assertEquals(8.0, result); + } + + @Test + public void testMultiMultiply() throws JsonLogicException { + String json = "{\"*\":[2,2,2,2,2]}"; + Object result = jsonLogic.apply(json, null); + + 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 testMultiplyWithEmptyArray() throws JsonLogicException { + String json = "{\"*\":[2,[]]}"; + Object result = jsonLogic.apply(json, null); + + assertEquals(null, result); // This matches reference impl at jsonlogic.com + } + + @Test + public void testDivide() throws JsonLogicException { + String json = "{\"/\":[4,2]}"; + Object result = jsonLogic.apply(json, null); + + assertEquals(2.0, result); + } + + @Test + public void testDivideBy0() throws JsonLogicException { + String json = "{\"/\":[4,0]}"; + Object result = jsonLogic.apply(json, null); + + assertEquals(Double.POSITIVE_INFINITY, result); + } + + @Test + public void testModulo() throws JsonLogicException { + String json = "{\"%\": [101,2]}"; + Object result = jsonLogic.apply(json, null); + + assertEquals(1.0, result); + } + + @Test + public void testMin() throws JsonLogicException { + String json = "{\"min\":[1,2,3]}"; + Object result = jsonLogic.apply(json, null); + + assertEquals(1.0, result); + } + + @Test + public void testMax() throws JsonLogicException { + String json = "{\"max\":[1,2,3]}"; + Object result = jsonLogic.apply(json, null); + + assertEquals(3.0, result); + } + + @Test + public void testDivideSingleNumber() throws JsonLogicException { + assertEquals(null, jsonLogic.apply("{\"/\": [0]}", null)); + } } diff --git a/src/test/java/io/github/jamsesso/jsonlogic/MergeExpressionTests.java b/src/test/java/io/github/jamsesso/jsonlogic/MergeExpressionTests.java index dcb8e7d..e694420 100644 --- a/src/test/java/io/github/jamsesso/jsonlogic/MergeExpressionTests.java +++ b/src/test/java/io/github/jamsesso/jsonlogic/MergeExpressionTests.java @@ -7,27 +7,27 @@ import static org.junit.Assert.assertEquals; public class MergeExpressionTests { - private static final JsonLogic jsonLogic = new JsonLogic(); - - @Test - public void testMerge() throws JsonLogicException { - Object result = jsonLogic.apply("{\"merge\": [[1, 2], [3, 4]]}", null); - - assertEquals(4, ((List) result).size()); - assertEquals(1.0, ((List) result).get(0)); - assertEquals(2.0, ((List) result).get(1)); - assertEquals(3.0, ((List) result).get(2)); - assertEquals(4.0, ((List) result).get(3)); - } - - @Test - public void testMergeWithNonArrays() throws JsonLogicException { - Object result = jsonLogic.apply("{\"merge\": [1, 2, [3, 4]]}", null); - - assertEquals(4, ((List) result).size()); - assertEquals(1.0, ((List) result).get(0)); - assertEquals(2.0, ((List) result).get(1)); - assertEquals(3.0, ((List) result).get(2)); - assertEquals(4.0, ((List) result).get(3)); - } + private static final JsonLogic jsonLogic = new JsonLogic(); + + @Test + public void testMerge() throws JsonLogicException { + Object result = jsonLogic.apply("{\"merge\": [[1, 2], [3, 4]]}", null); + + assertEquals(4, ((List) result).size()); + assertEquals(1.0, ((List) result).get(0)); + assertEquals(2.0, ((List) result).get(1)); + assertEquals(3.0, ((List) result).get(2)); + assertEquals(4.0, ((List) result).get(3)); + } + + @Test + public void testMergeWithNonArrays() throws JsonLogicException { + Object result = jsonLogic.apply("{\"merge\": [1, 2, [3, 4]]}", null); + + assertEquals(4, ((List) result).size()); + assertEquals(1.0, ((List) result).get(0)); + assertEquals(2.0, ((List) result).get(1)); + assertEquals(3.0, ((List) result).get(2)); + assertEquals(4.0, ((List) result).get(3)); + } } diff --git a/src/test/java/io/github/jamsesso/jsonlogic/MissingExpressionTests.java b/src/test/java/io/github/jamsesso/jsonlogic/MissingExpressionTests.java index 53b2d9e..7583c8f 100644 --- a/src/test/java/io/github/jamsesso/jsonlogic/MissingExpressionTests.java +++ b/src/test/java/io/github/jamsesso/jsonlogic/MissingExpressionTests.java @@ -9,76 +9,76 @@ import static org.junit.Assert.assertEquals; public class MissingExpressionTests { - private static final JsonLogic jsonLogic = new JsonLogic(); - - @Test - public void testMissing() throws JsonLogicException { - Map data = new HashMap() {{ - put("a", "apple"); - put("c", "carrot"); - }}; - Object result = jsonLogic.apply("{\"missing\": [\"a\", \"b\"]}", data); - - assertEquals(1, ((List) result).size()); - assertEquals("b", ((List) result).get(0)); - } - - @Test - public void testMissingSomeUnderThreshold() throws JsonLogicException { - Map data = new HashMap() {{ - put("a", "apple"); - put("c", "carrot"); - }}; - Object result = jsonLogic.apply("{\"missing_some\": [1, [\"a\", \"b\"]]}", data); - - assertEquals(0, ((List) result).size()); - } - - @Test - public void testMissingSomeOverThreshold() throws JsonLogicException { - Map data = new HashMap() {{ - put("a", "apple"); - }}; - Object result = jsonLogic.apply("{\"missing_some\": [2, [\"a\", \"b\", \"c\"]]}", data); - - assertEquals(2, ((List) result).size()); - assertEquals("b", ((List) result).get(0)); - assertEquals("c", ((List) result).get(1)); - } - - @Test - public void testMissingSomeComplexExpression() throws JsonLogicException { - Map data = new HashMap() {{ - put("first_name", "Bruce"); - put("last_name", "Wayne"); - }}; - String json = "{\"if\" :[\n" + - " {\"merge\": [\n" + - " {\"missing\":[\"first_name\", \"last_name\"]},\n" + - " {\"missing_some\":[1, [\"cell_phone\", \"home_phone\"] ]}\n" + - " ]},\n" + - " \"We require first name, last name, and one phone number.\",\n" + - " \"OK to proceed\"\n" + - "]}"; - Object result = jsonLogic.apply(json, data); - - assertEquals("We require first name, last name, and one phone number.", result); - } - - @Test - public void testMissingSomeWithNullData() throws JsonLogicException { - Object result = jsonLogic.apply("{\"missing_some\": [2, [\"a\", \"b\", \"c\"]]}", null); - - assertEquals(3, ((List) result).size()); - assertEquals("a", ((List) result).get(0)); - assertEquals("b", ((List) result).get(1)); - assertEquals("c", ((List) result).get(2)); - } - - @Test - public void testMissingSomeWithZeroThreshold() throws JsonLogicException { - Object result = jsonLogic.apply("{\"missing_some\": [0, [\"a\", \"b\", \"c\"]]}", null); - - assertEquals(0, ((List) result).size()); - } + private static final JsonLogic jsonLogic = new JsonLogic(); + + @Test + public void testMissing() throws JsonLogicException { + Map data = new HashMap() {{ + put("a", "apple"); + put("c", "carrot"); + }}; + Object result = jsonLogic.apply("{\"missing\": [\"a\", \"b\"]}", data); + + assertEquals(1, ((List) result).size()); + assertEquals("b", ((List) result).get(0)); + } + + @Test + public void testMissingSomeUnderThreshold() throws JsonLogicException { + Map data = new HashMap() {{ + put("a", "apple"); + put("c", "carrot"); + }}; + Object result = jsonLogic.apply("{\"missing_some\": [1, [\"a\", \"b\"]]}", data); + + assertEquals(0, ((List) result).size()); + } + + @Test + public void testMissingSomeOverThreshold() throws JsonLogicException { + Map data = new HashMap() {{ + put("a", "apple"); + }}; + Object result = jsonLogic.apply("{\"missing_some\": [2, [\"a\", \"b\", \"c\"]]}", data); + + assertEquals(2, ((List) result).size()); + assertEquals("b", ((List) result).get(0)); + assertEquals("c", ((List) result).get(1)); + } + + @Test + public void testMissingSomeComplexExpression() throws JsonLogicException { + Map data = new HashMap() {{ + put("first_name", "Bruce"); + put("last_name", "Wayne"); + }}; + String json = "{\"if\" :[\n" + + " {\"merge\": [\n" + + " {\"missing\":[\"first_name\", \"last_name\"]},\n" + + " {\"missing_some\":[1, [\"cell_phone\", \"home_phone\"] ]}\n" + + " ]},\n" + + " \"We require first name, last name, and one phone number.\",\n" + + " \"OK to proceed\"\n" + + "]}"; + Object result = jsonLogic.apply(json, data); + + assertEquals("We require first name, last name, and one phone number.", result); + } + + @Test + public void testMissingSomeWithNullData() throws JsonLogicException { + Object result = jsonLogic.apply("{\"missing_some\": [2, [\"a\", \"b\", \"c\"]]}", null); + + assertEquals(3, ((List) result).size()); + assertEquals("a", ((List) result).get(0)); + assertEquals("b", ((List) result).get(1)); + assertEquals("c", ((List) result).get(2)); + } + + @Test + public void testMissingSomeWithZeroThreshold() throws JsonLogicException { + Object result = jsonLogic.apply("{\"missing_some\": [0, [\"a\", \"b\", \"c\"]]}", null); + + assertEquals(0, ((List) result).size()); + } } diff --git a/src/test/java/io/github/jamsesso/jsonlogic/NotExpressionTests.java b/src/test/java/io/github/jamsesso/jsonlogic/NotExpressionTests.java index 6b50167..e7a079f 100644 --- a/src/test/java/io/github/jamsesso/jsonlogic/NotExpressionTests.java +++ b/src/test/java/io/github/jamsesso/jsonlogic/NotExpressionTests.java @@ -5,45 +5,45 @@ import static org.junit.Assert.assertEquals; public class NotExpressionTests { - private static final JsonLogic jsonLogic = new JsonLogic(); - - @Test - public void testSingleBoolean() throws JsonLogicException { - assertEquals(true, jsonLogic.apply("{\"!\": false}", null)); - } - - @Test - public void testSingleNumber() throws JsonLogicException { - assertEquals(true, jsonLogic.apply("{\"!\": 0}", null)); - } - - @Test - public void testSingleString() throws JsonLogicException { - assertEquals(true, jsonLogic.apply("{\"!\": \"\"}", null)); - } - - @Test - public void testSingleArray() throws JsonLogicException { - assertEquals(true, jsonLogic.apply("{\"!\": []}", null)); - } - - @Test - public void testDoubleBoolean() throws JsonLogicException { - assertEquals(false, jsonLogic.apply("{\"!!\": false}", null)); - } - - @Test - public void testDoubleNumber() throws JsonLogicException { - assertEquals(false, jsonLogic.apply("{\"!!\": 0}", null)); - } - - @Test - public void testDoubleString() throws JsonLogicException { - assertEquals(false, jsonLogic.apply("{\"!!\": \"\"}", null)); - } - - @Test - public void testDoubleArray() throws JsonLogicException { - assertEquals(false, jsonLogic.apply("{\"!!\": [[]]}", null)); - } + private static final JsonLogic jsonLogic = new JsonLogic(); + + @Test + public void testSingleBoolean() throws JsonLogicException { + assertEquals(true, jsonLogic.apply("{\"!\": false}", null)); + } + + @Test + public void testSingleNumber() throws JsonLogicException { + assertEquals(true, jsonLogic.apply("{\"!\": 0}", null)); + } + + @Test + public void testSingleString() throws JsonLogicException { + assertEquals(true, jsonLogic.apply("{\"!\": \"\"}", null)); + } + + @Test + public void testSingleArray() throws JsonLogicException { + assertEquals(true, jsonLogic.apply("{\"!\": []}", null)); + } + + @Test + public void testDoubleBoolean() throws JsonLogicException { + assertEquals(false, jsonLogic.apply("{\"!!\": false}", null)); + } + + @Test + public void testDoubleNumber() throws JsonLogicException { + assertEquals(false, jsonLogic.apply("{\"!!\": 0}", null)); + } + + @Test + public void testDoubleString() throws JsonLogicException { + assertEquals(false, jsonLogic.apply("{\"!!\": \"\"}", null)); + } + + @Test + public void testDoubleArray() throws JsonLogicException { + assertEquals(false, jsonLogic.apply("{\"!!\": [[]]}", null)); + } } diff --git a/src/test/java/io/github/jamsesso/jsonlogic/NumberTests.java b/src/test/java/io/github/jamsesso/jsonlogic/NumberTests.java index baa4ea8..3595858 100644 --- a/src/test/java/io/github/jamsesso/jsonlogic/NumberTests.java +++ b/src/test/java/io/github/jamsesso/jsonlogic/NumberTests.java @@ -7,21 +7,21 @@ import java.util.Map; public class NumberTests { - @Test - public void testConvertAllNumericInputToDouble() throws JsonLogicException { - JsonLogic jsonLogic = new JsonLogic(); - Map numbers = new HashMap() {{ - put("double", 1D); - put("float", 1F); - put("int", 1); - put("short", (short) 1); - put("long", 1L); - }}; + @Test + public void testConvertAllNumericInputToDouble() throws JsonLogicException { + JsonLogic jsonLogic = new JsonLogic(); + Map numbers = new HashMap() {{ + put("double", 1D); + put("float", 1F); + put("int", 1); + put("short", (short) 1); + put("long", 1L); + }}; - Assert.assertEquals(1D, jsonLogic.apply("{\"var\": \"double\"}", numbers)); - Assert.assertEquals(1D, jsonLogic.apply("{\"var\": \"float\"}", numbers)); - Assert.assertEquals(1D, jsonLogic.apply("{\"var\": \"int\"}", numbers)); - Assert.assertEquals(1D, jsonLogic.apply("{\"var\": \"short\"}", numbers)); - Assert.assertEquals(1D, jsonLogic.apply("{\"var\": \"long\"}", numbers)); - } + Assert.assertEquals(1D, jsonLogic.apply("{\"var\": \"double\"}", numbers)); + Assert.assertEquals(1D, jsonLogic.apply("{\"var\": \"float\"}", numbers)); + Assert.assertEquals(1D, jsonLogic.apply("{\"var\": \"int\"}", numbers)); + Assert.assertEquals(1D, jsonLogic.apply("{\"var\": \"short\"}", numbers)); + Assert.assertEquals(1D, jsonLogic.apply("{\"var\": \"long\"}", numbers)); + } } diff --git a/src/test/java/io/github/jamsesso/jsonlogic/NumericComparisonExpressionTests.java b/src/test/java/io/github/jamsesso/jsonlogic/NumericComparisonExpressionTests.java index d4633b1..586ece8 100644 --- a/src/test/java/io/github/jamsesso/jsonlogic/NumericComparisonExpressionTests.java +++ b/src/test/java/io/github/jamsesso/jsonlogic/NumericComparisonExpressionTests.java @@ -5,75 +5,75 @@ import static org.junit.Assert.assertEquals; public class NumericComparisonExpressionTests { - private static final JsonLogic jsonLogic = new JsonLogic(); + private static final JsonLogic jsonLogic = new JsonLogic(); - @Test - public void testLessThan() throws JsonLogicException { - String json = "{\"<\" : [1, 2]}"; - Object result = jsonLogic.apply(json, null); + @Test + public void testLessThan() throws JsonLogicException { + String json = "{\"<\" : [1, 2]}"; + Object result = jsonLogic.apply(json, null); - assertEquals(true, result); - } + assertEquals(true, result); + } - @Test - public void testLessThanOrEqual() throws JsonLogicException { - String json = "{\"<=\" : [1, 1]}"; - Object result = jsonLogic.apply(json, null); + @Test + public void testLessThanOrEqual() throws JsonLogicException { + String json = "{\"<=\" : [1, 1]}"; + Object result = jsonLogic.apply(json, null); - assertEquals(true, result); - } + assertEquals(true, result); + } - @Test - public void testGreaterThan() throws JsonLogicException { - String json = "{\">\" : [2, 1]}"; - Object result = jsonLogic.apply(json, null); + @Test + public void testGreaterThan() throws JsonLogicException { + String json = "{\">\" : [2, 1]}"; + Object result = jsonLogic.apply(json, null); - assertEquals(true, result); - } + assertEquals(true, result); + } - @Test - public void testGreaterThanOrEqual() throws JsonLogicException { - String json = "{\">=\" : [1, 1]}"; - Object result = jsonLogic.apply(json, null); + @Test + public void testGreaterThanOrEqual() throws JsonLogicException { + String json = "{\">=\" : [1, 1]}"; + Object result = jsonLogic.apply(json, null); - assertEquals(true, result); - } + assertEquals(true, result); + } - @Test - public void testBetweenExclusive() throws JsonLogicException { - String json = "{\"<\" : [1, 2, 3]}"; - Object result = jsonLogic.apply(json, null); + @Test + public void testBetweenExclusive() throws JsonLogicException { + String json = "{\"<\" : [1, 2, 3]}"; + Object result = jsonLogic.apply(json, null); - assertEquals(true, result); - } + assertEquals(true, result); + } - @Test - public void testBetweenInclusive() throws JsonLogicException { - String json = "{\"<=\" : [1, 1, 3]}"; - Object result = jsonLogic.apply(json, null); + @Test + public void testBetweenInclusive() throws JsonLogicException { + String json = "{\"<=\" : [1, 1, 3]}"; + Object result = jsonLogic.apply(json, null); - assertEquals(true, result); - } + assertEquals(true, result); + } - @Test - public void testGtBetweenExclusive() throws JsonLogicException { - String json = "{\">\" : [3, 2, 1]}"; - Object result = jsonLogic.apply(json, null); + @Test + public void testGtBetweenExclusive() throws JsonLogicException { + String json = "{\">\" : [3, 2, 1]}"; + Object result = jsonLogic.apply(json, null); - assertEquals(true, result); - } + assertEquals(true, result); + } - @Test - public void testGtBetweenInclusive() throws JsonLogicException { - String json = "{\">=\" : [3, 1, 1]}"; - Object result = jsonLogic.apply(json, null); + @Test + public void testGtBetweenInclusive() throws JsonLogicException { + String json = "{\">=\" : [3, 1, 1]}"; + Object result = jsonLogic.apply(json, null); - assertEquals(true, result); - } + 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)); - } + @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/java/io/github/jamsesso/jsonlogic/ReduceExpressionTests.java b/src/test/java/io/github/jamsesso/jsonlogic/ReduceExpressionTests.java index 5b0d814..a302b48 100644 --- a/src/test/java/io/github/jamsesso/jsonlogic/ReduceExpressionTests.java +++ b/src/test/java/io/github/jamsesso/jsonlogic/ReduceExpressionTests.java @@ -5,18 +5,18 @@ import static org.junit.Assert.assertEquals; public class ReduceExpressionTests { - private static final JsonLogic jsonLogic = new JsonLogic(); + private static final JsonLogic jsonLogic = new JsonLogic(); - @Test - public void testReduce() throws JsonLogicException { - String json = "{\"reduce\":[\n" + - " {\"var\":\"\"},\n" + - " {\"+\":[{\"var\":\"current\"}, {\"var\":\"accumulator\"}]},\n" + - " 0\n" + - "]}"; - int[] data = new int[] {1, 2, 3, 4, 5, 6}; - Object result = jsonLogic.apply(json, data); + @Test + public void testReduce() throws JsonLogicException { + String json = "{\"reduce\":[\n" + + " {\"var\":\"\"},\n" + + " {\"+\":[{\"var\":\"current\"}, {\"var\":\"accumulator\"}]},\n" + + " 0\n" + + "]}"; + int[] data = new int[]{1, 2, 3, 4, 5, 6}; + Object result = jsonLogic.apply(json, data); - assertEquals(21.0, result); - } + assertEquals(21.0, result); + } } diff --git a/src/test/java/io/github/jamsesso/jsonlogic/StrictEqualityExpressionTests.java b/src/test/java/io/github/jamsesso/jsonlogic/StrictEqualityExpressionTests.java index feb1351..54857ff 100644 --- a/src/test/java/io/github/jamsesso/jsonlogic/StrictEqualityExpressionTests.java +++ b/src/test/java/io/github/jamsesso/jsonlogic/StrictEqualityExpressionTests.java @@ -5,15 +5,15 @@ import static org.junit.Assert.assertEquals; public class StrictEqualityExpressionTests { - private static final JsonLogic jsonLogic = new JsonLogic(); + private static final JsonLogic jsonLogic = new JsonLogic(); - @Test - public void testSameValueSameType() throws JsonLogicException { - assertEquals(true, jsonLogic.apply("{\"===\": [1, 1.0]}", null)); - } + @Test + public void testSameValueSameType() throws JsonLogicException { + assertEquals(true, jsonLogic.apply("{\"===\": [1, 1.0]}", null)); + } - @Test - public void testSameValueDifferentType() throws JsonLogicException { - assertEquals(false, jsonLogic.apply("{\"===\": [1, \"1\"]}", null)); - } + @Test + public void testSameValueDifferentType() throws JsonLogicException { + assertEquals(false, jsonLogic.apply("{\"===\": [1, \"1\"]}", null)); + } } diff --git a/src/test/java/io/github/jamsesso/jsonlogic/StrictInequalityExpressionTests.java b/src/test/java/io/github/jamsesso/jsonlogic/StrictInequalityExpressionTests.java index 9443289..55b4549 100644 --- a/src/test/java/io/github/jamsesso/jsonlogic/StrictInequalityExpressionTests.java +++ b/src/test/java/io/github/jamsesso/jsonlogic/StrictInequalityExpressionTests.java @@ -5,15 +5,15 @@ import static org.junit.Assert.assertEquals; public class StrictInequalityExpressionTests { - private static final JsonLogic jsonLogic = new JsonLogic(); + private static final JsonLogic jsonLogic = new JsonLogic(); - @Test - public void testSameValueSameType() throws JsonLogicException { - assertEquals(false, jsonLogic.apply("{\"!==\": [1, 1.0]}", null)); - } + @Test + public void testSameValueSameType() throws JsonLogicException { + assertEquals(false, jsonLogic.apply("{\"!==\": [1, 1.0]}", null)); + } - @Test - public void testSameValueDifferentType() throws JsonLogicException { - assertEquals(true, jsonLogic.apply("{\"!==\": [1, \"1\"]}", null)); - } + @Test + public void testSameValueDifferentType() throws JsonLogicException { + assertEquals(true, jsonLogic.apply("{\"!==\": [1, \"1\"]}", null)); + } } diff --git a/src/test/java/io/github/jamsesso/jsonlogic/SubstringExpressionTests.java b/src/test/java/io/github/jamsesso/jsonlogic/SubstringExpressionTests.java index 96fb359..653f023 100644 --- a/src/test/java/io/github/jamsesso/jsonlogic/SubstringExpressionTests.java +++ b/src/test/java/io/github/jamsesso/jsonlogic/SubstringExpressionTests.java @@ -5,35 +5,35 @@ import static org.junit.Assert.assertEquals; public class SubstringExpressionTests { - private static final JsonLogic jsonLogic = new JsonLogic(); - - @Test - public void testSubstringSingleArg() throws JsonLogicException { - assertEquals("logic", jsonLogic.apply("{\"substr\": [\"jsonlogic\", 4]}", null)); - } - - @Test - public void testSubstringSingleNegativeArg() throws JsonLogicException { - assertEquals("logic", jsonLogic.apply("{\"substr\": [\"jsonlogic\", -5]}", null)); - } - - @Test - public void testSubstringDoubleArg() throws JsonLogicException { - assertEquals("son", jsonLogic.apply("{\"substr\": [\"jsonlogic\", 1, 3]}", null)); - } - - @Test - public void testSubstringDoubleNegativeArg() throws JsonLogicException { - assertEquals("log", jsonLogic.apply("{\"substr\": [\"jsonlogic\", 4, -2]}", null)); - } - - @Test - public void testSubstringSingleArgOutOfBounds() throws JsonLogicException { - assertEquals("", jsonLogic.apply("{\"substr\": [\"jsonlogic\", -40]}", null)); - } - - @Test - public void testSubstringDoubleArgOutOfBounds() throws JsonLogicException { - assertEquals("", jsonLogic.apply("{\"substr\": [\"jsonlogic\", 20, -40]}", null)); - } + private static final JsonLogic jsonLogic = new JsonLogic(); + + @Test + public void testSubstringSingleArg() throws JsonLogicException { + assertEquals("logic", jsonLogic.apply("{\"substr\": [\"jsonlogic\", 4]}", null)); + } + + @Test + public void testSubstringSingleNegativeArg() throws JsonLogicException { + assertEquals("logic", jsonLogic.apply("{\"substr\": [\"jsonlogic\", -5]}", null)); + } + + @Test + public void testSubstringDoubleArg() throws JsonLogicException { + assertEquals("son", jsonLogic.apply("{\"substr\": [\"jsonlogic\", 1, 3]}", null)); + } + + @Test + public void testSubstringDoubleNegativeArg() throws JsonLogicException { + assertEquals("log", jsonLogic.apply("{\"substr\": [\"jsonlogic\", 4, -2]}", null)); + } + + @Test + public void testSubstringSingleArgOutOfBounds() throws JsonLogicException { + assertEquals("", jsonLogic.apply("{\"substr\": [\"jsonlogic\", -40]}", null)); + } + + @Test + public void testSubstringDoubleArgOutOfBounds() throws JsonLogicException { + assertEquals("", jsonLogic.apply("{\"substr\": [\"jsonlogic\", 20, -40]}", null)); + } } diff --git a/src/test/java/io/github/jamsesso/jsonlogic/TruthyTests.java b/src/test/java/io/github/jamsesso/jsonlogic/TruthyTests.java index bda66ee..afbfc53 100644 --- a/src/test/java/io/github/jamsesso/jsonlogic/TruthyTests.java +++ b/src/test/java/io/github/jamsesso/jsonlogic/TruthyTests.java @@ -8,39 +8,39 @@ import static org.junit.Assert.assertTrue; public class TruthyTests { - @Test - public void testTruthyValues() { - // Zero - assertFalse(JsonLogic.truthy(0)); - - // Any non-zero number - assertTrue(JsonLogic.truthy(1.04)); - assertTrue(JsonLogic.truthy(-1)); - - // Empty array or collection - assertFalse(JsonLogic.truthy(Collections.EMPTY_LIST)); - assertFalse(JsonLogic.truthy(new int[0])); - - // Any non-empty array or collection - assertTrue(JsonLogic.truthy(Collections.singleton(1))); - assertTrue(JsonLogic.truthy(new boolean[] {false})); - - // Empty string - assertFalse(JsonLogic.truthy("")); - - // Any non-empty string - assertTrue(JsonLogic.truthy("hello world")); - assertTrue(JsonLogic.truthy("0")); - - // Null - assertFalse(JsonLogic.truthy(null)); - - // NaN and Infinity - assertFalse(JsonLogic.truthy(Double.NaN)); - assertFalse(JsonLogic.truthy(Float.NaN)); - assertTrue(JsonLogic.truthy(Double.POSITIVE_INFINITY)); - assertTrue(JsonLogic.truthy(Double.NEGATIVE_INFINITY)); - assertTrue(JsonLogic.truthy(Float.POSITIVE_INFINITY)); - assertTrue(JsonLogic.truthy(Float.NEGATIVE_INFINITY)); - } + @Test + public void testTruthyValues() { + // Zero + assertFalse(JsonLogic.truthy(0)); + + // Any non-zero number + assertTrue(JsonLogic.truthy(1.04)); + assertTrue(JsonLogic.truthy(-1)); + + // Empty array or collection + assertFalse(JsonLogic.truthy(Collections.EMPTY_LIST)); + assertFalse(JsonLogic.truthy(new int[0])); + + // Any non-empty array or collection + assertTrue(JsonLogic.truthy(Collections.singleton(1))); + assertTrue(JsonLogic.truthy(new boolean[]{false})); + + // Empty string + assertFalse(JsonLogic.truthy("")); + + // Any non-empty string + assertTrue(JsonLogic.truthy("hello world")); + assertTrue(JsonLogic.truthy("0")); + + // Null + assertFalse(JsonLogic.truthy(null)); + + // NaN and Infinity + assertFalse(JsonLogic.truthy(Double.NaN)); + assertFalse(JsonLogic.truthy(Float.NaN)); + assertTrue(JsonLogic.truthy(Double.POSITIVE_INFINITY)); + assertTrue(JsonLogic.truthy(Double.NEGATIVE_INFINITY)); + assertTrue(JsonLogic.truthy(Float.POSITIVE_INFINITY)); + assertTrue(JsonLogic.truthy(Float.NEGATIVE_INFINITY)); + } } diff --git a/src/test/java/io/github/jamsesso/jsonlogic/VariableTests.java b/src/test/java/io/github/jamsesso/jsonlogic/VariableTests.java index 980fc58..58e271f 100644 --- a/src/test/java/io/github/jamsesso/jsonlogic/VariableTests.java +++ b/src/test/java/io/github/jamsesso/jsonlogic/VariableTests.java @@ -14,203 +14,205 @@ import static org.junit.Assert.assertTrue; public class VariableTests { - private static final JsonLogic jsonLogic = new JsonLogic(); - - @Test - public void testEmptyString() throws JsonLogicException { - assertEquals(3.14, jsonLogic.apply("{\"var\": \"\"}", 3.14)); - } - - @Test - public void testMapAccess() throws JsonLogicException { - Map data = new HashMap() {{ - put("pi", 3.14); - }}; - - assertEquals(3.14, jsonLogic.apply("{\"var\": \"pi\"}", data)); - } - - @Test - public void testDefaultValue() throws JsonLogicException { - assertEquals(3.14, jsonLogic.apply("{\"var\": [\"pi\", 3.14]}", null)); - } - - @Test - public void testUndefined() throws JsonLogicException { - assertNull(jsonLogic.apply("{\"var\": [\"pi\"]}", null)); - assertNull(jsonLogic.apply("{\"var\": \"\"}", null)); - assertNull(jsonLogic.apply("{\"var\": 0}", null)); - } - - @Test - public void testArrayAccess() throws JsonLogicException { - String[] data = new String[] {"hello", "world"}; - - assertEquals("hello", jsonLogic.apply("{\"var\": 0}", data)); - assertEquals("world", jsonLogic.apply("{\"var\": 1}", data)); - assertNull(jsonLogic.apply("{\"var\": 2}", data)); - assertNull(jsonLogic.apply("{\"var\": 3}", data)); - } - - @Test - public void testArrayAccessWithStringKeys() throws JsonLogicException { - String[] data = new String[] {"hello", "world"}; - - assertEquals("hello", jsonLogic.apply("{\"var\": \"0\"}", data)); - assertEquals("world", jsonLogic.apply("{\"var\": \"1\"}", data)); - assertNull(jsonLogic.apply("{\"var\": \"2\"}", data)); - assertNull(jsonLogic.apply("{\"var\": \"3\"}", data)); - } - - @Test - public void testListAccess() throws JsonLogicException { - List data = Arrays.asList("hello", "world"); - - assertEquals("hello", jsonLogic.apply("{\"var\": 0}", data)); - assertEquals("world", jsonLogic.apply("{\"var\": 1}", data)); - assertNull(jsonLogic.apply("{\"var\": 2}", data)); - assertNull(jsonLogic.apply("{\"var\": 3}", data)); - } - - @Test - public void testListAccessWithStringKeys() throws JsonLogicException { - List data = Arrays.asList("hello", "world"); - - assertEquals("hello", jsonLogic.apply("{\"var\": \"0\"}", data)); - assertEquals("world", jsonLogic.apply("{\"var\": \"1\"}", data)); - assertNull(jsonLogic.apply("{\"var\": \"2\"}", data)); - assertNull(jsonLogic.apply("{\"var\": \"3\"}", data)); - } - - @Test - public void testComplexAccess() throws JsonLogicException { - Map data = new HashMap() {{ - put("users", Arrays.asList( - new HashMap() {{ - put("name", "John"); - put("followers", 1337); - }}, - new HashMap() {{ - put("name", "Jane"); - put("followers", 2048); - }} - )); - }}; - - assertEquals("John", jsonLogic.apply("{\"var\": \"users.0.name\"}", data)); - assertEquals(1337.0, jsonLogic.apply("{\"var\": \"users.0.followers\"}", data)); - assertEquals("Jane", jsonLogic.apply("{\"var\": \"users.1.name\"}", data)); - assertEquals(2048.0, jsonLogic.apply("{\"var\": \"users.1.followers\"}", data)); - } - - @Test - public void missingNestedMapKey_returnsDefault() throws JsonLogicException { - // data.a.b is missing -> should use default - String rule = "{\"var\": [\"a.b.c\", \"fallback\"]}"; - Map data = map("a", map("b", new HashMap<>())); - - Object result = jsonLogic.apply(rule, data); - - assertEquals("fallback", result); - } - - @Test - public void presentNullLeaf_returnsNull_notDefault() throws JsonLogicException { - // data.user.age present with value null -> should return null (no default) - String rule = "{\"var\": [\"user.age\", 42]}"; - Map user = new HashMap<>(); - user.put("age", null); - Map data = map("user", user); - - Object result = jsonLogic.apply(rule, data); - - assertNull(result); - } - - @Test - public void intermediateNull_returnsNull_notDefault() throws JsonLogicException { - // data.a.b is null before finishing path -> should return null (no default) - String rule = "{\"var\": [\"a.b.c\", \"fallback\"]}"; - Map data = map("a", map("b", null)); - - Object result = jsonLogic.apply(rule, data); - - assertNull(result); - } - - @Test - public void nonTraversableIntermediate_returnsNull_notDefault() throws JsonLogicException { - // data.a is a number; trying to access a.b -> should return null (no default) - String rule = "{\"var\": [\"a.b\", \"fallback\"]}"; - Map data = map("a", 5); - - Object result = jsonLogic.apply(rule, data); - - assertNull(result); - } - - @Test - public void arrayIndexWithinBounds_returnsElement_asDoubleForNumbers() throws JsonLogicException { - // items.1 exists -> should return 20 (as a double per evaluator.transform) - String rule = "{\"var\": [\"items.1\", 999]}"; - Map data = map("items", Arrays.asList(10, 20)); - - Object result = jsonLogic.apply(rule, data); - - assertTrue(result instanceof Number); - assertEquals(20.0, ((Number) result).doubleValue(), 0.0); - } - - @Test - public void arrayIndexOutOfBounds_returnsDefault() throws JsonLogicException { - // items.2 missing -> use default - String rule = "{\"var\": [\"items.2\", \"missing\"]}"; - Map data = map("items", Arrays.asList(10, 20)); - - Object result = jsonLogic.apply(rule, data); - - assertEquals("missing", result); - } - - @Test - public void arrayElementPresentButNull_returnsNull_notDefault() throws JsonLogicException { - // items.0 exists and is null -> should return null (no default) - String rule = "{\"var\": [\"items.0\", \"missing\"]}"; - Map data = map("items", Collections.singletonList(null)); - - Object result = jsonLogic.apply(rule, data); - - assertNull(result); - } - - @Test - public void topLevelNumericIndex_overList_works() throws JsonLogicException { - // {"var": [1, "missing"]} over a top-level list -> "banana" - String rule = "{\"var\": [1, \"missing\"]}"; - List data = Arrays.asList("apple", "banana", "carrot"); - - Object result = jsonLogic.apply(rule, data); + private static final JsonLogic jsonLogic = new JsonLogic(); - assertEquals("banana", result); - } + @Test + public void testEmptyString() throws JsonLogicException { + assertEquals(3.14, jsonLogic.apply("{\"var\": \"\"}", 3.14)); + } + + @Test + public void testMapAccess() throws JsonLogicException { + Map data = new HashMap() {{ + put("pi", 3.14); + }}; + + assertEquals(3.14, jsonLogic.apply("{\"var\": \"pi\"}", data)); + } + + @Test + public void testDefaultValue() throws JsonLogicException { + assertEquals(3.14, jsonLogic.apply("{\"var\": [\"pi\", 3.14]}", null)); + } + + @Test + public void testUndefined() throws JsonLogicException { + assertNull(jsonLogic.apply("{\"var\": [\"pi\"]}", null)); + assertNull(jsonLogic.apply("{\"var\": \"\"}", null)); + assertNull(jsonLogic.apply("{\"var\": 0}", null)); + } + + @Test + public void testArrayAccess() throws JsonLogicException { + String[] data = new String[]{"hello", "world"}; + + assertEquals("hello", jsonLogic.apply("{\"var\": 0}", data)); + assertEquals("world", jsonLogic.apply("{\"var\": 1}", data)); + assertNull(jsonLogic.apply("{\"var\": 2}", data)); + assertNull(jsonLogic.apply("{\"var\": 3}", data)); + } + + @Test + public void testArrayAccessWithStringKeys() throws JsonLogicException { + String[] data = new String[]{"hello", "world"}; + + assertEquals("hello", jsonLogic.apply("{\"var\": \"0\"}", data)); + assertEquals("world", jsonLogic.apply("{\"var\": \"1\"}", data)); + assertNull(jsonLogic.apply("{\"var\": \"2\"}", data)); + assertNull(jsonLogic.apply("{\"var\": \"3\"}", data)); + } - @Test - public void emptyVarKey_returnsWholeDataObject() throws JsonLogicException { - // {"var": ""} should return the entire data object (same instance) - String rule = "{\"var\": \"\"}"; - Map data = map("x", 1); + @Test + public void testListAccess() throws JsonLogicException { + List data = Arrays.asList("hello", "world"); - Object result = jsonLogic.apply(rule, data); + assertEquals("hello", jsonLogic.apply("{\"var\": 0}", data)); + assertEquals("world", jsonLogic.apply("{\"var\": 1}", data)); + assertNull(jsonLogic.apply("{\"var\": 2}", data)); + assertNull(jsonLogic.apply("{\"var\": 3}", data)); + } + + @Test + public void testListAccessWithStringKeys() throws JsonLogicException { + List data = Arrays.asList("hello", "world"); + + assertEquals("hello", jsonLogic.apply("{\"var\": \"0\"}", data)); + assertEquals("world", jsonLogic.apply("{\"var\": \"1\"}", data)); + assertNull(jsonLogic.apply("{\"var\": \"2\"}", data)); + assertNull(jsonLogic.apply("{\"var\": \"3\"}", data)); + } + + @Test + public void testComplexAccess() throws JsonLogicException { + Map data = new HashMap() {{ + put("users", Arrays.asList( + new HashMap() {{ + put("name", "John"); + put("followers", 1337); + }}, + new HashMap() {{ + put("name", "Jane"); + put("followers", 2048); + }} + )); + }}; + + assertEquals("John", jsonLogic.apply("{\"var\": \"users.0.name\"}", data)); + assertEquals(1337.0, jsonLogic.apply("{\"var\": \"users.0.followers\"}", data)); + assertEquals("Jane", jsonLogic.apply("{\"var\": \"users.1.name\"}", data)); + assertEquals(2048.0, jsonLogic.apply("{\"var\": \"users.1.followers\"}", data)); + } + + @Test + public void missingNestedMapKey_returnsDefault() throws JsonLogicException { + // data.a.b is missing -> should use default + String rule = "{\"var\": [\"a.b.c\", \"fallback\"]}"; + Map data = map("a", map("b", new HashMap<>())); + + Object result = jsonLogic.apply(rule, data); + + assertEquals("fallback", result); + } + + @Test + public void presentNullLeaf_returnsNull_notDefault() throws JsonLogicException { + // data.user.age present with value null -> should return null (no default) + String rule = "{\"var\": [\"user.age\", 42]}"; + Map user = new HashMap<>(); + user.put("age", null); + Map data = map("user", user); + + Object result = jsonLogic.apply(rule, data); + + assertNull(result); + } - assertSame("Should return the same data instance", data, result); - } + @Test + public void intermediateNull_returnsNull_notDefault() throws JsonLogicException { + // data.a.b is null before finishing path -> should return null (no default) + String rule = "{\"var\": [\"a.b.c\", \"fallback\"]}"; + Map data = map("a", map("b", null)); + + Object result = jsonLogic.apply(rule, data); + + assertNull(result); + } + + @Test + public void nonTraversableIntermediate_returnsNull_notDefault() throws JsonLogicException { + // data.a is a number; trying to access a.b -> should return null (no default) + String rule = "{\"var\": [\"a.b\", \"fallback\"]}"; + Map data = map("a", 5); + + Object result = jsonLogic.apply(rule, data); + + assertNull(result); + } + + @Test + public void arrayIndexWithinBounds_returnsElement_asDoubleForNumbers() throws JsonLogicException { + // items.1 exists -> should return 20 (as a double per evaluator.transform) + String rule = "{\"var\": [\"items.1\", 999]}"; + Map data = map("items", Arrays.asList(10, 20)); + + Object result = jsonLogic.apply(rule, data); + + assertTrue(result instanceof Number); + assertEquals(20.0, ((Number) result).doubleValue(), 0.0); + } + + @Test + public void arrayIndexOutOfBounds_returnsDefault() throws JsonLogicException { + // items.2 missing -> use default + String rule = "{\"var\": [\"items.2\", \"missing\"]}"; + Map data = map("items", Arrays.asList(10, 20)); + + Object result = jsonLogic.apply(rule, data); + + assertEquals("missing", result); + } + + @Test + public void arrayElementPresentButNull_returnsNull_notDefault() throws JsonLogicException { + // items.0 exists and is null -> should return null (no default) + String rule = "{\"var\": [\"items.0\", \"missing\"]}"; + Map data = map("items", Collections.singletonList(null)); + + Object result = jsonLogic.apply(rule, data); + + assertNull(result); + } + + @Test + public void topLevelNumericIndex_overList_works() throws JsonLogicException { + // {"var": [1, "missing"]} over a top-level list -> "banana" + String rule = "{\"var\": [1, \"missing\"]}"; + List data = Arrays.asList("apple", "banana", "carrot"); + + Object result = jsonLogic.apply(rule, data); + + assertEquals("banana", result); + } + + @Test + public void emptyVarKey_returnsWholeDataObject() throws JsonLogicException { + // {"var": ""} should return the entire data object (same instance) + String rule = "{\"var\": \"\"}"; + Map data = map("x", 1); + + Object result = jsonLogic.apply(rule, data); + + assertSame("Should return the same data instance", data, result); + } - /** Helper to make small maps concisely. */ - private static Map map(Object... kv) { - Map m = new HashMap<>(); - for (int i = 0; i < kv.length; i += 2) { - m.put((String) kv[i], kv[i + 1]); + /** + * Helper to make small maps concisely. + */ + private static Map map(Object... kv) { + Map m = new HashMap<>(); + for (int i = 0; i < kv.length; i += 2) { + m.put((String) kv[i], kv[i + 1]); + } + return m; } - return m; - } } diff --git a/src/test/resources/error-fixtures.json b/src/test/resources/error-fixtures.json index ab5f3b4..5435a25 100644 --- a/src/test/resources/error-fixtures.json +++ b/src/test/resources/error-fixtures.json @@ -6,272 +6,554 @@ "objects must have exactly 1 key defined, found 0" ], [ - {"all":[1]}, + { + "all": [ + 1 + ] + }, {}, "$.all", "all expects exactly 2 arguments" ], [ - {"all":[{"some":[]}, 1]}, + { + "all": [ + { + "some": [] + }, + 1 + ] + }, {}, "$.all[0].some", "some expects exactly 2 arguments" ], [ - {"all":[[1], {"none":[]}]}, + { + "all": [ + [ + 1 + ], + { + "none": [] + } + ] + }, {}, "$.all[1].none", "none expects exactly 2 arguments" ], [ - {"some":[0, 1]}, + { + "some": [ + 0, + 1 + ] + }, {}, "$.some[0]", "first argument to some must be a valid array" ], [ - {"none":[1, 2]}, + { + "none": [ + 1, + 2 + ] + }, {}, "$.none[0]", "first argument to none must be a valid array" ], [ - {"cat":["foo", {}]}, + { + "cat": [ + "foo", + {} + ] + }, {}, "$.cat[1]", "objects must have exactly 1 key defined, found 0" ], [ - {"==":[0]}, + { + "==": [ + 0 + ] + }, {}, "$.==", "equality expressions expect exactly 2 arguments" ], [ - {"filter":[0]}, + { + "filter": [ + 0 + ] + }, {}, "$.filter", "filter expects exactly 2 arguments" ], [ - {"filter":[1, 2]}, + { + "filter": [ + 1, + 2 + ] + }, {}, "$.filter[0]", "first argument to filter must be a valid array" ], [ - {"filter":["foo", {}]}, + { + "filter": [ + "foo", + {} + ] + }, {}, "$.filter[1]", "objects must have exactly 1 key defined, found 0" ], [ - {"if":[{}]}, + { + "if": [ + {} + ] + }, {}, "$.if[0]", "objects must have exactly 1 key defined, found 0" ], [ - {"if":[true,{}]}, + { + "if": [ + true, + {} + ] + }, {}, "$.if[1]", "objects must have exactly 1 key defined, found 0" ], [ - {"if":[false,1,{"filter":[1]}]}, + { + "if": [ + false, + 1, + { + "filter": [ + 1 + ] + } + ] + }, {}, "$.if[2].filter", "filter expects exactly 2 arguments" ], [ - {"if":[false,1,true,{"filter":[1]}]}, + { + "if": [ + false, + 1, + true, + { + "filter": [ + 1 + ] + } + ] + }, {}, "$.if[3].filter", "filter expects exactly 2 arguments" ], [ - {"!=":[0]}, + { + "!=": [ + 0 + ] + }, {}, "$.!=", "equality expressions expect exactly 2 arguments" ], [ - {"log":[]}, + { + "log": [] + }, {}, "$.log", "log operator requires exactly 1 argument" ], [ - {"and":[]}, + { + "and": [] + }, {}, "$.and", "and operator expects at least 1 argument" ], [ - {"and":[true,{"log":[]}]}, + { + "and": [ + true, + { + "log": [] + } + ] + }, {}, "$.and[1].log", "log operator requires exactly 1 argument" ], [ - {"or":[]}, + { + "or": [] + }, {}, "$.or", "or operator expects at least 1 argument" ], [ - {"map":[1]}, + { + "map": [ + 1 + ] + }, {}, "$.map", "map expects exactly 2 arguments" ], [ - {"+":[1, {"-": [2, {"*": [3, {"/": [4, {"log":[]}]}]}]}]}, + { + "+": [ + 1, + { + "-": [ + 2, + { + "*": [ + 3, + { + "/": [ + 4, + { + "log": [] + } + ] + } + ] + } + ] + } + ] + }, {}, "$.+[1].-[1].*[1]./[1].log", "log operator requires exactly 1 argument" ], [ - {"%":[1, {"min": [2, {"max": [3, {"log":[]}]}]}]}, + { + "%": [ + 1, + { + "min": [ + 2, + { + "max": [ + 3, + { + "log": [] + } + ] + } + ] + } + ] + }, {}, "$.%[1].min[1].max[1].log", "log operator requires exactly 1 argument" ], [ - {"merge":[1, 2, {"log":[]}]}, + { + "merge": [ + 1, + 2, + { + "log": [] + } + ] + }, {}, "$.merge[2].log", "log operator requires exactly 1 argument" ], [ - {"missing_some":[1]}, + { + "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": [ + 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": [] + } + ] + }, {}, "$.missing[1].log", "log operator requires exactly 1 argument" ], [ - {"!":[1, {"log":[]}]}, + { + "!": [ + 1, + { + "log": [] + } + ] + }, {}, "$.![1].log", "log operator requires exactly 1 argument" ], [ - {"!!":[{"log":[]}]}, + { + "!!": [ + { + "log": [] + } + ] + }, {}, "$.!![0].log", "log operator requires exactly 1 argument" ], [ - {"<":[1]}, + { + "<": [ + 1 + ] + }, {}, "$.<", "'<' requires at least 2 arguments" ], [ - {">":[1]}, + { + ">": [ + 1 + ] + }, {}, "$.>", "'>' requires at least 2 arguments" ], [ - {"<=":[1]}, + { + "<=": [ + 1 + ] + }, {}, "$.<=", "'<=' requires at least 2 arguments" ], [ - {">=":[1]}, + { + ">=": [ + 1 + ] + }, {}, "$.>=", "'>=' requires at least 2 arguments" ], [ - {">":[1, {"log":[]}]}, + { + ">": [ + 1, + { + "log": [] + } + ] + }, {}, "$.>[1].log", "log operator requires exactly 1 argument" ], [ - {">":[0, 1, 2, "three", 4, 5, {"log":[]}]}, + { + ">": [ + 0, + 1, + 2, + "three", + 4, + 5, + { + "log": [] + } + ] + }, {}, "$.>[6].log", "log operator requires exactly 1 argument" ], [ - {"reduce":[1]}, + { + "reduce": [ + 1 + ] + }, {}, "$.reduce", "reduce expects exactly 3 arguments" ], [ - {"reduce":[{"log":[]}, 2, 3]}, + { + "reduce": [ + { + "log": [] + }, + 2, + 3 + ] + }, {}, "$.reduce[0].log", "log operator requires exactly 1 argument" ], [ - {"reduce":[[1], {"log":[]}, 3]}, + { + "reduce": [ + [ + 1 + ], + { + "log": [] + }, + 3 + ] + }, {}, "$.reduce[1].log", "log operator requires exactly 1 argument" ], [ - {"reduce":[1, 2, {"log":[]}]}, + { + "reduce": [ + 1, + 2, + { + "log": [] + } + ] + }, {}, "$.reduce[2].log", "log operator requires exactly 1 argument" ], [ - {"===":[1]}, + { + "===": [ + 1 + ] + }, {}, "$.===", "equality expressions expect exactly 2 arguments" ], [ - {"!==":[1]}, + { + "!==": [ + 1 + ] + }, {}, "$.!==", "equality expressions expect exactly 2 arguments" ], [ - {"substr":["jsonlogic"]}, + { + "substr": [ + "jsonlogic" + ] + }, {}, "$.substr", "substr expects 2 or 3 arguments" ], [ - {"substr":["jsonlogic", "one"]}, + { + "substr": [ + "jsonlogic", + "one" + ] + }, {}, "$.substr[1]", "second argument to substr must be a number" ], [ - {"substr":["jsonlogic", 1, "two"]}, + { + "substr": [ + "jsonlogic", + 1, + "two" + ] + }, {}, "$.substr[2]", "third argument to substr must be an integer" ], [ - {"var":[[1, 2]]}, + { + "var": [ + [ + 1, + 2 + ] + ] + }, {}, "$.var[0]", "var first argument must be null, number, or string" ], [ - {"var":"key.foo"}, - {"key": [1, 2]}, + { + "var": "key.foo" + }, + { + "key": [ + 1, + 2 + ] + }, "$.var[0]", "java.lang.NumberFormatException: For input string: \"foo\"" ] diff --git a/src/test/resources/fixtures.json b/src/test/resources/fixtures.json index 8c4f7bf..cdf520b 100644 --- a/src/test/resources/fixtures.json +++ b/src/test/resources/fixtures.json @@ -1,6 +1,15 @@ [ [ - {"+": {"merge": [1, [2]]}}, + { + "+": { + "merge": [ + 1, + [ + 2 + ] + ] + } + }, null, 3 ], @@ -935,7 +944,10 @@ { "+": [ 1, - [2, 3] + [ + 2, + 3 + ] ] }, {}, @@ -1004,8 +1016,14 @@ [ { "*": [ - [3, 4], - [2, 3] + [ + 3, + 4 + ], + [ + 2, + 3 + ] ] }, {}, @@ -1464,7 +1482,6 @@ null, "apple" ], - [ { "if": [ @@ -3793,7 +3810,11 @@ { "var": "" }, - ["item1","item2","item3"] + [ + "item1", + "item2", + "item3" + ] ] } ] @@ -3812,12 +3833,18 @@ { "var": "" }, - ["item1","item2","item3"] + [ + "item1", + "item2", + "item3" + ] ] } ] }, - ["item1"], + [ + "item1" + ], true ], [ @@ -3831,12 +3858,18 @@ { "var": "" }, - ["item1","item2","item3"] + [ + "item1", + "item2", + "item3" + ] ] } ] }, - ["item4"], + [ + "item4" + ], false ], [ @@ -3850,7 +3883,11 @@ { "var": "" }, - ["item1","item2","item3"] + [ + "item1", + "item2", + "item3" + ] ] } ] @@ -3869,12 +3906,20 @@ { "var": "" }, - ["item1","item2","item3"] + [ + "item1", + "item2", + "item3" + ] ] } ] }, - { "item": ["item1"] }, + { + "item": [ + "item1" + ] + }, true ], [ @@ -3888,12 +3933,20 @@ { "var": "" }, - ["item1","item2","item3"] + [ + "item1", + "item2", + "item3" + ] ] } ] }, - { "item": ["item4"] }, + { + "item": [ + "item4" + ] + }, false ] ]