Skip to content

Commit

Permalink
Update ProperContains evaluator implementation (#1393)
Browse files Browse the repository at this point in the history
* Update ProperContains evaluator implementation

* Align library-based tests with XML-based tests

* Unskip test

---------

Co-authored-by: JP <[email protected]>
  • Loading branch information
antvaset and JPercival authored Aug 1, 2024
1 parent 0670c4a commit 7e91478
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,6 @@ 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",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -662,12 +662,52 @@
</test>
</group>
<group name="ProperContains">
<test name="ProperContains1">
<expression>null as List&lt;String&gt; properly includes 'a'</expression>
<output>false</output>
</test>
<test name="ProperContains2">
<expression>{} properly includes 'a'</expression>
<output>false</output>
</test>
<test name="ProperContains3">
<expression>{ 'a' } properly includes 'a'</expression>
<output>false</output>
</test>
<test name="ProperContains4">
<expression>{ null } properly includes null as String</expression>
<output>false</output>
</test>
<test name="ProperContainsNullRightFalse">
<expression>{'s', 'u', 'n'} properly includes null</expression>
<expression>{'s', 'u', 'n'} properly includes null as String</expression>
<output>false</output>
</test>
<test name="ProperContains5">
<expression>{ null, null } properly includes null as String</expression>
<output>false</output>
</test>
<test name="ProperContainsNullRightTrue">
<expression>{'s', 'u', 'n', null} properly includes null</expression>
<expression>{'s', 'u', 'n', null} properly includes null as String</expression>
<output>true</output>
</test>
<test name="ProperContains6">
<expression>{ 'a', 'b' } properly includes 'a'</expression>
<output>true</output>
</test>
<test name="ProperContains7">
<expression>{ 'a', 'a' } properly includes 'a'</expression>
<output>false</output>
</test>
<test name="ProperContains8">
<expression>{ 'a', 'b' } properly includes 'c'</expression>
<output>false</output>
</test>
<test name="ProperContains9">
<expression>{ 'a', null } properly includes 'a'</expression>
<output>null</output>
</test>
<test name="ProperContains10">
<expression>{ 'a', 'b', null } properly includes 'a'</expression>
<output>true</output>
</test>
<test name="ProperContainsTimeTrue">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,29 @@
Interval, T : The type of T must be the same as the point type of the interval.
For the List, T overload, this operator returns true if the given element is in the list,
and it is not the only element in the list, using equivalence semantics.
and it is not the only element in the list, using equality semantics, with the exception
that null elements are considered equal.
If the first argument is null, the result is false.
If the second argument is null, the result is true if the list contains any null elements
and at least one other element, and false otherwise.
For the Interval, T overload, this operator returns true if the given point is greater than
the starting point of the interval, and less than the ending point of the interval, as
determined by the Start and End operators.
If precision is specified and the point type is a date/time type, comparisons used in the
operation are performed at the specified precision.
If precision is specified and the point type is a Date, DateTime, or Time type, comparisons
used in the operation are performed at the specified precision.
If the first argument is null, the result is false.
If the second argument is null, the result is null.
*/

public class ProperContainsEvaluator {

public static Boolean properContains(Object left, Object right, State state) {

// If the first argument is null, the result is false.
if (left == null) {
return false;
}

if (left instanceof Interval) {
Boolean startProperContains = GreaterEvaluator.greater(right, ((Interval) left).getStart(), state);
Boolean endProperContains = LessEvaluator.less(right, ((Interval) left).getEnd(), state);
Expand All @@ -33,15 +45,59 @@ public static Boolean properContains(Object left, Object right, State state) {
} else if (left instanceof Iterable) {
List<?> leftList = (List<?>) left;

for (Object element : leftList) {
Boolean isElementInList = EquivalentEvaluator.equivalent(element, right, state);
if (isElementInList == null) {
return null;
// The result cannot be true if the list contains fewer than two elements
if (leftList.size() < 2) {
return false;
}

if (right == null) {

// The result is true if the list contains any null elements and at least one other element,
// and false otherwise

boolean listContainsNullElements = false;
boolean listContainsOtherElements = false;

for (Object element : leftList) {
if (element == null) {
listContainsNullElements = true;
continue;
}

listContainsOtherElements = true;
}

if (isElementInList && leftList.size() > 1) {
return true;
return listContainsNullElements && listContainsOtherElements;
}

// Return true if the given element is in the list, and it is not the only element in the list,
// using equality semantics

boolean listContainsGivenElement = false;
boolean listContainsOtherElements = false;
boolean listContainsElementsOfUnknownEquality = false;

for (Object element : leftList) {
Boolean equalResult = EqualEvaluator.equal(element, right, state);
if (equalResult == null) {
listContainsElementsOfUnknownEquality = true;
continue;
}
if (equalResult) {
listContainsGivenElement = true;
continue;
}
listContainsOtherElements = true;
}

// The given element is in the list and there are other elements, using equality semantics
if (listContainsGivenElement && listContainsOtherElements) {
return true;
}

// The above is false, but there are elements of unknown equality
if (listContainsElementsOfUnknownEquality) {
return null;
}

return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -584,7 +584,7 @@ void all_interval_operators() {
assertThat(value, is(true));

value = results.forExpression("ProperContainsTimeNull").value();
assertThat(value, is(false));
assertThat(value, is(nullValue()));

value = results.forExpression("ProperInNullRightFalse").value();
assertThat(value, is(false));
Expand All @@ -596,7 +596,7 @@ void all_interval_operators() {
assertThat(value, is(true));

value = results.forExpression("ProperInTimeNull").value();
assertThat(value, is(false));
assertThat(value, is(nullValue()));

value = results.forExpression("ProperIncludedInEmptyAndEmpty").value();
assertThat(value, is(false));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,8 +209,8 @@ 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 ProperContainsNullRightFalse: {'s', 'u', 'n'} properly includes null as String
define ProperContainsNullRightTrue: {'s', 'u', 'n', null} properly includes null as String
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

Expand Down

0 comments on commit 7e91478

Please sign in to comment.