// expression_parser_leaf_test.cpp /** * Copyright (C) 2013 10gen Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * As a special exception, the copyright holders give permission to link the * code of portions of this program with the OpenSSL library under certain * conditions as described in each individual source file and distribute * linked combinations including the program with the OpenSSL library. You * must comply with the GNU Affero General Public License in all respects for * all of the code used other than as permitted herein. If you modify file(s) * with this exception, you may extend this exception to your version of the * file(s), but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. If you delete this * exception statement from all source files in the program, then also delete * it in the license file. */ #define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kDefault #include "mongo/unittest/unittest.h" #include "mongo/db/matcher/expression_parser.h" #include "mongo/db/jsobj.h" #include "mongo/db/json.h" #include "mongo/db/matcher/expression.h" #include "mongo/db/matcher/expression_leaf.h" #include "mongo/util/log.h" namespace mongo { using std::endl; using std::string; TEST(MatchExpressionParserLeafTest, SimpleEQ2) { BSONObj query = BSON("x" << BSON("$eq" << 2)); StatusWithMatchExpression result = MatchExpressionParser::parse(query); ASSERT_TRUE(result.isOK()); std::unique_ptr destroy(result.getValue()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); ASSERT(result.getValue()->matchesBSON(BSON("x" << 2))); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 3))); } TEST(MatchExpressionParserLeafTest, SimpleEQUndefined) { BSONObj query = BSON("x" << BSON("$eq" << BSONUndefined)); StatusWithMatchExpression result = MatchExpressionParser::parse(query); ASSERT_FALSE(result.isOK()); } TEST(MatchExpressionParserLeafTest, SimpleGT1) { BSONObj query = BSON("x" << BSON("$gt" << 2)); StatusWithMatchExpression result = MatchExpressionParser::parse(query); ASSERT_TRUE(result.isOK()); std::unique_ptr destroy(result.getValue()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 2))); ASSERT(result.getValue()->matchesBSON(BSON("x" << 3))); } TEST(MatchExpressionParserLeafTest, SimpleLT1) { BSONObj query = BSON("x" << BSON("$lt" << 2)); StatusWithMatchExpression result = MatchExpressionParser::parse(query); ASSERT_TRUE(result.isOK()); std::unique_ptr destroy(result.getValue()); ASSERT(result.getValue()->matchesBSON(BSON("x" << 1))); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 2))); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 3))); } TEST(MatchExpressionParserLeafTest, SimpleGTE1) { BSONObj query = BSON("x" << BSON("$gte" << 2)); StatusWithMatchExpression result = MatchExpressionParser::parse(query); ASSERT_TRUE(result.isOK()); std::unique_ptr destroy(result.getValue()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); ASSERT(result.getValue()->matchesBSON(BSON("x" << 2))); ASSERT(result.getValue()->matchesBSON(BSON("x" << 3))); } TEST(MatchExpressionParserLeafTest, SimpleLTE1) { BSONObj query = BSON("x" << BSON("$lte" << 2)); StatusWithMatchExpression result = MatchExpressionParser::parse(query); ASSERT_TRUE(result.isOK()); std::unique_ptr destroy(result.getValue()); ASSERT(result.getValue()->matchesBSON(BSON("x" << 1))); ASSERT(result.getValue()->matchesBSON(BSON("x" << 2))); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 3))); } TEST(MatchExpressionParserLeafTest, SimpleNE1) { BSONObj query = BSON("x" << BSON("$ne" << 2)); StatusWithMatchExpression result = MatchExpressionParser::parse(query); ASSERT_TRUE(result.isOK()); std::unique_ptr destroy(result.getValue()); ASSERT(result.getValue()->matchesBSON(BSON("x" << 1))); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 2))); ASSERT(result.getValue()->matchesBSON(BSON("x" << 3))); } TEST(MatchExpressionParserLeafTest, SimpleModBad1) { BSONObj query = BSON("x" << BSON("$mod" << BSON_ARRAY(3 << 2))); StatusWithMatchExpression result = MatchExpressionParser::parse(query); ASSERT_TRUE(result.isOK()); std::unique_ptr destroy1(result.getValue()); query = BSON("x" << BSON("$mod" << BSON_ARRAY(3))); result = MatchExpressionParser::parse(query); ASSERT_TRUE(!result.isOK()); query = BSON("x" << BSON("$mod" << BSON_ARRAY(3 << 2 << 4))); result = MatchExpressionParser::parse(query); ASSERT_TRUE(!result.isOK()); query = BSON("x" << BSON("$mod" << BSON_ARRAY("q" << 2))); result = MatchExpressionParser::parse(query); ASSERT_TRUE(!result.isOK()); query = BSON("x" << BSON("$mod" << 3)); result = MatchExpressionParser::parse(query); ASSERT_TRUE(!result.isOK()); query = BSON("x" << BSON("$mod" << BSON("a" << 1 << "b" << 2))); result = MatchExpressionParser::parse(query); ASSERT_TRUE(!result.isOK()); } TEST(MatchExpressionParserLeafTest, SimpleMod1) { BSONObj query = BSON("x" << BSON("$mod" << BSON_ARRAY(3 << 2))); StatusWithMatchExpression result = MatchExpressionParser::parse(query); ASSERT_TRUE(result.isOK()); std::unique_ptr destroy(result.getValue()); ASSERT(result.getValue()->matchesBSON(BSON("x" << 5))); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 4))); ASSERT(result.getValue()->matchesBSON(BSON("x" << 8))); } TEST(MatchExpressionParserLeafTest, SimpleModNotNumber) { BSONObj query = BSON("x" << BSON("$mod" << BSON_ARRAY(2 << "r"))); StatusWithMatchExpression result = MatchExpressionParser::parse(query); ASSERT_TRUE(result.isOK()); std::unique_ptr destroy(result.getValue()); ASSERT(result.getValue()->matchesBSON(BSON("x" << 2))); ASSERT(result.getValue()->matchesBSON(BSON("x" << 4))); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 5))); ASSERT(!result.getValue()->matchesBSON(BSON("x" << "a"))); } TEST(MatchExpressionParserLeafTest, SimpleIN1) { BSONObj query = BSON("x" << BSON("$in" << BSON_ARRAY(2 << 3))); StatusWithMatchExpression result = MatchExpressionParser::parse(query); ASSERT_TRUE(result.isOK()); std::unique_ptr destroy(result.getValue()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); ASSERT(result.getValue()->matchesBSON(BSON("x" << 2))); ASSERT(result.getValue()->matchesBSON(BSON("x" << 3))); } TEST(MatchExpressionParserLeafTest, INSingleDBRef) { OID oid = OID::gen(); BSONObj query = BSON("x" << BSON("$in" << BSON_ARRAY(BSON("$ref" << "coll" << "$id" << oid << "$db" << "db")))); StatusWithMatchExpression result = MatchExpressionParser::parse(query); ASSERT_TRUE(result.isOK()); std::unique_ptr destroy(result.getValue()); OID oidx = OID::gen(); ASSERT(!result.getValue()->matchesBSON(BSON("x" << BSON("$ref" << "collx" << "$id" << oidx << "$db" << "db")))); ASSERT(!result.getValue()->matchesBSON(BSON("x" << BSON("$ref" << "coll" << "$id" << oidx << "$db" << "db")))); ASSERT(!result.getValue()->matchesBSON(BSON("x" << BSON("$id" << oid << "$ref" << "coll" << "$db" << "db")))); ASSERT(!result.getValue()->matchesBSON(BSON("x" << BSON("$id" << oid << "$ref" << "coll" << "$db" << "db")))); ASSERT(!result.getValue()->matchesBSON(BSON("x" << BSON_ARRAY(BSON("$id" << oid << "$ref" << "coll" << "$db" << "db"))))); ASSERT(!result.getValue()->matchesBSON(BSON("x" << BSON("$ref" << "coll" << "$id" << oid << "$db" << "dbx")))); ASSERT(!result.getValue()->matchesBSON(BSON("x" << BSON("$db" << "db" << "$ref" << "coll" << "$id" << oid)))); ASSERT(result.getValue()->matchesBSON(BSON("x" << BSON("$ref" << "coll" << "$id" << oid << "$db" << "db")))); ASSERT(result.getValue()->matchesBSON(BSON("x" << BSON_ARRAY(BSON("$ref" << "coll" << "$id" << oid << "$db" << "db"))))); ASSERT(result.getValue()->matchesBSON(BSON("x" << BSON_ARRAY(BSON("$ref" << "collx" << "$id" << oidx << "$db" << "db") << BSON("$ref" << "coll" << "$id" << oid << "$db" << "db"))))); } TEST(MatchExpressionParserLeafTest, INMultipleDBRef) { OID oid = OID::gen(); OID oidy = OID::gen(); BSONObj query = BSON("x" << BSON("$in" << BSON_ARRAY(BSON("$ref" << "colly" << "$id" << oidy << "$db" << "db") << BSON("$ref" << "coll" << "$id" << oid << "$db" << "db")))); StatusWithMatchExpression result = MatchExpressionParser::parse(query); ASSERT_TRUE(result.isOK()); std::unique_ptr destroy(result.getValue()); OID oidx = OID::gen(); ASSERT(!result.getValue()->matchesBSON(BSON("x" << BSON("$ref" << "collx" << "$id" << oidx << "$db" << "db")))); ASSERT(!result.getValue()->matchesBSON(BSON("x" << BSON("$ref" << "coll" << "$id" << oidx << "$db" << "db")))); ASSERT(!result.getValue()->matchesBSON(BSON("x" << BSON("$id" << oid << "$ref" << "coll" << "$db" << "db")))); ASSERT(!result.getValue()->matchesBSON(BSON("x" << BSON_ARRAY(BSON("$ref" << "coll" << "$id" << oidy << "$db" << "db"))))); ASSERT(!result.getValue()->matchesBSON(BSON("x" << BSON_ARRAY(BSON("$ref" << "colly" << "$id" << oid << "$db" << "db"))))); ASSERT(!result.getValue()->matchesBSON(BSON("x" << BSON_ARRAY(BSON("$id" << oid << "$ref" << "coll" << "$db" << "db"))))); ASSERT(!result.getValue()->matchesBSON(BSON("x" << BSON_ARRAY(BSON("$ref" << "coll" << "$id" << oid << "$db" << "dbx"))))); ASSERT(!result.getValue()->matchesBSON(BSON("x" << BSON_ARRAY(BSON("$id" << oidy << "$ref" << "colly" << "$db" << "db"))))); ASSERT(!result.getValue()->matchesBSON(BSON("x" << BSON_ARRAY(BSON("$ref" << "collx" << "$id" << oidx << "$db" << "db") << BSON("$ref" << "coll" << "$id" << oidx << "$db" << "db"))))); ASSERT(!result.getValue()->matchesBSON(BSON("x" << BSON_ARRAY(BSON("$ref" << "collx" << "$id" << oidx << "$db" << "db") << BSON("$ref" << "colly" << "$id" << oidx << "$db" << "db"))))); ASSERT(!result.getValue()->matchesBSON(BSON("x" << BSON_ARRAY(BSON("$ref" << "collx" << "$id" << oidx << "$db" << "db") << BSON("$ref" << "coll" << "$id" << oid << "$db" << "dbx"))))); ASSERT(result.getValue()->matchesBSON(BSON("x" << BSON("$ref" << "coll" << "$id" << oid << "$db" << "db")))); ASSERT(result.getValue()->matchesBSON(BSON("x" << BSON("$ref" << "colly" << "$id" << oidy << "$db" << "db")))); ASSERT(result.getValue()->matchesBSON(BSON("x" << BSON_ARRAY(BSON("$ref" << "coll" << "$id" << oid << "$db" << "db"))))); ASSERT(result.getValue()->matchesBSON(BSON("x" << BSON_ARRAY(BSON("$ref" << "colly" << "$id" << oidy << "$db" << "db"))))); ASSERT(result.getValue()->matchesBSON(BSON("x" << BSON_ARRAY(BSON("$ref" << "collx" << "$id" << oidx << "$db" << "db") << BSON("$ref" << "coll" << "$id" << oid << "$db" << "db"))))); ASSERT(result.getValue()->matchesBSON(BSON("x" << BSON_ARRAY(BSON("$ref" << "collx" << "$id" << oidx << "$db" << "db") << BSON("$ref" << "colly" << "$id" << oidy << "$db" << "db"))))); } TEST(MatchExpressionParserLeafTest, INDBRefWithOptionalField1) { OID oid = OID::gen(); BSONObj query = BSON("x" << BSON("$in" << BSON_ARRAY(BSON("$ref" << "coll" << "$id" << oid << "foo" << 12345)))); StatusWithMatchExpression result = MatchExpressionParser::parse(query); ASSERT_TRUE(result.isOK()); std::unique_ptr destroy(result.getValue()); OID oidx = OID::gen(); ASSERT(!result.getValue()->matchesBSON(BSON("x" << BSON("$ref" << "coll" << "$id" << oidx << "$db" << "db")))); ASSERT(result.getValue()->matchesBSON( BSON("x" << BSON_ARRAY(BSON("$ref" << "coll" << "$id" << oid << "foo" << 12345))))); ASSERT(result.getValue()->matchesBSON( BSON("x" << BSON_ARRAY(BSON("$ref" << "collx" << "$id" << oidx << "foo" << 12345) << BSON("$ref" << "coll" << "$id" << oid << "foo" << 12345))))); } TEST(MatchExpressionParserLeafTest, INInvalidDBRefs) { // missing $id BSONObj query = BSON("x" << BSON("$in" << BSON_ARRAY(BSON("$ref" << "coll")))); StatusWithMatchExpression result = MatchExpressionParser::parse(query); result = MatchExpressionParser::parse(query); // second field is not $id query = BSON("x" << BSON("$in" << BSON_ARRAY(BSON("$ref" << "coll" << "$foo" << 1)))); result = MatchExpressionParser::parse(query); ASSERT_FALSE(result.isOK()); OID oid = OID::gen(); // missing $ref field query = BSON("x" << BSON("$in" << BSON_ARRAY(BSON("$id" << oid << "foo" << 3)))); result = MatchExpressionParser::parse(query); ASSERT_FALSE(result.isOK()); // missing $id and $ref field query = BSON("x" << BSON("$in" << BSON_ARRAY(BSON("$db" << "test" << "foo" << 3)))); result = MatchExpressionParser::parse(query); ASSERT_FALSE(result.isOK()); } TEST(MatchExpressionParserLeafTest, INExpressionDocument) { BSONObj query = BSON("x" << BSON("$in" << BSON_ARRAY(BSON("$foo" << 1)))); StatusWithMatchExpression result = MatchExpressionParser::parse(query); ASSERT_FALSE(result.isOK()); } TEST(MatchExpressionParserLeafTest, INNotArray) { BSONObj query = BSON("x" << BSON("$in" << 5)); StatusWithMatchExpression result = MatchExpressionParser::parse(query); ASSERT_FALSE(result.isOK()); } TEST(MatchExpressionParserLeafTest, INUndefined) { BSONObj query = BSON("x" << BSON("$in" << BSON_ARRAY(BSONUndefined))); StatusWithMatchExpression result = MatchExpressionParser::parse(query); ASSERT_FALSE(result.isOK()); } TEST(MatchExpressionParserLeafTest, INNotElemMatch) { BSONObj query = BSON("x" << BSON("$in" << BSON_ARRAY(BSON("$elemMatch" << 1)))); StatusWithMatchExpression result = MatchExpressionParser::parse(query); ASSERT_FALSE(result.isOK()); } TEST(MatchExpressionParserLeafTest, INRegexTooLong) { string tooLargePattern(50 * 1000, 'z'); BSONObjBuilder inArray; inArray.appendRegex("0", tooLargePattern, ""); BSONObjBuilder operand; operand.appendArray("$in", inArray.obj()); BSONObj query = BSON("x" << operand.obj()); StatusWithMatchExpression result = MatchExpressionParser::parse(query); ASSERT_FALSE(result.isOK()); } TEST(MatchExpressionParserLeafTest, INRegexTooLong2) { string tooLargePattern(50 * 1000, 'z'); BSONObj query = BSON("x" << BSON("$in" << BSON_ARRAY(BSON("$regex" << tooLargePattern)))); StatusWithMatchExpression result = MatchExpressionParser::parse(query); ASSERT_FALSE(result.isOK()); } TEST(MatchExpressionParserLeafTest, INRegexStuff) { BSONObjBuilder inArray; inArray.appendRegex("0", "^a", ""); inArray.appendRegex("1", "B", "i"); inArray.append("2", 4); BSONObjBuilder operand; operand.appendArray("$in", inArray.obj()); BSONObj query = BSON("a" << operand.obj()); StatusWithMatchExpression result = MatchExpressionParser::parse(query); ASSERT_TRUE(result.isOK()); std::unique_ptr destroy(result.getValue()); BSONObj matchFirst = BSON("a" << "ax"); BSONObj matchFirstRegex = BSONObjBuilder().appendRegex("a", "^a", "").obj(); BSONObj matchSecond = BSON("a" << "qqb"); BSONObj matchSecondRegex = BSONObjBuilder().appendRegex("a", "B", "i").obj(); BSONObj matchThird = BSON("a" << 4); BSONObj notMatch = BSON("a" << "l"); BSONObj notMatchRegex = BSONObjBuilder().appendRegex("a", "B", "").obj(); ASSERT(result.getValue()->matchesBSON(matchFirst)); ASSERT(result.getValue()->matchesBSON(matchFirstRegex)); ASSERT(result.getValue()->matchesBSON(matchSecond)); ASSERT(result.getValue()->matchesBSON(matchSecondRegex)); ASSERT(result.getValue()->matchesBSON(matchThird)); ASSERT(!result.getValue()->matchesBSON(notMatch)); ASSERT(!result.getValue()->matchesBSON(notMatchRegex)); } TEST(MatchExpressionParserLeafTest, SimpleNIN1) { BSONObj query = BSON("x" << BSON("$nin" << BSON_ARRAY(2 << 3))); StatusWithMatchExpression result = MatchExpressionParser::parse(query); ASSERT_TRUE(result.isOK()); std::unique_ptr destroy(result.getValue()); ASSERT(result.getValue()->matchesBSON(BSON("x" << 1))); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 2))); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 3))); } TEST(MatchExpressionParserLeafTest, NINNotArray) { BSONObj query = BSON("x" << BSON("$nin" << 5)); StatusWithMatchExpression result = MatchExpressionParser::parse(query); ASSERT_FALSE(result.isOK()); } TEST(MatchExpressionParserLeafTest, Regex1) { BSONObjBuilder b; b.appendRegex("x", "abc", "i"); BSONObj query = b.obj(); StatusWithMatchExpression result = MatchExpressionParser::parse(query); ASSERT_TRUE(result.isOK()); std::unique_ptr destroy(result.getValue()); ASSERT(result.getValue()->matchesBSON(BSON("x" << "abc"))); ASSERT(result.getValue()->matchesBSON(BSON("x" << "ABC"))); ASSERT(!result.getValue()->matchesBSON(BSON("x" << "AC"))); } TEST(MatchExpressionParserLeafTest, Regex2) { BSONObj query = BSON("x" << BSON("$regex" << "abc" << "$options" << "i")); StatusWithMatchExpression result = MatchExpressionParser::parse(query); ASSERT_TRUE(result.isOK()); std::unique_ptr destroy(result.getValue()); ASSERT(result.getValue()->matchesBSON(BSON("x" << "abc"))); ASSERT(result.getValue()->matchesBSON(BSON("x" << "ABC"))); ASSERT(!result.getValue()->matchesBSON(BSON("x" << "AC"))); } TEST(MatchExpressionParserLeafTest, Regex3) { BSONObj query = BSON("x" << BSON("$options" << "i" << "$regex" << "abc")); StatusWithMatchExpression result = MatchExpressionParser::parse(query); log() << "result: " << result.getStatus() << endl; ASSERT_TRUE(result.isOK()); std::unique_ptr destroy(result.getValue()); ASSERT(result.getValue()->matchesBSON(BSON("x" << "abc"))); ASSERT(result.getValue()->matchesBSON(BSON("x" << "ABC"))); ASSERT(!result.getValue()->matchesBSON(BSON("x" << "AC"))); } TEST(MatchExpressionParserLeafTest, RegexBad) { BSONObj query = BSON("x" << BSON("$regex" << "abc" << "$optionas" << "i")); StatusWithMatchExpression result = MatchExpressionParser::parse(query); ASSERT_FALSE(result.isOK()); // $regex does not with numbers query = BSON("x" << BSON("$regex" << 123)); result = MatchExpressionParser::parse(query); ASSERT_FALSE(result.isOK()); query = BSON("x" << BSON("$regex" << BSON_ARRAY("abc"))); result = MatchExpressionParser::parse(query); ASSERT_FALSE(result.isOK()); query = BSON("x" << BSON("$optionas" << "i")); result = MatchExpressionParser::parse(query); ASSERT_FALSE(result.isOK()); query = BSON("x" << BSON("$options" << "i")); result = MatchExpressionParser::parse(query); ASSERT_FALSE(result.isOK()); } TEST(MatchExpressionParserLeafTest, ExistsYes1) { BSONObjBuilder b; b.appendBool("$exists", true); BSONObj query = BSON("x" << b.obj()); StatusWithMatchExpression result = MatchExpressionParser::parse(query); ASSERT_TRUE(result.isOK()); std::unique_ptr destroy(result.getValue()); ASSERT(result.getValue()->matchesBSON(BSON("x" << "abc"))); ASSERT(!result.getValue()->matchesBSON(BSON("y" << "AC"))); } TEST(MatchExpressionParserLeafTest, ExistsNO1) { BSONObjBuilder b; b.appendBool("$exists", false); BSONObj query = BSON("x" << b.obj()); StatusWithMatchExpression result = MatchExpressionParser::parse(query); ASSERT_TRUE(result.isOK()); std::unique_ptr destroy(result.getValue()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << "abc"))); ASSERT(result.getValue()->matchesBSON(BSON("y" << "AC"))); } TEST(MatchExpressionParserLeafTest, Type1) { BSONObj query = BSON("x" << BSON("$type" << String)); StatusWithMatchExpression result = MatchExpressionParser::parse(query); ASSERT_TRUE(result.isOK()); std::unique_ptr destroy(result.getValue()); ASSERT(result.getValue()->matchesBSON(BSON("x" << "abc"))); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 5))); } TEST(MatchExpressionParserLeafTest, Type2) { BSONObj query = BSON("x" << BSON("$type" << (double)NumberDouble)); StatusWithMatchExpression result = MatchExpressionParser::parse(query); ASSERT_TRUE(result.isOK()); std::unique_ptr destroy(result.getValue()); ASSERT(result.getValue()->matchesBSON(BSON("x" << 5.3))); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 5))); } TEST(MatchExpressionParserLeafTest, TypeDoubleOperator) { BSONObj query = BSON("x" << BSON("$type" << 1.5)); StatusWithMatchExpression result = MatchExpressionParser::parse(query); ASSERT_TRUE(result.isOK()); std::unique_ptr destroy(result.getValue()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 5.3))); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 5))); } TEST(MatchExpressionParserLeafTest, TypeNull) { BSONObj query = BSON("x" << BSON("$type" << jstNULL)); StatusWithMatchExpression result = MatchExpressionParser::parse(query); ASSERT_TRUE(result.isOK()); std::unique_ptr destroy(result.getValue()); ASSERT(!result.getValue()->matchesBSON(BSONObj())); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 5))); BSONObjBuilder b; b.appendNull("x"); ASSERT(result.getValue()->matchesBSON(b.obj())); } TEST(MatchExpressionParserLeafTest, TypeBadType) { BSONObjBuilder b; b.append("$type", (JSTypeMax + 1)); BSONObj query = BSON("x" << b.obj()); StatusWithMatchExpression result = MatchExpressionParser::parse(query); ASSERT_TRUE(result.isOK()); std::unique_ptr destroy(result.getValue()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 5.3))); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 5))); } TEST(MatchExpressionParserLeafTest, TypeBad) { BSONObj query = BSON("x" << BSON("$type" << BSON("x" << 1))); StatusWithMatchExpression result = MatchExpressionParser::parse(query); ASSERT_FALSE(result.isOK()); } }