diff options
Diffstat (limited to 'src/mongo/db/matcher/expression_serialization_test.cpp')
-rw-r--r-- | src/mongo/db/matcher/expression_serialization_test.cpp | 791 |
1 files changed, 791 insertions, 0 deletions
diff --git a/src/mongo/db/matcher/expression_serialization_test.cpp b/src/mongo/db/matcher/expression_serialization_test.cpp new file mode 100644 index 00000000000..39a472adef6 --- /dev/null +++ b/src/mongo/db/matcher/expression_serialization_test.cpp @@ -0,0 +1,791 @@ +/** + * Copyright (C) 2016 MongoDB 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 <http://www.gnu.org/licenses/>. + * + * 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. + */ + +// Unit tests for MatchExpression::serialize serialization. + +#include "mongo/platform/basic.h" + +#include "mongo/db/json.h" +#include "mongo/db/matcher/expression.h" +#include "mongo/db/matcher/expression_parser.h" +#include "mongo/db/matcher/extensions_callback_noop.h" +#include "mongo/db/matcher/matcher.h" +#include "mongo/unittest/unittest.h" + +namespace mongo { +namespace { + +using std::pair; +using std::string; +using std::unique_ptr; + +BSONObj serialize(MatchExpression* match) { + BSONObjBuilder bob; + match->serialize(&bob); + return bob.obj(); +} + +TEST(SerializeBasic, AndExpressionWithOneChildSerializesCorrectly) { + Matcher original(fromjson("{$and: [{x: 0}]}"), ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), fromjson("{$and: [{x: {$eq: 0}}]}")); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); + + BSONObj obj = fromjson("{x: 1}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson("{x: 0}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); +} + +TEST(SerializeBasic, AndExpressionWithTwoChildrenSerializesCorrectly) { + Matcher original(fromjson("{$and: [{x: 1}, {x: 2}]}"), ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), fromjson("{$and: [{x: {$eq: 1}}, {x: {$eq: 2}}]}")); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); + + BSONObj obj = fromjson("{x: 1}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson("{x: [1, 2]}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); +} + +TEST(SerializeBasic, AndExpressionWithTwoIdenticalChildrenSerializesCorrectly) { + Matcher original(fromjson("{$and: [{x: 1}, {x: 1}]}"), ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), fromjson("{$and: [{x: {$eq: 1}}, {x: {$eq: 1}}]}")); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); + + BSONObj obj = fromjson("{x: 1}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson("{x: -1}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); +} + +TEST(SerializeBasic, ExpressionOr) { + Matcher original(fromjson("{$or: [{x: 'A'}, {x: 'B'}]}"), ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), fromjson("{$or: [{x: {$eq: 'A'}}, {x: {$eq: 'B'}}]}")); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); + + BSONObj obj = fromjson("{x: 'A'}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson("{x: 'a'}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); +} + +TEST(SerializeBasic, ExpressionElemMatchObjectSerializesCorrectly) { + Matcher original(fromjson("{x: {$elemMatch: {a: {$gt: 0}, b: {$gt: 0}}}}"), + ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), + fromjson("{x: {$elemMatch: {$and: [{a: {$gt: 0}}, {b: {$gt: 0}}]}}}")); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); + + BSONObj obj = fromjson("{x: [{a: 1, b: -1}, {a: -1, b: 1}]}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson("{x: [{a: 1, b: 1}, {a: 0, b: 0}]}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); +} + +TEST(SerializeBasic, ExpressionElemMatchObjectWithEmptyStringSerializesCorrectly) { + Matcher original(fromjson("{'': {$elemMatch: {a: {$gt: 0}, b: {$gt: 0}}}}"), + ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), + fromjson("{'': {$elemMatch: {$and: [{a: {$gt: 0}}, {b: {$gt: 0}}]}}}")); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); + + BSONObj obj = fromjson("{'': [{a: 1, b: -1}, {a: -1, b: 1}]}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson("{'': [{a: 1, b: 1}, {a: 0, b: 0}]}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); +} + +TEST(SerializeBasic, ExpressionElemMatchValueSerializesCorrectly) { + Matcher original(fromjson("{x: {$elemMatch: {$lt: 1, $gt: -1}}}"), ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), fromjson("{x: {$elemMatch: {$lt: 1, $gt: -1}}}")); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); + + BSONObj obj = fromjson("{x: [{a: 1, b: -1}, {a: -1, b: 1}]}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson("{x: [{a: 1, b: 1}, {a: 0, b: 0}]}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson("{x: [1, 0]}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); +} + +TEST(SerializeBasic, ExpressionElemMatchValueWithEmptyStringSerializesCorrectly) { + Matcher original(fromjson("{x: {$elemMatch: {$lt: 1, $gt: -1}}}"), ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), fromjson("{x: {$elemMatch: {$lt: 1, $gt: -1}}}")); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); + + BSONObj obj = fromjson("{x: [{a: 1, b: -1}, {a: -1, b: 1}]}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson("{x: [{a: 1, b: 1}, {a: 0, b: 0}]}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson("{x: [1, 0]}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); +} + +TEST(SerializeBasic, ExpressionSizeSerializesCorrectly) { + Matcher original(fromjson("{x: {$size: 2}}"), ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), fromjson("{x: {$size: 2}}")); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); + + BSONObj obj = fromjson("{x: [1, 2, 3]}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson("{x: [1, 2]}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); +} + +TEST(SerializeBasic, ExpressionAllSerializesCorrectly) { + Matcher original(fromjson("{x: {$all: [1, 2]}}"), ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), fromjson("{$and: [{x: {$eq: 1}}, {x: {$eq: 2}}]}")); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); + + BSONObj obj = fromjson("{x: [1, 2, 3]}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson("{x: [1, 3]}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); +} + +TEST(SerializeBasic, ExpressionAllWithEmptyArraySerializesCorrectly) { + Matcher original(fromjson("{x: {$all: []}}"), ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), fromjson("{x: {$all: []}}")); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); + + BSONObj obj = fromjson("{x: [1, 2, 3]}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); +} + +TEST(SerializeBasic, ExpressionAllWithRegex) { + Matcher original(fromjson("{x: {$all: [/a.b.c/, /.d.e./]}}"), ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), fromjson("{$and: [{x: /a.b.c/}, {x: /.d.e./}]}")); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); + + BSONObj obj = fromjson("{x: 'abcde'}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson("{x: 'adbec'}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); +} + +TEST(SerializeBasic, ExpressionEqSerializesCorrectly) { + Matcher original(fromjson("{x: {$eq: {a: 1}}}"), ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), fromjson("{x: {$eq: {a: 1}}}")); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); + + BSONObj obj = fromjson("{x: {a: 1}}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson("{x: {a: [1, 2]}}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson("{x: {a: 2}}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); +} + +TEST(SerializeBasic, ExpressionNeSerializesCorrectly) { + Matcher original(fromjson("{x: {$ne: {a: 1}}}"), ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), fromjson("{$nor: [{x: {$eq: {a: 1}}}]}")); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); + + BSONObj obj = fromjson("{x: {a: 1}}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson("{x: {a: [1, 2]}}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); +} + +TEST(SerializeBasic, ExpressionLtSerializesCorrectly) { + Matcher original(fromjson("{x: {$lt: 3}}"), ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), fromjson("{x: {$lt: 3}}")); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); + + BSONObj obj = fromjson("{x: 3}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson("{x: 2.9}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); +} + +TEST(SerializeBasic, ExpressionGtSerializesCorrectly) { + Matcher original(fromjson("{x: {$gt: 3}}"), ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), fromjson("{x: {$gt: 3}}")); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); + + BSONObj obj = fromjson("{x: 3}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson("{x: 3.1}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); +} + +TEST(SerializeBasic, ExpressionGteSerializesCorrectly) { + Matcher original(fromjson("{x: {$gte: 3}}"), ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), fromjson("{x: {$gte: 3}}")); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); + + BSONObj obj = fromjson("{x: 3}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson("{x: 2}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); +} + +TEST(SerializeBasic, ExpressionLteSerializesCorrectly) { + Matcher original(fromjson("{x: {$lte: 3}}"), ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), fromjson("{x: {$lte: 3}}")); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); + + BSONObj obj = fromjson("{x: 3}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson("{x: 4}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); +} + +TEST(SerializeBasic, ExpressionRegexWithObjSerializesCorrectly) { + Matcher original(fromjson("{x: {$regex: 'a.b'}}"), ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), fromjson("{x: {$regex: 'a.b'}}")); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); + + BSONObj obj = fromjson("{x: 'abc'}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson("{x: 'acb'}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); +} + +TEST(SerializeBasic, ExpressionRegexWithValueSerializesCorrectly) { + Matcher original(fromjson("{x: /a.b/i}"), ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), fromjson("{x: {$regex: 'a.b', $options: 'i'}}")); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); + + BSONObj obj = fromjson("{x: 'abc'}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson("{x: 'acb'}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); +} + +TEST(SerializeBasic, ExpressionRegexWithValueAndOptionsSerializesCorrectly) { + Matcher original(fromjson("{x: /a.b/}"), ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), fromjson("{x: {$regex: 'a.b'}}")); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); + + BSONObj obj = fromjson("{x: 'abc'}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson("{x: 'acb'}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); +} + +TEST(SerializeBasic, ExpressionRegexWithEqObjSerializesCorrectly) { + Matcher original(fromjson("{x: {$eq: {$regex: 'a.b'}}}"), ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), fromjson("{x: {$eq: {$regex: 'a.b'}}}")); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); + + BSONObj obj = fromjson("{x: 'abc'}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson("{x: 'acb'}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson("{x: /a.b.c/}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); +} + +TEST(SerializeBasic, ExpressionModSerializesCorrectly) { + Matcher original(fromjson("{x: {$mod: [2, 1]}}"), ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), fromjson("{x: {$mod: [2, 1]}}")); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); + + BSONObj obj = fromjson("{x: 1}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson("{x: 2}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); +} + +TEST(SerializeBasic, ExpressionExistsTrueSerializesCorrectly) { + Matcher original(fromjson("{x: {$exists: true}}"), ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), fromjson("{x: {$exists: true}}")); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); + + BSONObj obj = fromjson("{x: 1}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson("{a: 1}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); +} + +TEST(SerializeBasic, ExpressionExistsFalseSerializesCorrectly) { + Matcher original(fromjson("{x: {$exists: false}}"), ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), fromjson("{$nor: [{x: {$exists: true}}]}")); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); + + BSONObj obj = fromjson("{x: 1}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson("{a: 1}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); +} + +TEST(SerializeBasic, ExpressionInSerializesCorrectly) { + Matcher original(fromjson("{x: {$in: [1, 2, 3]}}"), ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), fromjson("{x: {$in: [1, 2, 3]}}")); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); + + BSONObj obj = fromjson("{x: 1}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson("{x: 4}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson("{x: [1, 2]}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); +} + +TEST(SerializeBasic, ExpressionInWithEmptyArraySerializesCorrectly) { + Matcher original(fromjson("{x: {$in: []}}"), ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), fromjson("{x: {$in: []}}")); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); + + BSONObj obj = fromjson("{x: 1}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); +} + +TEST(SerializeBasic, ExpressionInWithRegexSerializesCorrectly) { + Matcher original(fromjson("{x: {$in: [/\\d+/, /\\w+/]}}"), ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), fromjson("{x: {$in: [/\\d+/, /\\w+/]}}")); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); + + BSONObj obj = fromjson("{x: '1234'}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson("{x: 'abcd'}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson("{x: '1a2b'}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); +} + +TEST(SerializeBasic, ExpressionNinSerializesCorrectly) { + Matcher original(fromjson("{x: {$nin: [1, 2, 3]}}"), ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), fromjson("{$nor: [{x: {$in: [1, 2, 3]}}]}")); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); + + BSONObj obj = fromjson("{x: 1}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson("{x: 4}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson("{x: [1, 2]}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); +} + +TEST(SerializeBasic, ExpressionBitsAllSetSerializesCorrectly) { + Matcher original(fromjson("{x: {$bitsAllSet: [1, 3]}}"), ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), fromjson("{x: {$bitsAllSet: [1, 3]}}")); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); + + BSONObj obj = fromjson("{x: 2}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson("{x: 10}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); +} + +TEST(SerializeBasic, ExpressionBitsAllClearSerializesCorrectly) { + Matcher original(fromjson("{x: {$bitsAllClear: [1, 3]}}"), ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), fromjson("{x: {$bitsAllClear: [1, 3]}}")); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); + + BSONObj obj = fromjson("{x: 2}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson("{x: 1}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); +} + +TEST(SerializeBasic, ExpressionBitsAnySetSerializesCorrectly) { + Matcher original(fromjson("{x: {$bitsAnySet: [1, 3]}}"), ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), fromjson("{x: {$bitsAnySet: [1, 3]}}")); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); + + BSONObj obj = fromjson("{x: 2}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson("{x: 4}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); +} + +TEST(SerializeBasic, ExpressionBitsAnyClearSerializesCorrectly) { + Matcher original(fromjson("{x: {$bitsAnyClear: [1, 3]}}"), ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), fromjson("{x: {$bitsAnyClear: [1, 3]}}")); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); + + BSONObj obj = fromjson("{x: 2}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson("{x: 1}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson("{x: 10}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); +} + +TEST(SerializeBasic, ExpressionNotSerializesCorrectly) { + Matcher original(fromjson("{x: {$not: {$eq: 3}}}"), ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), fromjson("{$nor: [{$and: [{x: {$eq: 3}}]}]}")); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); + + BSONObj obj = fromjson("{x: 3}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson("{x: 4}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); +} + +TEST(SerializeBasic, ExpressionNotWithMultipleChildrenSerializesCorrectly) { + Matcher original(fromjson("{x: {$not: {$lt: 1, $gt: 3}}}"), ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), + fromjson("{$nor: [{$and: [{x: {$lt: 1}}, {x: {$gt: 3}}]}]}}")); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); + + BSONObj obj = fromjson("{x: 2}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson("{x: 4}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); +} + +TEST(SerializeBasic, ExpressionNotWithBitTestSerializesCorrectly) { + Matcher original(fromjson("{x: {$not: {$bitsAnySet: [1, 3]}}}"), ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), fromjson("{$nor: [{$and: [{x: {$bitsAnySet: [1, 3]}}]}]}")); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); + + BSONObj obj = fromjson("{x: 2}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson("{x: 4}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); +} + +TEST(SerializeBasic, ExpressionNotWithRegexObjSerializesCorrectly) { + Matcher original(fromjson("{x: {$not: {$regex: 'a.b'}}}"), ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), fromjson("{$nor: [{x: /a.b/}]}")); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); + + BSONObj obj = fromjson("{x: 'abc'}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson("{x: 'acb'}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); +} + +TEST(SerializeBasic, ExpressionNotWithRegexValueSerializesCorrectly) { + Matcher original(fromjson("{x: {$not: /a.b/}}"), ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), fromjson("{$nor: [{x: /a.b/}]}")); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); + + BSONObj obj = fromjson("{x: 'abc'}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson("{x: 'acb'}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); +} + +TEST(SerializeBasic, ExpressionNotWithRegexValueAndOptionsSerializesCorrectly) { + Matcher original(fromjson("{x: {$not: /a.b/i}}"), ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), fromjson("{$nor: [{x: /a.b/i}]}")); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); + + BSONObj obj = fromjson("{x: 'abc'}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson("{x: 'acb'}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); +} + +TEST(SerializeBasic, ExpressionNotWithGeoSerializesCorrectly) { + Matcher original(fromjson( + "{x: {$not: {$geoIntersects: {$geometry: {type: 'Polygon', " + "coordinates: [[[0,0], [5,0], " + "[5, 5], [0, 5], [0, 0]]]}}}}}"), + ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), + fromjson( + "{$nor: [{$and: [{x: {$geoIntersects: {$geometry: {type: 'Polygon', coordinates: " + "[[[0,0], " + "[5,0], [5, 5], [0, 5], [0, 0]]]}}}}]}]}")); + + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); + BSONObj obj = + fromjson("{x: {type: 'Polygon', coordinates: [[4, 4], [4, 6], [6, 6], [6, 4], [4, 4]]}}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson( + "{x: {type: 'Polygon', coordinates: [[4, 4], [4, 4.5], [4.5, 4.5], [4.5, 4], [4, 4]]}}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson( + "{x: {type: 'Polygon', coordinates: [[5.5, 5.5], [5.5, 6], [6, 6], [6, 5.5], [5.5, " + "5.5]]}}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); +} + +TEST(SerializeBasic, ExpressionNorSerializesCorrectly) { + Matcher original(fromjson("{$nor: [{x: 3}, {x: {$lt: 1}}]}"), ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), fromjson("{$nor: [{x: {$eq: 3}}, {x: {$lt: 1}}]}")); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); + + BSONObj obj = fromjson("{x: 3}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson("{x: 0}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson("{x: 2}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); +} + +TEST(SerializeBasic, ExpressionTypeSerializesCorrectly) { + Matcher original(fromjson("{x: {$type: 2}}"), ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), fromjson("{x: {$type: 2}}")); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); + + BSONObj obj = fromjson("{x: 3}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson("{x: '3'}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); +} + +TEST(SerializeBasic, ExpressionTypeWithNumberSerializesCorrectly) { + Matcher original(fromjson("{x: {$type: 'number'}}"), ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), fromjson("{x: {$type: 'number'}}")); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); + + BSONObj obj = fromjson("{x: 3}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson("{x: '3'}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); +} + +TEST(SerializeBasic, ExpressionEmptySerializesCorrectly) { + Matcher original(fromjson("{}"), ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), fromjson("{}")); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); + + BSONObj obj = fromjson("{x: 3}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); +} + +TEST(SerializeBasic, ExpressionWhereSerializesCorrectly) { + Matcher original(fromjson("{$where: 'this.a == this.b'}"), ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), + BSONObjBuilder().appendCodeWScope("$where", "this.a == this.b", BSONObj()).obj()); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); +} + +TEST(SerializeBasic, ExpressionWhereWithScopeSerializesCorrectly) { + Matcher original(BSON("$where" << BSONCodeWScope("this.a == this.b", BSON("x" << 3))), + ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), + BSON("$where" << BSONCodeWScope("this.a == this.b", BSON("x" << 3)))); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); +} + +TEST(SerializeBasic, ExpressionCommentSerializesCorrectly) { + Matcher original(fromjson("{$comment: 'Hello'}"), ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), fromjson("{}")); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); + + BSONObj obj = fromjson("{a: 1, b: 2}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson("{a: 'z', b: 'z'}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); +} + +TEST(SerializeBasic, ExpressionGeoWithinSerializesCorrectly) { + Matcher original( + fromjson( + "{x: {$geoWithin: {$geometry: " + "{type: 'Polygon', coordinates: [[[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]]]}}}}"), + ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), + fromjson( + "{x: {$geoWithin: {$geometry: {type: 'Polygon', coordinates: [[[0,0], [10,0], " + "[10, 10], [0, 10], [0, 0]]]}}}}")); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); + + BSONObj obj = fromjson("{x: {type: 'Point', coordinates: [5, 5]}}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson("{x: {type: 'Point', coordinates: [50, 50]}}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); +} + +TEST(SerializeBasic, ExpressionGeoIntersectsSerializesCorrectly) { + Matcher original( + fromjson( + "{x: {$geoIntersects: {$geometry: {type: 'Polygon', coordinates: [[[0,0], [5,0], [5, " + "5], [0, 5], [0, 0]]]}}}}"), + ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), + fromjson( + "{x: {$geoIntersects: {$geometry: {type: 'Polygon', coordinates: [[[0,0], [5,0], " + "[5, 5], [0, 5], [0, 0]]]}}}}")); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); + + BSONObj obj = + fromjson("{x: {type: 'Polygon', coordinates: [[4, 4], [4, 6], [6, 6], [6, 4], [4, 4]]}}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson( + "{x: {type: 'Polygon', coordinates: [[4, 4], [4, 4.5], [4.5, 4.5], [4.5, 4], [4, 4]]}}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); + + obj = fromjson( + "{x: {type: 'Polygon', coordinates: [[5.5, 5.5], [5.5, 6], [6, 6], [6, 5.5], [5.5, " + "5.5]]}}"); + ASSERT_EQ(original.matches(obj), reserialized.matches(obj)); +} + +TEST(SerializeBasic, ExpressionNearSerializesCorrectly) { + Matcher original( + fromjson( + "{x: {$near: {$geometry: {type: 'Point', coordinates: [0, 0]}, $maxDistance: 10, " + "$minDistance: 1}}}"), + ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), + fromjson( + "{x: {$near: {$geometry: {type: 'Point', coordinates: [0, 0]}, $maxDistance: 10, " + "$minDistance: 1}}}")); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); +} + +TEST(SerializeBasic, ExpressionNearSphereSerializesCorrectly) { + Matcher original( + fromjson( + "{x: {$nearSphere: {$geometry: {type: 'Point', coordinates: [0, 0]}, $maxDistance: 10, " + "$minDistance: 1}}}"), + ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), + fromjson( + "{x: {$nearSphere: {$geometry: {type: 'Point', coordinates: [0, 0]}, " + "$maxDistance: 10, $minDistance: 1}}}")); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); +} + +TEST(SerializeBasic, ExpressionTextSerializesCorrectly) { + Matcher original(fromjson("{$text: {$search: 'a', $language: 'en', $caseSensitive: true}}"), + ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), + fromjson( + "{$text: {$search: 'a', $language: 'en', $caseSensitive: true, " + "$diacriticSensitive: false}}")); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); +} + +TEST(SerializeBasic, ExpressionTextWithDefaultLanguageSerializesCorrectly) { + Matcher original(fromjson("{$text: {$search: 'a', $caseSensitive: false}}"), + ExtensionsCallbackNoop()); + Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ASSERT_EQ(*reserialized.getQuery(), + fromjson( + "{$text: {$search: 'a', $language: '', $caseSensitive: false, " + "$diacriticSensitive: false}}")); + ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); +} + +} // namespace +} // namespace mongo |