{"id":30111174,"url":"https://github.com/limitium/camuda-eval","last_synced_at":"2025-10-20T04:51:01.470Z","repository":{"id":308515401,"uuid":"1028456973","full_name":"limitium/camuda-eval","owner":"limitium","description":null,"archived":false,"fork":false,"pushed_at":"2025-08-06T11:30:06.000Z","size":70,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-08-06T11:34:33.526Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/limitium.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-07-29T14:57:27.000Z","updated_at":"2025-08-06T11:30:10.000Z","dependencies_parsed_at":"2025-08-06T11:34:35.981Z","dependency_job_id":"e793cda9-fa2b-425a-ac90-34ead6bb3555","html_url":"https://github.com/limitium/camuda-eval","commit_stats":null,"previous_names":["limitium/camuda-eval"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/limitium/camuda-eval","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/limitium%2Fcamuda-eval","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/limitium%2Fcamuda-eval/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/limitium%2Fcamuda-eval/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/limitium%2Fcamuda-eval/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/limitium","download_url":"https://codeload.github.com/limitium/camuda-eval/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/limitium%2Fcamuda-eval/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":269681301,"owners_count":24458595,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-10T02:00:08.965Z","response_time":71,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-08-10T05:30:43.236Z","updated_at":"2025-10-20T04:51:01.466Z","avatar_url":"https://github.com/limitium.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Camunda DMN Evaluator (Multi-Module)\n\nThis project provides a modular Java framework for evaluating Camunda DMN decision tables and collecting test coverage, with YAML-based test definitions.\n\n## Modules\n\n- **evaluator**: Core DMN evaluation logic, coverage collection, and YAML reporting utilities.\n- **evaluator-test**: All tests and test resources (DMN and YAML files). Depends on `evaluator`.\n\n## Build \u0026 Test\n\n```sh\n./gradlew build\n./gradlew :evaluator-test:test\n```\n\n## Directory Structure\n\n- `evaluator/` - Core library\n- `evaluator-test/` - Tests and test resources\n- `build.gradle` - Root build config (minimal)\n- `.gitignore` - Standard Java/Gradle ignores\n\n## Usage Examples\n\n### DmnEvaluator - Core Evaluation\n\nThe `DmnEvaluator` class provides methods to load and evaluate DMN decision tables with support for typed outputs.\n\n#### Basic Usage\n\n```java\nimport limitium.art.camunda.evaluator.DmnEvaluator;\nimport org.camunda.bpm.engine.variable.Variables;\nimport java.nio.file.Paths;\n\n// Load DMN from file\nDmnEvaluator evaluator = new DmnEvaluator();\nDmnEvaluator.DmnDecisionEvaluator decision = evaluator.loadRule(\n    Paths.get(\"src/main/resources/my-decision.dmn\"), \n    \"MyDecision\"\n);\n\n// Evaluate with variables\nVariableMap vars = Variables.createVariables()\n    .putValue(\"age\", 25)\n    .putValue(\"country\", \"US\");\n\n// Get raw result\nDmnDecisionResult result = decision.evaluate(vars);\nString output = result.getSingleResult().getSingleEntry();\n```\n\n#### Typed Evaluation Methods\n\n```java\n// String output\nString stringResult = decision.evaluateToString(vars);\n\n// Boolean output (supports boolean values and \"true\"/\"false\" strings)\nBoolean boolResult = decision.evaluateToBoolean(vars);\n\n// Number output (supports numeric values and numeric strings)\nNumber numResult = decision.evaluateToNumber(vars);\n\n// Using Map instead of VariableMap\nMap\u003cString, Object\u003e inputMap = Map.of(\"age\", 25, \"country\", \"US\");\nString result = decision.evaluateToString(inputMap);\n```\n\n#### String-based DMN Loading\n\n```java\nString dmnXml = \"\u003c?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?\u003e\" +\n    \"\u003cdefinitions xmlns=\\\"https://www.omg.org/spec/DMN/20191111/MODEL/\\\"\u003e\" +\n    \"  \u003cdecision id=\\\"MyDecision\\\"\u003e\" +\n    \"    \u003cdecisionTable hitPolicy=\\\"FIRST\\\"\u003e\" +\n    \"      \u003cinput id=\\\"age\\\"\u003e\" +\n    \"        \u003cinputExpression typeRef=\\\"number\\\"\u003e\u003ctext\u003eage\u003c/text\u003e\u003c/inputExpression\u003e\" +\n    \"      \u003c/input\u003e\" +\n    \"      \u003coutput id=\\\"result\\\" typeRef=\\\"string\\\"/\u003e\" +\n    \"      \u003crule id=\\\"rule1\\\"\u003e\" +\n    \"        \u003cinputEntry\u003e\u003ctext\u003eage \u003e= 18\u003c/text\u003e\u003c/inputEntry\u003e\" +\n    \"        \u003coutputEntry\u003e\u003ctext\u003e\\\"Adult\\\"\u003c/text\u003e\u003c/outputEntry\u003e\" +\n    \"      \u003c/rule\u003e\" +\n    \"    \u003c/decisionTable\u003e\" +\n    \"  \u003c/decision\u003e\" +\n    \"\u003c/definitions\u003e\";\n\nDmnEvaluator.DmnDecisionEvaluator decision = evaluator.loadRuleFromString(dmnXml, \"MyDecision\");\n```\n\n#### Coverage Collection\n\n```java\n// Enable coverage collection\nevaluator.setCollectCoverage(true);\n\n// Run evaluations...\ndecision.evaluate(vars);\n\n// Get coverage events\nList\u003cDmnEvaluator.CoverageEvent\u003e events = evaluator.getCoverageEvents();\nfor (DmnEvaluator.CoverageEvent event : events) {\n    System.out.println(\"Decision: \" + event.decisionKey + \n                      \", Rule: \" + event.ruleId + \n                      \", Parameters: \" + event.parameters);\n}\n```\n\n### DmnYamlTestFactory - YAML-based Testing\n\nThe `DmnYamlTestFactory` creates JUnit 5 dynamic tests from YAML test specifications.\n\n#### YAML Test Format\n\nCreate a YAML file (e.g., `my-decision.yaml`) alongside your DMN file:\n\n```yaml\ntests:\n  - description: \"Adult user should get adult recommendation\"\n    decision: \"AgeDecision\"\n    in:\n      age: 25\n      country: \"US\"\n    out: \"Adult\"\n    \n  - description: \"Minor user should get minor recommendation\"\n    decision: \"AgeDecision\"\n    in:\n      age: 16\n      country: \"US\"\n    out: \"Minor\"\n    \n  - description: \"Boolean decision test\"\n    decision: \"EligibleDecision\"\n    in:\n      age: 21\n      hasLicense: true\n    out: true\n    \n  - description: \"Numeric decision test\"\n    decision: \"ScoreDecision\"\n    in:\n      points: 85\n    out: 100\n```\n\n#### JUnit 5 Integration\n\n```java\nimport limitium.art.camunda.evaluator.junit.DmnYamlTestFactory;\nimport org.junit.jupiter.api.DynamicTest;\nimport org.junit.jupiter.api.TestFactory;\nimport java.nio.file.Paths;\nimport java.util.stream.Stream;\n\npublic class MyDmnTests {\n    \n    @TestFactory\n    Stream\u003cDynamicTest\u003e dmnTests() throws Exception {\n        return DmnYamlTestFactory.from(Paths.get(\"src/test/resources\"));\n    }\n    \n    // Or with separate DMN and YAML directories\n    @TestFactory\n    Stream\u003cDynamicTest\u003e dmnTestsSeparate() throws Exception {\n        return DmnYamlTestFactory.from(\n            Paths.get(\"src/test/resources/dmn\"),\n            Paths.get(\"src/test/resources/yaml\")\n        );\n    }\n}\n```\n\n#### Supported Output Types\n\nThe factory supports multiple output types in YAML:\n\n```yaml\ntests:\n  # String output\n  - decision: \"StringDecision\"\n    in: { input: \"value\" }\n    out: \"result\"\n    \n  # Boolean output\n  - decision: \"BooleanDecision\"\n    in: { flag: true }\n    out: true\n    \n  # Number output (integer)\n  - decision: \"NumberDecision\"\n    in: { value: 42 }\n    out: 100\n    \n  # Number output (decimal)\n  - decision: \"DecimalDecision\"\n    in: { value: 1.5 }\n    out: 3.14\n```\n\n#### Coverage Reports\n\nWhen using `DmnYamlTestFactory`, coverage reports are automatically generated at JVM shutdown:\n\n```\n=== DMN Test Coverage Report (YAML) ===\nsrc/test/resources/my-decision.dmn:\n  AgeDecision:\n    totalRules: 2\n    coveredRules: 2\n    coverage: 1.0\n    uncoveredRules: []\n  _summary:\n    totalRules: 2\n    coveredRules: 2\n    coverage: 1.0\n=== End of Coverage Report ===\n```\n\n## Adding DMN or YAML Tests\n\nPlace DMN and YAML files in `evaluator-test/src/test/resources/` and test classes in `evaluator-test/src/test/java/limitium/art/camunda/evaluator/`.\n\n## Requirements\n- Java 8+\n- Gradle 7+\n\n## Dependencies\n\n- Camunda DMN Engine 7.17.0\n- JUnit 5.10.0\n- SnakeYAML 2.2\n\n---\n\nFor more examples, see the test files in the `evaluator-test` module. ","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flimitium%2Fcamuda-eval","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flimitium%2Fcamuda-eval","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flimitium%2Fcamuda-eval/lists"}