diff --git a/client-java/controller/src/main/java/org/evomaster/client/java/controller/mongo/MongoHeuristicsCalculator.java b/client-java/controller/src/main/java/org/evomaster/client/java/controller/mongo/MongoHeuristicsCalculator.java index bfc6c52ff5..a153cf4108 100644 --- a/client-java/controller/src/main/java/org/evomaster/client/java/controller/mongo/MongoHeuristicsCalculator.java +++ b/client-java/controller/src/main/java/org/evomaster/client/java/controller/mongo/MongoHeuristicsCalculator.java @@ -274,9 +274,17 @@ private Truthness computeHeuristicComparisonNonNullValues(Object actualValue, Ob truthnessOfComparison = SqlExpressionEvaluator.calculateTruthnessForStringComparison(actualString, expectedString, comparisonOperatorType); } else { - // If both types are supported, but no actual comparison logic is defined, - // we considered them to be incompatible, therefore the comparison returns false. - truthnessOfComparison = C_FALSE; + /* + Both types are supported, but no comparison logic is defined for this combination, + ie the two values are of different, mutually incomparable BSON types. + MongoDB considers such values to be different from each other: an equality check is + then false, but an inequality check is true. Ordering comparisons do not match across + different BSON types either, so those stay false as well. + */ + truthnessOfComparison = + comparisonOperatorType == SqlExpressionEvaluator.ComparisonOperatorType.NOT_EQUALS_TO + ? TRUE_C + : C_FALSE; } return truthnessOfComparison; } @@ -327,10 +335,7 @@ private Truthness computeHeuristic(EqualsOperation operation, Object document actualValue = null; } - return computeHeuristicComparisonNullableValues( - expectedValue, - actualValue, - SqlExpressionEvaluator.ComparisonOperatorType.EQUALS_TO); + return computeHeuristicForMatchedValue(expectedValue, actualValue); } private Truthness computeHeuristicComparisonNullableValues(Object expectedValue, Object actualValue, SqlExpressionEvaluator.ComparisonOperatorType comparisonOperatorType) { @@ -384,10 +389,7 @@ private Truthness computeHeuristic(NotEqualsOperation operation, Object docum } else { actualValue = null; } - return computeHeuristicComparisonNullableValues( - expectedValue, - actualValue, - SqlExpressionEvaluator.ComparisonOperatorType.NOT_EQUALS_TO); + return computeHeuristicForMatchedValue(expectedValue, actualValue).invert(); } @@ -484,8 +486,27 @@ private Truthness computeHeuristic(AndOperation operation, Object document) { private Truthness computeHeuristic(InOperation operation, Object document) { requireNonNullQueryAndDocument(operation, document); - List expectedValueList = operation.getValues(); - final String fieldName = operation.getFieldName(); + return computeHeuristicForMembership(operation.getFieldName(), operation.getValues(), document); + } + + /** + * Computes the heuristic score for the membership of a field's value in a list of expected + * values, ie the condition shared by {"f",{"$in": [...]}} and, negated, by + * {"f",{"$nin": [...]}}. The condition holds when the field matches any one of the expected + * values, in the sense of {@link #computeHeuristicForMatchedValue(Object, Object)}. + * + * @param fieldName the name of the field the query is about + * @param expectedValues the values the query lists as candidates + * @param document the BSON document to evaluate the heuristic score against + * @return a Truthness object representing how close the field is to holding one of the values + */ + private Truthness computeHeuristicForMembership(String fieldName, List expectedValues, Object document) { + Objects.requireNonNull(expectedValues); + + if (expectedValues.isEmpty()) { + // no candidate value can be matched + return C_FALSE; + } final Object actualValue; if (documentContainsField(document, fieldName)) { @@ -497,41 +518,39 @@ private Truthness computeHeuristic(InOperation operation, Object document) { actualValue = null; } - final Truthness res; - if (actualValue instanceof List) { - List actualValueList = (List) actualValue; - res = buildOrAggregationTruthness(actualValueList.stream() - .map(value -> computeHeuristic(value, expectedValueList)) - .toArray(Truthness[]::new)); - } else { - res = computeHeuristic(actualValue, expectedValueList); - } - return res; - } - - private Truthness computeHeuristic(Object actualValue, List expectedValueList) { - Objects.requireNonNull(expectedValueList); - - Truthness res = buildOrAggregationTruthness(expectedValueList.stream() - .map(expectedValue -> computeHeuristicComparisonNullableValues(expectedValue, actualValue, SqlExpressionEvaluator.ComparisonOperatorType.EQUALS_TO)) + return buildOrAggregationTruthness(expectedValues.stream() + .map(expectedValue -> computeHeuristicForMatchedValue(expectedValue, actualValue)) .toArray(Truthness[]::new)); - return res; } private Truthness computeHeuristic(NotInOperation operation, Object document) { requireNonNullQueryAndDocument(operation, document); - List expectedValues = operation.getValues(); final String fieldName = operation.getFieldName(); if (!documentContainsField(document, fieldName)) { + // a value that is not there cannot be one of the excluded ones return TRUE_C; - } else { - Object actualValue = getValue(document, fieldName); - return computeHeuristic(actualValue, expectedValues).invert(); } + /* + $nin is the negation of $in, so it must consider the array elements in the same way: + a document whose array holds any of the excluded values does not match. + */ + return computeHeuristicForMembership(fieldName, operation.getValues(), document).invert(); } + /** + * Computes the heuristic score for a {"f",{"$all": [v1, ..., vn] }} query. + * The condition holds when "f" matches every one of the expected values, so the score is an + * AND aggregation over them. Note the direction: extra elements in the document are + * irrelevant, whereas a missing expected value makes the condition false. + * The field does not have to hold an array: a scalar matches a $all listing only values + * equal to it, which is why {"f": "a"} is matched by {"$all": ["a"]}. + * + * @param operation the {"f",{"$all": [...]}} query encapsulated as an AllOperation + * @param document the BSON document to evaluate the heuristic score against + * @return a Truthness object representing the distance of the document from meeting the condition + */ private Truthness computeHeuristic(AllOperation operation, Object document) { requireNonNullQueryAndDocument(operation, document); @@ -542,23 +561,47 @@ private Truthness computeHeuristic(AllOperation operation, Object document) { } else if (expectedValues.isEmpty()) { return C_FALSE; } else { - Object actualValues = getValue(document, fieldName); - if (actualValues == null || !(actualValues instanceof List)) { - return C_FALSE; - } else { - List actualValuesList = (List) actualValues; - if (actualValuesList.isEmpty()) { - return C_FALSE; - } else { - Truthness res = buildAndAggregationTruthness(actualValuesList - .stream() - .map(actualValuesListElement -> - computeHeuristic(actualValuesListElement, expectedValues)) - .toArray(Truthness[]::new)); - return buildSafeScaledTruthness(res); - } - } + Object actualValue = getValue(document, fieldName); + Truthness res = buildAndAggregationTruthness(expectedValues + .stream() + .map(expectedValue -> computeHeuristicForMatchedValue(expectedValue, actualValue)) + .toArray(Truthness[]::new)); + return buildSafeScaledTruthness(res); + } + } + + /** + * Computes the heuristic score for MongoDB's matching of a field against a single value, + * ie the condition that the field holds that value. The field matches when its own value is + * the expected one, and also, if it holds an array, when any element of that array is. + * Both readings apply at once: {"f": ["a","b"]} is matched both by the value ["a","b"] and + * by the value "a". + * + * @param expectedValue the value the query requires the field to hold + * @param actualValue the value held by the field in the document, possibly an array or null + * @return a Truthness object representing how close the field is to holding the expected value + */ + private Truthness computeHeuristicForMatchedValue(Object expectedValue, Object actualValue) { + + Truthness wholeValue = computeHeuristicComparisonNullableValues(expectedValue, actualValue, + SqlExpressionEvaluator.ComparisonOperatorType.EQUALS_TO); + + if (!(actualValue instanceof List)) { + return wholeValue; + } + + /* + The array as a whole is one of the options, which is also what makes an empty array + work: it holds no element to compare, but it can still be equal to the expected value. + */ + List actualValueList = (List) actualValue; + Truthness[] options = new Truthness[actualValueList.size() + 1]; + options[0] = wholeValue; + for (int i = 0; i < actualValueList.size(); i++) { + options[i + 1] = computeHeuristicComparisonNullableValues(expectedValue, + actualValueList.get(i), SqlExpressionEvaluator.ComparisonOperatorType.EQUALS_TO); } + return buildOrAggregationTruthness(options); } private static Truthness buildSafeScaledTruthness(Truthness truthness) { @@ -724,13 +767,14 @@ private Truthness computeHeuristic(BitsOperation operation, Object document) { private Truthness computeHeuristic(NotOperation operation, Object document) { requireNonNullQueryAndDocument(operation, document); - String fieldName = operation.getFieldName(); - if (!documentContainsField(document, fieldName)) { - return TRUE_C; - } else { - QueryOperation condition = operation.getCondition(); - return computeHeuristicOnDocument(condition, document).invert(); - } + /* + No special case for a missing field here. Several operators do match a document in + which the field is absent (eg $ne, $nin, and $exists with "false"), and $not must then + be false. The inner operators already treat an absent field as a null value, so + negating their score is correct whether or not the field is there. + */ + QueryOperation condition = operation.getCondition(); + return computeHeuristicOnDocument(condition, document).invert(); } private Truthness computeHeuristic(NorOperation operation, Object document) { @@ -909,6 +953,9 @@ private Truthness calculateTruthnessForListComparison(List actualList, List(Arrays.asList("a", "b"))); + Bson bson = Filters.nin("tags", new ArrayList<>(Arrays.asList("a"))); + Truthness distance = new MongoHeuristicsCalculator().computeHeuristicDocument(convertToDocument(bson), doc); + assertTrue(distance.isFalse()); + } + + @Test + public void testNotInArrayFieldHoldingNoExcludedValue() { + Document doc = new Document().append("tags", new ArrayList<>(Arrays.asList("a", "b"))); + Bson bson = Filters.nin("tags", new ArrayList<>(Arrays.asList("z"))); + Truthness distance = new MongoHeuristicsCalculator().computeHeuristicDocument(convertToDocument(bson), doc); + assertTrue(distance.isTrue()); + } + + @Test + public void testInAndNotInOnEmptyArrayField() { + Document doc = new Document().append("tags", Collections.emptyList()); + MongoHeuristicsCalculator calculator = new MongoHeuristicsCalculator(); + + Bson in = Filters.in("tags", new ArrayList<>(Arrays.asList("a"))); + Bson nin = Filters.nin("tags", new ArrayList<>(Arrays.asList("a"))); + + assertTrue(calculator.computeHeuristicDocument(convertToDocument(in), doc).isFalse()); + assertTrue(calculator.computeHeuristicDocument(convertToDocument(nin), doc).isTrue()); + } + + @Test + public void testInAndNotInOnEmptyExpectedList() { + Document doc = new Document().append("tags", new ArrayList<>(Arrays.asList("a", "b"))); + MongoHeuristicsCalculator calculator = new MongoHeuristicsCalculator(); + + Bson in = Filters.in("tags", Collections.emptyList()); + Bson nin = Filters.nin("tags", Collections.emptyList()); + + assertTrue(calculator.computeHeuristicDocument(convertToDocument(in), doc).isFalse()); + assertTrue(calculator.computeHeuristicDocument(convertToDocument(nin), doc).isTrue()); + } + @Test public void testAll() { Document doc = new Document().append("employees", new ArrayList<>(Arrays.asList(1, 5, 6))); @@ -273,6 +314,108 @@ public void testAllBothActualAndExpectedListsAreEmpty() { assertTrue(calculator.computeHeuristicDocument(convertToDocument(allQuery), document).isFalse()); } + @Test + public void testAllOnScalarField() { + // a scalar matches a $all that only lists values equal to it + Document doc = new Document().append("tag", "a"); + MongoHeuristicsCalculator calculator = new MongoHeuristicsCalculator(); + + assertTrue(calculator.computeHeuristicDocument( + convertToDocument(Filters.all("tag", Arrays.asList("a"))), doc).isTrue()); + assertTrue(calculator.computeHeuristicDocument( + convertToDocument(Filters.all("tag", Arrays.asList("a", "a"))), doc).isTrue()); + assertTrue(calculator.computeHeuristicDocument( + convertToDocument(Filters.all("tag", Arrays.asList("a", "b"))), doc).isFalse()); + assertTrue(calculator.computeHeuristicDocument( + convertToDocument(Filters.all("tag", Arrays.asList("b"))), doc).isFalse()); + } + + @Test + public void testAllMatchingTheArrayAsAWhole() { + // the expected value can be the array itself, not only one of its elements + Document doc = new Document().append("tags", new ArrayList<>(Arrays.asList("a", "b"))); + Bson query = Filters.all("tags", Arrays.asList(Arrays.asList("a", "b"))); + assertTrue(new MongoHeuristicsCalculator() + .computeHeuristicDocument(convertToDocument(query), doc).isTrue()); + } + + @Test + public void testInMatchingTheArrayAsAWhole() { + Document doc = new Document().append("tags", new ArrayList<>(Arrays.asList("a", "b"))); + MongoHeuristicsCalculator calculator = new MongoHeuristicsCalculator(); + + Bson sameOrder = Filters.in("tags", Arrays.asList(Arrays.asList("a", "b"))); + Bson otherOrder = Filters.in("tags", Arrays.asList(Arrays.asList("b", "a"))); + + // an array is equal to another one only when their elements are in the same order + assertTrue(calculator.computeHeuristicDocument(convertToDocument(sameOrder), doc).isTrue()); + assertTrue(calculator.computeHeuristicDocument(convertToDocument(otherOrder), doc).isFalse()); + } + + @Test + public void testNotInMatchingTheArrayAsAWhole() { + Document doc = new Document().append("tags", new ArrayList<>(Arrays.asList("a", "b"))); + Bson query = Filters.nin("tags", Arrays.asList(Arrays.asList("a", "b"))); + assertTrue(new MongoHeuristicsCalculator() + .computeHeuristicDocument(convertToDocument(query), doc).isFalse()); + } + + @Test + public void testInOnEmptyArrayFieldMatchingTheEmptyArray() { + // the empty array holds no element, but it is still equal to the empty array + Document doc = new Document().append("tags", Collections.emptyList()); + MongoHeuristicsCalculator calculator = new MongoHeuristicsCalculator(); + + Bson in = Filters.in("tags", Arrays.asList(Collections.emptyList())); + Bson nin = Filters.nin("tags", Arrays.asList(Collections.emptyList())); + + assertTrue(calculator.computeHeuristicDocument(convertToDocument(in), doc).isTrue()); + assertTrue(calculator.computeHeuristicDocument(convertToDocument(nin), doc).isFalse()); + } + + @Test + public void testInMatchingAnArrayElementThatIsItselfAnArray() { + Document doc = new Document().append("tags", + new ArrayList<>(Arrays.asList(Arrays.asList("a", "b"), "c"))); + Bson query = Filters.in("tags", Arrays.asList(Arrays.asList("a", "b"))); + assertTrue(new MongoHeuristicsCalculator() + .computeHeuristicDocument(convertToDocument(query), doc).isTrue()); + } + + @Test + public void testAllMatchesWhenDocumentArrayHasExtraElements() { + // $all only requires the expected values to be present; extra elements are irrelevant + Document doc = new Document().append("employees", new ArrayList<>(Arrays.asList(1, 5, 6))); + Bson allQuery = Filters.all("employees", new ArrayList<>(Arrays.asList(1, 5))); + MongoHeuristicsCalculator calculator = new MongoHeuristicsCalculator(); + assertTrue(calculator.computeHeuristicDocument(convertToDocument(allQuery), doc).isTrue()); + } + + @Test + public void testAllDoesNotMatchWhenAnExpectedValueIsMissing() { + // the array contains 1, but not 2 nor 3, so the condition does not hold + Document doc = new Document().append("employees", new ArrayList<>(Arrays.asList(1))); + Bson allQuery = Filters.all("employees", new ArrayList<>(Arrays.asList(1, 2, 3))); + MongoHeuristicsCalculator calculator = new MongoHeuristicsCalculator(); + assertTrue(calculator.computeHeuristicDocument(convertToDocument(allQuery), doc).isFalse()); + } + + @Test + public void testAllGivesBetterScoreWhenFewerExpectedValuesAreMissing() { + Bson allQuery = Filters.all("employees", new ArrayList<>(Arrays.asList(1, 2, 3))); + Document closer = new Document().append("employees", new ArrayList<>(Arrays.asList(1, 2))); + Document farther = new Document().append("employees", new ArrayList<>(Arrays.asList(1))); + + MongoHeuristicsCalculator calculator = new MongoHeuristicsCalculator(); + Truthness closerTruthness = calculator.computeHeuristicDocument(convertToDocument(allQuery), closer); + Truthness fartherTruthness = calculator.computeHeuristicDocument(convertToDocument(allQuery), farther); + + assertTrue(closerTruthness.isFalse()); + assertTrue(fartherTruthness.isFalse()); + assertTrue(closerTruthness.getOfTrue() > fartherTruthness.getOfTrue(), + "a document missing fewer expected values must be scored closer to true"); + } + @Test public void testSize() { @@ -527,6 +670,40 @@ public void testNotMissingField() { assertTrue(distanceMatch.isTrue()); } + @Test + public void testNotMissingFieldWithInnerOperatorThatMatchesAbsentField() { + /* + $ne, $nin and $exists:false all match a document in which the field is absent, + so negating them must not match. This is the case a blanket "true when the field + is missing" answer gets wrong. + */ + Document doc = new Document().append("name", "Bob"); // "age" field is undefined + MongoHeuristicsCalculator calculator = new MongoHeuristicsCalculator(); + + Bson notNotEquals = Filters.not(Filters.ne("age", 5)); + Bson notNotIn = Filters.not(Filters.nin("age", new ArrayList<>(Arrays.asList(1, 2)))); + Bson notExistsFalse = Filters.not(Filters.exists("age", false)); + + assertTrue(calculator.computeHeuristicDocument(convertToDocument(notNotEquals), doc).isFalse()); + assertTrue(calculator.computeHeuristicDocument(convertToDocument(notNotIn), doc).isFalse()); + assertTrue(calculator.computeHeuristicDocument(convertToDocument(notExistsFalse), doc).isFalse()); + } + + @Test + public void testNotMissingFieldWithInnerOperatorThatDoesNotMatchAbsentField() { + // the complementary cases, which must stay true once the missing-field shortcut is gone + Document doc = new Document().append("name", "Bob"); // "age" field is undefined + MongoHeuristicsCalculator calculator = new MongoHeuristicsCalculator(); + + Bson notEquals = Filters.not(Filters.eq("age", 5)); + Bson notIn = Filters.not(Filters.in("age", new ArrayList<>(Arrays.asList(1, 2)))); + Bson notExistsTrue = Filters.not(Filters.exists("age", true)); + + assertTrue(calculator.computeHeuristicDocument(convertToDocument(notEquals), doc).isTrue()); + assertTrue(calculator.computeHeuristicDocument(convertToDocument(notIn), doc).isTrue()); + assertTrue(calculator.computeHeuristicDocument(convertToDocument(notExistsTrue), doc).isTrue()); + } + @Test public void testNotNullValue() { Document doc = new Document().append("age", null); @@ -655,6 +832,39 @@ public void testEqualsStringOnBooleanField() { assertTrue(distance.isFalse()); } + @Test + public void testNotEqualsStringOnIntegerField() { + // values of different, incomparable BSON types are different, so $ne holds + Document doc = new Document().append("value", 42); + Bson bson = Filters.ne("value", "abc"); + + Truthness distance = new MongoHeuristicsCalculator().computeHeuristicDocument(convertToDocument(bson), doc); + + assertTrue(distance.isTrue()); + } + + @Test + public void testNotEqualsIntegerOnBooleanField() { + Document doc = new Document().append("value", true); + Bson bson = Filters.ne("value", 1); + + Truthness distance = new MongoHeuristicsCalculator().computeHeuristicDocument(convertToDocument(bson), doc); + + assertTrue(distance.isTrue()); + } + + @Test + public void testOrderingComparisonsStayFalseAcrossIncomparableTypes() { + // unlike $ne, ordering operators do not match across different BSON types + Document doc = new Document().append("value", 42); + MongoHeuristicsCalculator calculator = new MongoHeuristicsCalculator(); + + assertTrue(calculator.computeHeuristicDocument(convertToDocument(Filters.gt("value", "abc")), doc).isFalse()); + assertTrue(calculator.computeHeuristicDocument(convertToDocument(Filters.gte("value", "abc")), doc).isFalse()); + assertTrue(calculator.computeHeuristicDocument(convertToDocument(Filters.lt("value", "abc")), doc).isFalse()); + assertTrue(calculator.computeHeuristicDocument(convertToDocument(Filters.lte("value", "abc")), doc).isFalse()); + } + @Test public void testEqualsDouble() { Document doc = new Document().append("score", 10.5d); @@ -975,6 +1185,48 @@ public void testEqualsLists() { assertTrue(distanceNotMatch.isFalse()); } + @Test + public void testEqualsMatchingAnElementOfAnArrayField() { + // a field holding an array matches a value when any of its elements is that value + Document doc = new Document().append("tags", new ArrayList<>(Arrays.asList("a", "b"))); + MongoHeuristicsCalculator calculator = new MongoHeuristicsCalculator(); + + assertTrue(calculator.computeHeuristicDocument( + convertToDocument(Filters.eq("tags", "a")), doc).isTrue()); + assertTrue(calculator.computeHeuristicDocument( + convertToDocument(Filters.ne("tags", "a")), doc).isFalse()); + + assertTrue(calculator.computeHeuristicDocument( + convertToDocument(Filters.eq("tags", "z")), doc).isFalse()); + assertTrue(calculator.computeHeuristicDocument( + convertToDocument(Filters.ne("tags", "z")), doc).isTrue()); + } + + @Test + public void testEqualsMatchingAnArrayFieldAsAWhole() { + // the same field is also matched by the array itself, not only by its elements + Document doc = new Document().append("tags", new ArrayList<>(Arrays.asList("a", "b"))); + MongoHeuristicsCalculator calculator = new MongoHeuristicsCalculator(); + + assertTrue(calculator.computeHeuristicDocument( + convertToDocument(Filters.eq("tags", Arrays.asList("a", "b"))), doc).isTrue()); + assertTrue(calculator.computeHeuristicDocument( + convertToDocument(Filters.ne("tags", Arrays.asList("a", "b"))), doc).isFalse()); + } + + @Test + public void testEqualsBetweenEmptyLists() { + // two empty arrays are equal; comparing them used to have no element to aggregate over + Document doc = new Document().append("employees", Collections.emptyList()); + MongoHeuristicsCalculator calculator = new MongoHeuristicsCalculator(); + + Bson equals = Filters.eq("employees", Collections.emptyList()); + Bson notEquals = Filters.ne("employees", Collections.emptyList()); + + assertTrue(calculator.computeHeuristicDocument(convertToDocument(equals), doc).isTrue()); + assertTrue(calculator.computeHeuristicDocument(convertToDocument(notEquals), doc).isFalse()); + } + @Test public void testNotEqualsLists() { Document doc = new Document().append("employees", Arrays.asList("Alice")); diff --git a/core-tests/e2e-tests/spring/spring-rest-mongo/src/main/java/com/mongo/mongoqueries/MongoQueriesController.java b/core-tests/e2e-tests/spring/spring-rest-mongo/src/main/java/com/mongo/mongoqueries/MongoQueriesController.java index 64ddbb0594..b2f32ee577 100644 --- a/core-tests/e2e-tests/spring/spring-rest-mongo/src/main/java/com/mongo/mongoqueries/MongoQueriesController.java +++ b/core-tests/e2e-tests/spring/spring-rest-mongo/src/main/java/com/mongo/mongoqueries/MongoQueriesController.java @@ -155,6 +155,34 @@ public ResponseEntity findAll() { return executeQuery(new Document("tags", new Document("$all", Arrays.asList("a", "b")))); } + /** + * "name" holds a string, so it is of a different, incomparable BSON type than the + * number being compared against. MongoDB considers such values different, so $ne holds. + */ + @GetMapping("neCrossType") + public ResponseEntity findNeCrossType() { + return executeQuery(new Document("name", new Document("$ne", 42))); + } + + /** + * "tags" holds an array, so $nin must look at its elements: only a document whose + * array does not hold "a" satisfies this. + */ + @GetMapping("ninArrayField") + public ResponseEntity findNinArrayField() { + return executeQuery(new Document("tags", new Document("$nin", Arrays.asList("a")))); + } + + /** + * $exists with "false" matches a document in which the field is absent, so negating it + * must match only the documents that do have the field. + */ + @GetMapping("notExistsFalse") + public ResponseEntity findNotExistsFalse() { + return executeQuery(new Document("description", + new Document("$not", new Document("$exists", false)))); + } + @GetMapping("type") public ResponseEntity findType() { return executeQuery(new Document("name", new Document("$type", 2))); diff --git a/core-tests/e2e-tests/spring/spring-rest-mongo/src/test/java/org/evomaster/e2etests/spring/rest/mongo/mongoqueries/MongoQueriesEMTest.java b/core-tests/e2e-tests/spring/spring-rest-mongo/src/test/java/org/evomaster/e2etests/spring/rest/mongo/mongoqueries/MongoQueriesEMTest.java index 86a9ce5cb5..034b48d6dc 100644 --- a/core-tests/e2e-tests/spring/spring-rest-mongo/src/test/java/org/evomaster/e2etests/spring/rest/mongo/mongoqueries/MongoQueriesEMTest.java +++ b/core-tests/e2e-tests/spring/spring-rest-mongo/src/test/java/org/evomaster/e2etests/spring/rest/mongo/mongoqueries/MongoQueriesEMTest.java @@ -57,6 +57,9 @@ public void testRunEM() throws Throwable { assertHasAtLeastOne(solution, HttpVerb.GET, 200, "/mongoqueries/bitsAllSet", null); assertHasAtLeastOne(solution, HttpVerb.GET, 200, "/mongoqueries/bitsAnyClear", null); assertHasAtLeastOne(solution, HttpVerb.GET, 200, "/mongoqueries/all", null); + assertHasAtLeastOne(solution, HttpVerb.GET, 200, "/mongoqueries/neCrossType", null); + assertHasAtLeastOne(solution, HttpVerb.GET, 200, "/mongoqueries/ninArrayField", null); + assertHasAtLeastOne(solution, HttpVerb.GET, 200, "/mongoqueries/notExistsFalse", null); assertHasAtLeastOne(solution, HttpVerb.GET, 200, "/mongoqueries/type", null); assertHasAtLeastOne(solution, HttpVerb.GET, 200, "/mongoqueries/exists", null); assertHasAtLeastOne(solution, HttpVerb.GET, 200, "/mongoqueries/nor", null);