From 54dec11e6150121df822b3552b155bb5fd583fe2 Mon Sep 17 00:00:00 2001 From: Anton Vasetenkov Date: Thu, 20 Jun 2024 19:21:46 +1200 Subject: [PATCH 1/5] Fixes for ProperContains, ProperIncludedIn, ProperIncludes, ProperIn evaluators handling nulls. --- .../org/hl7/fhirpath/CQLOperationsR4Test.java | 3 -- .../hl7/fhirpath/cql/CqlListOperatorsTest.xml | 16 +++++------ .../executing/ProperContainsEvaluator.java | 4 +++ .../elm/executing/ProperInEvaluator.java | 3 ++ .../executing/ProperIncludedInEvaluator.java | 18 +----------- .../executing/ProperIncludesEvaluator.java | 28 +++---------------- .../engine/execution/ListOperatorsTest.java | 20 ++++++------- .../engine/execution/CqlListOperatorsTest.cql | 8 +++--- .../engine/execution/CqlPerformanceTest.cql | 8 +++--- .../cqf/cql/engine/execution/CqlTestSuite.cql | 8 +++--- 10 files changed, 42 insertions(+), 74 deletions(-) diff --git a/Src/java/engine-fhir/src/test/java/org/hl7/fhirpath/CQLOperationsR4Test.java b/Src/java/engine-fhir/src/test/java/org/hl7/fhirpath/CQLOperationsR4Test.java index 4721cfd8c..97c2ee191 100644 --- a/Src/java/engine-fhir/src/test/java/org/hl7/fhirpath/CQLOperationsR4Test.java +++ b/Src/java/engine-fhir/src/test/java/org/hl7/fhirpath/CQLOperationsR4Test.java @@ -118,11 +118,8 @@ public static Object[][] dataMethod() { "cql/CqlListOperatorsTest/NotEqual/NotEqual123AndABC", "cql/CqlListOperatorsTest/NotEqual/NotEqual123AndString123", "cql/CqlListOperatorsTest/NotEqual/NotEqualABCAnd123", - "cql/CqlListOperatorsTest/ProperContains/ProperContainsNullRightFalse", "cql/CqlListOperatorsTest/ProperContains/ProperContainsTimeNull", "cql/CqlListOperatorsTest/ProperIn/ProperInTimeNull", - "cql/CqlListOperatorsTest/ProperlyIncludedIn/ProperlyIncludedInNulRight", - "cql/CqlListOperatorsTest/ProperlyIncludes/ProperlyIncludesNullLeft", "cql/CqlListOperatorsTest/Union/UnionListNullAndListNull", "cql/CqlStringOperatorsTest/toString tests/DateTimeToString3", "cql/CqlTypeOperatorsTest/As/AsQuantity", diff --git a/Src/java/engine-fhir/src/test/resources/org/hl7/fhirpath/cql/CqlListOperatorsTest.xml b/Src/java/engine-fhir/src/test/resources/org/hl7/fhirpath/cql/CqlListOperatorsTest.xml index ce3bc6364..049797e0e 100644 --- a/Src/java/engine-fhir/src/test/resources/org/hl7/fhirpath/cql/CqlListOperatorsTest.xml +++ b/Src/java/engine-fhir/src/test/resources/org/hl7/fhirpath/cql/CqlListOperatorsTest.xml @@ -650,13 +650,13 @@ - + {'s', 'u', 'n'} properly includes null - false + null - + {'s', 'u', 'n', null} properly includes null - true + null { @T15:59:59, @T20:59:59.999, @T20:59:49.999 } properly includes @T15:59:59 @@ -668,13 +668,13 @@ - + null properly included in {'s', 'u', 'n'} - false + null - + null properly included in {'s', 'u', 'n', null} - true + null @T15:59:59 properly included in { @T15:59:59, @T20:59:59.999, @T20:59:49.999 } diff --git a/Src/java/engine/src/main/java/org/opencds/cqf/cql/engine/elm/executing/ProperContainsEvaluator.java b/Src/java/engine/src/main/java/org/opencds/cqf/cql/engine/elm/executing/ProperContainsEvaluator.java index 5f100816f..2d52b2f28 100644 --- a/Src/java/engine/src/main/java/org/opencds/cqf/cql/engine/elm/executing/ProperContainsEvaluator.java +++ b/Src/java/engine/src/main/java/org/opencds/cqf/cql/engine/elm/executing/ProperContainsEvaluator.java @@ -55,6 +55,10 @@ public static Boolean properContains(Object left, Object right, State state) { } public static Boolean properContains(Object left, Object right, String precision, State state) { + if (left == null || right == null) { + return null; + } + if (left instanceof Interval && right instanceof BaseTemporal) { Boolean startProperContains = AfterEvaluator.after(right, ((Interval) left).getStart(), precision, state); Boolean endProperContains = BeforeEvaluator.before(right, ((Interval) left).getEnd(), precision, state); diff --git a/Src/java/engine/src/main/java/org/opencds/cqf/cql/engine/elm/executing/ProperInEvaluator.java b/Src/java/engine/src/main/java/org/opencds/cqf/cql/engine/elm/executing/ProperInEvaluator.java index 158d2f5d8..e4b52ac2a 100644 --- a/Src/java/engine/src/main/java/org/opencds/cqf/cql/engine/elm/executing/ProperInEvaluator.java +++ b/Src/java/engine/src/main/java/org/opencds/cqf/cql/engine/elm/executing/ProperInEvaluator.java @@ -28,6 +28,9 @@ public static Boolean properIn(Object left, Object right, String precision, Stat } public static Object internalEvaluate(Object left, Object right, String precision, State state) { + if (left == null || right == null) { + return null; + } if (precision != null) { return properIn(left, right, precision, state); diff --git a/Src/java/engine/src/main/java/org/opencds/cqf/cql/engine/elm/executing/ProperIncludedInEvaluator.java b/Src/java/engine/src/main/java/org/opencds/cqf/cql/engine/elm/executing/ProperIncludedInEvaluator.java index c119f822a..2eb374a69 100644 --- a/Src/java/engine/src/main/java/org/opencds/cqf/cql/engine/elm/executing/ProperIncludedInEvaluator.java +++ b/Src/java/engine/src/main/java/org/opencds/cqf/cql/engine/elm/executing/ProperIncludedInEvaluator.java @@ -23,30 +23,14 @@ properly included in(left List, right list) Boolean The properly included in operator for lists returns true if every element of the first list is in the second list and the first list is strictly smaller than the second list. This operator uses the notion of equivalence to determine whether or not two elements are the same. -If the left argument is null, the result is true if the right argument is not empty. Otherwise, if the right argument is null, the result is false. +If either argument is null, the result is null. Note that the order of elements does not matter for the purposes of determining inclusion. */ public class ProperIncludedInEvaluator { public static Object properlyIncludedIn(Object left, Object right, String precision, State state) { - if (left == null && right == null) { - return null; - } - try { - if (left == null) { - return right instanceof Interval - ? ProperIncludesEvaluator.intervalProperlyIncludes((Interval) right, null, precision, state) - : ProperIncludesEvaluator.listProperlyIncludes((Iterable) right, null, state); - } - - if (right == null) { - return left instanceof Interval - ? ProperIncludesEvaluator.intervalProperlyIncludes(null, (Interval) left, precision, state) - : ProperIncludesEvaluator.listProperlyIncludes(null, (Iterable) left, state); - } - return ProperIncludesEvaluator.properlyIncludes(right, left, precision, state); } catch (InvalidOperatorArgument e) { throw new InvalidOperatorArgument( diff --git a/Src/java/engine/src/main/java/org/opencds/cqf/cql/engine/elm/executing/ProperIncludesEvaluator.java b/Src/java/engine/src/main/java/org/opencds/cqf/cql/engine/elm/executing/ProperIncludesEvaluator.java index 08c559b19..fa7f6c99b 100644 --- a/Src/java/engine/src/main/java/org/opencds/cqf/cql/engine/elm/executing/ProperIncludesEvaluator.java +++ b/Src/java/engine/src/main/java/org/opencds/cqf/cql/engine/elm/executing/ProperIncludesEvaluator.java @@ -24,33 +24,21 @@ properly includes(left List, right List) Boolean The properly includes operator for lists returns true if the first list contains every element of the second list, a nd the first list is strictly larger than the second list. This operator uses the notion of equivalence to determine whether or not two elements are the same. -If the left argument is null, the result is false, else if the right argument is null, the result is true if the left argument is not empty. +If either argument is null, the result is null. Note that the order of elements does not matter for the purposes of determining inclusion. */ public class ProperIncludesEvaluator { public static Boolean properlyIncludes(Object left, Object right, String precision, State state) { - if (left == null && right == null) { + if (left == null || right == null) { return null; } - if (left == null) { - return right instanceof Interval - ? intervalProperlyIncludes(null, (Interval) right, precision, state) - : listProperlyIncludes(null, (Iterable) right, state); - } - - if (right == null) { - return left instanceof Interval - ? intervalProperlyIncludes((Interval) left, null, precision, state) - : listProperlyIncludes((Iterable) left, null, state); - } - - if (left instanceof Interval && right instanceof Interval) { + if (left instanceof Interval) { return intervalProperlyIncludes((Interval) left, (Interval) right, precision, state); } - if (left instanceof Iterable && right instanceof Iterable) { + if (left instanceof Iterable) { return listProperlyIncludes((Iterable) left, (Iterable) right, state); } @@ -62,10 +50,6 @@ public static Boolean properlyIncludes(Object left, Object right, String precisi } public static Boolean intervalProperlyIncludes(Interval left, Interval right, String precision, State state) { - if (left == null || right == null) { - return null; - } - Object leftStart = left.getStart(); Object leftEnd = left.getEnd(); Object rightStart = right.getStart(); @@ -88,10 +72,6 @@ public static Boolean intervalProperlyIncludes(Interval left, Interval right, St } public static Boolean listProperlyIncludes(Iterable left, Iterable right, State state) { - if (left == null) { - return false; - } - int leftCount = (int) StreamSupport.stream(((Iterable) left).spliterator(), false).count(); diff --git a/Src/java/engine/src/test/java/org/opencds/cqf/cql/engine/execution/ListOperatorsTest.java b/Src/java/engine/src/test/java/org/opencds/cqf/cql/engine/execution/ListOperatorsTest.java index 193bd8faa..595bce2c6 100644 --- a/Src/java/engine/src/test/java/org/opencds/cqf/cql/engine/execution/ListOperatorsTest.java +++ b/Src/java/engine/src/test/java/org/opencds/cqf/cql/engine/execution/ListOperatorsTest.java @@ -569,16 +569,16 @@ void all_interval_operators() { assertThat(value, is(false)); value = results.forExpression("ProperlyIncludesNullLeft").value(); - assertThat(value, is(false)); + assertThat(value, is(nullValue())); value = results.forExpression("ProperlyIncludes1And111").value(); assertThat(value, is(false)); - value = results.forExpression("ProperContainsNullRightFalse").value(); - assertThat(value, is(false)); + value = results.forExpression("ProperContainsNullRightWithoutNull").value(); + assertThat(value, is(nullValue())); - value = results.forExpression("ProperContainsNullRightTrue").value(); - assertThat(value, is(true)); + value = results.forExpression("ProperContainsNullRightWithNull").value(); + assertThat(value, is(nullValue())); value = results.forExpression("ProperContainsTimeTrue").value(); assertThat(value, is(true)); @@ -586,11 +586,11 @@ void all_interval_operators() { value = results.forExpression("ProperContainsTimeNull").value(); assertThat(value, is(false)); - value = results.forExpression("ProperInNullRightFalse").value(); - assertThat(value, is(false)); + value = results.forExpression("ProperInNullRightWithoutNull").value(); + assertThat(value, is(nullValue())); - value = results.forExpression("ProperInNullRightTrue").value(); - assertThat(value, is(true)); + value = results.forExpression("ProperInNullRightWithNull").value(); + assertThat(value, is(nullValue())); value = results.forExpression("ProperInTimeTrue").value(); assertThat(value, is(true)); @@ -626,7 +626,7 @@ void all_interval_operators() { assertThat(value, is(false)); value = results.forExpression("ProperlyIncludedInNullRight").value(); - assertThat(value, is(false)); + assertThat(value, is(nullValue())); value = results.forExpression("ProperlyIncludedIn11And1").value(); assertThat(value, is(false)); diff --git a/Src/java/engine/src/test/resources/org/opencds/cqf/cql/engine/execution/CqlListOperatorsTest.cql b/Src/java/engine/src/test/resources/org/opencds/cqf/cql/engine/execution/CqlListOperatorsTest.cql index 8131bbc4f..8ff7a5bb8 100644 --- a/Src/java/engine/src/test/resources/org/opencds/cqf/cql/engine/execution/CqlListOperatorsTest.cql +++ b/Src/java/engine/src/test/resources/org/opencds/cqf/cql/engine/execution/CqlListOperatorsTest.cql @@ -209,14 +209,14 @@ define ProperlyIncludesNullLeft: null properly includes {2} define ProperlyIncludes1And111: {1} properly includes {1, 1} //ProperContains -define ProperContainsNullRightFalse: {'s', 'u', 'n'} properly includes null -define ProperContainsNullRightTrue: {'s', 'u', 'n', null} properly includes null +define ProperContainsNullRightWithoutNull: {'s', 'u', 'n'} properly includes null +define ProperContainsNullRightWithNull: {'s', 'u', 'n', null} properly includes null define ProperContainsTimeTrue: { @T15:59:59, @T20:59:59.999, @T20:59:49.999 } properly includes @T15:59:59 define ProperContainsTimeNull: { @T15:59:59.999, @T20:59:59.999, @T20:59:49.999 } properly includes @T15:59:59 //ProperIn -define ProperInNullRightFalse: null properly included in {'s', 'u', 'n'} -define ProperInNullRightTrue: null properly included in {'s', 'u', 'n', null} +define ProperInNullRightWithoutNull: null properly included in {'s', 'u', 'n'} +define ProperInNullRightWithNull: null properly included in {'s', 'u', 'n', null} define ProperInTimeTrue: @T15:59:59 properly included in { @T15:59:59, @T20:59:59.999, @T20:59:49.999 } define ProperInTimeNull: @T15:59:59 properly included in { @T15:59:59.999, @T20:59:59.999, @T20:59:49.999 } diff --git a/Src/java/engine/src/test/resources/org/opencds/cqf/cql/engine/execution/CqlPerformanceTest.cql b/Src/java/engine/src/test/resources/org/opencds/cqf/cql/engine/execution/CqlPerformanceTest.cql index 54baf2603..c34b1dfcd 100644 --- a/Src/java/engine/src/test/resources/org/opencds/cqf/cql/engine/execution/CqlPerformanceTest.cql +++ b/Src/java/engine/src/test/resources/org/opencds/cqf/cql/engine/execution/CqlPerformanceTest.cql @@ -4789,8 +4789,8 @@ define test_ProperIncludes_IsSame: TestMessage(not ProperIncludes_IsSame, 'Prope define test_ProperIncludes_IsNotIncluded: TestMessage(not ProperIncludes_IsNotIncluded, 'ProperIncludes_IsNotIncluded', toString(false), toString(ProperIncludes_IsNotIncluded)) define test_ProperIncludes_TuplesIncluded: TestMessage(ProperIncludes_TuplesIncluded, 'ProperIncludes_TuplesIncluded', toString(true), toString(ProperIncludes_TuplesIncluded)) define test_ProperIncludes_TuplesNotIncluded: TestMessage(not ProperIncludes_TuplesNotIncluded, 'ProperIncludes_TuplesNotIncluded', toString(false), toString(ProperIncludes_TuplesNotIncluded)) -define test_ProperIncludes_NullIncludes: TestMessage(not ProperIncludes_NullIncludes, 'ProperIncludes_NullIncludes', toString(false), toString(ProperIncludes_NullIncludes)) -define test_ProperIncludes_NullIncluded: TestMessage(ProperIncludes_NullIncluded, 'ProperIncludes_NullIncluded', toString(true), toString(ProperIncludes_NullIncluded)) +define test_ProperIncludes_NullIncludes: TestMessage(ProperIncludes_NullIncludes is null, 'ProperIncludes_NullIncludes', 'null', toString(ProperIncludes_NullIncludes)) +define test_ProperIncludes_NullIncluded: TestMessage(ProperIncludes_NullIncluded is null, 'ProperIncludes_NullIncluded', 'null', toString(ProperIncludes_NullIncluded)) // ProperIncludedIn define ProperIncludedIn_IsIncluded: {2, 3, 4} properly included in {1, 2, 3, 4, 5} @@ -4808,8 +4808,8 @@ define test_ProperIncludedIn_IsSame: TestMessage(not ProperIncludedIn_IsSame, 'P define test_ProperIncludedIn_IsNotIncluded: TestMessage(not ProperIncludedIn_IsNotIncluded, 'ProperIncludedIn_IsNotIncluded', toString(false), toString(ProperIncludedIn_IsNotIncluded)) define test_ProperIncludedIn_TuplesIncluded: TestMessage(ProperIncludedIn_TuplesIncluded, 'ProperIncludedIn_TuplesIncluded', toString(true), toString(ProperIncludedIn_TuplesIncluded)) define test_ProperIncludedIn_TuplesNotIncluded: TestMessage(not ProperIncludedIn_TuplesNotIncluded, 'ProperIncludedIn_TuplesNotIncluded', toString(false), toString(ProperIncludedIn_TuplesNotIncluded)) -define test_ProperIncludedIn_NullIncludes: TestMessage(not ProperIncludedIn_NullIncludes, 'ProperIncludedIn_NullIncludes', toString(false), toString(ProperIncludedIn_NullIncludes)) -define test_ProperIncludedIn_NullIncluded: TestMessage(ProperIncludedIn_NullIncluded, 'ProperIncludedIn_NullIncluded', toString(true), toString(ProperIncludedIn_NullIncluded)) +define test_ProperIncludedIn_NullIncludes: TestMessage(ProperIncludedIn_NullIncludes is null, 'ProperIncludedIn_NullIncludes', 'null', toString(ProperIncludedIn_NullIncludes)) +define test_ProperIncludedIn_NullIncluded: TestMessage(ProperIncludedIn_NullIncluded is null, 'ProperIncludedIn_NullIncluded', 'null', toString(ProperIncludedIn_NullIncluded)) // Flatten define Flatten_ListOfLists: flatten { {1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {9, 8, 7, 6, 5}, {4}, {3, 2, 1} } diff --git a/Src/java/engine/src/test/resources/org/opencds/cqf/cql/engine/execution/CqlTestSuite.cql b/Src/java/engine/src/test/resources/org/opencds/cqf/cql/engine/execution/CqlTestSuite.cql index 8b55ce0cf..3aa59f57d 100644 --- a/Src/java/engine/src/test/resources/org/opencds/cqf/cql/engine/execution/CqlTestSuite.cql +++ b/Src/java/engine/src/test/resources/org/opencds/cqf/cql/engine/execution/CqlTestSuite.cql @@ -4789,8 +4789,8 @@ define test_ProperIncludes_IsSame: TestMessage(not ProperIncludes_IsSame, 'Prope define test_ProperIncludes_IsNotIncluded: TestMessage(not ProperIncludes_IsNotIncluded, 'ProperIncludes_IsNotIncluded', toString(false), toString(ProperIncludes_IsNotIncluded)) define test_ProperIncludes_TuplesIncluded: TestMessage(ProperIncludes_TuplesIncluded, 'ProperIncludes_TuplesIncluded', toString(true), toString(ProperIncludes_TuplesIncluded)) define test_ProperIncludes_TuplesNotIncluded: TestMessage(not ProperIncludes_TuplesNotIncluded, 'ProperIncludes_TuplesNotIncluded', toString(false), toString(ProperIncludes_TuplesNotIncluded)) -define test_ProperIncludes_NullIncludes: TestMessage(not ProperIncludes_NullIncludes, 'ProperIncludes_NullIncludes', toString(false), toString(ProperIncludes_NullIncludes)) -define test_ProperIncludes_NullIncluded: TestMessage(ProperIncludes_NullIncluded, 'ProperIncludes_NullIncluded', toString(true), toString(ProperIncludes_NullIncluded)) +define test_ProperIncludes_NullIncludes: TestMessage(ProperIncludes_NullIncludes is null, 'ProperIncludes_NullIncludes', 'null', toString(ProperIncludes_NullIncludes)) +define test_ProperIncludes_NullIncluded: TestMessage(ProperIncludes_NullIncluded is null, 'ProperIncludes_NullIncluded', 'null', toString(ProperIncludes_NullIncluded)) // ProperIncludedIn define ProperIncludedIn_IsIncluded: {2, 3, 4} properly included in {1, 2, 3, 4, 5} @@ -4808,8 +4808,8 @@ define test_ProperIncludedIn_IsSame: TestMessage(not ProperIncludedIn_IsSame, 'P define test_ProperIncludedIn_IsNotIncluded: TestMessage(not ProperIncludedIn_IsNotIncluded, 'ProperIncludedIn_IsNotIncluded', toString(false), toString(ProperIncludedIn_IsNotIncluded)) define test_ProperIncludedIn_TuplesIncluded: TestMessage(ProperIncludedIn_TuplesIncluded, 'ProperIncludedIn_TuplesIncluded', toString(true), toString(ProperIncludedIn_TuplesIncluded)) define test_ProperIncludedIn_TuplesNotIncluded: TestMessage(not ProperIncludedIn_TuplesNotIncluded, 'ProperIncludedIn_TuplesNotIncluded', toString(false), toString(ProperIncludedIn_TuplesNotIncluded)) -define test_ProperIncludedIn_NullIncludes: TestMessage(not ProperIncludedIn_NullIncludes, 'ProperIncludedIn_NullIncludes', toString(false), toString(ProperIncludedIn_NullIncludes)) -define test_ProperIncludedIn_NullIncluded: TestMessage(ProperIncludedIn_NullIncluded, 'ProperIncludedIn_NullIncluded', toString(true), toString(ProperIncludedIn_NullIncluded)) +define test_ProperIncludedIn_NullIncludes: TestMessage(ProperIncludedIn_NullIncludes is null, 'ProperIncludedIn_NullIncludes', 'null', toString(ProperIncludedIn_NullIncludes)) +define test_ProperIncludedIn_NullIncluded: TestMessage(ProperIncludedIn_NullIncluded is null, 'ProperIncludedIn_NullIncluded', 'null', toString(ProperIncludedIn_NullIncluded)) // Flatten define Flatten_ListOfLists: flatten { {1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {9, 8, 7, 6, 5}, {4}, {3, 2, 1} } From 67e2b09b25dffa584239fba78b2e0b0ac9163b59 Mon Sep 17 00:00:00 2001 From: Anton Vasetenkov Date: Thu, 27 Jun 2024 21:22:45 +1200 Subject: [PATCH 2/5] Add tests for the TruncatedDivide, ProperContains, ProperIn evaluators --- .../fhirpath/cql/CqlArithmeticFunctionsTest.xml | 12 ++++++++++++ .../hl7/fhirpath/cql/CqlListOperatorsTest.xml | 16 ++++++++++++---- .../elm/executing/ProperIncludesEvaluator.java | 4 ---- .../execution/CqlArithmeticFunctionsTest.java | 12 ++++++++++++ .../cql/engine/execution/ListOperatorsTest.java | 14 ++++++++++---- .../execution/CqlArithmeticFunctionsTest.cql | 4 ++++ .../engine/execution/CqlListOperatorsTest.cql | 10 ++++++---- 7 files changed, 56 insertions(+), 16 deletions(-) diff --git a/Src/java/engine-fhir/src/test/resources/org/hl7/fhirpath/cql/CqlArithmeticFunctionsTest.xml b/Src/java/engine-fhir/src/test/resources/org/hl7/fhirpath/cql/CqlArithmeticFunctionsTest.xml index a667d780e..31e07726b 100644 --- a/Src/java/engine-fhir/src/test/resources/org/hl7/fhirpath/cql/CqlArithmeticFunctionsTest.xml +++ b/Src/java/engine-fhir/src/test/resources/org/hl7/fhirpath/cql/CqlArithmeticFunctionsTest.xml @@ -777,6 +777,10 @@ 2 div 1 2 + + 2 div 0 + null + 10 div 3 3 @@ -785,10 +789,18 @@ 10L div 3L 3L + + 10L div 0L + null + 10.1 div 3.1 3.0 + + 10.1 div 0.0 + null + -2 div -1 2 diff --git a/Src/java/engine-fhir/src/test/resources/org/hl7/fhirpath/cql/CqlListOperatorsTest.xml b/Src/java/engine-fhir/src/test/resources/org/hl7/fhirpath/cql/CqlListOperatorsTest.xml index 049797e0e..07ec4dc94 100644 --- a/Src/java/engine-fhir/src/test/resources/org/hl7/fhirpath/cql/CqlListOperatorsTest.xml +++ b/Src/java/engine-fhir/src/test/resources/org/hl7/fhirpath/cql/CqlListOperatorsTest.xml @@ -650,14 +650,18 @@ - + {'s', 'u', 'n'} properly includes null null - + {'s', 'u', 'n', null} properly includes null null + + null as List<String> properly includes 's' + null + { @T15:59:59, @T20:59:59.999, @T20:59:49.999 } properly includes @T15:59:59 true @@ -668,14 +672,18 @@ - + null properly included in {'s', 'u', 'n'} null - + null properly included in {'s', 'u', 'n', null} null + + 's' properly included in null as List<String> + null + @T15:59:59 properly included in { @T15:59:59, @T20:59:59.999, @T20:59:49.999 } true diff --git a/Src/java/engine/src/main/java/org/opencds/cqf/cql/engine/elm/executing/ProperIncludesEvaluator.java b/Src/java/engine/src/main/java/org/opencds/cqf/cql/engine/elm/executing/ProperIncludesEvaluator.java index fa7f6c99b..6a0dc3f3d 100644 --- a/Src/java/engine/src/main/java/org/opencds/cqf/cql/engine/elm/executing/ProperIncludesEvaluator.java +++ b/Src/java/engine/src/main/java/org/opencds/cqf/cql/engine/elm/executing/ProperIncludesEvaluator.java @@ -75,10 +75,6 @@ public static Boolean listProperlyIncludes(Iterable left, Iterable right, int leftCount = (int) StreamSupport.stream(((Iterable) left).spliterator(), false).count(); - if (right == null) { - return leftCount > 0; - } - return AndEvaluator.and( IncludedInEvaluator.listIncludedIn(right, left, state), GreaterEvaluator.greater( diff --git a/Src/java/engine/src/test/java/org/opencds/cqf/cql/engine/execution/CqlArithmeticFunctionsTest.java b/Src/java/engine/src/test/java/org/opencds/cqf/cql/engine/execution/CqlArithmeticFunctionsTest.java index e156bc907..a2809848e 100644 --- a/Src/java/engine/src/test/java/org/opencds/cqf/cql/engine/execution/CqlArithmeticFunctionsTest.java +++ b/Src/java/engine/src/test/java/org/opencds/cqf/cql/engine/execution/CqlArithmeticFunctionsTest.java @@ -796,12 +796,24 @@ void truncatedDivide() { value = engine.expression(library, "TruncatedDivide2By1").value(); assertThat(value, is(2)); + value = engine.expression(library, "TruncatedDivide2By0").value(); + assertThat(value, is(nullValue())); + value = engine.expression(library, "TruncatedDivide10By3").value(); assertThat(value, is(3)); + value = engine.expression(library, "TruncatedDivide10LBy3L").value(); + assertThat(value, is(3L)); + + value = engine.expression(library, "TruncatedDivide10LBy0L").value(); + assertThat(value, is(nullValue())); + value = engine.expression(library, "TruncatedDivide10d1By3D1").value(); assertThat((BigDecimal) value, comparesEqualTo(BigDecimal.valueOf(3.0))); + value = engine.expression(library, "TruncatedDivide10D1By0D").value(); + assertThat(value, is(nullValue())); + value = engine.expression(library, "TruncatedDivideNeg2ByNeg1").value(); assertThat(value, is(2)); diff --git a/Src/java/engine/src/test/java/org/opencds/cqf/cql/engine/execution/ListOperatorsTest.java b/Src/java/engine/src/test/java/org/opencds/cqf/cql/engine/execution/ListOperatorsTest.java index 1112bf844..35369f584 100644 --- a/Src/java/engine/src/test/java/org/opencds/cqf/cql/engine/execution/ListOperatorsTest.java +++ b/Src/java/engine/src/test/java/org/opencds/cqf/cql/engine/execution/ListOperatorsTest.java @@ -574,10 +574,13 @@ void all_interval_operators() { value = results.forExpression("ProperlyIncludes1And111").value(); assertThat(value, is(false)); - value = results.forExpression("ProperContainsNullRightWithoutNull").value(); + value = results.forExpression("ProperContainsNullRight1").value(); assertThat(value, is(nullValue())); - value = results.forExpression("ProperContainsNullRightWithNull").value(); + value = results.forExpression("ProperContainsNullRight2").value(); + assertThat(value, is(nullValue())); + + value = results.forExpression("ProperContainsNullLeft").value(); assertThat(value, is(nullValue())); value = results.forExpression("ProperContainsTimeTrue").value(); @@ -586,10 +589,13 @@ void all_interval_operators() { value = results.forExpression("ProperContainsTimeNull").value(); assertThat(value, is(false)); - value = results.forExpression("ProperInNullRightWithoutNull").value(); + value = results.forExpression("ProperInNullLeft1").value(); + assertThat(value, is(nullValue())); + + value = results.forExpression("ProperInNullLeft2").value(); assertThat(value, is(nullValue())); - value = results.forExpression("ProperInNullRightWithNull").value(); + value = results.forExpression("ProperInNullRight").value(); assertThat(value, is(nullValue())); value = results.forExpression("ProperInTimeTrue").value(); diff --git a/Src/java/engine/src/test/resources/org/opencds/cqf/cql/engine/execution/CqlArithmeticFunctionsTest.cql b/Src/java/engine/src/test/resources/org/opencds/cqf/cql/engine/execution/CqlArithmeticFunctionsTest.cql index 0da7327ec..590c2859e 100644 --- a/Src/java/engine/src/test/resources/org/opencds/cqf/cql/engine/execution/CqlArithmeticFunctionsTest.cql +++ b/Src/java/engine/src/test/resources/org/opencds/cqf/cql/engine/execution/CqlArithmeticFunctionsTest.cql @@ -236,8 +236,12 @@ define TruncateNeg1D9: Truncate(-1.9) //Truncated Divide define TruncatedDivideNull: (null as Integer) div (null as Integer) define TruncatedDivide2By1: 2 div 1 +define TruncatedDivide2By0: 2 div 0 define TruncatedDivide10By3: 10 div 3 +define TruncatedDivide10LBy3L: 10L div 3L +define TruncatedDivide10LBy0L: 10L div 0L define TruncatedDivide10d1By3D1: 10.1 div 3.1 +define TruncatedDivide10D1By0D: 10.1 div 0.0 define TruncatedDivideNeg2ByNeg1: -2 div -1 define TruncatedDivideNeg10ByNeg3: -10 div -3 define TruncatedDivideNeg10d1ByNeg3D1: -10.1 div -3.1 diff --git a/Src/java/engine/src/test/resources/org/opencds/cqf/cql/engine/execution/CqlListOperatorsTest.cql b/Src/java/engine/src/test/resources/org/opencds/cqf/cql/engine/execution/CqlListOperatorsTest.cql index 8ff7a5bb8..38aeeab17 100644 --- a/Src/java/engine/src/test/resources/org/opencds/cqf/cql/engine/execution/CqlListOperatorsTest.cql +++ b/Src/java/engine/src/test/resources/org/opencds/cqf/cql/engine/execution/CqlListOperatorsTest.cql @@ -209,14 +209,16 @@ define ProperlyIncludesNullLeft: null properly includes {2} define ProperlyIncludes1And111: {1} properly includes {1, 1} //ProperContains -define ProperContainsNullRightWithoutNull: {'s', 'u', 'n'} properly includes null -define ProperContainsNullRightWithNull: {'s', 'u', 'n', null} properly includes null +define ProperContainsNullRight1: {'s', 'u', 'n'} properly includes null +define ProperContainsNullRight2: {'s', 'u', 'n', null} properly includes null +define ProperContainsNullLeft: null as List properly includes 's' define ProperContainsTimeTrue: { @T15:59:59, @T20:59:59.999, @T20:59:49.999 } properly includes @T15:59:59 define ProperContainsTimeNull: { @T15:59:59.999, @T20:59:59.999, @T20:59:49.999 } properly includes @T15:59:59 //ProperIn -define ProperInNullRightWithoutNull: null properly included in {'s', 'u', 'n'} -define ProperInNullRightWithNull: null properly included in {'s', 'u', 'n', null} +define ProperInNullLeft1: null properly included in {'s', 'u', 'n'} +define ProperInNullLeft2: null properly included in {'s', 'u', 'n', null} +define ProperInNullRight: 's' properly included in null as List define ProperInTimeTrue: @T15:59:59 properly included in { @T15:59:59, @T20:59:59.999, @T20:59:49.999 } define ProperInTimeNull: @T15:59:59 properly included in { @T15:59:59.999, @T20:59:59.999, @T20:59:49.999 } From ca6e541b7aa66ac323c4fda5712b52dcd6b83d82 Mon Sep 17 00:00:00 2001 From: Anton Vasetenkov Date: Fri, 28 Jun 2024 08:06:34 +1200 Subject: [PATCH 3/5] Add tests for the MinValue and MaxValue evaluators --- .../cql/CqlArithmeticFunctionsTest.xml | 16 +++++++++++++++ .../execution/CqlArithmeticFunctionsTest.java | 20 +++++++++++++++++++ .../execution/CqlArithmeticFunctionsTest.cql | 4 ++++ 3 files changed, 40 insertions(+) diff --git a/Src/java/engine-fhir/src/test/resources/org/hl7/fhirpath/cql/CqlArithmeticFunctionsTest.xml b/Src/java/engine-fhir/src/test/resources/org/hl7/fhirpath/cql/CqlArithmeticFunctionsTest.xml index 31e07726b..599c6c3ee 100644 --- a/Src/java/engine-fhir/src/test/resources/org/hl7/fhirpath/cql/CqlArithmeticFunctionsTest.xml +++ b/Src/java/engine-fhir/src/test/resources/org/hl7/fhirpath/cql/CqlArithmeticFunctionsTest.xml @@ -335,6 +335,14 @@ minimum Time @T00:00:00.000 + + minimum Boolean + + + + minimum null + null + @@ -362,6 +370,14 @@ maximum Time @T23:59:59.999 + + maximum Boolean + + + + maximum null + null + diff --git a/Src/java/engine/src/test/java/org/opencds/cqf/cql/engine/execution/CqlArithmeticFunctionsTest.java b/Src/java/engine/src/test/java/org/opencds/cqf/cql/engine/execution/CqlArithmeticFunctionsTest.java index a2809848e..04d1f9793 100644 --- a/Src/java/engine/src/test/java/org/opencds/cqf/cql/engine/execution/CqlArithmeticFunctionsTest.java +++ b/Src/java/engine/src/test/java/org/opencds/cqf/cql/engine/execution/CqlArithmeticFunctionsTest.java @@ -374,6 +374,16 @@ void maximum() { value = engine.expression(library, "TimeMaxValue").value(); assertTrue(EquivalentEvaluator.equivalent(value, new Time(23, 59, 59, 999))); + + try { + value = engine.expression(library, "BooleanMaxValue").value(); + fail(); + } catch (UndefinedResult ae) { + assertThat(ae.getMessage(), is("The Maximum operator is not implemented for type Boolean")); + } + + value = engine.expression(library, "NullMaxValue").value(); + assertThat(value, is(nullValue())); } /** @@ -396,6 +406,16 @@ void minimum() { value = engine.expression(library, "TimeMinValue").value(); assertTrue(EquivalentEvaluator.equivalent(value, new Time(0, 0, 0, 0))); + + try { + value = engine.expression(library, "BooleanMinValue").value(); + fail(); + } catch (UndefinedResult ae) { + assertThat(ae.getMessage(), is("The Minimum operator is not implemented for type Boolean")); + } + + value = engine.expression(library, "NullMinValue").value(); + assertThat(value, is(nullValue())); } /** diff --git a/Src/java/engine/src/test/resources/org/opencds/cqf/cql/engine/execution/CqlArithmeticFunctionsTest.cql b/Src/java/engine/src/test/resources/org/opencds/cqf/cql/engine/execution/CqlArithmeticFunctionsTest.cql index 590c2859e..2be100216 100644 --- a/Src/java/engine/src/test/resources/org/opencds/cqf/cql/engine/execution/CqlArithmeticFunctionsTest.cql +++ b/Src/java/engine/src/test/resources/org/opencds/cqf/cql/engine/execution/CqlArithmeticFunctionsTest.cql @@ -105,6 +105,8 @@ define DecimalMinValue: minimum Decimal define QuantityMinValue: minimum Quantity define DateTimeMinValue: minimum DateTime define TimeMinValue: minimum Time +define BooleanMinValue: minimum Boolean +define NullMinValue: minimum null //MaxValue define IntegerMaxValue: maximum Integer @@ -113,6 +115,8 @@ define DecimalMaxValue: maximum Decimal define QuantityMaxValue: maximum Quantity define DateTimeMaxValue: maximum DateTime define TimeMaxValue: maximum Time +define BooleanMaxValue: maximum Boolean +define NullMaxValue: maximum null //Modulo define ModuloNull : 1 mod null From 9c67f094e95983eea14300b0af07804ae4e0f492 Mon Sep 17 00:00:00 2001 From: Anton Vasetenkov Date: Fri, 28 Jun 2024 08:16:42 +1200 Subject: [PATCH 4/5] Remove bad test --- .../org/hl7/fhirpath/cql/CqlArithmeticFunctionsTest.xml | 8 -------- .../cql/engine/execution/CqlArithmeticFunctionsTest.java | 6 ------ .../cql/engine/execution/CqlArithmeticFunctionsTest.cql | 2 -- 3 files changed, 16 deletions(-) diff --git a/Src/java/engine-fhir/src/test/resources/org/hl7/fhirpath/cql/CqlArithmeticFunctionsTest.xml b/Src/java/engine-fhir/src/test/resources/org/hl7/fhirpath/cql/CqlArithmeticFunctionsTest.xml index 599c6c3ee..46be4dff1 100644 --- a/Src/java/engine-fhir/src/test/resources/org/hl7/fhirpath/cql/CqlArithmeticFunctionsTest.xml +++ b/Src/java/engine-fhir/src/test/resources/org/hl7/fhirpath/cql/CqlArithmeticFunctionsTest.xml @@ -339,10 +339,6 @@ minimum Boolean - - minimum null - null - @@ -374,10 +370,6 @@ maximum Boolean - - maximum null - null - diff --git a/Src/java/engine/src/test/java/org/opencds/cqf/cql/engine/execution/CqlArithmeticFunctionsTest.java b/Src/java/engine/src/test/java/org/opencds/cqf/cql/engine/execution/CqlArithmeticFunctionsTest.java index 04d1f9793..6a217c1d3 100644 --- a/Src/java/engine/src/test/java/org/opencds/cqf/cql/engine/execution/CqlArithmeticFunctionsTest.java +++ b/Src/java/engine/src/test/java/org/opencds/cqf/cql/engine/execution/CqlArithmeticFunctionsTest.java @@ -381,9 +381,6 @@ void maximum() { } catch (UndefinedResult ae) { assertThat(ae.getMessage(), is("The Maximum operator is not implemented for type Boolean")); } - - value = engine.expression(library, "NullMaxValue").value(); - assertThat(value, is(nullValue())); } /** @@ -413,9 +410,6 @@ void minimum() { } catch (UndefinedResult ae) { assertThat(ae.getMessage(), is("The Minimum operator is not implemented for type Boolean")); } - - value = engine.expression(library, "NullMinValue").value(); - assertThat(value, is(nullValue())); } /** diff --git a/Src/java/engine/src/test/resources/org/opencds/cqf/cql/engine/execution/CqlArithmeticFunctionsTest.cql b/Src/java/engine/src/test/resources/org/opencds/cqf/cql/engine/execution/CqlArithmeticFunctionsTest.cql index 2be100216..41bde4ada 100644 --- a/Src/java/engine/src/test/resources/org/opencds/cqf/cql/engine/execution/CqlArithmeticFunctionsTest.cql +++ b/Src/java/engine/src/test/resources/org/opencds/cqf/cql/engine/execution/CqlArithmeticFunctionsTest.cql @@ -106,7 +106,6 @@ define QuantityMinValue: minimum Quantity define DateTimeMinValue: minimum DateTime define TimeMinValue: minimum Time define BooleanMinValue: minimum Boolean -define NullMinValue: minimum null //MaxValue define IntegerMaxValue: maximum Integer @@ -116,7 +115,6 @@ define QuantityMaxValue: maximum Quantity define DateTimeMaxValue: maximum DateTime define TimeMaxValue: maximum Time define BooleanMaxValue: maximum Boolean -define NullMaxValue: maximum null //Modulo define ModuloNull : 1 mod null From c19f82c7fb284790d6deed629769e46cbecfeaea Mon Sep 17 00:00:00 2001 From: Anton Vasetenkov Date: Fri, 28 Jun 2024 08:27:47 +1200 Subject: [PATCH 5/5] Fix BooleanMinValue and BooleanMaxValue tests --- .../cqf/cql/engine/execution/CqlArithmeticFunctionsTest.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Src/java/engine/src/test/java/org/opencds/cqf/cql/engine/execution/CqlArithmeticFunctionsTest.java b/Src/java/engine/src/test/java/org/opencds/cqf/cql/engine/execution/CqlArithmeticFunctionsTest.java index 6a217c1d3..3a44cffe0 100644 --- a/Src/java/engine/src/test/java/org/opencds/cqf/cql/engine/execution/CqlArithmeticFunctionsTest.java +++ b/Src/java/engine/src/test/java/org/opencds/cqf/cql/engine/execution/CqlArithmeticFunctionsTest.java @@ -9,6 +9,7 @@ import org.junit.jupiter.api.Test; import org.opencds.cqf.cql.engine.elm.executing.*; import org.opencds.cqf.cql.engine.exception.CqlException; +import org.opencds.cqf.cql.engine.exception.InvalidOperatorArgument; import org.opencds.cqf.cql.engine.exception.UndefinedResult; import org.opencds.cqf.cql.engine.runtime.*; @@ -378,7 +379,7 @@ void maximum() { try { value = engine.expression(library, "BooleanMaxValue").value(); fail(); - } catch (UndefinedResult ae) { + } catch (InvalidOperatorArgument ae) { assertThat(ae.getMessage(), is("The Maximum operator is not implemented for type Boolean")); } } @@ -407,7 +408,7 @@ void minimum() { try { value = engine.expression(library, "BooleanMinValue").value(); fail(); - } catch (UndefinedResult ae) { + } catch (InvalidOperatorArgument ae) { assertThat(ae.getMessage(), is("The Minimum operator is not implemented for type Boolean")); } }