summaryrefslogtreecommitdiff
path: root/src/mongo/db/matcher/expression_algo_test.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/matcher/expression_algo_test.cpp')
-rw-r--r--src/mongo/db/matcher/expression_algo_test.cpp1173
1 files changed, 587 insertions, 586 deletions
diff --git a/src/mongo/db/matcher/expression_algo_test.cpp b/src/mongo/db/matcher/expression_algo_test.cpp
index 63af7a52c96..a108a7a7f3b 100644
--- a/src/mongo/db/matcher/expression_algo_test.cpp
+++ b/src/mongo/db/matcher/expression_algo_test.cpp
@@ -40,591 +40,592 @@
namespace mongo {
- /**
- * A MatchExpression does not hold the memory for BSONElements, so use ParsedMatchExpression to
- * ensure that the BSONObj outlives the MatchExpression.
- */
- class ParsedMatchExpression {
- public:
- ParsedMatchExpression(const std::string& str)
- : _obj(fromjson(str)) {
- StatusWithMatchExpression result = MatchExpressionParser::parse(_obj);
- ASSERT_OK(result.getStatus());
- _expr.reset(result.getValue());
- }
-
- const MatchExpression* get() const { return _expr.get(); }
-
- private:
- const BSONObj _obj;
- std::unique_ptr<MatchExpression> _expr;
- };
-
- TEST(ExpressionAlgoIsSubsetOf, NullAndOmittedField) {
- // Verify that ComparisonMatchExpression::init() prohibits creating a match expression with
- // an Undefined type.
- BSONObj undefined = fromjson("{a: undefined}");
- ASSERT_EQUALS(ErrorCodes::BadValue, MatchExpressionParser::parse(undefined).getStatus());
-
- ParsedMatchExpression empty("{}");
- ParsedMatchExpression null("{a: null}");
-
- ASSERT_TRUE(expression::isSubsetOf(null.get(), empty.get()));
- ASSERT_FALSE(expression::isSubsetOf(empty.get(), null.get()));
-
- ParsedMatchExpression b1("{b: 1}");
- ParsedMatchExpression aNullB1("{a: null, b: 1}");
-
- ASSERT_TRUE(expression::isSubsetOf(aNullB1.get(), b1.get()));
- ASSERT_FALSE(expression::isSubsetOf(b1.get(), aNullB1.get()));
-
- ParsedMatchExpression a1C3("{a: 1, c: 3}");
- ParsedMatchExpression a1BNullC3("{a: 1, b: null, c: 3}");
-
- ASSERT_TRUE(expression::isSubsetOf(a1BNullC3.get(), a1C3.get()));
- ASSERT_FALSE(expression::isSubsetOf(a1C3.get(), a1BNullC3.get()));
- }
-
- TEST(ExpressionAlgoIsSubsetOf, NullAndIn) {
- ParsedMatchExpression eqNull("{x: null}");
- ParsedMatchExpression inNull("{x: {$in: [null]}}");
- ParsedMatchExpression inNullOr2("{x: {$in: [null, 2]}}");
-
- ASSERT_TRUE(expression::isSubsetOf(inNull.get(), eqNull.get()));
- ASSERT_FALSE(expression::isSubsetOf(inNullOr2.get(), eqNull.get()));
- }
-
- TEST(ExpressionAlgoIsSubsetOf, NullAndExists) {
- ParsedMatchExpression null("{x: null}");
- ParsedMatchExpression exists("{x: {$exists: true}}");
- ASSERT_FALSE(expression::isSubsetOf(null.get(), exists.get()));
- ASSERT_FALSE(expression::isSubsetOf(exists.get(), null.get()));
- }
-
- TEST(ExpressionAlgoIsSubsetOf, Compare_NaN) {
- ParsedMatchExpression nan("{x: NaN}");
- ParsedMatchExpression lt("{x: {$lt: 5}}");
- ParsedMatchExpression lte("{x: {$lte: 5}}");
- ParsedMatchExpression gte("{x: {$gte: 5}}");
- ParsedMatchExpression gt("{x: {$gt: 5}}");
- ParsedMatchExpression in("{x: {$in: [5]}}");
-
- ASSERT_TRUE(expression::isSubsetOf(nan.get(), nan.get()));
- ASSERT_FALSE(expression::isSubsetOf(nan.get(), lt.get()));
- ASSERT_FALSE(expression::isSubsetOf(lt.get(), nan.get()));
- ASSERT_FALSE(expression::isSubsetOf(nan.get(), lte.get()));
- ASSERT_FALSE(expression::isSubsetOf(lte.get(), nan.get()));
- ASSERT_FALSE(expression::isSubsetOf(nan.get(), gte.get()));
- ASSERT_FALSE(expression::isSubsetOf(gte.get(), nan.get()));
- ASSERT_FALSE(expression::isSubsetOf(nan.get(), gt.get()));
- ASSERT_FALSE(expression::isSubsetOf(gt.get(), nan.get()));
- ASSERT_FALSE(expression::isSubsetOf(nan.get(), in.get()));
- ASSERT_FALSE(expression::isSubsetOf(in.get(), nan.get()));
- }
-
- TEST(ExpressionAlgoIsSubsetOf, Compare_EQ) {
- ParsedMatchExpression a5("{a: 5}");
- ParsedMatchExpression a6("{a: 6}");
- ParsedMatchExpression b5("{b: 5}");
-
- ASSERT_TRUE(expression::isSubsetOf(a5.get(), a5.get()));
- ASSERT_FALSE(expression::isSubsetOf(a5.get(), a6.get()));
- ASSERT_FALSE(expression::isSubsetOf(a5.get(), b5.get()));
- }
-
- TEST(ExpressionAlgoIsSubsetOf, CompareAnd_EQ) {
- ParsedMatchExpression a1B2("{a: 1, b: 2}");
- ParsedMatchExpression a1B7("{a: 1, b: 7}");
- ParsedMatchExpression a1("{a: 1}");
- ParsedMatchExpression b2("{b: 2}");
-
- ASSERT_TRUE(expression::isSubsetOf(a1B2.get(), a1B2.get()));
- ASSERT_FALSE(expression::isSubsetOf(a1B2.get(), a1B7.get()));
-
- ASSERT_TRUE(expression::isSubsetOf(a1B2.get(), a1.get()));
- ASSERT_TRUE(expression::isSubsetOf(a1B2.get(), b2.get()));
- ASSERT_FALSE(expression::isSubsetOf(a1B7.get(), b2.get()));
- }
-
- TEST(ExpressionAlgoIsSubsetOf, CompareAnd_GT) {
- ParsedMatchExpression filter("{a: {$gt: 5}, b: {$gt: 6}}");
- ParsedMatchExpression query("{a: {$gt: 5}, b: {$gt: 6}, c: {$gt: 7}}");
-
- ASSERT_TRUE(expression::isSubsetOf(query.get(), filter.get()));
- ASSERT_FALSE(expression::isSubsetOf(filter.get(), query.get()));
- }
-
- TEST(ExpressionAlgoIsSubsetOf, CompareOr_LT) {
- ParsedMatchExpression lt5("{a: {$lt: 5}}");
- ParsedMatchExpression eq2OrEq3("{$or: [{a: 2}, {a: 3}]}");
- ParsedMatchExpression eq4OrEq5("{$or: [{a: 4}, {a: 5}]}");
- ParsedMatchExpression eq4OrEq6("{$or: [{a: 4}, {a: 6}]}");
-
- ASSERT_TRUE(expression::isSubsetOf(eq2OrEq3.get(), lt5.get()));
- ASSERT_FALSE(expression::isSubsetOf(eq4OrEq5.get(), lt5.get()));
- ASSERT_FALSE(expression::isSubsetOf(eq4OrEq6.get(), lt5.get()));
- }
-
- TEST(ExpressionAlgoIsSubsetOf, CompareOr_GTE) {
- ParsedMatchExpression gte5("{a: {$gte: 5}}");
- ParsedMatchExpression eq4OrEq6("{$or: [{a: 4}, {a: 6}]}");
- ParsedMatchExpression eq5OrEq6("{$or: [{a: 5}, {a: 6}]}");
- ParsedMatchExpression eq7OrEq8("{$or: [{a: 7}, {a: 8}]}");
-
- ASSERT_FALSE(expression::isSubsetOf(eq4OrEq6.get(), gte5.get()));
- ASSERT_TRUE(expression::isSubsetOf(eq5OrEq6.get(), gte5.get()));
- ASSERT_TRUE(expression::isSubsetOf(eq7OrEq8.get(), gte5.get()));
- }
-
- TEST(ExpressionAlgoIsSubsetOf, DifferentCanonicalTypes) {
- ParsedMatchExpression number("{x: {$gt: 1}}");
- ParsedMatchExpression string("{x: {$gt: 'a'}}");
- ASSERT_FALSE(expression::isSubsetOf(number.get(), string.get()));
- ASSERT_FALSE(expression::isSubsetOf(string.get(), number.get()));
- }
-
- TEST(ExpressionAlgoIsSubsetOf, DifferentNumberTypes) {
- ParsedMatchExpression numberDouble("{x: 5.0}");
- ParsedMatchExpression numberInt("{x: NumberInt(5)}");
- ParsedMatchExpression numberLong("{x: NumberLong(5)}");
-
- ASSERT_TRUE(expression::isSubsetOf(numberDouble.get(), numberInt.get()));
- ASSERT_TRUE(expression::isSubsetOf(numberDouble.get(), numberLong.get()));
- ASSERT_TRUE(expression::isSubsetOf(numberInt.get(), numberDouble.get()));
- ASSERT_TRUE(expression::isSubsetOf(numberInt.get(), numberLong.get()));
- ASSERT_TRUE(expression::isSubsetOf(numberLong.get(), numberDouble.get()));
- ASSERT_TRUE(expression::isSubsetOf(numberLong.get(), numberInt.get()));
- }
-
- TEST(ExpressionAlgoIsSubsetOf, PointInUnboundedRange) {
- ParsedMatchExpression a4("{a: 4}");
- ParsedMatchExpression a5("{a: 5}");
- ParsedMatchExpression a6("{a: 6}");
- ParsedMatchExpression b5("{b: 5}");
-
- ParsedMatchExpression lt5("{a: {$lt: 5}}");
- ParsedMatchExpression lte5("{a: {$lte: 5}}");
- ParsedMatchExpression gte5("{a: {$gte: 5}}");
- ParsedMatchExpression gt5("{a: {$gt: 5}}");
-
- ASSERT_TRUE(expression::isSubsetOf(a4.get(), lte5.get()));
- ASSERT_TRUE(expression::isSubsetOf(a5.get(), lte5.get()));
- ASSERT_FALSE(expression::isSubsetOf(a6.get(), lte5.get()));
-
- ASSERT_TRUE(expression::isSubsetOf(a4.get(), lt5.get()));
- ASSERT_FALSE(expression::isSubsetOf(a5.get(), lt5.get()));
- ASSERT_FALSE(expression::isSubsetOf(a6.get(), lt5.get()));
-
- ASSERT_FALSE(expression::isSubsetOf(a4.get(), gte5.get()));
- ASSERT_TRUE(expression::isSubsetOf(a5.get(), gte5.get()));
- ASSERT_TRUE(expression::isSubsetOf(a6.get(), gte5.get()));
-
- ASSERT_FALSE(expression::isSubsetOf(a4.get(), gt5.get()));
- ASSERT_FALSE(expression::isSubsetOf(a5.get(), gt5.get()));
- ASSERT_TRUE(expression::isSubsetOf(a6.get(), gt5.get()));
-
- // An unbounded range query does not match a subset of documents of a point query.
- ASSERT_FALSE(expression::isSubsetOf(lt5.get(), a5.get()));
- ASSERT_FALSE(expression::isSubsetOf(lte5.get(), a5.get()));
- ASSERT_FALSE(expression::isSubsetOf(gte5.get(), a5.get()));
- ASSERT_FALSE(expression::isSubsetOf(gt5.get(), a5.get()));
-
- // Cannot be a subset if comparing different field names.
- ASSERT_FALSE(expression::isSubsetOf(b5.get(), lt5.get()));
- ASSERT_FALSE(expression::isSubsetOf(b5.get(), lte5.get()));
- ASSERT_FALSE(expression::isSubsetOf(b5.get(), gte5.get()));
- ASSERT_FALSE(expression::isSubsetOf(b5.get(), gt5.get()));
- }
-
- TEST(ExpressionAlgoIsSubsetOf, PointInBoundedRange) {
- ParsedMatchExpression filter("{a: {$gt: 5, $lt: 10}}");
- ParsedMatchExpression query("{a: 6}");
-
- ASSERT_TRUE(expression::isSubsetOf(query.get(), filter.get()));
- ASSERT_FALSE(expression::isSubsetOf(filter.get(), query.get()));
- }
-
- TEST(ExpressionAlgoIsSubsetOf, PointInBoundedRange_FakeAnd) {
- ParsedMatchExpression filter("{a: {$gt: 5, $lt: 10}}");
- ParsedMatchExpression query("{$and: [{a: 6}, {a: 6}]}");
-
- ASSERT_TRUE(expression::isSubsetOf(query.get(), filter.get()));
- ASSERT_FALSE(expression::isSubsetOf(filter.get(), query.get()));
- }
-
- TEST(ExpressionAlgoIsSubsetOf, MultiplePointsInBoundedRange) {
- ParsedMatchExpression filter("{a: {$gt: 5, $lt: 10}}");
- ParsedMatchExpression queryAllInside("{a: {$in: [6, 7, 8]}}");
- ParsedMatchExpression queryStraddleLower("{a: {$in: [4.9, 5.1]}}");
- ParsedMatchExpression queryStraddleUpper("{a: {$in: [9.9, 10.1]}}");
-
- ASSERT_TRUE(expression::isSubsetOf(queryAllInside.get(), filter.get()));
- ASSERT_FALSE(expression::isSubsetOf(queryStraddleLower.get(), filter.get()));
- ASSERT_FALSE(expression::isSubsetOf(queryStraddleUpper.get(), filter.get()));
- }
-
- TEST(ExpressionAlgoIsSubsetOf, PointInCompoundRange) {
- ParsedMatchExpression filter("{a: {$gt: 5}, b: {$gt: 6}, c: {$gt: 7}}");
- ParsedMatchExpression query("{a: 10, b: 10, c: 10}");
-
- ASSERT_TRUE(expression::isSubsetOf(query.get(), filter.get()));
- ASSERT_FALSE(expression::isSubsetOf(filter.get(), query.get()));
- }
-
- TEST(ExpressionAlgoIsSubsetOf, Compare_LT_LTE) {
- ParsedMatchExpression lte4("{x: {$lte: 4}}");
- ParsedMatchExpression lt5("{x: {$lt: 5}}");
- ParsedMatchExpression lte5("{x: {$lte: 5}}");
- ParsedMatchExpression lt6("{x: {$lt: 6}}");
-
- ASSERT_TRUE(expression::isSubsetOf(lte4.get(), lte5.get()));
- ASSERT_TRUE(expression::isSubsetOf(lt5.get(), lte5.get()));
- ASSERT_TRUE(expression::isSubsetOf(lte5.get(), lte5.get()));
- ASSERT_FALSE(expression::isSubsetOf(lt6.get(), lte5.get()));
-
- ASSERT_TRUE(expression::isSubsetOf(lte4.get(), lt5.get()));
- ASSERT_TRUE(expression::isSubsetOf(lt5.get(), lt5.get()));
- ASSERT_FALSE(expression::isSubsetOf(lte5.get(), lt5.get()));
- ASSERT_FALSE(expression::isSubsetOf(lt6.get(), lt5.get()));
- }
-
- TEST(ExpressionAlgoIsSubsetOf, Compare_GT_GTE) {
- ParsedMatchExpression gte6("{x: {$gte: 6}}");
- ParsedMatchExpression gt5("{x: {$gt: 5}}");
- ParsedMatchExpression gte5("{x: {$gte: 5}}");
- ParsedMatchExpression gt4("{x: {$gt: 4}}");
-
- ASSERT_TRUE(expression::isSubsetOf(gte6.get(), gte5.get()));
- ASSERT_TRUE(expression::isSubsetOf(gt5.get(), gte5.get()));
- ASSERT_TRUE(expression::isSubsetOf(gte5.get(), gte5.get()));
- ASSERT_FALSE(expression::isSubsetOf(gt4.get(), gte5.get()));
-
- ASSERT_TRUE(expression::isSubsetOf(gte6.get(), gt5.get()));
- ASSERT_TRUE(expression::isSubsetOf(gt5.get(), gt5.get()));
- ASSERT_FALSE(expression::isSubsetOf(gte5.get(), gt5.get()));
- ASSERT_FALSE(expression::isSubsetOf(gt4.get(), gt5.get()));
- }
-
- TEST(ExpressionAlgoIsSubsetOf, BoundedRangeInUnboundedRange) {
- ParsedMatchExpression filter("{a: {$gt: 1}}");
- ParsedMatchExpression query("{a: {$gt: 5, $lt: 10}}");
-
- ASSERT_TRUE(expression::isSubsetOf(query.get(), filter.get()));
- ASSERT_FALSE(expression::isSubsetOf(filter.get(), query.get()));
- }
-
- TEST(ExpressionAlgoIsSubsetOf, MultipleRangesInUnboundedRange) {
- ParsedMatchExpression filter("{a: {$gt: 1}}");
- ParsedMatchExpression negative("{$or: [{a: {$gt: 5, $lt: 10}}, {a: {$lt: 0}}]}");
- ParsedMatchExpression unbounded("{$or: [{a: {$gt: 5, $lt: 10}}, {a: {$gt: 15}}]}");
- ParsedMatchExpression bounded("{$or: [{a: {$gt: 5, $lt: 10}}, {a: {$gt: 20, $lt: 30}}]}");
-
- ASSERT_FALSE(expression::isSubsetOf(negative.get(), filter.get()));
- ASSERT_TRUE(expression::isSubsetOf(unbounded.get(), filter.get()));
- ASSERT_TRUE(expression::isSubsetOf(bounded.get(), filter.get()));
- }
-
- TEST(ExpressionAlgoIsSubsetOf, MultipleFields) {
- ParsedMatchExpression filter("{a: {$gt: 5}, b: {$lt: 10}}");
- ParsedMatchExpression onlyA("{$or: [{a: 6, b: {$lt: 4}}, {a: {$gt: 11}}]}");
- ParsedMatchExpression onlyB("{$or: [{b: {$lt: 4}}, {a: {$gt: 11}, b: 9}]}");
- ParsedMatchExpression both("{$or: [{a: 6, b: {$lt: 4}}, {a: {$gt: 11}, b: 9}]}");
-
- ASSERT_FALSE(expression::isSubsetOf(onlyA.get(), filter.get()));
- ASSERT_FALSE(expression::isSubsetOf(onlyB.get(), filter.get()));
- ASSERT_TRUE(expression::isSubsetOf(both.get(), filter.get()));
- }
-
- TEST(ExpressionAlgoIsSubsetOf, Compare_LT_In) {
- ParsedMatchExpression lt("{a: {$lt: 5}}");
-
- ParsedMatchExpression inLt("{a: {$in: [4.9]}}");
- ParsedMatchExpression inEq("{a: {$in: [5]}}");
- ParsedMatchExpression inGt("{a: {$in: [5.1]}}");
- ParsedMatchExpression inNull("{a: {$in: [null]}}");
-
- ParsedMatchExpression inAllEq("{a: {$in: [5, 5.0]}}");
- ParsedMatchExpression inAllLte("{a: {$in: [4.9, 5]}}");
- ParsedMatchExpression inAllLt("{a: {$in: [2, 3, 4]}}");
- ParsedMatchExpression inStraddle("{a: {$in: [4, 6]}}");
- ParsedMatchExpression inLtAndNull("{a: {$in: [1, null]}}");
-
- ASSERT_TRUE(expression::isSubsetOf(inLt.get(), lt.get()));
- ASSERT_FALSE(expression::isSubsetOf(inEq.get(), lt.get()));
- ASSERT_FALSE(expression::isSubsetOf(inGt.get(), lt.get()));
-
- ASSERT_FALSE(expression::isSubsetOf(inAllEq.get(), lt.get()));
- ASSERT_FALSE(expression::isSubsetOf(inAllLte.get(), lt.get()));
- ASSERT_TRUE(expression::isSubsetOf(inAllLt.get(), lt.get()));
- ASSERT_FALSE(expression::isSubsetOf(inStraddle.get(), lt.get()));
- ASSERT_FALSE(expression::isSubsetOf(inLtAndNull.get(), lt.get()));
- }
-
- TEST(ExpressionAlgoIsSubsetOf, Compare_LTE_In) {
- ParsedMatchExpression lte("{a: {$lte: 5}}");
-
- ParsedMatchExpression inLt("{a: {$in: [4.9]}}");
- ParsedMatchExpression inEq("{a: {$in: [5]}}");
- ParsedMatchExpression inGt("{a: {$in: [5.1]}}");
- ParsedMatchExpression inNull("{a: {$in: [null]}}");
-
- ParsedMatchExpression inAllEq("{a: {$in: [5, 5.0]}}");
- ParsedMatchExpression inAllLte("{a: {$in: [4.9, 5]}}");
- ParsedMatchExpression inAllLt("{a: {$in: [2, 3, 4]}}");
- ParsedMatchExpression inStraddle("{a: {$in: [4, 6]}}");
- ParsedMatchExpression inLtAndNull("{a: {$in: [1, null]}}");
-
- ASSERT_TRUE(expression::isSubsetOf(inLt.get(), lte.get()));
- ASSERT_TRUE(expression::isSubsetOf(inEq.get(), lte.get()));
- ASSERT_FALSE(expression::isSubsetOf(inGt.get(), lte.get()));
-
- ASSERT_TRUE(expression::isSubsetOf(inAllEq.get(), lte.get()));
- ASSERT_TRUE(expression::isSubsetOf(inAllLte.get(), lte.get()));
- ASSERT_TRUE(expression::isSubsetOf(inAllLt.get(), lte.get()));
- ASSERT_FALSE(expression::isSubsetOf(inStraddle.get(), lte.get()));
- ASSERT_FALSE(expression::isSubsetOf(inLtAndNull.get(), lte.get()));
- }
-
- TEST(ExpressionAlgoIsSubsetOf, Compare_EQ_In) {
- ParsedMatchExpression eq("{a: 5}");
-
- ParsedMatchExpression inLt("{a: {$in: [4.9]}}");
- ParsedMatchExpression inEq("{a: {$in: [5]}}");
- ParsedMatchExpression inGt("{a: {$in: [5.1]}}");
- ParsedMatchExpression inNull("{a: {$in: [null]}}");
-
- ParsedMatchExpression inAllEq("{a: {$in: [5, 5.0]}}");
- ParsedMatchExpression inStraddle("{a: {$in: [4, 6]}}");
- ParsedMatchExpression inEqAndNull("{a: {$in: [5, null]}}");
-
- ASSERT_FALSE(expression::isSubsetOf(inLt.get(), eq.get()));
- ASSERT_TRUE(expression::isSubsetOf(inEq.get(), eq.get()));
- ASSERT_FALSE(expression::isSubsetOf(inGt.get(), eq.get()));
-
- ASSERT_TRUE(expression::isSubsetOf(inAllEq.get(), eq.get()));
- ASSERT_FALSE(expression::isSubsetOf(inStraddle.get(), eq.get()));
- ASSERT_FALSE(expression::isSubsetOf(inEqAndNull.get(), eq.get()));
- }
-
- TEST(ExpressionAlgoIsSubsetOf, Compare_GT_In) {
- ParsedMatchExpression gt("{a: {$gt: 5}}");
-
- ParsedMatchExpression inLt("{a: {$in: [4.9]}}");
- ParsedMatchExpression inEq("{a: {$in: [5]}}");
- ParsedMatchExpression inGt("{a: {$in: [5.1]}}");
- ParsedMatchExpression inNull("{a: {$in: [null]}}");
-
- ParsedMatchExpression inAllEq("{a: {$in: [5, 5.0]}}");
- ParsedMatchExpression inAllGte("{a: {$in: [5, 5.1]}}");
- ParsedMatchExpression inAllGt("{a: {$in: [6, 7, 8]}}");
- ParsedMatchExpression inStraddle("{a: {$in: [4, 6]}}");
- ParsedMatchExpression inGtAndNull("{a: {$in: [9, null]}}");
-
- ASSERT_FALSE(expression::isSubsetOf(inLt.get(), gt.get()));
- ASSERT_FALSE(expression::isSubsetOf(inEq.get(), gt.get()));
- ASSERT_TRUE(expression::isSubsetOf(inGt.get(), gt.get()));
-
- ASSERT_FALSE(expression::isSubsetOf(inAllEq.get(), gt.get()));
- ASSERT_FALSE(expression::isSubsetOf(inAllGte.get(), gt.get()));
- ASSERT_TRUE(expression::isSubsetOf(inAllGt.get(), gt.get()));
- ASSERT_FALSE(expression::isSubsetOf(inStraddle.get(), gt.get()));
- ASSERT_FALSE(expression::isSubsetOf(inGtAndNull.get(), gt.get()));
- }
-
- TEST(ExpressionAlgoIsSubsetOf, Compare_GTE_In) {
- ParsedMatchExpression gte("{a: {$gte: 5}}");
-
- ParsedMatchExpression inLt("{a: {$in: [4.9]}}");
- ParsedMatchExpression inEq("{a: {$in: [5]}}");
- ParsedMatchExpression inGt("{a: {$in: [5.1]}}");
- ParsedMatchExpression inNull("{a: {$in: [null]}}");
-
- ParsedMatchExpression inAllEq("{a: {$in: [5, 5.0]}}");
- ParsedMatchExpression inAllGte("{a: {$in: [5, 5.1]}}");
- ParsedMatchExpression inAllGt("{a: {$in: [6, 7, 8]}}");
- ParsedMatchExpression inStraddle("{a: {$in: [4, 6]}}");
- ParsedMatchExpression inGtAndNull("{a: {$in: [9, null]}}");
-
- ASSERT_FALSE(expression::isSubsetOf(inLt.get(), gte.get()));
- ASSERT_TRUE(expression::isSubsetOf(inEq.get(), gte.get()));
- ASSERT_TRUE(expression::isSubsetOf(inGt.get(), gte.get()));
-
- ASSERT_TRUE(expression::isSubsetOf(inAllEq.get(), gte.get()));
- ASSERT_TRUE(expression::isSubsetOf(inAllGte.get(), gte.get()));
- ASSERT_TRUE(expression::isSubsetOf(inAllGt.get(), gte.get()));
- ASSERT_FALSE(expression::isSubsetOf(inStraddle.get(), gte.get()));
- ASSERT_FALSE(expression::isSubsetOf(inGtAndNull.get(), gte.get()));
- }
-
- TEST(ExpressionAlgoIsSubsetOf, RegexAndIn) {
- ParsedMatchExpression eq1("{x: 1}");
- ParsedMatchExpression eqA("{x: 'a'}");
- ParsedMatchExpression inRegexA("{x: {$in: [/a/]}}");
- ParsedMatchExpression inRegexAbc("{x: {$in: [/abc/]}}");
- ParsedMatchExpression inRegexAOrEq1("{x: {$in: [/a/, 1]}}");
- ParsedMatchExpression inRegexAOrNull("{x: {$in: [/a/, null]}}");
-
- ASSERT_TRUE(expression::isSubsetOf(inRegexA.get(), inRegexA.get()));
- ASSERT_FALSE(expression::isSubsetOf(inRegexAbc.get(), inRegexA.get()));
- ASSERT_FALSE(expression::isSubsetOf(inRegexA.get(), inRegexAOrEq1.get()));
- ASSERT_FALSE(expression::isSubsetOf(inRegexAOrEq1.get(), eq1.get()));
- ASSERT_FALSE(expression::isSubsetOf(inRegexA.get(), eqA.get()));
- ASSERT_FALSE(expression::isSubsetOf(inRegexAOrNull.get(), eqA.get()));
- }
-
- TEST(ExpressionAlgoIsSubsetOf, Exists) {
- ParsedMatchExpression aExists("{a: {$exists: true}}");
- ParsedMatchExpression bExists("{b: {$exists: true}}");
- ParsedMatchExpression aExistsBExists("{a: {$exists: true}, b: {$exists: true}}");
- ParsedMatchExpression aExistsBExistsC5("{a: {$exists: true}, b: {$exists: true}, c: 5}");
-
- ASSERT_TRUE(expression::isSubsetOf(aExists.get(), aExists.get()));
- ASSERT_FALSE(expression::isSubsetOf(aExists.get(), bExists.get()));
-
- ASSERT_TRUE(expression::isSubsetOf(aExistsBExists.get(), aExists.get()));
- ASSERT_TRUE(expression::isSubsetOf(aExistsBExists.get(), bExists.get()));
- ASSERT_FALSE(expression::isSubsetOf(aExistsBExists.get(), aExistsBExistsC5.get()));
-
- ASSERT_TRUE(expression::isSubsetOf(aExistsBExistsC5.get(), aExists.get()));
- ASSERT_TRUE(expression::isSubsetOf(aExistsBExistsC5.get(), bExists.get()));
- ASSERT_TRUE(expression::isSubsetOf(aExistsBExistsC5.get(), aExistsBExists.get()));
- }
-
- TEST(ExpressionAlgoIsSubsetOf, Compare_Exists) {
- ParsedMatchExpression exists("{a: {$exists: true}}");
- ParsedMatchExpression eq("{a: 1}");
- ParsedMatchExpression gt("{a: {$gt: 4}}");
- ParsedMatchExpression lte("{a: {$lte: 7}}");
-
- ASSERT_TRUE(expression::isSubsetOf(eq.get(), exists.get()));
- ASSERT_TRUE(expression::isSubsetOf(gt.get(), exists.get()));
- ASSERT_TRUE(expression::isSubsetOf(lte.get(), exists.get()));
-
- ASSERT_FALSE(expression::isSubsetOf(exists.get(), eq.get()));
- ASSERT_FALSE(expression::isSubsetOf(exists.get(), gt.get()));
- ASSERT_FALSE(expression::isSubsetOf(exists.get(), lte.get()));
- }
-
- TEST(ExpressionAlgoIsSubsetOf, Type) {
- ParsedMatchExpression aType1("{a: {$type: 1}}");
- ParsedMatchExpression aType2("{a: {$type: 2}}");
- ParsedMatchExpression bType2("{b: {$type: 2}}");
-
- ASSERT_FALSE(expression::isSubsetOf(aType1.get(), aType2.get()));
- ASSERT_FALSE(expression::isSubsetOf(aType2.get(), aType1.get()));
-
- ASSERT_TRUE(expression::isSubsetOf(aType2.get(), aType2.get()));
- ASSERT_FALSE(expression::isSubsetOf(aType2.get(), bType2.get()));
- }
-
- TEST(ExpressionAlgoIsSubsetOf, TypeAndExists) {
- ParsedMatchExpression aExists("{a: {$exists: true}}");
- ParsedMatchExpression aType2("{a: {$type: 2}}");
- ParsedMatchExpression bType2("{b: {$type: 2}}");
-
- ASSERT_TRUE(expression::isSubsetOf(aType2.get(), aExists.get()));
- ASSERT_FALSE(expression::isSubsetOf(aExists.get(), aType2.get()));
- ASSERT_FALSE(expression::isSubsetOf(bType2.get(), aExists.get()));
- }
-
- TEST(ExpressionAlgoIsSubsetOf, AllAndExists) {
- ParsedMatchExpression aExists("{a: {$exists: true}}");
- ParsedMatchExpression aAll("{a: {$all: ['x', 'y', 'z']}}");
- ParsedMatchExpression bAll("{b: {$all: ['x', 'y', 'z']}}");
- ParsedMatchExpression aAllWithNull("{a: {$all: ['x', null, 'z']}}");
-
- ASSERT_TRUE(expression::isSubsetOf(aAll.get(), aExists.get()));
- ASSERT_FALSE(expression::isSubsetOf(bAll.get(), aExists.get()));
- ASSERT_TRUE(expression::isSubsetOf(aAllWithNull.get(), aExists.get()));
- }
-
- TEST(ExpressionAlgoIsSubsetOf, ElemMatchAndExists_Value) {
- ParsedMatchExpression aExists("{a: {$exists: true}}");
- ParsedMatchExpression aElemMatch("{a: {$elemMatch: {$gt: 5, $lte: 10}}}");
- ParsedMatchExpression bElemMatch("{b: {$elemMatch: {$gt: 5, $lte: 10}}}");
- ParsedMatchExpression aElemMatchNull("{a: {$elemMatch: {$eq: null}}}");
-
- ASSERT_TRUE(expression::isSubsetOf(aElemMatch.get(), aExists.get()));
- ASSERT_FALSE(expression::isSubsetOf(aExists.get(), aElemMatch.get()));
- ASSERT_FALSE(expression::isSubsetOf(bElemMatch.get(), aExists.get()));
- ASSERT_TRUE(expression::isSubsetOf(aElemMatchNull.get(), aExists.get()));
- }
-
- TEST(ExpressionAlgoIsSubsetOf, ElemMatchAndExists_Object) {
- ParsedMatchExpression aExists("{a: {$exists: true}}");
- ParsedMatchExpression aElemMatch("{a: {$elemMatch: {x: {$gt: 5}, y: {$lte: 10}}}}");
- ParsedMatchExpression bElemMatch("{b: {$elemMatch: {x: {$gt: 5}, y: {$lte: 10}}}}");
- ParsedMatchExpression aElemMatchNull("{a: {$elemMatch: {x: null, y: null}}}");
-
- ASSERT_TRUE(expression::isSubsetOf(aElemMatch.get(), aExists.get()));
- ASSERT_FALSE(expression::isSubsetOf(aExists.get(), aElemMatch.get()));
- ASSERT_FALSE(expression::isSubsetOf(bElemMatch.get(), aExists.get()));
- ASSERT_TRUE(expression::isSubsetOf(aElemMatchNull.get(), aExists.get()));
- }
-
- TEST(ExpressionAlgoIsSubsetOf, SizeAndExists) {
- ParsedMatchExpression aExists("{a: {$exists: true}}");
- ParsedMatchExpression aSize0("{a: {$size: 0}}");
- ParsedMatchExpression aSize1("{a: {$size: 1}}");
- ParsedMatchExpression aSize3("{a: {$size: 3}}");
- ParsedMatchExpression bSize3("{b: {$size: 3}}");
-
- ASSERT_TRUE(expression::isSubsetOf(aSize0.get(), aExists.get()));
- ASSERT_TRUE(expression::isSubsetOf(aSize1.get(), aExists.get()));
- ASSERT_TRUE(expression::isSubsetOf(aSize3.get(), aExists.get()));
- ASSERT_FALSE(expression::isSubsetOf(aExists.get(), aSize3.get()));
- ASSERT_FALSE(expression::isSubsetOf(bSize3.get(), aExists.get()));
- }
-
- TEST(ExpressionAlgoIsSubsetOf, ModAndExists) {
- ParsedMatchExpression aExists("{a: {$exists: true}}");
- ParsedMatchExpression aMod5("{a: {$mod: [5, 0]}}");
- ParsedMatchExpression bMod5("{b: {$mod: [5, 0]}}");
-
- ASSERT_TRUE(expression::isSubsetOf(aMod5.get(), aExists.get()));
- ASSERT_FALSE(expression::isSubsetOf(bMod5.get(), aExists.get()));
- }
-
- TEST(ExpressionAlgoIsSubsetOf, RegexAndExists) {
- ParsedMatchExpression aExists("{a: {$exists: true}}");
- ParsedMatchExpression aRegex("{a: {$regex: 'pattern'}}");
- ParsedMatchExpression bRegex("{b: {$regex: 'pattern'}}");
-
- ASSERT_TRUE(expression::isSubsetOf(aRegex.get(), aExists.get()));
- ASSERT_FALSE(expression::isSubsetOf(bRegex.get(), aExists.get()));
- }
-
- TEST(ExpressionAlgoIsSubsetOf, InAndExists) {
- ParsedMatchExpression aExists("{a: {$exists: true}}");
- ParsedMatchExpression aIn("{a: {$in: [1, 2, 3]}}");
- ParsedMatchExpression bIn("{b: {$in: [1, 2, 3]}}");
- ParsedMatchExpression aInWithNull("{a: {$in: [1, null, 3]}}");
-
- ASSERT_TRUE(expression::isSubsetOf(aIn.get(), aExists.get()));
- ASSERT_FALSE(expression::isSubsetOf(bIn.get(), aExists.get()));
- ASSERT_FALSE(expression::isSubsetOf(aInWithNull.get(), aExists.get()));
- }
-
- TEST(ExpressionAlgoIsSubsetOf, NinAndExists) {
- ParsedMatchExpression aExists("{a: {$exists: true}}");
- ParsedMatchExpression aNin("{a: {$nin: [1, 2, 3]}}");
- ParsedMatchExpression bNin("{b: {$nin: [1, 2, 3]}}");
- ParsedMatchExpression aNinWithNull("{a: {$nin: [1, null, 3]}}");
-
- ASSERT_FALSE(expression::isSubsetOf(aNin.get(), aExists.get()));
- ASSERT_FALSE(expression::isSubsetOf(bNin.get(), aExists.get()));
- ASSERT_TRUE(expression::isSubsetOf(aNinWithNull.get(), aExists.get()));
- }
-
- TEST(ExpressionAlgoIsSubsetOf, Compare_Exists_NE) {
- ParsedMatchExpression aExists("{a: {$exists: true}}");
- ParsedMatchExpression aNotEqual1("{a: {$ne: 1}}");
- ParsedMatchExpression bNotEqual1("{b: {$ne: 1}}");
- ParsedMatchExpression aNotEqualNull("{a: {$ne: null}}");
-
- ASSERT_FALSE(expression::isSubsetOf(aNotEqual1.get(), aExists.get()));
- ASSERT_FALSE(expression::isSubsetOf(bNotEqual1.get(), aExists.get()));
- ASSERT_TRUE(expression::isSubsetOf(aNotEqualNull.get(), aExists.get()));
- }
+/**
+ * A MatchExpression does not hold the memory for BSONElements, so use ParsedMatchExpression to
+ * ensure that the BSONObj outlives the MatchExpression.
+ */
+class ParsedMatchExpression {
+public:
+ ParsedMatchExpression(const std::string& str) : _obj(fromjson(str)) {
+ StatusWithMatchExpression result = MatchExpressionParser::parse(_obj);
+ ASSERT_OK(result.getStatus());
+ _expr.reset(result.getValue());
+ }
+
+ const MatchExpression* get() const {
+ return _expr.get();
+ }
+
+private:
+ const BSONObj _obj;
+ std::unique_ptr<MatchExpression> _expr;
+};
+
+TEST(ExpressionAlgoIsSubsetOf, NullAndOmittedField) {
+ // Verify that ComparisonMatchExpression::init() prohibits creating a match expression with
+ // an Undefined type.
+ BSONObj undefined = fromjson("{a: undefined}");
+ ASSERT_EQUALS(ErrorCodes::BadValue, MatchExpressionParser::parse(undefined).getStatus());
+
+ ParsedMatchExpression empty("{}");
+ ParsedMatchExpression null("{a: null}");
+
+ ASSERT_TRUE(expression::isSubsetOf(null.get(), empty.get()));
+ ASSERT_FALSE(expression::isSubsetOf(empty.get(), null.get()));
+
+ ParsedMatchExpression b1("{b: 1}");
+ ParsedMatchExpression aNullB1("{a: null, b: 1}");
+
+ ASSERT_TRUE(expression::isSubsetOf(aNullB1.get(), b1.get()));
+ ASSERT_FALSE(expression::isSubsetOf(b1.get(), aNullB1.get()));
+
+ ParsedMatchExpression a1C3("{a: 1, c: 3}");
+ ParsedMatchExpression a1BNullC3("{a: 1, b: null, c: 3}");
+
+ ASSERT_TRUE(expression::isSubsetOf(a1BNullC3.get(), a1C3.get()));
+ ASSERT_FALSE(expression::isSubsetOf(a1C3.get(), a1BNullC3.get()));
+}
+
+TEST(ExpressionAlgoIsSubsetOf, NullAndIn) {
+ ParsedMatchExpression eqNull("{x: null}");
+ ParsedMatchExpression inNull("{x: {$in: [null]}}");
+ ParsedMatchExpression inNullOr2("{x: {$in: [null, 2]}}");
+
+ ASSERT_TRUE(expression::isSubsetOf(inNull.get(), eqNull.get()));
+ ASSERT_FALSE(expression::isSubsetOf(inNullOr2.get(), eqNull.get()));
+}
+
+TEST(ExpressionAlgoIsSubsetOf, NullAndExists) {
+ ParsedMatchExpression null("{x: null}");
+ ParsedMatchExpression exists("{x: {$exists: true}}");
+ ASSERT_FALSE(expression::isSubsetOf(null.get(), exists.get()));
+ ASSERT_FALSE(expression::isSubsetOf(exists.get(), null.get()));
+}
+
+TEST(ExpressionAlgoIsSubsetOf, Compare_NaN) {
+ ParsedMatchExpression nan("{x: NaN}");
+ ParsedMatchExpression lt("{x: {$lt: 5}}");
+ ParsedMatchExpression lte("{x: {$lte: 5}}");
+ ParsedMatchExpression gte("{x: {$gte: 5}}");
+ ParsedMatchExpression gt("{x: {$gt: 5}}");
+ ParsedMatchExpression in("{x: {$in: [5]}}");
+
+ ASSERT_TRUE(expression::isSubsetOf(nan.get(), nan.get()));
+ ASSERT_FALSE(expression::isSubsetOf(nan.get(), lt.get()));
+ ASSERT_FALSE(expression::isSubsetOf(lt.get(), nan.get()));
+ ASSERT_FALSE(expression::isSubsetOf(nan.get(), lte.get()));
+ ASSERT_FALSE(expression::isSubsetOf(lte.get(), nan.get()));
+ ASSERT_FALSE(expression::isSubsetOf(nan.get(), gte.get()));
+ ASSERT_FALSE(expression::isSubsetOf(gte.get(), nan.get()));
+ ASSERT_FALSE(expression::isSubsetOf(nan.get(), gt.get()));
+ ASSERT_FALSE(expression::isSubsetOf(gt.get(), nan.get()));
+ ASSERT_FALSE(expression::isSubsetOf(nan.get(), in.get()));
+ ASSERT_FALSE(expression::isSubsetOf(in.get(), nan.get()));
+}
+
+TEST(ExpressionAlgoIsSubsetOf, Compare_EQ) {
+ ParsedMatchExpression a5("{a: 5}");
+ ParsedMatchExpression a6("{a: 6}");
+ ParsedMatchExpression b5("{b: 5}");
+
+ ASSERT_TRUE(expression::isSubsetOf(a5.get(), a5.get()));
+ ASSERT_FALSE(expression::isSubsetOf(a5.get(), a6.get()));
+ ASSERT_FALSE(expression::isSubsetOf(a5.get(), b5.get()));
+}
+
+TEST(ExpressionAlgoIsSubsetOf, CompareAnd_EQ) {
+ ParsedMatchExpression a1B2("{a: 1, b: 2}");
+ ParsedMatchExpression a1B7("{a: 1, b: 7}");
+ ParsedMatchExpression a1("{a: 1}");
+ ParsedMatchExpression b2("{b: 2}");
+
+ ASSERT_TRUE(expression::isSubsetOf(a1B2.get(), a1B2.get()));
+ ASSERT_FALSE(expression::isSubsetOf(a1B2.get(), a1B7.get()));
+
+ ASSERT_TRUE(expression::isSubsetOf(a1B2.get(), a1.get()));
+ ASSERT_TRUE(expression::isSubsetOf(a1B2.get(), b2.get()));
+ ASSERT_FALSE(expression::isSubsetOf(a1B7.get(), b2.get()));
+}
+
+TEST(ExpressionAlgoIsSubsetOf, CompareAnd_GT) {
+ ParsedMatchExpression filter("{a: {$gt: 5}, b: {$gt: 6}}");
+ ParsedMatchExpression query("{a: {$gt: 5}, b: {$gt: 6}, c: {$gt: 7}}");
+
+ ASSERT_TRUE(expression::isSubsetOf(query.get(), filter.get()));
+ ASSERT_FALSE(expression::isSubsetOf(filter.get(), query.get()));
+}
+
+TEST(ExpressionAlgoIsSubsetOf, CompareOr_LT) {
+ ParsedMatchExpression lt5("{a: {$lt: 5}}");
+ ParsedMatchExpression eq2OrEq3("{$or: [{a: 2}, {a: 3}]}");
+ ParsedMatchExpression eq4OrEq5("{$or: [{a: 4}, {a: 5}]}");
+ ParsedMatchExpression eq4OrEq6("{$or: [{a: 4}, {a: 6}]}");
+
+ ASSERT_TRUE(expression::isSubsetOf(eq2OrEq3.get(), lt5.get()));
+ ASSERT_FALSE(expression::isSubsetOf(eq4OrEq5.get(), lt5.get()));
+ ASSERT_FALSE(expression::isSubsetOf(eq4OrEq6.get(), lt5.get()));
+}
+
+TEST(ExpressionAlgoIsSubsetOf, CompareOr_GTE) {
+ ParsedMatchExpression gte5("{a: {$gte: 5}}");
+ ParsedMatchExpression eq4OrEq6("{$or: [{a: 4}, {a: 6}]}");
+ ParsedMatchExpression eq5OrEq6("{$or: [{a: 5}, {a: 6}]}");
+ ParsedMatchExpression eq7OrEq8("{$or: [{a: 7}, {a: 8}]}");
+
+ ASSERT_FALSE(expression::isSubsetOf(eq4OrEq6.get(), gte5.get()));
+ ASSERT_TRUE(expression::isSubsetOf(eq5OrEq6.get(), gte5.get()));
+ ASSERT_TRUE(expression::isSubsetOf(eq7OrEq8.get(), gte5.get()));
+}
+
+TEST(ExpressionAlgoIsSubsetOf, DifferentCanonicalTypes) {
+ ParsedMatchExpression number("{x: {$gt: 1}}");
+ ParsedMatchExpression string("{x: {$gt: 'a'}}");
+ ASSERT_FALSE(expression::isSubsetOf(number.get(), string.get()));
+ ASSERT_FALSE(expression::isSubsetOf(string.get(), number.get()));
+}
+
+TEST(ExpressionAlgoIsSubsetOf, DifferentNumberTypes) {
+ ParsedMatchExpression numberDouble("{x: 5.0}");
+ ParsedMatchExpression numberInt("{x: NumberInt(5)}");
+ ParsedMatchExpression numberLong("{x: NumberLong(5)}");
+
+ ASSERT_TRUE(expression::isSubsetOf(numberDouble.get(), numberInt.get()));
+ ASSERT_TRUE(expression::isSubsetOf(numberDouble.get(), numberLong.get()));
+ ASSERT_TRUE(expression::isSubsetOf(numberInt.get(), numberDouble.get()));
+ ASSERT_TRUE(expression::isSubsetOf(numberInt.get(), numberLong.get()));
+ ASSERT_TRUE(expression::isSubsetOf(numberLong.get(), numberDouble.get()));
+ ASSERT_TRUE(expression::isSubsetOf(numberLong.get(), numberInt.get()));
+}
+
+TEST(ExpressionAlgoIsSubsetOf, PointInUnboundedRange) {
+ ParsedMatchExpression a4("{a: 4}");
+ ParsedMatchExpression a5("{a: 5}");
+ ParsedMatchExpression a6("{a: 6}");
+ ParsedMatchExpression b5("{b: 5}");
+
+ ParsedMatchExpression lt5("{a: {$lt: 5}}");
+ ParsedMatchExpression lte5("{a: {$lte: 5}}");
+ ParsedMatchExpression gte5("{a: {$gte: 5}}");
+ ParsedMatchExpression gt5("{a: {$gt: 5}}");
+
+ ASSERT_TRUE(expression::isSubsetOf(a4.get(), lte5.get()));
+ ASSERT_TRUE(expression::isSubsetOf(a5.get(), lte5.get()));
+ ASSERT_FALSE(expression::isSubsetOf(a6.get(), lte5.get()));
+
+ ASSERT_TRUE(expression::isSubsetOf(a4.get(), lt5.get()));
+ ASSERT_FALSE(expression::isSubsetOf(a5.get(), lt5.get()));
+ ASSERT_FALSE(expression::isSubsetOf(a6.get(), lt5.get()));
+
+ ASSERT_FALSE(expression::isSubsetOf(a4.get(), gte5.get()));
+ ASSERT_TRUE(expression::isSubsetOf(a5.get(), gte5.get()));
+ ASSERT_TRUE(expression::isSubsetOf(a6.get(), gte5.get()));
+
+ ASSERT_FALSE(expression::isSubsetOf(a4.get(), gt5.get()));
+ ASSERT_FALSE(expression::isSubsetOf(a5.get(), gt5.get()));
+ ASSERT_TRUE(expression::isSubsetOf(a6.get(), gt5.get()));
+
+ // An unbounded range query does not match a subset of documents of a point query.
+ ASSERT_FALSE(expression::isSubsetOf(lt5.get(), a5.get()));
+ ASSERT_FALSE(expression::isSubsetOf(lte5.get(), a5.get()));
+ ASSERT_FALSE(expression::isSubsetOf(gte5.get(), a5.get()));
+ ASSERT_FALSE(expression::isSubsetOf(gt5.get(), a5.get()));
+
+ // Cannot be a subset if comparing different field names.
+ ASSERT_FALSE(expression::isSubsetOf(b5.get(), lt5.get()));
+ ASSERT_FALSE(expression::isSubsetOf(b5.get(), lte5.get()));
+ ASSERT_FALSE(expression::isSubsetOf(b5.get(), gte5.get()));
+ ASSERT_FALSE(expression::isSubsetOf(b5.get(), gt5.get()));
+}
+
+TEST(ExpressionAlgoIsSubsetOf, PointInBoundedRange) {
+ ParsedMatchExpression filter("{a: {$gt: 5, $lt: 10}}");
+ ParsedMatchExpression query("{a: 6}");
+
+ ASSERT_TRUE(expression::isSubsetOf(query.get(), filter.get()));
+ ASSERT_FALSE(expression::isSubsetOf(filter.get(), query.get()));
+}
+
+TEST(ExpressionAlgoIsSubsetOf, PointInBoundedRange_FakeAnd) {
+ ParsedMatchExpression filter("{a: {$gt: 5, $lt: 10}}");
+ ParsedMatchExpression query("{$and: [{a: 6}, {a: 6}]}");
+
+ ASSERT_TRUE(expression::isSubsetOf(query.get(), filter.get()));
+ ASSERT_FALSE(expression::isSubsetOf(filter.get(), query.get()));
+}
+
+TEST(ExpressionAlgoIsSubsetOf, MultiplePointsInBoundedRange) {
+ ParsedMatchExpression filter("{a: {$gt: 5, $lt: 10}}");
+ ParsedMatchExpression queryAllInside("{a: {$in: [6, 7, 8]}}");
+ ParsedMatchExpression queryStraddleLower("{a: {$in: [4.9, 5.1]}}");
+ ParsedMatchExpression queryStraddleUpper("{a: {$in: [9.9, 10.1]}}");
+
+ ASSERT_TRUE(expression::isSubsetOf(queryAllInside.get(), filter.get()));
+ ASSERT_FALSE(expression::isSubsetOf(queryStraddleLower.get(), filter.get()));
+ ASSERT_FALSE(expression::isSubsetOf(queryStraddleUpper.get(), filter.get()));
+}
+
+TEST(ExpressionAlgoIsSubsetOf, PointInCompoundRange) {
+ ParsedMatchExpression filter("{a: {$gt: 5}, b: {$gt: 6}, c: {$gt: 7}}");
+ ParsedMatchExpression query("{a: 10, b: 10, c: 10}");
+
+ ASSERT_TRUE(expression::isSubsetOf(query.get(), filter.get()));
+ ASSERT_FALSE(expression::isSubsetOf(filter.get(), query.get()));
+}
+
+TEST(ExpressionAlgoIsSubsetOf, Compare_LT_LTE) {
+ ParsedMatchExpression lte4("{x: {$lte: 4}}");
+ ParsedMatchExpression lt5("{x: {$lt: 5}}");
+ ParsedMatchExpression lte5("{x: {$lte: 5}}");
+ ParsedMatchExpression lt6("{x: {$lt: 6}}");
+
+ ASSERT_TRUE(expression::isSubsetOf(lte4.get(), lte5.get()));
+ ASSERT_TRUE(expression::isSubsetOf(lt5.get(), lte5.get()));
+ ASSERT_TRUE(expression::isSubsetOf(lte5.get(), lte5.get()));
+ ASSERT_FALSE(expression::isSubsetOf(lt6.get(), lte5.get()));
+
+ ASSERT_TRUE(expression::isSubsetOf(lte4.get(), lt5.get()));
+ ASSERT_TRUE(expression::isSubsetOf(lt5.get(), lt5.get()));
+ ASSERT_FALSE(expression::isSubsetOf(lte5.get(), lt5.get()));
+ ASSERT_FALSE(expression::isSubsetOf(lt6.get(), lt5.get()));
+}
+
+TEST(ExpressionAlgoIsSubsetOf, Compare_GT_GTE) {
+ ParsedMatchExpression gte6("{x: {$gte: 6}}");
+ ParsedMatchExpression gt5("{x: {$gt: 5}}");
+ ParsedMatchExpression gte5("{x: {$gte: 5}}");
+ ParsedMatchExpression gt4("{x: {$gt: 4}}");
+
+ ASSERT_TRUE(expression::isSubsetOf(gte6.get(), gte5.get()));
+ ASSERT_TRUE(expression::isSubsetOf(gt5.get(), gte5.get()));
+ ASSERT_TRUE(expression::isSubsetOf(gte5.get(), gte5.get()));
+ ASSERT_FALSE(expression::isSubsetOf(gt4.get(), gte5.get()));
+
+ ASSERT_TRUE(expression::isSubsetOf(gte6.get(), gt5.get()));
+ ASSERT_TRUE(expression::isSubsetOf(gt5.get(), gt5.get()));
+ ASSERT_FALSE(expression::isSubsetOf(gte5.get(), gt5.get()));
+ ASSERT_FALSE(expression::isSubsetOf(gt4.get(), gt5.get()));
+}
+
+TEST(ExpressionAlgoIsSubsetOf, BoundedRangeInUnboundedRange) {
+ ParsedMatchExpression filter("{a: {$gt: 1}}");
+ ParsedMatchExpression query("{a: {$gt: 5, $lt: 10}}");
+
+ ASSERT_TRUE(expression::isSubsetOf(query.get(), filter.get()));
+ ASSERT_FALSE(expression::isSubsetOf(filter.get(), query.get()));
+}
+
+TEST(ExpressionAlgoIsSubsetOf, MultipleRangesInUnboundedRange) {
+ ParsedMatchExpression filter("{a: {$gt: 1}}");
+ ParsedMatchExpression negative("{$or: [{a: {$gt: 5, $lt: 10}}, {a: {$lt: 0}}]}");
+ ParsedMatchExpression unbounded("{$or: [{a: {$gt: 5, $lt: 10}}, {a: {$gt: 15}}]}");
+ ParsedMatchExpression bounded("{$or: [{a: {$gt: 5, $lt: 10}}, {a: {$gt: 20, $lt: 30}}]}");
+
+ ASSERT_FALSE(expression::isSubsetOf(negative.get(), filter.get()));
+ ASSERT_TRUE(expression::isSubsetOf(unbounded.get(), filter.get()));
+ ASSERT_TRUE(expression::isSubsetOf(bounded.get(), filter.get()));
+}
+
+TEST(ExpressionAlgoIsSubsetOf, MultipleFields) {
+ ParsedMatchExpression filter("{a: {$gt: 5}, b: {$lt: 10}}");
+ ParsedMatchExpression onlyA("{$or: [{a: 6, b: {$lt: 4}}, {a: {$gt: 11}}]}");
+ ParsedMatchExpression onlyB("{$or: [{b: {$lt: 4}}, {a: {$gt: 11}, b: 9}]}");
+ ParsedMatchExpression both("{$or: [{a: 6, b: {$lt: 4}}, {a: {$gt: 11}, b: 9}]}");
+
+ ASSERT_FALSE(expression::isSubsetOf(onlyA.get(), filter.get()));
+ ASSERT_FALSE(expression::isSubsetOf(onlyB.get(), filter.get()));
+ ASSERT_TRUE(expression::isSubsetOf(both.get(), filter.get()));
+}
+
+TEST(ExpressionAlgoIsSubsetOf, Compare_LT_In) {
+ ParsedMatchExpression lt("{a: {$lt: 5}}");
+
+ ParsedMatchExpression inLt("{a: {$in: [4.9]}}");
+ ParsedMatchExpression inEq("{a: {$in: [5]}}");
+ ParsedMatchExpression inGt("{a: {$in: [5.1]}}");
+ ParsedMatchExpression inNull("{a: {$in: [null]}}");
+
+ ParsedMatchExpression inAllEq("{a: {$in: [5, 5.0]}}");
+ ParsedMatchExpression inAllLte("{a: {$in: [4.9, 5]}}");
+ ParsedMatchExpression inAllLt("{a: {$in: [2, 3, 4]}}");
+ ParsedMatchExpression inStraddle("{a: {$in: [4, 6]}}");
+ ParsedMatchExpression inLtAndNull("{a: {$in: [1, null]}}");
+
+ ASSERT_TRUE(expression::isSubsetOf(inLt.get(), lt.get()));
+ ASSERT_FALSE(expression::isSubsetOf(inEq.get(), lt.get()));
+ ASSERT_FALSE(expression::isSubsetOf(inGt.get(), lt.get()));
+
+ ASSERT_FALSE(expression::isSubsetOf(inAllEq.get(), lt.get()));
+ ASSERT_FALSE(expression::isSubsetOf(inAllLte.get(), lt.get()));
+ ASSERT_TRUE(expression::isSubsetOf(inAllLt.get(), lt.get()));
+ ASSERT_FALSE(expression::isSubsetOf(inStraddle.get(), lt.get()));
+ ASSERT_FALSE(expression::isSubsetOf(inLtAndNull.get(), lt.get()));
+}
+
+TEST(ExpressionAlgoIsSubsetOf, Compare_LTE_In) {
+ ParsedMatchExpression lte("{a: {$lte: 5}}");
+
+ ParsedMatchExpression inLt("{a: {$in: [4.9]}}");
+ ParsedMatchExpression inEq("{a: {$in: [5]}}");
+ ParsedMatchExpression inGt("{a: {$in: [5.1]}}");
+ ParsedMatchExpression inNull("{a: {$in: [null]}}");
+
+ ParsedMatchExpression inAllEq("{a: {$in: [5, 5.0]}}");
+ ParsedMatchExpression inAllLte("{a: {$in: [4.9, 5]}}");
+ ParsedMatchExpression inAllLt("{a: {$in: [2, 3, 4]}}");
+ ParsedMatchExpression inStraddle("{a: {$in: [4, 6]}}");
+ ParsedMatchExpression inLtAndNull("{a: {$in: [1, null]}}");
+
+ ASSERT_TRUE(expression::isSubsetOf(inLt.get(), lte.get()));
+ ASSERT_TRUE(expression::isSubsetOf(inEq.get(), lte.get()));
+ ASSERT_FALSE(expression::isSubsetOf(inGt.get(), lte.get()));
+
+ ASSERT_TRUE(expression::isSubsetOf(inAllEq.get(), lte.get()));
+ ASSERT_TRUE(expression::isSubsetOf(inAllLte.get(), lte.get()));
+ ASSERT_TRUE(expression::isSubsetOf(inAllLt.get(), lte.get()));
+ ASSERT_FALSE(expression::isSubsetOf(inStraddle.get(), lte.get()));
+ ASSERT_FALSE(expression::isSubsetOf(inLtAndNull.get(), lte.get()));
+}
+
+TEST(ExpressionAlgoIsSubsetOf, Compare_EQ_In) {
+ ParsedMatchExpression eq("{a: 5}");
+
+ ParsedMatchExpression inLt("{a: {$in: [4.9]}}");
+ ParsedMatchExpression inEq("{a: {$in: [5]}}");
+ ParsedMatchExpression inGt("{a: {$in: [5.1]}}");
+ ParsedMatchExpression inNull("{a: {$in: [null]}}");
+
+ ParsedMatchExpression inAllEq("{a: {$in: [5, 5.0]}}");
+ ParsedMatchExpression inStraddle("{a: {$in: [4, 6]}}");
+ ParsedMatchExpression inEqAndNull("{a: {$in: [5, null]}}");
+
+ ASSERT_FALSE(expression::isSubsetOf(inLt.get(), eq.get()));
+ ASSERT_TRUE(expression::isSubsetOf(inEq.get(), eq.get()));
+ ASSERT_FALSE(expression::isSubsetOf(inGt.get(), eq.get()));
+
+ ASSERT_TRUE(expression::isSubsetOf(inAllEq.get(), eq.get()));
+ ASSERT_FALSE(expression::isSubsetOf(inStraddle.get(), eq.get()));
+ ASSERT_FALSE(expression::isSubsetOf(inEqAndNull.get(), eq.get()));
+}
+
+TEST(ExpressionAlgoIsSubsetOf, Compare_GT_In) {
+ ParsedMatchExpression gt("{a: {$gt: 5}}");
+
+ ParsedMatchExpression inLt("{a: {$in: [4.9]}}");
+ ParsedMatchExpression inEq("{a: {$in: [5]}}");
+ ParsedMatchExpression inGt("{a: {$in: [5.1]}}");
+ ParsedMatchExpression inNull("{a: {$in: [null]}}");
+
+ ParsedMatchExpression inAllEq("{a: {$in: [5, 5.0]}}");
+ ParsedMatchExpression inAllGte("{a: {$in: [5, 5.1]}}");
+ ParsedMatchExpression inAllGt("{a: {$in: [6, 7, 8]}}");
+ ParsedMatchExpression inStraddle("{a: {$in: [4, 6]}}");
+ ParsedMatchExpression inGtAndNull("{a: {$in: [9, null]}}");
+
+ ASSERT_FALSE(expression::isSubsetOf(inLt.get(), gt.get()));
+ ASSERT_FALSE(expression::isSubsetOf(inEq.get(), gt.get()));
+ ASSERT_TRUE(expression::isSubsetOf(inGt.get(), gt.get()));
+
+ ASSERT_FALSE(expression::isSubsetOf(inAllEq.get(), gt.get()));
+ ASSERT_FALSE(expression::isSubsetOf(inAllGte.get(), gt.get()));
+ ASSERT_TRUE(expression::isSubsetOf(inAllGt.get(), gt.get()));
+ ASSERT_FALSE(expression::isSubsetOf(inStraddle.get(), gt.get()));
+ ASSERT_FALSE(expression::isSubsetOf(inGtAndNull.get(), gt.get()));
+}
+
+TEST(ExpressionAlgoIsSubsetOf, Compare_GTE_In) {
+ ParsedMatchExpression gte("{a: {$gte: 5}}");
+
+ ParsedMatchExpression inLt("{a: {$in: [4.9]}}");
+ ParsedMatchExpression inEq("{a: {$in: [5]}}");
+ ParsedMatchExpression inGt("{a: {$in: [5.1]}}");
+ ParsedMatchExpression inNull("{a: {$in: [null]}}");
+
+ ParsedMatchExpression inAllEq("{a: {$in: [5, 5.0]}}");
+ ParsedMatchExpression inAllGte("{a: {$in: [5, 5.1]}}");
+ ParsedMatchExpression inAllGt("{a: {$in: [6, 7, 8]}}");
+ ParsedMatchExpression inStraddle("{a: {$in: [4, 6]}}");
+ ParsedMatchExpression inGtAndNull("{a: {$in: [9, null]}}");
+
+ ASSERT_FALSE(expression::isSubsetOf(inLt.get(), gte.get()));
+ ASSERT_TRUE(expression::isSubsetOf(inEq.get(), gte.get()));
+ ASSERT_TRUE(expression::isSubsetOf(inGt.get(), gte.get()));
+
+ ASSERT_TRUE(expression::isSubsetOf(inAllEq.get(), gte.get()));
+ ASSERT_TRUE(expression::isSubsetOf(inAllGte.get(), gte.get()));
+ ASSERT_TRUE(expression::isSubsetOf(inAllGt.get(), gte.get()));
+ ASSERT_FALSE(expression::isSubsetOf(inStraddle.get(), gte.get()));
+ ASSERT_FALSE(expression::isSubsetOf(inGtAndNull.get(), gte.get()));
+}
+
+TEST(ExpressionAlgoIsSubsetOf, RegexAndIn) {
+ ParsedMatchExpression eq1("{x: 1}");
+ ParsedMatchExpression eqA("{x: 'a'}");
+ ParsedMatchExpression inRegexA("{x: {$in: [/a/]}}");
+ ParsedMatchExpression inRegexAbc("{x: {$in: [/abc/]}}");
+ ParsedMatchExpression inRegexAOrEq1("{x: {$in: [/a/, 1]}}");
+ ParsedMatchExpression inRegexAOrNull("{x: {$in: [/a/, null]}}");
+
+ ASSERT_TRUE(expression::isSubsetOf(inRegexA.get(), inRegexA.get()));
+ ASSERT_FALSE(expression::isSubsetOf(inRegexAbc.get(), inRegexA.get()));
+ ASSERT_FALSE(expression::isSubsetOf(inRegexA.get(), inRegexAOrEq1.get()));
+ ASSERT_FALSE(expression::isSubsetOf(inRegexAOrEq1.get(), eq1.get()));
+ ASSERT_FALSE(expression::isSubsetOf(inRegexA.get(), eqA.get()));
+ ASSERT_FALSE(expression::isSubsetOf(inRegexAOrNull.get(), eqA.get()));
+}
+
+TEST(ExpressionAlgoIsSubsetOf, Exists) {
+ ParsedMatchExpression aExists("{a: {$exists: true}}");
+ ParsedMatchExpression bExists("{b: {$exists: true}}");
+ ParsedMatchExpression aExistsBExists("{a: {$exists: true}, b: {$exists: true}}");
+ ParsedMatchExpression aExistsBExistsC5("{a: {$exists: true}, b: {$exists: true}, c: 5}");
+
+ ASSERT_TRUE(expression::isSubsetOf(aExists.get(), aExists.get()));
+ ASSERT_FALSE(expression::isSubsetOf(aExists.get(), bExists.get()));
+
+ ASSERT_TRUE(expression::isSubsetOf(aExistsBExists.get(), aExists.get()));
+ ASSERT_TRUE(expression::isSubsetOf(aExistsBExists.get(), bExists.get()));
+ ASSERT_FALSE(expression::isSubsetOf(aExistsBExists.get(), aExistsBExistsC5.get()));
+
+ ASSERT_TRUE(expression::isSubsetOf(aExistsBExistsC5.get(), aExists.get()));
+ ASSERT_TRUE(expression::isSubsetOf(aExistsBExistsC5.get(), bExists.get()));
+ ASSERT_TRUE(expression::isSubsetOf(aExistsBExistsC5.get(), aExistsBExists.get()));
+}
+
+TEST(ExpressionAlgoIsSubsetOf, Compare_Exists) {
+ ParsedMatchExpression exists("{a: {$exists: true}}");
+ ParsedMatchExpression eq("{a: 1}");
+ ParsedMatchExpression gt("{a: {$gt: 4}}");
+ ParsedMatchExpression lte("{a: {$lte: 7}}");
+
+ ASSERT_TRUE(expression::isSubsetOf(eq.get(), exists.get()));
+ ASSERT_TRUE(expression::isSubsetOf(gt.get(), exists.get()));
+ ASSERT_TRUE(expression::isSubsetOf(lte.get(), exists.get()));
+
+ ASSERT_FALSE(expression::isSubsetOf(exists.get(), eq.get()));
+ ASSERT_FALSE(expression::isSubsetOf(exists.get(), gt.get()));
+ ASSERT_FALSE(expression::isSubsetOf(exists.get(), lte.get()));
+}
+
+TEST(ExpressionAlgoIsSubsetOf, Type) {
+ ParsedMatchExpression aType1("{a: {$type: 1}}");
+ ParsedMatchExpression aType2("{a: {$type: 2}}");
+ ParsedMatchExpression bType2("{b: {$type: 2}}");
+
+ ASSERT_FALSE(expression::isSubsetOf(aType1.get(), aType2.get()));
+ ASSERT_FALSE(expression::isSubsetOf(aType2.get(), aType1.get()));
+
+ ASSERT_TRUE(expression::isSubsetOf(aType2.get(), aType2.get()));
+ ASSERT_FALSE(expression::isSubsetOf(aType2.get(), bType2.get()));
+}
+
+TEST(ExpressionAlgoIsSubsetOf, TypeAndExists) {
+ ParsedMatchExpression aExists("{a: {$exists: true}}");
+ ParsedMatchExpression aType2("{a: {$type: 2}}");
+ ParsedMatchExpression bType2("{b: {$type: 2}}");
+
+ ASSERT_TRUE(expression::isSubsetOf(aType2.get(), aExists.get()));
+ ASSERT_FALSE(expression::isSubsetOf(aExists.get(), aType2.get()));
+ ASSERT_FALSE(expression::isSubsetOf(bType2.get(), aExists.get()));
+}
+
+TEST(ExpressionAlgoIsSubsetOf, AllAndExists) {
+ ParsedMatchExpression aExists("{a: {$exists: true}}");
+ ParsedMatchExpression aAll("{a: {$all: ['x', 'y', 'z']}}");
+ ParsedMatchExpression bAll("{b: {$all: ['x', 'y', 'z']}}");
+ ParsedMatchExpression aAllWithNull("{a: {$all: ['x', null, 'z']}}");
+
+ ASSERT_TRUE(expression::isSubsetOf(aAll.get(), aExists.get()));
+ ASSERT_FALSE(expression::isSubsetOf(bAll.get(), aExists.get()));
+ ASSERT_TRUE(expression::isSubsetOf(aAllWithNull.get(), aExists.get()));
+}
+
+TEST(ExpressionAlgoIsSubsetOf, ElemMatchAndExists_Value) {
+ ParsedMatchExpression aExists("{a: {$exists: true}}");
+ ParsedMatchExpression aElemMatch("{a: {$elemMatch: {$gt: 5, $lte: 10}}}");
+ ParsedMatchExpression bElemMatch("{b: {$elemMatch: {$gt: 5, $lte: 10}}}");
+ ParsedMatchExpression aElemMatchNull("{a: {$elemMatch: {$eq: null}}}");
+
+ ASSERT_TRUE(expression::isSubsetOf(aElemMatch.get(), aExists.get()));
+ ASSERT_FALSE(expression::isSubsetOf(aExists.get(), aElemMatch.get()));
+ ASSERT_FALSE(expression::isSubsetOf(bElemMatch.get(), aExists.get()));
+ ASSERT_TRUE(expression::isSubsetOf(aElemMatchNull.get(), aExists.get()));
+}
+
+TEST(ExpressionAlgoIsSubsetOf, ElemMatchAndExists_Object) {
+ ParsedMatchExpression aExists("{a: {$exists: true}}");
+ ParsedMatchExpression aElemMatch("{a: {$elemMatch: {x: {$gt: 5}, y: {$lte: 10}}}}");
+ ParsedMatchExpression bElemMatch("{b: {$elemMatch: {x: {$gt: 5}, y: {$lte: 10}}}}");
+ ParsedMatchExpression aElemMatchNull("{a: {$elemMatch: {x: null, y: null}}}");
+
+ ASSERT_TRUE(expression::isSubsetOf(aElemMatch.get(), aExists.get()));
+ ASSERT_FALSE(expression::isSubsetOf(aExists.get(), aElemMatch.get()));
+ ASSERT_FALSE(expression::isSubsetOf(bElemMatch.get(), aExists.get()));
+ ASSERT_TRUE(expression::isSubsetOf(aElemMatchNull.get(), aExists.get()));
+}
+
+TEST(ExpressionAlgoIsSubsetOf, SizeAndExists) {
+ ParsedMatchExpression aExists("{a: {$exists: true}}");
+ ParsedMatchExpression aSize0("{a: {$size: 0}}");
+ ParsedMatchExpression aSize1("{a: {$size: 1}}");
+ ParsedMatchExpression aSize3("{a: {$size: 3}}");
+ ParsedMatchExpression bSize3("{b: {$size: 3}}");
+
+ ASSERT_TRUE(expression::isSubsetOf(aSize0.get(), aExists.get()));
+ ASSERT_TRUE(expression::isSubsetOf(aSize1.get(), aExists.get()));
+ ASSERT_TRUE(expression::isSubsetOf(aSize3.get(), aExists.get()));
+ ASSERT_FALSE(expression::isSubsetOf(aExists.get(), aSize3.get()));
+ ASSERT_FALSE(expression::isSubsetOf(bSize3.get(), aExists.get()));
+}
+
+TEST(ExpressionAlgoIsSubsetOf, ModAndExists) {
+ ParsedMatchExpression aExists("{a: {$exists: true}}");
+ ParsedMatchExpression aMod5("{a: {$mod: [5, 0]}}");
+ ParsedMatchExpression bMod5("{b: {$mod: [5, 0]}}");
+
+ ASSERT_TRUE(expression::isSubsetOf(aMod5.get(), aExists.get()));
+ ASSERT_FALSE(expression::isSubsetOf(bMod5.get(), aExists.get()));
+}
+
+TEST(ExpressionAlgoIsSubsetOf, RegexAndExists) {
+ ParsedMatchExpression aExists("{a: {$exists: true}}");
+ ParsedMatchExpression aRegex("{a: {$regex: 'pattern'}}");
+ ParsedMatchExpression bRegex("{b: {$regex: 'pattern'}}");
+
+ ASSERT_TRUE(expression::isSubsetOf(aRegex.get(), aExists.get()));
+ ASSERT_FALSE(expression::isSubsetOf(bRegex.get(), aExists.get()));
+}
+
+TEST(ExpressionAlgoIsSubsetOf, InAndExists) {
+ ParsedMatchExpression aExists("{a: {$exists: true}}");
+ ParsedMatchExpression aIn("{a: {$in: [1, 2, 3]}}");
+ ParsedMatchExpression bIn("{b: {$in: [1, 2, 3]}}");
+ ParsedMatchExpression aInWithNull("{a: {$in: [1, null, 3]}}");
+
+ ASSERT_TRUE(expression::isSubsetOf(aIn.get(), aExists.get()));
+ ASSERT_FALSE(expression::isSubsetOf(bIn.get(), aExists.get()));
+ ASSERT_FALSE(expression::isSubsetOf(aInWithNull.get(), aExists.get()));
+}
+
+TEST(ExpressionAlgoIsSubsetOf, NinAndExists) {
+ ParsedMatchExpression aExists("{a: {$exists: true}}");
+ ParsedMatchExpression aNin("{a: {$nin: [1, 2, 3]}}");
+ ParsedMatchExpression bNin("{b: {$nin: [1, 2, 3]}}");
+ ParsedMatchExpression aNinWithNull("{a: {$nin: [1, null, 3]}}");
+
+ ASSERT_FALSE(expression::isSubsetOf(aNin.get(), aExists.get()));
+ ASSERT_FALSE(expression::isSubsetOf(bNin.get(), aExists.get()));
+ ASSERT_TRUE(expression::isSubsetOf(aNinWithNull.get(), aExists.get()));
+}
+
+TEST(ExpressionAlgoIsSubsetOf, Compare_Exists_NE) {
+ ParsedMatchExpression aExists("{a: {$exists: true}}");
+ ParsedMatchExpression aNotEqual1("{a: {$ne: 1}}");
+ ParsedMatchExpression bNotEqual1("{b: {$ne: 1}}");
+ ParsedMatchExpression aNotEqualNull("{a: {$ne: null}}");
+
+ ASSERT_FALSE(expression::isSubsetOf(aNotEqual1.get(), aExists.get()));
+ ASSERT_FALSE(expression::isSubsetOf(bNotEqual1.get(), aExists.get()));
+ ASSERT_TRUE(expression::isSubsetOf(aNotEqualNull.get(), aExists.get()));
+}
} // namespace mongo