From 9f10714158f6c69a8517358998f3383e02728a4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luiz=20H=2E=20Rapat=C3=A3o?= Date: Thu, 6 Jun 2024 00:01:19 +0100 Subject: [PATCH] feat: modularize project (#22) * create module to allow using kotlin evaluator without importing rhino libraries * create module to contain jackson serialization --- JSON.md | 18 +- README.md | 10 +- build.gradle | 154 +++++++----------- .../projects/ruleset/engine/Evaluator.kt | 3 +- .../ruleset/engine/context/EvalContext.kt | 0 .../ruleset/engine/context/EvalEngine.kt | 0 .../ruleset/engine/types/Expression.kt | 0 .../ruleset/engine/types/OnFailure.kt | 0 .../projects/ruleset/engine/types/Operator.kt | 0 .../engine/types/builder/BetweenBuilder.kt | 0 .../engine/types/builder/ExpressionBuilder.kt | 0 .../engine/types/builder/MatcherBuilder.kt | 0 .../builder/extensions/BetweenExtensions.kt | 0 .../builder/extensions/BooleanExtensions.kt | 0 .../builder/extensions/ContainsExtensions.kt | 0 .../builder/extensions/GenericExtensions.kt | 0 .../extensions/GreaterThanExtensions.kt | 0 .../builder/extensions/LessThanExtensions.kt | 0 .../builder/extensions/WithExtensions.kt | 0 jackson/build.gradle | 9 + .../ruleset/jackson/ExpressionMixin.kt | 0 .../jackson}/SerializationExamplesBuilder.kt | 5 +- .../ruleset/jackson}/SerializationTest.kt | 15 +- kotlin-evaluator/build.gradle | 36 ++++ .../engine/evaluator/kotlin/KotlinContext.kt | 0 .../evaluator/kotlin/KotlinEvalEngine.kt | 6 +- .../ruleset/engine/evaluator/kotlin/Parser.kt | 0 .../evaluator/kotlin/KotlinBenchmark.kt | 7 + .../evaluator/kotlin/KotlinEvalEngineTest.kt | 5 + rhino-evaluator/build.gradle | 37 +++++ .../ruleset/engine/evaluator/rhino/Parser.kt | 0 .../engine/evaluator/rhino/RhinoContext.kt | 0 .../engine/evaluator/rhino/RhinoEvalEngine.kt | 0 .../evaluator/rhino/parameters/MapInjector.kt | 0 .../rhino/parameters/ParameterInjector.kt | 0 .../rhino/parameters/TypedInjector.kt | 0 .../engine/evaluator/rhino/RhinoBenchmark.kt | 7 + .../evaluator/rhino/RhinoEvalEngineTest.kt | 5 + settings.gradle | 6 + .../engine/evaluator/rhino/ParserTest.kt | 83 ---------- tests/build.gradle | 7 + .../ruleset/engine/BaseEngineBenchmark.kt | 49 +++--- .../ruleset/engine/BaseEvaluatorTest.kt | 64 +++++--- .../ruleset/engine/cases/ContainsCases.kt | 0 .../ruleset/engine/cases/ExpressionCases.kt | 9 +- .../ruleset/engine/cases/MatcherCases.kt | 9 + .../ruleset/engine/cases/OnFailureCases.kt | 3 + .../ruleset/engine/cases/OperatorWithCases.kt | 0 .../projects/ruleset/engine/cases/TestData.kt | 24 +-- .../projects/ruleset/engine/helper/Helper.kt | 9 - .../ruleset/engine/types/ExpressionTest.kt | 29 ++-- 51 files changed, 324 insertions(+), 285 deletions(-) rename {src => core/src}/main/kotlin/com/rapatao/projects/ruleset/engine/Evaluator.kt (96%) rename {src => core/src}/main/kotlin/com/rapatao/projects/ruleset/engine/context/EvalContext.kt (100%) rename {src => core/src}/main/kotlin/com/rapatao/projects/ruleset/engine/context/EvalEngine.kt (100%) rename {src => core/src}/main/kotlin/com/rapatao/projects/ruleset/engine/types/Expression.kt (100%) rename {src => core/src}/main/kotlin/com/rapatao/projects/ruleset/engine/types/OnFailure.kt (100%) rename {src => core/src}/main/kotlin/com/rapatao/projects/ruleset/engine/types/Operator.kt (100%) rename {src => core/src}/main/kotlin/com/rapatao/projects/ruleset/engine/types/builder/BetweenBuilder.kt (100%) rename {src => core/src}/main/kotlin/com/rapatao/projects/ruleset/engine/types/builder/ExpressionBuilder.kt (100%) rename {src => core/src}/main/kotlin/com/rapatao/projects/ruleset/engine/types/builder/MatcherBuilder.kt (100%) rename {src => core/src}/main/kotlin/com/rapatao/projects/ruleset/engine/types/builder/extensions/BetweenExtensions.kt (100%) rename {src => core/src}/main/kotlin/com/rapatao/projects/ruleset/engine/types/builder/extensions/BooleanExtensions.kt (100%) rename {src => core/src}/main/kotlin/com/rapatao/projects/ruleset/engine/types/builder/extensions/ContainsExtensions.kt (100%) rename {src => core/src}/main/kotlin/com/rapatao/projects/ruleset/engine/types/builder/extensions/GenericExtensions.kt (100%) rename {src => core/src}/main/kotlin/com/rapatao/projects/ruleset/engine/types/builder/extensions/GreaterThanExtensions.kt (100%) rename {src => core/src}/main/kotlin/com/rapatao/projects/ruleset/engine/types/builder/extensions/LessThanExtensions.kt (100%) rename {src => core/src}/main/kotlin/com/rapatao/projects/ruleset/engine/types/builder/extensions/WithExtensions.kt (100%) create mode 100644 jackson/build.gradle rename {src => jackson/src}/main/kotlin/com/rapatao/projects/ruleset/jackson/ExpressionMixin.kt (100%) rename {src/test/kotlin/com/rapatao/projects/ruleset => jackson/src/test/kotlin/com/rapatao/projects/ruleset/jackson}/SerializationExamplesBuilder.kt (97%) rename {src/test/kotlin/com/rapatao/projects/ruleset/engine => jackson/src/test/kotlin/com/rapatao/projects/ruleset/jackson}/SerializationTest.kt (78%) create mode 100644 kotlin-evaluator/build.gradle rename {src => kotlin-evaluator/src}/main/kotlin/com/rapatao/projects/ruleset/engine/evaluator/kotlin/KotlinContext.kt (100%) rename {src => kotlin-evaluator/src}/main/kotlin/com/rapatao/projects/ruleset/engine/evaluator/kotlin/KotlinEvalEngine.kt (92%) rename {src => kotlin-evaluator/src}/main/kotlin/com/rapatao/projects/ruleset/engine/evaluator/kotlin/Parser.kt (100%) create mode 100644 kotlin-evaluator/src/test/kotlin/com/rapatao/projects/ruleset/engine/evaluator/kotlin/KotlinBenchmark.kt create mode 100644 kotlin-evaluator/src/test/kotlin/com/rapatao/projects/ruleset/engine/evaluator/kotlin/KotlinEvalEngineTest.kt create mode 100644 rhino-evaluator/build.gradle rename {src => rhino-evaluator/src}/main/kotlin/com/rapatao/projects/ruleset/engine/evaluator/rhino/Parser.kt (100%) rename {src => rhino-evaluator/src}/main/kotlin/com/rapatao/projects/ruleset/engine/evaluator/rhino/RhinoContext.kt (100%) rename {src => rhino-evaluator/src}/main/kotlin/com/rapatao/projects/ruleset/engine/evaluator/rhino/RhinoEvalEngine.kt (100%) rename {src => rhino-evaluator/src}/main/kotlin/com/rapatao/projects/ruleset/engine/evaluator/rhino/parameters/MapInjector.kt (100%) rename {src => rhino-evaluator/src}/main/kotlin/com/rapatao/projects/ruleset/engine/evaluator/rhino/parameters/ParameterInjector.kt (100%) rename {src => rhino-evaluator/src}/main/kotlin/com/rapatao/projects/ruleset/engine/evaluator/rhino/parameters/TypedInjector.kt (100%) create mode 100644 rhino-evaluator/src/test/kotlin/com/rapatao/projects/ruleset/engine/evaluator/rhino/RhinoBenchmark.kt create mode 100644 rhino-evaluator/src/test/kotlin/com/rapatao/projects/ruleset/engine/evaluator/rhino/RhinoEvalEngineTest.kt delete mode 100644 src/test/kotlin/com/rapatao/projects/ruleset/engine/evaluator/rhino/ParserTest.kt create mode 100644 tests/build.gradle rename src/test/kotlin/com/rapatao/projects/ruleset/engine/EngineBenchmark.kt => tests/src/main/kotlin/com/rapatao/projects/ruleset/engine/BaseEngineBenchmark.kt (54%) rename src/test/kotlin/com/rapatao/projects/ruleset/engine/EvaluatorTest.kt => tests/src/main/kotlin/com/rapatao/projects/ruleset/engine/BaseEvaluatorTest.kt (59%) rename {src/test => tests/src/main}/kotlin/com/rapatao/projects/ruleset/engine/cases/ContainsCases.kt (100%) rename {src/test => tests/src/main}/kotlin/com/rapatao/projects/ruleset/engine/cases/ExpressionCases.kt (97%) rename {src/test => tests/src/main}/kotlin/com/rapatao/projects/ruleset/engine/cases/MatcherCases.kt (97%) rename {src/test => tests/src/main}/kotlin/com/rapatao/projects/ruleset/engine/cases/OnFailureCases.kt (97%) rename {src/test => tests/src/main}/kotlin/com/rapatao/projects/ruleset/engine/cases/OperatorWithCases.kt (100%) rename {src/test => tests/src/main}/kotlin/com/rapatao/projects/ruleset/engine/cases/TestData.kt (54%) rename {src/test => tests/src/main}/kotlin/com/rapatao/projects/ruleset/engine/helper/Helper.kt (77%) rename {src/test => tests/src/main}/kotlin/com/rapatao/projects/ruleset/engine/types/ExpressionTest.kt (67%) diff --git a/JSON.md b/JSON.md index f356fa4..8db25fa 100644 --- a/JSON.md +++ b/JSON.md @@ -2,7 +2,7 @@ This file is automatically generated during the test phase. -To see more details, check its source: [here](src/test/kotlin/com/rapatao/projects/ruleset/SerializationExamplesBuilder.kt). +To see more details, check its source: [here](src/test/kotlin/com/rapatao/projects/ruleset/jackson/SerializationExamplesBuilder.kt). * equalsTo: @@ -1795,6 +1795,22 @@ To see more details, check its source: [here](src/test/kotlin/com/rapatao/projec } ``` +```json +{ + "left" : "item.arrTags", + "operator" : "CONTAINS", + "right" : "\"in_array\"" +} +``` + +```json +{ + "left" : "item.arrTags", + "operator" : "CONTAINS", + "right" : "\"not_in_array\"" +} +``` + ```json { "left" : "item.name", diff --git a/README.md b/README.md index 7754930..613369b 100644 --- a/README.md +++ b/README.md @@ -11,13 +11,15 @@ Below are the available engines that can be used to evaluate expressions: ### Mozilla Rhino (JavaScript) engine implementation -[Rhino](https://github.com/mozilla/rhino) is an open-source, embeddable JavaScript interpreter from Mozilla. -This engine implementation supports using JavaScript expressions inside the rule operands. +[Mozilla Rhino](https://github.com/mozilla/rhino) is an open-source, embeddable JavaScript interpreter from Mozilla. +This engine implementation supports using JavaScript expressions inside the rule operands and is particularly useful +when rules contain complex logic or when you want to leverage JavaScript's extensive library of functions. ### Kotlin (internal) engine implementation -This engine only uses Kotlin code to support all Operator functions., supporting all Operator functions. -Although it provides an expressive performance, it doesn't support Kotlin expression into the expression operands. +This engine uses only Kotlin code to support all Operator functions, offering expressive performance. Although it +doesn't support Kotlin expressions inside the expression operands, it can be a suitable choice for simpler rule sets or +projects where you prefer using a statically-typed language like Kotlin. Supported types: diff --git a/build.gradle b/build.gradle index 43f897d..5e54ff0 100644 --- a/build.gradle +++ b/build.gradle @@ -1,9 +1,7 @@ -import kotlinx.kover.gradle.plugin.dsl.MetricType - plugins { id "java-library" id "signing" - id 'maven-publish' + id "maven-publish" id "org.jetbrains.kotlin.jvm" version "${kotlinVersion}" id "io.gitlab.arturbosch.detekt" version "${detektVersion}" id "org.jetbrains.kotlinx.kover" version "${koverVersion}" @@ -11,74 +9,81 @@ plugins { id "com.github.ben-manes.versions" version "${BenManerVersionsVersion}" } -group "com.rapatao.ruleset" +allprojects { + apply plugin: "java-library" + apply plugin: "signing" + apply plugin: "maven-publish" + apply plugin: "org.jetbrains.kotlin.jvm" + apply plugin: "io.gitlab.arturbosch.detekt" + apply plugin: "org.jetbrains.kotlinx.kover" +// apply plugin: "io.github.gradle-nexus.publish-plugin" + apply plugin: "com.github.ben-manes.versions" -repositories { - mavenCentral() -} + group "com.rapatao.ruleset" -dependencies { - implementation("org.jetbrains.kotlin:kotlin-stdlib:${kotlinVersion}") - implementation("org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion}") + repositories { + mavenCentral() + } - implementation("org.mozilla:rhino:${rhinoVersion}") + dependencies { + implementation("org.jetbrains.kotlin:kotlin-stdlib:${kotlinVersion}") + implementation("org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion}") + } - compileOnly("com.fasterxml.jackson.core:jackson-databind:${jacksonVersion}") - compileOnly("com.fasterxml.jackson.module:jackson-module-kotlin:${jacksonVersion}") - testImplementation("com.fasterxml.jackson.core:jackson-databind:${jacksonVersion}") - testImplementation("com.fasterxml.jackson.module:jackson-module-kotlin:${jacksonVersion}") + test { + useJUnitPlatform() + } - testRuntimeOnly("org.junit.platform:junit-platform-launcher") - testImplementation("org.junit.jupiter:junit-jupiter:${junitVersion}") - testImplementation("org.hamcrest:hamcrest:${hamcrestVersion}") -} + java { + withSourcesJar() + withJavadocJar() + toolchain { + languageVersion = JavaLanguageVersion.of(11) + } + } -test { - useJUnitPlatform() -} + detekt { + buildUponDefaultConfig = true + allRules = false + } -java { - withSourcesJar() - withJavadocJar() - toolchain { - languageVersion = JavaLanguageVersion.of(11) + signing { + useGpgCmd() + sign publishing.publications } -} -detekt { - buildUponDefaultConfig = true - allRules = false -} + publishing { + publications { + maven(MavenPublication) { + from components.java -koverReport { - verify { - rule { - enabled = true - bound { - metric = MetricType.BRANCH - minValue = 80 - } - bound { - metric = MetricType.LINE - minValue = 90 - } - bound { - metric = MetricType.INSTRUCTION - minValue = 90 + pom { + name = "RuleSet Engine" + description = "Simple yet powerful rules engine that offers the flexibility of using the built-in engine and creating a custom one." + url = "https://github.com/rapatao/ruleset-engine" + packaging = "jar" + licenses { + license { + name = "The Apache License, Version 2.0" + url = "http://www.apache.org/licenses/LICENSE-2.0.txt" + } + } + developers { + developer { + id = "rapatao" + name = "Luiz Henrique Rapatao" + email = "rapatao@rapatao.com" + } + } + scm { + connection = "scm:git:git://github.com/rapatao/ruleset-engine.git" + developerConnection = "scm:git:ssh://github.com/rapatao/ruleset-engine.git" + url = "https://github.com/rapatao/ruleset-engine" + } + } } } } - - defaults { - html { - onCheck = true - } - } -} - -signing { - useGpgCmd() - sign publishing.publications } nexusPublishing { @@ -89,36 +94,3 @@ nexusPublishing { } } } - -publishing { - publications { - maven(MavenPublication) { - from components.java - - pom { - name = "RuleSet Engine" - description = "A simple but fully customizable rule engine" - url = "https://github.com/rapatao/ruleset-engine" - packaging = "jar" - licenses { - license { - name = "The Apache License, Version 2.0" - url = "http://www.apache.org/licenses/LICENSE-2.0.txt" - } - } - developers { - developer { - id = "rapatao" - name = "Luiz Henrique Rapatao" - email = "rapatao@rapatao.com" - } - } - scm { - connection = "scm:git:git://github.com/rapatao/ruleset-engine.git" - developerConnection = "scm:git:ssh://github.com/rapatao/ruleset-engine.git" - url = "https://github.com/rapatao/ruleset-engine" - } - } - } - } -} diff --git a/src/main/kotlin/com/rapatao/projects/ruleset/engine/Evaluator.kt b/core/src/main/kotlin/com/rapatao/projects/ruleset/engine/Evaluator.kt similarity index 96% rename from src/main/kotlin/com/rapatao/projects/ruleset/engine/Evaluator.kt rename to core/src/main/kotlin/com/rapatao/projects/ruleset/engine/Evaluator.kt index fc7a61e..93589e4 100644 --- a/src/main/kotlin/com/rapatao/projects/ruleset/engine/Evaluator.kt +++ b/core/src/main/kotlin/com/rapatao/projects/ruleset/engine/Evaluator.kt @@ -2,7 +2,6 @@ package com.rapatao.projects.ruleset.engine import com.rapatao.projects.ruleset.engine.context.EvalContext import com.rapatao.projects.ruleset.engine.context.EvalEngine -import com.rapatao.projects.ruleset.engine.evaluator.rhino.RhinoEvalEngine import com.rapatao.projects.ruleset.engine.types.Expression import com.rapatao.projects.ruleset.engine.types.OnFailure @@ -12,7 +11,7 @@ import com.rapatao.projects.ruleset.engine.types.OnFailure * @property engine The factory used to create a context for evaluating the expressions. */ class Evaluator( - private val engine: EvalEngine = RhinoEvalEngine(), + private val engine: EvalEngine, ) { /** diff --git a/src/main/kotlin/com/rapatao/projects/ruleset/engine/context/EvalContext.kt b/core/src/main/kotlin/com/rapatao/projects/ruleset/engine/context/EvalContext.kt similarity index 100% rename from src/main/kotlin/com/rapatao/projects/ruleset/engine/context/EvalContext.kt rename to core/src/main/kotlin/com/rapatao/projects/ruleset/engine/context/EvalContext.kt diff --git a/src/main/kotlin/com/rapatao/projects/ruleset/engine/context/EvalEngine.kt b/core/src/main/kotlin/com/rapatao/projects/ruleset/engine/context/EvalEngine.kt similarity index 100% rename from src/main/kotlin/com/rapatao/projects/ruleset/engine/context/EvalEngine.kt rename to core/src/main/kotlin/com/rapatao/projects/ruleset/engine/context/EvalEngine.kt diff --git a/src/main/kotlin/com/rapatao/projects/ruleset/engine/types/Expression.kt b/core/src/main/kotlin/com/rapatao/projects/ruleset/engine/types/Expression.kt similarity index 100% rename from src/main/kotlin/com/rapatao/projects/ruleset/engine/types/Expression.kt rename to core/src/main/kotlin/com/rapatao/projects/ruleset/engine/types/Expression.kt diff --git a/src/main/kotlin/com/rapatao/projects/ruleset/engine/types/OnFailure.kt b/core/src/main/kotlin/com/rapatao/projects/ruleset/engine/types/OnFailure.kt similarity index 100% rename from src/main/kotlin/com/rapatao/projects/ruleset/engine/types/OnFailure.kt rename to core/src/main/kotlin/com/rapatao/projects/ruleset/engine/types/OnFailure.kt diff --git a/src/main/kotlin/com/rapatao/projects/ruleset/engine/types/Operator.kt b/core/src/main/kotlin/com/rapatao/projects/ruleset/engine/types/Operator.kt similarity index 100% rename from src/main/kotlin/com/rapatao/projects/ruleset/engine/types/Operator.kt rename to core/src/main/kotlin/com/rapatao/projects/ruleset/engine/types/Operator.kt diff --git a/src/main/kotlin/com/rapatao/projects/ruleset/engine/types/builder/BetweenBuilder.kt b/core/src/main/kotlin/com/rapatao/projects/ruleset/engine/types/builder/BetweenBuilder.kt similarity index 100% rename from src/main/kotlin/com/rapatao/projects/ruleset/engine/types/builder/BetweenBuilder.kt rename to core/src/main/kotlin/com/rapatao/projects/ruleset/engine/types/builder/BetweenBuilder.kt diff --git a/src/main/kotlin/com/rapatao/projects/ruleset/engine/types/builder/ExpressionBuilder.kt b/core/src/main/kotlin/com/rapatao/projects/ruleset/engine/types/builder/ExpressionBuilder.kt similarity index 100% rename from src/main/kotlin/com/rapatao/projects/ruleset/engine/types/builder/ExpressionBuilder.kt rename to core/src/main/kotlin/com/rapatao/projects/ruleset/engine/types/builder/ExpressionBuilder.kt diff --git a/src/main/kotlin/com/rapatao/projects/ruleset/engine/types/builder/MatcherBuilder.kt b/core/src/main/kotlin/com/rapatao/projects/ruleset/engine/types/builder/MatcherBuilder.kt similarity index 100% rename from src/main/kotlin/com/rapatao/projects/ruleset/engine/types/builder/MatcherBuilder.kt rename to core/src/main/kotlin/com/rapatao/projects/ruleset/engine/types/builder/MatcherBuilder.kt diff --git a/src/main/kotlin/com/rapatao/projects/ruleset/engine/types/builder/extensions/BetweenExtensions.kt b/core/src/main/kotlin/com/rapatao/projects/ruleset/engine/types/builder/extensions/BetweenExtensions.kt similarity index 100% rename from src/main/kotlin/com/rapatao/projects/ruleset/engine/types/builder/extensions/BetweenExtensions.kt rename to core/src/main/kotlin/com/rapatao/projects/ruleset/engine/types/builder/extensions/BetweenExtensions.kt diff --git a/src/main/kotlin/com/rapatao/projects/ruleset/engine/types/builder/extensions/BooleanExtensions.kt b/core/src/main/kotlin/com/rapatao/projects/ruleset/engine/types/builder/extensions/BooleanExtensions.kt similarity index 100% rename from src/main/kotlin/com/rapatao/projects/ruleset/engine/types/builder/extensions/BooleanExtensions.kt rename to core/src/main/kotlin/com/rapatao/projects/ruleset/engine/types/builder/extensions/BooleanExtensions.kt diff --git a/src/main/kotlin/com/rapatao/projects/ruleset/engine/types/builder/extensions/ContainsExtensions.kt b/core/src/main/kotlin/com/rapatao/projects/ruleset/engine/types/builder/extensions/ContainsExtensions.kt similarity index 100% rename from src/main/kotlin/com/rapatao/projects/ruleset/engine/types/builder/extensions/ContainsExtensions.kt rename to core/src/main/kotlin/com/rapatao/projects/ruleset/engine/types/builder/extensions/ContainsExtensions.kt diff --git a/src/main/kotlin/com/rapatao/projects/ruleset/engine/types/builder/extensions/GenericExtensions.kt b/core/src/main/kotlin/com/rapatao/projects/ruleset/engine/types/builder/extensions/GenericExtensions.kt similarity index 100% rename from src/main/kotlin/com/rapatao/projects/ruleset/engine/types/builder/extensions/GenericExtensions.kt rename to core/src/main/kotlin/com/rapatao/projects/ruleset/engine/types/builder/extensions/GenericExtensions.kt diff --git a/src/main/kotlin/com/rapatao/projects/ruleset/engine/types/builder/extensions/GreaterThanExtensions.kt b/core/src/main/kotlin/com/rapatao/projects/ruleset/engine/types/builder/extensions/GreaterThanExtensions.kt similarity index 100% rename from src/main/kotlin/com/rapatao/projects/ruleset/engine/types/builder/extensions/GreaterThanExtensions.kt rename to core/src/main/kotlin/com/rapatao/projects/ruleset/engine/types/builder/extensions/GreaterThanExtensions.kt diff --git a/src/main/kotlin/com/rapatao/projects/ruleset/engine/types/builder/extensions/LessThanExtensions.kt b/core/src/main/kotlin/com/rapatao/projects/ruleset/engine/types/builder/extensions/LessThanExtensions.kt similarity index 100% rename from src/main/kotlin/com/rapatao/projects/ruleset/engine/types/builder/extensions/LessThanExtensions.kt rename to core/src/main/kotlin/com/rapatao/projects/ruleset/engine/types/builder/extensions/LessThanExtensions.kt diff --git a/src/main/kotlin/com/rapatao/projects/ruleset/engine/types/builder/extensions/WithExtensions.kt b/core/src/main/kotlin/com/rapatao/projects/ruleset/engine/types/builder/extensions/WithExtensions.kt similarity index 100% rename from src/main/kotlin/com/rapatao/projects/ruleset/engine/types/builder/extensions/WithExtensions.kt rename to core/src/main/kotlin/com/rapatao/projects/ruleset/engine/types/builder/extensions/WithExtensions.kt diff --git a/jackson/build.gradle b/jackson/build.gradle new file mode 100644 index 0000000..de011b9 --- /dev/null +++ b/jackson/build.gradle @@ -0,0 +1,9 @@ +dependencies { + implementation project(":core") + + implementation("com.fasterxml.jackson.core:jackson-databind:${jacksonVersion}") + implementation("com.fasterxml.jackson.module:jackson-module-kotlin:${jacksonVersion}") + + testImplementation project(":tests") + testImplementation project(":kotlin-evaluator") +} diff --git a/src/main/kotlin/com/rapatao/projects/ruleset/jackson/ExpressionMixin.kt b/jackson/src/main/kotlin/com/rapatao/projects/ruleset/jackson/ExpressionMixin.kt similarity index 100% rename from src/main/kotlin/com/rapatao/projects/ruleset/jackson/ExpressionMixin.kt rename to jackson/src/main/kotlin/com/rapatao/projects/ruleset/jackson/ExpressionMixin.kt diff --git a/src/test/kotlin/com/rapatao/projects/ruleset/SerializationExamplesBuilder.kt b/jackson/src/test/kotlin/com/rapatao/projects/ruleset/jackson/SerializationExamplesBuilder.kt similarity index 97% rename from src/test/kotlin/com/rapatao/projects/ruleset/SerializationExamplesBuilder.kt rename to jackson/src/test/kotlin/com/rapatao/projects/ruleset/jackson/SerializationExamplesBuilder.kt index 0af4c2b..df1d1a8 100644 --- a/src/test/kotlin/com/rapatao/projects/ruleset/SerializationExamplesBuilder.kt +++ b/jackson/src/test/kotlin/com/rapatao/projects/ruleset/jackson/SerializationExamplesBuilder.kt @@ -1,4 +1,4 @@ -package com.rapatao.projects.ruleset +package com.rapatao.projects.ruleset.jackson import com.fasterxml.jackson.annotation.JsonInclude import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper @@ -17,7 +17,6 @@ import com.rapatao.projects.ruleset.engine.types.builder.extensions.lessOrEqualT import com.rapatao.projects.ruleset.engine.types.builder.extensions.lessThan import com.rapatao.projects.ruleset.engine.types.builder.extensions.notEqualsTo import com.rapatao.projects.ruleset.engine.types.builder.extensions.startsWith -import com.rapatao.projects.ruleset.jackson.ExpressionMixin import org.junit.jupiter.api.Test import java.nio.file.Path import java.nio.file.Paths @@ -138,7 +137,7 @@ internal class SerializationExamplesBuilder { } private fun createJsonMD(): Path { - val jsonMD = Paths.get("JSON.md") + val jsonMD = Paths.get("../JSON.md") if (jsonMD.exists()) { jsonMD.writeText("") diff --git a/src/test/kotlin/com/rapatao/projects/ruleset/engine/SerializationTest.kt b/jackson/src/test/kotlin/com/rapatao/projects/ruleset/jackson/SerializationTest.kt similarity index 78% rename from src/test/kotlin/com/rapatao/projects/ruleset/engine/SerializationTest.kt rename to jackson/src/test/kotlin/com/rapatao/projects/ruleset/jackson/SerializationTest.kt index 036389a..3de7e69 100644 --- a/src/test/kotlin/com/rapatao/projects/ruleset/engine/SerializationTest.kt +++ b/jackson/src/test/kotlin/com/rapatao/projects/ruleset/jackson/SerializationTest.kt @@ -1,11 +1,12 @@ -package com.rapatao.projects.ruleset.engine +package com.rapatao.projects.ruleset.jackson +import com.fasterxml.jackson.annotation.JsonInclude +import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.fasterxml.jackson.module.kotlin.readValue import com.rapatao.projects.ruleset.engine.cases.TestData -import com.rapatao.projects.ruleset.engine.context.EvalEngine +import com.rapatao.projects.ruleset.engine.evaluator.kotlin.KotlinEvalEngine import com.rapatao.projects.ruleset.engine.helper.Helper.compareMatcher import com.rapatao.projects.ruleset.engine.helper.Helper.doEvaluationTest -import com.rapatao.projects.ruleset.engine.helper.Helper.mapper import com.rapatao.projects.ruleset.engine.types.Expression import com.rapatao.projects.ruleset.engine.types.OnFailure.THROW import com.rapatao.projects.ruleset.engine.types.OnFailure.TRUE @@ -17,6 +18,10 @@ import org.junit.jupiter.params.provider.MethodSource class SerializationTest { + private val mapper = jacksonObjectMapper() + .setSerializationInclusion(JsonInclude.Include.NON_NULL) + .addMixIn(Expression::class.java, ExpressionMixin::class.java) + companion object { @JvmStatic fun tests() = TestData.allCases() @@ -24,14 +29,14 @@ class SerializationTest { @ParameterizedTest @MethodSource("tests") - fun doSerializationTest(engine: EvalEngine, matcher: Expression, expected: Boolean) { + fun doSerializationTest(matcher: Expression, expected: Boolean) { val json = mapper.writeValueAsString(matcher) val matcherFromJson = mapper.readValue(json) compareMatcher(matcher, matcherFromJson) - doEvaluationTest(engine, matcherFromJson, expected) + doEvaluationTest(KotlinEvalEngine(), matcherFromJson, expected) } @Test diff --git a/kotlin-evaluator/build.gradle b/kotlin-evaluator/build.gradle new file mode 100644 index 0000000..4586a5a --- /dev/null +++ b/kotlin-evaluator/build.gradle @@ -0,0 +1,36 @@ +import kotlinx.kover.gradle.plugin.dsl.MetricType + +dependencies { + api project(":core") + + testImplementation project(":tests") +} + +koverReport { + verify { + rule { + enabled = true + bound { + enabled = true + metric = MetricType.BRANCH + minValue = 70 + } + bound { + enabled = true + metric = MetricType.LINE + minValue = 90 + } + bound { + enabled = true + metric = MetricType.INSTRUCTION + minValue = 90 + } + } + } + + defaults { + html { + onCheck = true + } + } +} diff --git a/src/main/kotlin/com/rapatao/projects/ruleset/engine/evaluator/kotlin/KotlinContext.kt b/kotlin-evaluator/src/main/kotlin/com/rapatao/projects/ruleset/engine/evaluator/kotlin/KotlinContext.kt similarity index 100% rename from src/main/kotlin/com/rapatao/projects/ruleset/engine/evaluator/kotlin/KotlinContext.kt rename to kotlin-evaluator/src/main/kotlin/com/rapatao/projects/ruleset/engine/evaluator/kotlin/KotlinContext.kt diff --git a/src/main/kotlin/com/rapatao/projects/ruleset/engine/evaluator/kotlin/KotlinEvalEngine.kt b/kotlin-evaluator/src/main/kotlin/com/rapatao/projects/ruleset/engine/evaluator/kotlin/KotlinEvalEngine.kt similarity index 92% rename from src/main/kotlin/com/rapatao/projects/ruleset/engine/evaluator/kotlin/KotlinEvalEngine.kt rename to kotlin-evaluator/src/main/kotlin/com/rapatao/projects/ruleset/engine/evaluator/kotlin/KotlinEvalEngine.kt index 946747a..2b2a217 100644 --- a/src/main/kotlin/com/rapatao/projects/ruleset/engine/evaluator/kotlin/KotlinEvalEngine.kt +++ b/kotlin-evaluator/src/main/kotlin/com/rapatao/projects/ruleset/engine/evaluator/kotlin/KotlinEvalEngine.kt @@ -35,7 +35,11 @@ open class KotlinEvalEngine : EvalEngine { } input is Array<*> -> { - parseKeys(node, params, input) + params[node] = input + + input.forEachIndexed { index, value -> + parseKeys("${node}[${index}]", params, value) + } } input is Map<*, *> -> { diff --git a/src/main/kotlin/com/rapatao/projects/ruleset/engine/evaluator/kotlin/Parser.kt b/kotlin-evaluator/src/main/kotlin/com/rapatao/projects/ruleset/engine/evaluator/kotlin/Parser.kt similarity index 100% rename from src/main/kotlin/com/rapatao/projects/ruleset/engine/evaluator/kotlin/Parser.kt rename to kotlin-evaluator/src/main/kotlin/com/rapatao/projects/ruleset/engine/evaluator/kotlin/Parser.kt diff --git a/kotlin-evaluator/src/test/kotlin/com/rapatao/projects/ruleset/engine/evaluator/kotlin/KotlinBenchmark.kt b/kotlin-evaluator/src/test/kotlin/com/rapatao/projects/ruleset/engine/evaluator/kotlin/KotlinBenchmark.kt new file mode 100644 index 0000000..0a3149b --- /dev/null +++ b/kotlin-evaluator/src/test/kotlin/com/rapatao/projects/ruleset/engine/evaluator/kotlin/KotlinBenchmark.kt @@ -0,0 +1,7 @@ +package com.rapatao.projects.ruleset.engine.evaluator.kotlin + +import com.rapatao.projects.ruleset.engine.BaseEngineBenchmark + +fun main(args: Array) { + BaseEngineBenchmark(KotlinEvalEngine()).main(args) +} diff --git a/kotlin-evaluator/src/test/kotlin/com/rapatao/projects/ruleset/engine/evaluator/kotlin/KotlinEvalEngineTest.kt b/kotlin-evaluator/src/test/kotlin/com/rapatao/projects/ruleset/engine/evaluator/kotlin/KotlinEvalEngineTest.kt new file mode 100644 index 0000000..b94ef9c --- /dev/null +++ b/kotlin-evaluator/src/test/kotlin/com/rapatao/projects/ruleset/engine/evaluator/kotlin/KotlinEvalEngineTest.kt @@ -0,0 +1,5 @@ +package com.rapatao.projects.ruleset.engine.evaluator.kotlin + +import com.rapatao.projects.ruleset.engine.BaseEvaluatorTest + +class KotlinEvalEngineTest : BaseEvaluatorTest(KotlinEvalEngine()) diff --git a/rhino-evaluator/build.gradle b/rhino-evaluator/build.gradle new file mode 100644 index 0000000..c0a9527 --- /dev/null +++ b/rhino-evaluator/build.gradle @@ -0,0 +1,37 @@ +import kotlinx.kover.gradle.plugin.dsl.MetricType + +dependencies { + api project(":core") + api("org.mozilla:rhino:${rhinoVersion}") + + testImplementation project(":tests") +} + +koverReport { + verify { + rule { + enabled = true + bound { + enabled = true + metric = MetricType.BRANCH + minValue = 80 + } + bound { + enabled = true + metric = MetricType.LINE + minValue = 90 + } + bound { + enabled = true + metric = MetricType.INSTRUCTION + minValue = 90 + } + } + } + + defaults { + html { + onCheck = true + } + } +} diff --git a/src/main/kotlin/com/rapatao/projects/ruleset/engine/evaluator/rhino/Parser.kt b/rhino-evaluator/src/main/kotlin/com/rapatao/projects/ruleset/engine/evaluator/rhino/Parser.kt similarity index 100% rename from src/main/kotlin/com/rapatao/projects/ruleset/engine/evaluator/rhino/Parser.kt rename to rhino-evaluator/src/main/kotlin/com/rapatao/projects/ruleset/engine/evaluator/rhino/Parser.kt diff --git a/src/main/kotlin/com/rapatao/projects/ruleset/engine/evaluator/rhino/RhinoContext.kt b/rhino-evaluator/src/main/kotlin/com/rapatao/projects/ruleset/engine/evaluator/rhino/RhinoContext.kt similarity index 100% rename from src/main/kotlin/com/rapatao/projects/ruleset/engine/evaluator/rhino/RhinoContext.kt rename to rhino-evaluator/src/main/kotlin/com/rapatao/projects/ruleset/engine/evaluator/rhino/RhinoContext.kt diff --git a/src/main/kotlin/com/rapatao/projects/ruleset/engine/evaluator/rhino/RhinoEvalEngine.kt b/rhino-evaluator/src/main/kotlin/com/rapatao/projects/ruleset/engine/evaluator/rhino/RhinoEvalEngine.kt similarity index 100% rename from src/main/kotlin/com/rapatao/projects/ruleset/engine/evaluator/rhino/RhinoEvalEngine.kt rename to rhino-evaluator/src/main/kotlin/com/rapatao/projects/ruleset/engine/evaluator/rhino/RhinoEvalEngine.kt diff --git a/src/main/kotlin/com/rapatao/projects/ruleset/engine/evaluator/rhino/parameters/MapInjector.kt b/rhino-evaluator/src/main/kotlin/com/rapatao/projects/ruleset/engine/evaluator/rhino/parameters/MapInjector.kt similarity index 100% rename from src/main/kotlin/com/rapatao/projects/ruleset/engine/evaluator/rhino/parameters/MapInjector.kt rename to rhino-evaluator/src/main/kotlin/com/rapatao/projects/ruleset/engine/evaluator/rhino/parameters/MapInjector.kt diff --git a/src/main/kotlin/com/rapatao/projects/ruleset/engine/evaluator/rhino/parameters/ParameterInjector.kt b/rhino-evaluator/src/main/kotlin/com/rapatao/projects/ruleset/engine/evaluator/rhino/parameters/ParameterInjector.kt similarity index 100% rename from src/main/kotlin/com/rapatao/projects/ruleset/engine/evaluator/rhino/parameters/ParameterInjector.kt rename to rhino-evaluator/src/main/kotlin/com/rapatao/projects/ruleset/engine/evaluator/rhino/parameters/ParameterInjector.kt diff --git a/src/main/kotlin/com/rapatao/projects/ruleset/engine/evaluator/rhino/parameters/TypedInjector.kt b/rhino-evaluator/src/main/kotlin/com/rapatao/projects/ruleset/engine/evaluator/rhino/parameters/TypedInjector.kt similarity index 100% rename from src/main/kotlin/com/rapatao/projects/ruleset/engine/evaluator/rhino/parameters/TypedInjector.kt rename to rhino-evaluator/src/main/kotlin/com/rapatao/projects/ruleset/engine/evaluator/rhino/parameters/TypedInjector.kt diff --git a/rhino-evaluator/src/test/kotlin/com/rapatao/projects/ruleset/engine/evaluator/rhino/RhinoBenchmark.kt b/rhino-evaluator/src/test/kotlin/com/rapatao/projects/ruleset/engine/evaluator/rhino/RhinoBenchmark.kt new file mode 100644 index 0000000..fd28d50 --- /dev/null +++ b/rhino-evaluator/src/test/kotlin/com/rapatao/projects/ruleset/engine/evaluator/rhino/RhinoBenchmark.kt @@ -0,0 +1,7 @@ +package com.rapatao.projects.ruleset.engine.evaluator.rhino + +import com.rapatao.projects.ruleset.engine.BaseEngineBenchmark + +fun main(args: Array) { + BaseEngineBenchmark(RhinoEvalEngine()).main(args) +} diff --git a/rhino-evaluator/src/test/kotlin/com/rapatao/projects/ruleset/engine/evaluator/rhino/RhinoEvalEngineTest.kt b/rhino-evaluator/src/test/kotlin/com/rapatao/projects/ruleset/engine/evaluator/rhino/RhinoEvalEngineTest.kt new file mode 100644 index 0000000..476bc52 --- /dev/null +++ b/rhino-evaluator/src/test/kotlin/com/rapatao/projects/ruleset/engine/evaluator/rhino/RhinoEvalEngineTest.kt @@ -0,0 +1,5 @@ +package com.rapatao.projects.ruleset.engine.evaluator.rhino + +import com.rapatao.projects.ruleset.engine.BaseEvaluatorTest + +class RhinoEvalEngineTest : BaseEvaluatorTest(RhinoEvalEngine()) diff --git a/settings.gradle b/settings.gradle index 9bec8ee..4814013 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1,7 @@ rootProject.name = 'ruleset-engine' + +include('core') +include('rhino-evaluator') +include('kotlin-evaluator') +include('jackson') +include('tests') diff --git a/src/test/kotlin/com/rapatao/projects/ruleset/engine/evaluator/rhino/ParserTest.kt b/src/test/kotlin/com/rapatao/projects/ruleset/engine/evaluator/rhino/ParserTest.kt deleted file mode 100644 index c89a6fd..0000000 --- a/src/test/kotlin/com/rapatao/projects/ruleset/engine/evaluator/rhino/ParserTest.kt +++ /dev/null @@ -1,83 +0,0 @@ -package com.rapatao.projects.ruleset.engine.evaluator.rhino - -import com.rapatao.projects.ruleset.engine.types.Expression -import com.rapatao.projects.ruleset.engine.types.Operator -import com.rapatao.projects.ruleset.engine.types.builder.extensions.endsWith -import com.rapatao.projects.ruleset.engine.types.builder.extensions.equalsTo -import com.rapatao.projects.ruleset.engine.types.builder.extensions.expContains -import com.rapatao.projects.ruleset.engine.types.builder.extensions.greaterOrEqualThan -import com.rapatao.projects.ruleset.engine.types.builder.extensions.greaterThan -import com.rapatao.projects.ruleset.engine.types.builder.extensions.lessOrEqualThan -import com.rapatao.projects.ruleset.engine.types.builder.extensions.lessThan -import com.rapatao.projects.ruleset.engine.types.builder.extensions.notEqualsTo -import com.rapatao.projects.ruleset.engine.types.builder.extensions.startsWith -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.emptyString -import org.hamcrest.Matchers.hasSize -import org.hamcrest.Matchers.not -import org.junit.jupiter.api.Test -import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.Arguments -import org.junit.jupiter.params.provider.MethodSource - -class ParserTest { - - companion object { - @JvmStatic - fun cases() = listOf( - Arguments.of( - ("field" equalsTo 10), - ), - Arguments.of( - ("field" notEqualsTo 10), - ), - Arguments.of( - ("field" greaterThan 10), - ), - Arguments.of( - ("field" greaterOrEqualThan 10), - ), - Arguments.of( - ("field" lessThan 10), - ), - Arguments.of( - ("field" lessOrEqualThan 10), - ), - Arguments.of( - ("field" startsWith 10), - ), - Arguments.of( - ("field" endsWith 10), - ), - Arguments.of( - ("field" expContains "iel"), - ), - ) - } - - @ParameterizedTest - @MethodSource("cases") - fun `parse as expected`(expression: Expression) { - assertThat(Parser.parse(expression), not(emptyString())) - } - - @Test - fun `all operator is mapped`() { - val values: Set = Operator.entries.toSet() - - val withCases: Set = cases().mapNotNull { - val expression: Expression = it.get().first() as Expression - expression.operator() - }.toSet() - - assertThat(values.subtract(withCases), hasSize(0)) - - val parsed = values.map { - Parser.parse(Expression(left = "field", operator = it, right = 10)) - }.filter { - !it.contains("null") && it.trim().isNotEmpty() - }.toSet() - - assertThat(parsed, hasSize(values.size)) - } -} diff --git a/tests/build.gradle b/tests/build.gradle new file mode 100644 index 0000000..5286198 --- /dev/null +++ b/tests/build.gradle @@ -0,0 +1,7 @@ +dependencies { + implementation project(":core") + + runtimeOnly("org.junit.platform:junit-platform-launcher") + api("org.junit.jupiter:junit-jupiter:${junitVersion}") + api("org.hamcrest:hamcrest:${hamcrestVersion}") +} diff --git a/src/test/kotlin/com/rapatao/projects/ruleset/engine/EngineBenchmark.kt b/tests/src/main/kotlin/com/rapatao/projects/ruleset/engine/BaseEngineBenchmark.kt similarity index 54% rename from src/test/kotlin/com/rapatao/projects/ruleset/engine/EngineBenchmark.kt rename to tests/src/main/kotlin/com/rapatao/projects/ruleset/engine/BaseEngineBenchmark.kt index 11eb211..1012ecc 100644 --- a/src/test/kotlin/com/rapatao/projects/ruleset/engine/EngineBenchmark.kt +++ b/tests/src/main/kotlin/com/rapatao/projects/ruleset/engine/BaseEngineBenchmark.kt @@ -7,34 +7,28 @@ import kotlin.time.Duration import kotlin.time.DurationUnit import kotlin.time.measureTimedValue -fun main(args: Array) { +class BaseEngineBenchmark(private val evalEngine: EvalEngine) { + @Suppress("MagicNumber") + fun main(args: Array) { - val evaluators = TestData.engines() - .map { it.get().first { arg -> arg is EvalEngine } } - .map { it as EvalEngine } - .map { Evaluator(engine = it) } + val cases = TestData.cases() + .map { it.get().first { arg -> arg is Expression } } + .map { it as Expression } - val cases = TestData.cases() - .map { it.get().first { arg -> arg is Expression } } - .map { it as Expression } + val evaluator = Evaluator(engine = evalEngine) - // ini: warmup - evaluators.forEach { evaluator -> + // ini: warmup println("warmup ${evaluator.engine().name()}: start") repeat(100) { cases.forEach { expression -> evaluator.evaluate(expression, TestData.inputData) } } println("warmup ${evaluator.engine().name()}: done") - } - // end: warmup + // end: warmup - val times = evaluators.associate { - it.engine().name() to mutableListOf() - }.toMutableMap() + val times = mutableListOf() - val iterations = args.firstOrNull()?.let { Integer.parseInt(it) } ?: 1000 + val iterations = args.firstOrNull()?.let { Integer.parseInt(it) } ?: 1000 - println() + println() - evaluators.forEach { evaluator -> repeat(iterations) { val time = measureTimedValue { @@ -43,24 +37,23 @@ fun main(args: Array) { print("\r${evaluator.engine().name()}: ${it + 1}") - times[evaluator.engine().name()]?.add(time.duration) + times.add(time.duration) } - } + println() - println() + println() - times.forEach { (engine, results) -> - val total = results.reduce { acc, duration -> acc + duration } + val total = times.reduce { acc, duration -> acc + duration } - println("$engine> iterations: $iterations") + println("$evalEngine> iterations: $iterations") println(" ops: " + (iterations * cases.size)) println(" ops/s: " + ((iterations * cases.size) / total.toDouble(DurationUnit.SECONDS))) println(" total: $total") - println(" max: " + results.max()) - println(" min: " + results.min()) - println(" avg: " + (total / results.size)) + println(" max: " + times.max()) + println(" min: " + times.min()) + println(" avg: " + (total / times.size)) - val sortedResults = results.sorted() + val sortedResults = times.sorted() listOf(0.50, 0.75, 0.90, 0.95, 0.99).forEach { p -> println( " p${(p * 100).toInt()}: " + sortedResults[(sortedResults.size * p).toInt() diff --git a/src/test/kotlin/com/rapatao/projects/ruleset/engine/EvaluatorTest.kt b/tests/src/main/kotlin/com/rapatao/projects/ruleset/engine/BaseEvaluatorTest.kt similarity index 59% rename from src/test/kotlin/com/rapatao/projects/ruleset/engine/EvaluatorTest.kt rename to tests/src/main/kotlin/com/rapatao/projects/ruleset/engine/BaseEvaluatorTest.kt index 77eff69..02e798b 100644 --- a/src/test/kotlin/com/rapatao/projects/ruleset/engine/EvaluatorTest.kt +++ b/tests/src/main/kotlin/com/rapatao/projects/ruleset/engine/BaseEvaluatorTest.kt @@ -9,20 +9,22 @@ import com.rapatao.projects.ruleset.engine.types.builder.MatcherBuilder.allMatch import com.rapatao.projects.ruleset.engine.types.builder.extensions.equalsTo import com.rapatao.projects.ruleset.engine.types.builder.extensions.ifFail import org.hamcrest.MatcherAssert.assertThat +import org.hamcrest.Matchers.emptyString import org.hamcrest.Matchers.equalTo +import org.hamcrest.Matchers.not +import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.Arguments import org.junit.jupiter.params.provider.MethodSource -internal class EvaluatorTest { +abstract class BaseEvaluatorTest( + private val evalEngine: EvalEngine +) { companion object { - @JvmStatic - fun engines() = TestData.engines() - @JvmStatic fun tests() = TestData.allCases() @@ -32,42 +34,42 @@ internal class EvaluatorTest { @ParameterizedTest @MethodSource("tests") - fun runEvaluationTest(engine: EvalEngine, ruleSet: Expression, expected: Boolean) { + fun runEvaluationTest(ruleSet: Expression, expected: Boolean) { println(ruleSet) - doEvaluationTest(engine, ruleSet, expected) + doEvaluationTest(evalEngine, ruleSet, expected) } @ParameterizedTest @MethodSource("onFailure") - fun `assert onFailure`(engine: EvalEngine, ruleSet: Expression, expected: Boolean, isError: Boolean) { + fun asserOnFailure(ruleSet: Expression, expected: Boolean, isError: Boolean) { println(ruleSet) if (isError) { assertThrows { - doEvaluationTest(engine, ruleSet, expected) + doEvaluationTest(evalEngine, ruleSet, expected) } } else { - doEvaluationTest(engine, ruleSet, expected) + doEvaluationTest(evalEngine, ruleSet, expected) } } @Test - fun `run single test case`() { - val caseNumber = 242 + @Suppress("MagicNumber") + fun assertSingleCaseForDebugging() { + val caseNumber = 122 val cases: List = tests() val test = cases[caseNumber - 1].get() runEvaluationTest( - test[0] as EvalEngine, - test[1] as Expression, - test[2] as Boolean + test[0] as Expression, + test[1] as Boolean ) } - @ParameterizedTest - @MethodSource("engines") - fun `should support map as input data`(engine: EvalEngine) { + @Test + @DisplayName("should support map as input data") + fun assertMapAsInputDataSupport() { val input = mapOf( "item" to mapOf( "price" to 0, @@ -86,36 +88,44 @@ internal class EvaluatorTest { "attributes.info.description" equalsTo "\"super description\"", ) - val result = Evaluator(engine = engine).evaluate(rule, input) + val result = Evaluator(engine = evalEngine).evaluate(rule, input) assertThat(result, equalTo(true)) } - @ParameterizedTest - @MethodSource("engines") - fun `should throw exception when failure was not defined`(engine: EvalEngine) { + @Test + @DisplayName("should throw exception when failure was not defined") + @Suppress("MagicNumber") + fun assertThrowExceptionWhenFailureIsNotDefined() { val invalidRule = "[]unkown$" equalsTo 10 val input = mapOf() assertThrows { - Evaluator(engine = engine).evaluate(invalidRule, input) + Evaluator(engine = evalEngine).evaluate(invalidRule, input) } } - @ParameterizedTest - @MethodSource("engines") - fun `should override value when failure was defined`(engine: EvalEngine) { + @Test + @DisplayName("should override value when failure was defined") + @Suppress("MagicNumber") + fun assertOverrideValueWhenFailureIsDefined() { val invalidRule = "[]unkown$" equalsTo 10 val input = mapOf() assertThat( - Evaluator(engine = engine).evaluate(invalidRule ifFail OnFailure.TRUE, input), + Evaluator(engine = evalEngine).evaluate(invalidRule ifFail OnFailure.TRUE, input), equalTo(true) ) assertThat( - Evaluator(engine = engine).evaluate(invalidRule ifFail OnFailure.FALSE, input), + Evaluator(engine = evalEngine).evaluate(invalidRule ifFail OnFailure.FALSE, input), equalTo(false) ) } + + @Test + @DisplayName("evaluator must have a non empty name") + fun assertEvaluatorMustHaveName() { + assertThat(evalEngine.name(), not(emptyString())) + } } diff --git a/src/test/kotlin/com/rapatao/projects/ruleset/engine/cases/ContainsCases.kt b/tests/src/main/kotlin/com/rapatao/projects/ruleset/engine/cases/ContainsCases.kt similarity index 100% rename from src/test/kotlin/com/rapatao/projects/ruleset/engine/cases/ContainsCases.kt rename to tests/src/main/kotlin/com/rapatao/projects/ruleset/engine/cases/ContainsCases.kt diff --git a/src/test/kotlin/com/rapatao/projects/ruleset/engine/cases/ExpressionCases.kt b/tests/src/main/kotlin/com/rapatao/projects/ruleset/engine/cases/ExpressionCases.kt similarity index 97% rename from src/test/kotlin/com/rapatao/projects/ruleset/engine/cases/ExpressionCases.kt rename to tests/src/main/kotlin/com/rapatao/projects/ruleset/engine/cases/ExpressionCases.kt index 67c3ba7..6928a92 100644 --- a/src/test/kotlin/com/rapatao/projects/ruleset/engine/cases/ExpressionCases.kt +++ b/tests/src/main/kotlin/com/rapatao/projects/ruleset/engine/cases/ExpressionCases.kt @@ -28,6 +28,7 @@ object ExpressionCases { lessOrEqualThanCases() + greaterOrEqualThanCases() + @Suppress("MagicNumber") private fun greaterOrEqualThanCases() = listOf( Arguments.of( "item.price" greaterOrEqualThan 1, @@ -55,6 +56,7 @@ object ExpressionCases { ), ) + @Suppress("MagicNumber") private fun lessOrEqualThanCases() = listOf( Arguments.of( "item.price" lessOrEqualThan 100, @@ -82,6 +84,7 @@ object ExpressionCases { ), ) + @Suppress("MagicNumber") private fun lessThanCases() = listOf( Arguments.of( "item.price" lessThan 100, @@ -109,6 +112,7 @@ object ExpressionCases { ), ) + @Suppress("MagicNumber") private fun greaterThanCases() = listOf( Arguments.of( "item.price" greaterThan 0, @@ -132,6 +136,7 @@ object ExpressionCases { ), ) + @Suppress("MagicNumber") private fun equalsCases() = listOf( Arguments.of( "item.price" equalsTo 10, @@ -142,7 +147,7 @@ object ExpressionCases { false ), ) - + @Suppress("MagicNumber") private fun notEqualsCases() = listOf( Arguments.of( "item.price" notEqualsTo 0, @@ -216,7 +221,7 @@ object ExpressionCases { ), ) - @SuppressWarnings("LongMethod") + @Suppress("MagicNumber", "LongMethod") private fun betweenCases() = listOf( Arguments.of( "item.price" from 5 to 15, diff --git a/src/test/kotlin/com/rapatao/projects/ruleset/engine/cases/MatcherCases.kt b/tests/src/main/kotlin/com/rapatao/projects/ruleset/engine/cases/MatcherCases.kt similarity index 97% rename from src/test/kotlin/com/rapatao/projects/ruleset/engine/cases/MatcherCases.kt rename to tests/src/main/kotlin/com/rapatao/projects/ruleset/engine/cases/MatcherCases.kt index 21f8833..17e628a 100644 --- a/src/test/kotlin/com/rapatao/projects/ruleset/engine/cases/MatcherCases.kt +++ b/tests/src/main/kotlin/com/rapatao/projects/ruleset/engine/cases/MatcherCases.kt @@ -3,6 +3,7 @@ package com.rapatao.projects.ruleset.engine.cases import com.rapatao.projects.ruleset.engine.types.builder.MatcherBuilder.allMatch import com.rapatao.projects.ruleset.engine.types.builder.MatcherBuilder.anyMatch import com.rapatao.projects.ruleset.engine.types.builder.MatcherBuilder.noneMatch +import com.rapatao.projects.ruleset.engine.types.builder.extensions.expContains import com.rapatao.projects.ruleset.engine.types.builder.extensions.greaterOrEqualThan import com.rapatao.projects.ruleset.engine.types.builder.extensions.lessOrEqualThan import org.junit.jupiter.params.provider.Arguments @@ -401,5 +402,13 @@ object MatcherCases { ), false ), + Arguments.of( + "item.arrTags" expContains "\"in_array\"", + true + ), + Arguments.of( + "item.arrTags" expContains "\"not_in_array\"", + false + ), ) } diff --git a/src/test/kotlin/com/rapatao/projects/ruleset/engine/cases/OnFailureCases.kt b/tests/src/main/kotlin/com/rapatao/projects/ruleset/engine/cases/OnFailureCases.kt similarity index 97% rename from src/test/kotlin/com/rapatao/projects/ruleset/engine/cases/OnFailureCases.kt rename to tests/src/main/kotlin/com/rapatao/projects/ruleset/engine/cases/OnFailureCases.kt index 3360447..f9cbaea 100644 --- a/src/test/kotlin/com/rapatao/projects/ruleset/engine/cases/OnFailureCases.kt +++ b/tests/src/main/kotlin/com/rapatao/projects/ruleset/engine/cases/OnFailureCases.kt @@ -9,6 +9,7 @@ object OnFailureCases { fun cases(): List = anyMatchCases() + allMatchCases() + noneMatchCases() + @Suppress("MagicNumber") private fun anyMatchCases(): List = listOf( Arguments.of( Expression( @@ -51,6 +52,7 @@ object OnFailureCases { ), ) + @Suppress("MagicNumber") private fun allMatchCases(): List = listOf( Arguments.of( Expression( @@ -93,6 +95,7 @@ object OnFailureCases { ), ) + @Suppress("MagicNumber") private fun noneMatchCases(): List = listOf( Arguments.of( Expression( diff --git a/src/test/kotlin/com/rapatao/projects/ruleset/engine/cases/OperatorWithCases.kt b/tests/src/main/kotlin/com/rapatao/projects/ruleset/engine/cases/OperatorWithCases.kt similarity index 100% rename from src/test/kotlin/com/rapatao/projects/ruleset/engine/cases/OperatorWithCases.kt rename to tests/src/main/kotlin/com/rapatao/projects/ruleset/engine/cases/OperatorWithCases.kt diff --git a/src/test/kotlin/com/rapatao/projects/ruleset/engine/cases/TestData.kt b/tests/src/main/kotlin/com/rapatao/projects/ruleset/engine/cases/TestData.kt similarity index 54% rename from src/test/kotlin/com/rapatao/projects/ruleset/engine/cases/TestData.kt rename to tests/src/main/kotlin/com/rapatao/projects/ruleset/engine/cases/TestData.kt index 556e0cb..f1dfd28 100644 --- a/src/test/kotlin/com/rapatao/projects/ruleset/engine/cases/TestData.kt +++ b/tests/src/main/kotlin/com/rapatao/projects/ruleset/engine/cases/TestData.kt @@ -1,8 +1,5 @@ package com.rapatao.projects.ruleset.engine.cases -import com.rapatao.projects.ruleset.engine.context.EvalEngine -import com.rapatao.projects.ruleset.engine.evaluator.kotlin.KotlinEvalEngine -import com.rapatao.projects.ruleset.engine.evaluator.rhino.RhinoEvalEngine import org.junit.jupiter.params.provider.Arguments import java.math.BigDecimal @@ -18,6 +15,7 @@ object TestData { val falseValue: Boolean = false, val name: String, val tags: List, + val arrTags: Array, ) val inputData = RequestData( @@ -26,26 +24,14 @@ object TestData { price = BigDecimal.TEN, tags = listOf( "test", "brand-new" - ) + ), + arrTags = arrayOf("in_array") ) ) - fun engines(): List = listOf( - Arguments.of(RhinoEvalEngine()), - Arguments.of(KotlinEvalEngine()), - ) + fun allCases(): List = cases() - fun allCases(): List = cases().flatMap { - engines().map { engine -> - Arguments.of(engine.get().first { it is EvalEngine }, *it.get()) - } - } - - fun onFailureCases(): List = (OnFailureCases.cases()).flatMap { - engines().map { engine -> - Arguments.of(engine.get().first { it is EvalEngine }, *it.get()) - } - } + fun onFailureCases(): List = (OnFailureCases.cases()) fun cases() = ExpressionCases.cases() + diff --git a/src/test/kotlin/com/rapatao/projects/ruleset/engine/helper/Helper.kt b/tests/src/main/kotlin/com/rapatao/projects/ruleset/engine/helper/Helper.kt similarity index 77% rename from src/test/kotlin/com/rapatao/projects/ruleset/engine/helper/Helper.kt rename to tests/src/main/kotlin/com/rapatao/projects/ruleset/engine/helper/Helper.kt index bb18ea4..4bf7710 100644 --- a/src/test/kotlin/com/rapatao/projects/ruleset/engine/helper/Helper.kt +++ b/tests/src/main/kotlin/com/rapatao/projects/ruleset/engine/helper/Helper.kt @@ -1,23 +1,14 @@ package com.rapatao.projects.ruleset.engine.helper -import com.fasterxml.jackson.annotation.JsonInclude -import com.fasterxml.jackson.databind.ObjectMapper -import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.rapatao.projects.ruleset.engine.Evaluator import com.rapatao.projects.ruleset.engine.cases.TestData import com.rapatao.projects.ruleset.engine.context.EvalEngine import com.rapatao.projects.ruleset.engine.types.Expression -import com.rapatao.projects.ruleset.jackson.ExpressionMixin import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.equalTo object Helper { - @JvmStatic - val mapper: ObjectMapper = jacksonObjectMapper() - .setSerializationInclusion(JsonInclude.Include.NON_NULL) - .addMixIn(Expression::class.java, ExpressionMixin::class.java) - fun doEvaluationTest(engine: EvalEngine, ruleSet: Expression, expected: Boolean) { val evaluator = Evaluator(engine = engine) diff --git a/src/test/kotlin/com/rapatao/projects/ruleset/engine/types/ExpressionTest.kt b/tests/src/main/kotlin/com/rapatao/projects/ruleset/engine/types/ExpressionTest.kt similarity index 67% rename from src/test/kotlin/com/rapatao/projects/ruleset/engine/types/ExpressionTest.kt rename to tests/src/main/kotlin/com/rapatao/projects/ruleset/engine/types/ExpressionTest.kt index e173622..64575e2 100644 --- a/src/test/kotlin/com/rapatao/projects/ruleset/engine/types/ExpressionTest.kt +++ b/tests/src/main/kotlin/com/rapatao/projects/ruleset/engine/types/ExpressionTest.kt @@ -2,18 +2,21 @@ package com.rapatao.projects.ruleset.engine.types import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.equalTo +import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test class ExpressionTest { @Test - fun `empty expression must be invalid`() { + @DisplayName("empty expression must be invalid") + fun assertEmptyExpression() { val exp = Expression() assertThat(exp.isValid(), equalTo(false)) } @Test - fun `expression with operator is valid`() { + @DisplayName("expression with operator is valid") + fun assertExpressionValid() { val exp = Expression( operator = Operator.EQUALS, ) @@ -22,7 +25,8 @@ class ExpressionTest { } @Test - fun `no operator, but with noneMatch is valid`() { + @DisplayName("no operator, but with noneMatch is valid") + fun assertNoOperatorByNoneMatch() { val exp = Expression( noneMatch = listOf(Expression(operator = Operator.EQUALS)), ) @@ -31,7 +35,8 @@ class ExpressionTest { } @Test - fun `no operator, but with anyMatch is valid`() { + @DisplayName("no operator, but with anyMatch is valid") + fun assertNoOperatorButWithAnyMatch() { val exp = Expression( anyMatch = listOf(Expression(operator = Operator.EQUALS)), ) @@ -40,7 +45,8 @@ class ExpressionTest { } @Test - fun `no operator, but with allMatch is valid`() { + @DisplayName("no operator, but with allMatch is valid") + fun assertNoOperatorButWithAllMatch() { val exp = Expression( allMatch = listOf(Expression(operator = Operator.EQUALS)), ) @@ -49,7 +55,8 @@ class ExpressionTest { } @Test - fun `is valid if group and operator is set and valid`() { + @DisplayName("is valid if group and operator is set and valid") + fun assertIsValidIfGroupAndOperatorIsSetAndValid() { val exp = Expression( allMatch = listOf(Expression(operator = Operator.EQUALS)), noneMatch = listOf(Expression(operator = Operator.EQUALS)), @@ -59,9 +66,9 @@ class ExpressionTest { assertThat(exp.isValid(), equalTo(true)) } - @Test - fun `is invalid if allMatch contains an invalid expression`() { + @DisplayName("is invalid if allMatch contains an invalid expression") + fun assertIsInvalidIfAllMatchContainsAnInvalidExpression() { val exp = Expression( allMatch = listOf(Expression()), noneMatch = listOf(Expression(operator = Operator.EQUALS)), @@ -72,7 +79,8 @@ class ExpressionTest { } @Test - fun `is invalid if noneMatch contains an invalid expression`() { + @DisplayName("is invalid if noneMatch contains an invalid expression") + fun assertIsInvalidIfNoneMatchContainsInvalidExpression() { val exp = Expression( allMatch = listOf(Expression(operator = Operator.EQUALS)), noneMatch = listOf(Expression()), @@ -83,7 +91,8 @@ class ExpressionTest { } @Test - fun `is invalid if anyMatch contains an invalid expression`() { + @DisplayName("is invalid if anyMatch contains an invalid expression") + fun assertIsInvalidIfAnyMatchContainsInvalidExpression() { val exp = Expression( allMatch = listOf(Expression(operator = Operator.EQUALS)), noneMatch = listOf(Expression(operator = Operator.EQUALS)),