// expression_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.
*/
#include "mongo/platform/basic.h"
#include "mongo/db/matcher/expression.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/json.h"
#include "mongo/db/matcher/expression_leaf.h"
#include "mongo/db/matcher/expression_tree.h"
#include "mongo/unittest/unittest.h"
namespace mongo {
TEST(LeafMatchExpressionTest, Equal1) {
BSONObj temp = BSON("x" << 5);
EqualityMatchExpression e;
e.init("x", temp["x"]).transitional_ignore();
ASSERT_TRUE(e.matchesBSON(fromjson("{ x : 5 }")));
ASSERT_TRUE(e.matchesBSON(fromjson("{ x : [5] }")));
ASSERT_TRUE(e.matchesBSON(fromjson("{ x : [1,5] }")));
ASSERT_TRUE(e.matchesBSON(fromjson("{ x : [1,5,2] }")));
ASSERT_TRUE(e.matchesBSON(fromjson("{ x : [5,2] }")));
ASSERT_FALSE(e.matchesBSON(fromjson("{ x : null }")));
ASSERT_FALSE(e.matchesBSON(fromjson("{ x : 6 }")));
ASSERT_FALSE(e.matchesBSON(fromjson("{ x : [4,2] }")));
ASSERT_FALSE(e.matchesBSON(fromjson("{ x : [[5]] }")));
}
TEST(LeafMatchExpressionTest, Comp1) {
BSONObj temp = BSON("x" << 5);
{
LTEMatchExpression e;
e.init("x", temp["x"]).transitional_ignore();
ASSERT_TRUE(e.matchesBSON(fromjson("{ x : 5 }")));
ASSERT_TRUE(e.matchesBSON(fromjson("{ x : 4 }")));
ASSERT_FALSE(e.matchesBSON(fromjson("{ x : 6 }")));
ASSERT_FALSE(e.matchesBSON(fromjson("{ x : 'eliot' }")));
}
{
LTMatchExpression e;
e.init("x", temp["x"]).transitional_ignore();
ASSERT_FALSE(e.matchesBSON(fromjson("{ x : 5 }")));
ASSERT_TRUE(e.matchesBSON(fromjson("{ x : 4 }")));
ASSERT_FALSE(e.matchesBSON(fromjson("{ x : 6 }")));
ASSERT_FALSE(e.matchesBSON(fromjson("{ x : 'eliot' }")));
}
{
GTEMatchExpression e;
e.init("x", temp["x"]).transitional_ignore();
ASSERT_TRUE(e.matchesBSON(fromjson("{ x : 5 }")));
ASSERT_FALSE(e.matchesBSON(fromjson("{ x : 4 }")));
ASSERT_TRUE(e.matchesBSON(fromjson("{ x : 6 }")));
ASSERT_FALSE(e.matchesBSON(fromjson("{ x : 'eliot' }")));
}
{
GTMatchExpression e;
e.init("x", temp["x"]).transitional_ignore();
ASSERT_FALSE(e.matchesBSON(fromjson("{ x : 5 }")));
ASSERT_FALSE(e.matchesBSON(fromjson("{ x : 4 }")));
ASSERT_TRUE(e.matchesBSON(fromjson("{ x : 6 }")));
ASSERT_FALSE(e.matchesBSON(fromjson("{ x : 'eliot' }")));
}
}
TEST(MatchesBSONElement, ScalarEquality) {
auto filterObj = fromjson("{i: 5}");
EqualityMatchExpression filter;
ASSERT_OK(filter.init("i", filterObj["i"]));
auto aFive = fromjson("{a: 5}");
auto iFive = fromjson("{i: 5}");
ASSERT_TRUE(filter.matchesBSONElement(aFive["a"]));
ASSERT_TRUE(filter.matchesBSON(iFive));
auto aSix = fromjson("{a: 6}");
auto iSix = fromjson("{i: 6}");
ASSERT_FALSE(filter.matchesBSONElement(aSix["a"]));
ASSERT_FALSE(filter.matchesBSON(iSix));
auto aArrMatch1 = fromjson("{a: [5, 6]}");
auto iArrMatch1 = fromjson("{i: [5, 6]}");
ASSERT_TRUE(filter.matchesBSONElement(aArrMatch1["a"]));
ASSERT_TRUE(filter.matchesBSON(iArrMatch1));
auto aArrMatch2 = fromjson("{a: [6, 5]}");
auto iArrMatch2 = fromjson("{i: [6, 5]}");
ASSERT_TRUE(filter.matchesBSONElement(aArrMatch2["a"]));
ASSERT_TRUE(filter.matchesBSON(iArrMatch2));
auto aArrNoMatch = fromjson("{a: [6, 6]}");
auto iArrNoMatch = fromjson("{i: [6, 6]}");
ASSERT_FALSE(filter.matchesBSONElement(aArrNoMatch["a"]));
ASSERT_FALSE(filter.matchesBSON(iArrNoMatch));
auto aObj = fromjson("{a: {i: 5}}");
auto iObj = fromjson("{i: {i: 5}}");
ASSERT_FALSE(filter.matchesBSONElement(aObj["a"]));
ASSERT_FALSE(filter.matchesBSON(iObj));
auto aObjArr = fromjson("{a: [{i: 5}]}");
auto iObjArr = fromjson("{i: [{i: 5}]}");
ASSERT_FALSE(filter.matchesBSONElement(aObjArr["a"]));
ASSERT_FALSE(filter.matchesBSON(iObjArr));
}
TEST(MatchesBSONElement, DottedPathEquality) {
auto filterObj = fromjson("{'i.a': 5}");
EqualityMatchExpression filter;
ASSERT_OK(filter.init("i.a", filterObj["i.a"]));
auto aFive = fromjson("{a: 5}");
auto iFive = fromjson("{i: 5}");
ASSERT_FALSE(filter.matchesBSONElement(aFive["a"]));
ASSERT_FALSE(filter.matchesBSON(iFive));
auto aArr = fromjson("{a: [5]}");
auto iArr = fromjson("{i: [5]}");
ASSERT_FALSE(filter.matchesBSONElement(aArr["a"]));
ASSERT_FALSE(filter.matchesBSON(iArr));
auto aObjMatch = fromjson("{a: {a: 5, b: 6}}");
auto iObjMatch = fromjson("{i: {a: 5, b: 6}}");
ASSERT_TRUE(filter.matchesBSONElement(aObjMatch["a"]));
ASSERT_TRUE(filter.matchesBSON(iObjMatch));
auto aObjNoMatch1 = fromjson("{a: {a: 6}}");
auto iObjNoMatch1 = fromjson("{i: {a: 6}}");
ASSERT_FALSE(filter.matchesBSONElement(aObjNoMatch1["a"]));
ASSERT_FALSE(filter.matchesBSON(iObjNoMatch1));
auto aObjNoMatch2 = fromjson("{a: {b: 5}}");
auto iObjNoMatch2 = fromjson("{i: {b: 5}}");
ASSERT_FALSE(filter.matchesBSONElement(aObjNoMatch2["a"]));
ASSERT_FALSE(filter.matchesBSON(iObjNoMatch2));
auto aObjArrMatch1 = fromjson("{a: [{a: 5}, {a: 6}]}");
auto iObjArrMatch1 = fromjson("{i: [{a: 5}, {a: 6}]}");
ASSERT_TRUE(filter.matchesBSONElement(aObjArrMatch1["a"]));
ASSERT_TRUE(filter.matchesBSON(iObjArrMatch1));
auto aObjArrMatch2 = fromjson("{a: [{a: 6}, {a: 5}]}");
auto iObjArrMatch2 = fromjson("{i: [{a: 6}, {a: 5}]}");
ASSERT_TRUE(filter.matchesBSONElement(aObjArrMatch2["a"]));
ASSERT_TRUE(filter.matchesBSON(iObjArrMatch2));
auto aObjArrNoMatch1 = fromjson("{a: [{a: 6}, {a: 6}]}");
auto iObjArrNoMatch1 = fromjson("{i: [{a: 6}, {a: 6}]}");
ASSERT_FALSE(filter.matchesBSONElement(aObjArrNoMatch1["a"]));
ASSERT_FALSE(filter.matchesBSON(iObjArrNoMatch1));
auto aObjArrNoMatch2 = fromjson("{a: [{b: 5}, {b: 5}]}");
auto iObjArrNoMatch2 = fromjson("{i: [{b: 5}, {b: 5}]}");
ASSERT_FALSE(filter.matchesBSONElement(aObjArrNoMatch2["a"]));
ASSERT_FALSE(filter.matchesBSON(iObjArrNoMatch2));
}
TEST(MatchesBSONElement, ArrayIndexEquality) {
auto filterObj = fromjson("{'i.1': 5}");
EqualityMatchExpression filter;
ASSERT_OK(filter.init("i.1", filterObj["i.1"]));
auto aFive = fromjson("{a: 5}");
auto iFive = fromjson("{i: 5}");
ASSERT_FALSE(filter.matchesBSONElement(aFive["a"]));
ASSERT_FALSE(filter.matchesBSON(iFive));
auto aArrMatch = fromjson("{a: [6, 5]}");
auto iArrMatch = fromjson("{i: [6, 5]}");
ASSERT_TRUE(filter.matchesBSONElement(aArrMatch["a"]));
ASSERT_TRUE(filter.matchesBSON(iArrMatch));
auto aArrNoMatch = fromjson("{a: [5, 6]}");
auto iArrNoMatch = fromjson("{i: [5, 6]}");
ASSERT_FALSE(filter.matchesBSONElement(aArrNoMatch["a"]));
ASSERT_FALSE(filter.matchesBSON(iArrNoMatch));
auto aObjMatch = fromjson("{a: {'1': 5}}");
auto iObjMatch = fromjson("{i: {'1': 5}}");
ASSERT_TRUE(filter.matchesBSONElement(aObjMatch["a"]));
ASSERT_TRUE(filter.matchesBSON(iObjMatch));
auto aObjNoMatch = fromjson("{a: {i: 5}}");
auto iObjNoMatch = fromjson("{i: {i: 5}}");
ASSERT_FALSE(filter.matchesBSONElement(aObjNoMatch["a"]));
ASSERT_FALSE(filter.matchesBSON(iObjNoMatch));
auto aObjArrMatch = fromjson("{a: [{'1': 5}]}");
auto iObjArrMatch = fromjson("{i: [{'1': 5}]}");
ASSERT_TRUE(filter.matchesBSONElement(aObjArrMatch["a"]));
ASSERT_TRUE(filter.matchesBSON(iObjArrMatch));
auto aObjArrNoMatch = fromjson("{a: [{i: 6}, {i: 5}]}");
auto iObjArrNoMatch = fromjson("{i: [{i: 6}, {i: 5}]}");
ASSERT_FALSE(filter.matchesBSONElement(aObjArrNoMatch["a"]));
ASSERT_FALSE(filter.matchesBSON(iObjArrNoMatch));
auto aArrArr = fromjson("{a: [[6, 5], [6, 5]]}");
auto iArrArr = fromjson("{i: [[6, 5], [6, 5]]}");
ASSERT_FALSE(filter.matchesBSONElement(aArrArr["a"]));
ASSERT_FALSE(filter.matchesBSON(iArrArr));
}
TEST(MatchesBSONElement, ObjectEquality) {
auto filterObj = fromjson("{i: {a: 5}}");
EqualityMatchExpression filter;
ASSERT_OK(filter.init("i", filterObj["i"]));
auto aFive = fromjson("{a: 5}");
auto iFive = fromjson("{i: 5}");
ASSERT_FALSE(filter.matchesBSONElement(aFive["a"]));
ASSERT_FALSE(filter.matchesBSON(iFive));
auto aArr = fromjson("{a: [5]}");
auto iArr = fromjson("{i: [5]}");
ASSERT_FALSE(filter.matchesBSONElement(aArr["a"]));
ASSERT_FALSE(filter.matchesBSON(iArr));
auto aObjMatch = fromjson("{a: {a: 5}}");
auto iObjMatch = fromjson("{i: {a: 5}}");
ASSERT_TRUE(filter.matchesBSONElement(aObjMatch["a"]));
ASSERT_TRUE(filter.matchesBSON(iObjMatch));
auto aObjNoMatch1 = fromjson("{a: {a: 5, b: 6}}");
auto iObjNoMatch1 = fromjson("{i: {a: 5, b: 6}}");
ASSERT_FALSE(filter.matchesBSONElement(aObjNoMatch1["a"]));
ASSERT_FALSE(filter.matchesBSON(iObjNoMatch1));
auto aObjNoMatch2 = fromjson("{a: {a: 6}}");
auto iObjNoMatch2 = fromjson("{i: {a: 6}}");
ASSERT_FALSE(filter.matchesBSONElement(aObjNoMatch2["a"]));
ASSERT_FALSE(filter.matchesBSON(iObjNoMatch2));
auto aObjNoMatch3 = fromjson("{a: {b: 5}}");
auto iObjNoMatch3 = fromjson("{i: {b: 5}}");
ASSERT_FALSE(filter.matchesBSONElement(aObjNoMatch3["a"]));
ASSERT_FALSE(filter.matchesBSON(iObjNoMatch3));
auto aObjArrMatch1 = fromjson("{a: [{a: 5}, {a: 6}]}");
auto iObjArrMatch1 = fromjson("{i: [{a: 5}, {a: 6}]}");
ASSERT_TRUE(filter.matchesBSONElement(aObjArrMatch1["a"]));
ASSERT_TRUE(filter.matchesBSON(iObjArrMatch1));
auto aObjArrMatch2 = fromjson("{a: [{a: 6}, {a: 5}]}");
auto iObjArrMatch2 = fromjson("{i: [{a: 6}, {a: 5}]}");
ASSERT_TRUE(filter.matchesBSONElement(aObjArrMatch2["a"]));
ASSERT_TRUE(filter.matchesBSON(iObjArrMatch2));
auto aObjArrNoMatch = fromjson("{a: [{a: 6}, {a: 6}]}");
auto iObjArrNoMatch = fromjson("{i: [{a: 6}, {a: 6}]}");
ASSERT_FALSE(filter.matchesBSONElement(aObjArrNoMatch["a"]));
ASSERT_FALSE(filter.matchesBSON(iObjArrNoMatch));
}
TEST(MatchesBSONElement, ArrayEquality) {
auto filterObj = fromjson("{i: [5]}");
EqualityMatchExpression filter;
ASSERT_OK(filter.init("i", filterObj["i"]));
auto aFive = fromjson("{a: 5}");
auto iFive = fromjson("{i: 5}");
ASSERT_FALSE(filter.matchesBSONElement(aFive["a"]));
ASSERT_FALSE(filter.matchesBSON(iFive));
auto aArrMatch = fromjson("{a: [5]}");
auto iArrMatch = fromjson("{i: [5]}");
ASSERT_TRUE(filter.matchesBSONElement(aArrMatch["a"]));
ASSERT_TRUE(filter.matchesBSON(iArrMatch));
auto aArrNoMatch = fromjson("{a: [5, 6]}");
auto iArrNoMatch = fromjson("{i: [5, 6]}");
ASSERT_FALSE(filter.matchesBSONElement(aArrNoMatch["a"]));
ASSERT_FALSE(filter.matchesBSON(iArrNoMatch));
auto aObj = fromjson("{a: {i: [5]}}");
auto iObj = fromjson("{i: {i: [5]}}");
ASSERT_FALSE(filter.matchesBSONElement(aObj["a"]));
ASSERT_FALSE(filter.matchesBSON(iObj));
auto aObjArr = fromjson("{a: [{i: [5]}]}");
auto iObjArr = fromjson("{i: [{i: [5]}]}");
ASSERT_FALSE(filter.matchesBSONElement(aObjArr["a"]));
ASSERT_FALSE(filter.matchesBSON(iObjArr));
}
TEST(MatchesBSONElement, LogicalExpression) {
auto clauseObj1 = fromjson("{i: 5}");
auto clauseObj2 = fromjson("{'i.a': 6}");
std::unique_ptr clause1(new EqualityMatchExpression());
ASSERT_OK(clause1->init("i", clauseObj1["i"]));
std::unique_ptr clause2(new EqualityMatchExpression());
ASSERT_OK(clause2->init("i.a", clauseObj2["i.a"]));
OrMatchExpression filter;
filter.add(clause1.release());
filter.add(clause2.release());
auto aClause1 = fromjson("{a: 5}");
auto iClause1 = fromjson("{i: 5}");
ASSERT_TRUE(filter.matchesBSONElement(aClause1["a"]));
ASSERT_TRUE(filter.matchesBSON(iClause1));
auto aClause2 = fromjson("{a: {a: 6}}");
auto iClause2 = fromjson("{i: {a: 6}}");
ASSERT_TRUE(filter.matchesBSONElement(aClause2["a"]));
ASSERT_TRUE(filter.matchesBSON(iClause2));
auto aNoMatch1 = fromjson("{a: 6}");
auto iNoMatch1 = fromjson("{i: 6}");
ASSERT_FALSE(filter.matchesBSONElement(aNoMatch1["a"]));
ASSERT_FALSE(filter.matchesBSON(iNoMatch1));
auto aNoMatch2 = fromjson("{a: {a: 5}}");
auto iNoMatch2 = fromjson("{i: {a: 5}}");
ASSERT_FALSE(filter.matchesBSONElement(aNoMatch2["a"]));
ASSERT_FALSE(filter.matchesBSON(iNoMatch2));
}
} // namespace mongo