diff options
Diffstat (limited to 'src/mongo/db/matcher/expression_tree_test.cpp')
| -rw-r--r-- | src/mongo/db/matcher/expression_tree_test.cpp | 571 |
1 files changed, 571 insertions, 0 deletions
diff --git a/src/mongo/db/matcher/expression_tree_test.cpp b/src/mongo/db/matcher/expression_tree_test.cpp new file mode 100644 index 00000000000..c0ba4cead87 --- /dev/null +++ b/src/mongo/db/matcher/expression_tree_test.cpp @@ -0,0 +1,571 @@ +/** + * Copyright (C) 2012 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 <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 MatchMatchExpression operator implementations in match_operators.{h,cpp}. */ + +#include "mongo/unittest/unittest.h" + +#include "mongo/db/jsobj.h" +#include "mongo/db/json.h" +#include "mongo/db/matcher/expression.h" +#include "mongo/db/matcher/expression_tree.h" +#include "mongo/db/matcher/expression_leaf.h" + +namespace mongo { + + TEST( NotMatchExpression, MatchesScalar ) { + BSONObj baseOperand = BSON( "$lt" << 5 ); + auto_ptr<ComparisonMatchExpression> lt( new LTMatchExpression() ); + ASSERT( lt->init( "a", baseOperand[ "$lt" ] ).isOK() ); + NotMatchExpression notOp; + ASSERT( notOp.init( lt.release() ).isOK() ); + ASSERT( notOp.matchesBSON( BSON( "a" << 6 ), NULL ) ); + ASSERT( !notOp.matchesBSON( BSON( "a" << 4 ), NULL ) ); + } + + TEST( NotMatchExpression, MatchesArray ) { + BSONObj baseOperand = BSON( "$lt" << 5 ); + auto_ptr<ComparisonMatchExpression> lt( new LTMatchExpression() ); + ASSERT( lt->init( "a", baseOperand[ "$lt" ] ).isOK() ); + NotMatchExpression notOp; + ASSERT( notOp.init( lt.release() ).isOK() ); + ASSERT( notOp.matchesBSON( BSON( "a" << BSON_ARRAY( 6 ) ), NULL ) ); + ASSERT( !notOp.matchesBSON( BSON( "a" << BSON_ARRAY( 4 ) ), NULL ) ); + // All array elements must match. + ASSERT( !notOp.matchesBSON( BSON( "a" << BSON_ARRAY( 4 << 5 << 6 ) ), NULL ) ); + } + + TEST( NotMatchExpression, ElemMatchKey ) { + BSONObj baseOperand = BSON( "$lt" << 5 ); + auto_ptr<ComparisonMatchExpression> lt( new LTMatchExpression() ); + ASSERT( lt->init( "a", baseOperand[ "$lt" ] ).isOK() ); + NotMatchExpression notOp; + ASSERT( notOp.init( lt.release() ).isOK() ); + MatchDetails details; + details.requestElemMatchKey(); + ASSERT( !notOp.matchesBSON( BSON( "a" << BSON_ARRAY( 1 ) ), &details ) ); + ASSERT( !details.hasElemMatchKey() ); + ASSERT( notOp.matchesBSON( BSON( "a" << 6 ), &details ) ); + ASSERT( !details.hasElemMatchKey() ); + ASSERT( notOp.matchesBSON( BSON( "a" << BSON_ARRAY( 6 ) ), &details ) ); + // elemMatchKey is not implemented for negative match operators. + ASSERT( !details.hasElemMatchKey() ); + } + /* + TEST( NotMatchExpression, MatchesIndexKey ) { + BSONObj baseOperand = BSON( "$lt" << 5 ); + auto_ptr<ComparisonMatchExpression> lt( new ComparisonMatchExpression() ); + ASSERT( lt->init( "a", baseOperand[ "$lt" ] ).isOK() ); + NotMatchExpression notOp; + ASSERT( notOp.init( lt.release() ).isOK() ); + IndexSpec indexSpec( BSON( "a" << 1 ) ); + BSONObj indexKey = BSON( "" << "7" ); + ASSERT( MatchMatchExpression::PartialMatchResult_Unknown == + notOp.matchesIndexKey( indexKey, indexSpec ) ); + } + */ + + /** + TEST( AndOp, MatchesElementSingleClause ) { + BSONObj baseOperand = BSON( "$lt" << 5 ); + BSONObj match = BSON( "a" << 4 ); + BSONObj notMatch = BSON( "a" << 5 ); + auto_ptr<ComparisonMatchExpression> lt( new ComparisonMatchExpression() ); + ASSERT( lt->init( "", baseOperand[ "$lt" ] ).isOK() ); + OwnedPointerVector<MatchMatchExpression> subMatchExpressions; + subMatchExpressions.mutableVector().push_back( lt.release() ); + AndOp andOp; + ASSERT( andOp.init( &subMatchExpressions ).isOK() ); + ASSERT( andOp.matchesSingleElement( match[ "a" ] ) ); + ASSERT( !andOp.matchesSingleElement( notMatch[ "a" ] ) ); + } + */ + + TEST( AndOp, NoClauses ) { + AndMatchExpression andMatchExpression; + ASSERT( andMatchExpression.matchesBSON( BSONObj(), NULL ) ); + } + + TEST( AndOp, MatchesElementThreeClauses ) { + BSONObj baseOperand1 = BSON( "$lt" << "z1" ); + BSONObj baseOperand2 = BSON( "$gt" << "a1" ); + BSONObj match = BSON( "a" << "r1" ); + BSONObj notMatch1 = BSON( "a" << "z1" ); + BSONObj notMatch2 = BSON( "a" << "a1" ); + BSONObj notMatch3 = BSON( "a" << "r" ); + + auto_ptr<ComparisonMatchExpression> sub1( new LTMatchExpression() ); + ASSERT( sub1->init( "a", baseOperand1[ "$lt" ] ).isOK() ); + auto_ptr<ComparisonMatchExpression> sub2( new GTMatchExpression() ); + ASSERT( sub2->init( "a", baseOperand2[ "$gt" ] ).isOK() ); + auto_ptr<RegexMatchExpression> sub3( new RegexMatchExpression() ); + ASSERT( sub3->init( "a", "1", "" ).isOK() ); + + AndMatchExpression andOp; + andOp.add( sub1.release() ); + andOp.add( sub2.release() ); + andOp.add( sub3.release() ); + + ASSERT( andOp.matchesBSON( match ) ); + ASSERT( !andOp.matchesBSON( notMatch1 ) ); + ASSERT( !andOp.matchesBSON( notMatch2 ) ); + ASSERT( !andOp.matchesBSON( notMatch3 ) ); + } + + TEST( AndOp, MatchesSingleClause ) { + BSONObj baseOperand = BSON( "$ne" << 5 ); + auto_ptr<ComparisonMatchExpression> eq( new EqualityMatchExpression() ); + ASSERT( eq->init( "a", baseOperand[ "$ne" ] ).isOK() ); + auto_ptr<NotMatchExpression> ne( new NotMatchExpression() ); + ASSERT( ne->init( eq.release() ).isOK() ); + + AndMatchExpression andOp; + andOp.add( ne.release() ); + + ASSERT( andOp.matchesBSON( BSON( "a" << 4 ), NULL ) ); + ASSERT( andOp.matchesBSON( BSON( "a" << BSON_ARRAY( 4 << 6 ) ), NULL ) ); + ASSERT( !andOp.matchesBSON( BSON( "a" << 5 ), NULL ) ); + ASSERT( !andOp.matchesBSON( BSON( "a" << BSON_ARRAY( 4 << 5 ) ), NULL ) ); + } + + TEST( AndOp, MatchesThreeClauses ) { + BSONObj baseOperand1 = BSON( "$gt" << 1 ); + BSONObj baseOperand2 = BSON( "$lt" << 10 ); + BSONObj baseOperand3 = BSON( "$lt" << 100 ); + + auto_ptr<ComparisonMatchExpression> sub1( new GTMatchExpression() ); + ASSERT( sub1->init( "a", baseOperand1[ "$gt" ] ).isOK() ); + + auto_ptr<ComparisonMatchExpression> sub2( new LTMatchExpression() ); + ASSERT( sub2->init( "a", baseOperand2[ "$lt" ] ).isOK() ); + + auto_ptr<ComparisonMatchExpression> sub3( new LTMatchExpression() ); + ASSERT( sub3->init( "b", baseOperand3[ "$lt" ] ).isOK() ); + + AndMatchExpression andOp; + andOp.add( sub1.release() ); + andOp.add( sub2.release() ); + andOp.add( sub3.release() ); + + ASSERT( andOp.matchesBSON( BSON( "a" << 5 << "b" << 6 ), NULL ) ); + ASSERT( !andOp.matchesBSON( BSON( "a" << 5 ), NULL ) ); + ASSERT( !andOp.matchesBSON( BSON( "b" << 6 ), NULL ) ); + ASSERT( !andOp.matchesBSON( BSON( "a" << 1 << "b" << 6 ), NULL ) ); + ASSERT( !andOp.matchesBSON( BSON( "a" << 10 << "b" << 6 ), NULL ) ); + } + + TEST( AndOp, ElemMatchKey ) { + BSONObj baseOperand1 = BSON( "a" << 1 ); + BSONObj baseOperand2 = BSON( "b" << 2 ); + + auto_ptr<ComparisonMatchExpression> sub1( new EqualityMatchExpression() ); + ASSERT( sub1->init( "a", baseOperand1[ "a" ] ).isOK() ); + + auto_ptr<ComparisonMatchExpression> sub2( new EqualityMatchExpression() ); + ASSERT( sub2->init( "b", baseOperand2[ "b" ] ).isOK() ); + + AndMatchExpression andOp; + andOp.add( sub1.release() ); + andOp.add( sub2.release() ); + + MatchDetails details; + details.requestElemMatchKey(); + ASSERT( !andOp.matchesBSON( BSON( "a" << BSON_ARRAY( 1 ) ), &details ) ); + ASSERT( !details.hasElemMatchKey() ); + ASSERT( !andOp.matchesBSON( BSON( "b" << BSON_ARRAY( 2 ) ), &details ) ); + ASSERT( !details.hasElemMatchKey() ); + ASSERT( andOp.matchesBSON( BSON( "a" << BSON_ARRAY( 1 ) << "b" << BSON_ARRAY( 1 << 2 ) ), + &details ) ); + ASSERT( details.hasElemMatchKey() ); + // The elem match key for the second $and clause is recorded. + ASSERT_EQUALS( "1", details.elemMatchKey() ); + } + + /** + TEST( AndOp, MatchesIndexKeyWithoutUnknown ) { + BSONObj baseOperand1 = BSON( "$gt" << 1 ); + BSONObj baseOperand2 = BSON( "$lt" << 5 ); + auto_ptr<ComparisonMatchExpression> sub1( new ComparisonMatchExpression() ); + ASSERT( sub1->init( "a", baseOperand1[ "$gt" ] ).isOK() ); + auto_ptr<ComparisonMatchExpression> sub2( new ComparisonMatchExpression() ); + ASSERT( sub2->init( "a", baseOperand2[ "$lt" ] ).isOK() ); + OwnedPointerVector<MatchMatchExpression> subMatchExpressions; + subMatchExpressions.mutableVector().push_back( sub1.release() ); + subMatchExpressions.mutableVector().push_back( sub2.release() ); + AndOp andOp; + ASSERT( andOp.init( &subMatchExpressions ).isOK() ); + IndexSpec indexSpec( BSON( "a" << 1 ) ); + ASSERT( MatchMatchExpression::PartialMatchResult_True == + andOp.matchesIndexKey( BSON( "" << 3 ), indexSpec ) ); + ASSERT( MatchMatchExpression::PartialMatchResult_False == + andOp.matchesIndexKey( BSON( "" << 0 ), indexSpec ) ); + ASSERT( MatchMatchExpression::PartialMatchResult_False == + andOp.matchesIndexKey( BSON( "" << 6 ), indexSpec ) ); + } + + TEST( AndOp, MatchesIndexKeyWithUnknown ) { + BSONObj baseOperand1 = BSON( "$gt" << 1 ); + BSONObj baseOperand2 = BSON( "$lt" << 5 ); + // This part will return PartialMatchResult_Unknown. + BSONObj baseOperand3 = BSON( "$ne" << 5 ); + auto_ptr<ComparisonMatchExpression> sub1( new ComparisonMatchExpression() ); + ASSERT( sub1->init( "a", baseOperand1[ "$gt" ] ).isOK() ); + auto_ptr<ComparisonMatchExpression> sub2( new ComparisonMatchExpression() ); + ASSERT( sub2->init( "a", baseOperand2[ "$lt" ] ).isOK() ); + auto_ptr<NeOp> sub3( new NeOp() ); + ASSERT( sub3->init( "a", baseOperand3[ "$ne" ] ).isOK() ); + OwnedPointerVector<MatchMatchExpression> subMatchExpressions; + subMatchExpressions.mutableVector().push_back( sub1.release() ); + subMatchExpressions.mutableVector().push_back( sub2.release() ); + subMatchExpressions.mutableVector().push_back( sub3.release() ); + AndOp andOp; + ASSERT( andOp.init( &subMatchExpressions ).isOK() ); + IndexSpec indexSpec( BSON( "a" << 1 ) ); + ASSERT( MatchMatchExpression::PartialMatchResult_Unknown == + andOp.matchesIndexKey( BSON( "" << 3 ), indexSpec ) ); + ASSERT( MatchMatchExpression::PartialMatchResult_False == + andOp.matchesIndexKey( BSON( "" << 0 ), indexSpec ) ); + ASSERT( MatchMatchExpression::PartialMatchResult_False == + andOp.matchesIndexKey( BSON( "" << 6 ), indexSpec ) ); + } + */ + + /** + TEST( OrOp, MatchesElementSingleClause ) { + BSONObj baseOperand = BSON( "$lt" << 5 ); + BSONObj match = BSON( "a" << 4 ); + BSONObj notMatch = BSON( "a" << 5 ); + auto_ptr<ComparisonMatchExpression> lt( new ComparisonMatchExpression() ); + ASSERT( lt->init( "a", baseOperand[ "$lt" ] ).isOK() ); + OwnedPointerVector<MatchMatchExpression> subMatchExpressions; + subMatchExpressions.mutableVector().push_back( lt.release() ); + OrOp orOp; + ASSERT( orOp.init( &subMatchExpressions ).isOK() ); + ASSERT( orOp.matchesSingleElement( match[ "a" ] ) ); + ASSERT( !orOp.matchesSingleElement( notMatch[ "a" ] ) ); + } + */ + + TEST( OrOp, NoClauses ) { + OrMatchExpression orOp; + ASSERT( !orOp.matchesBSON( BSONObj(), NULL ) ); + } + /* + TEST( OrOp, MatchesElementThreeClauses ) { + BSONObj baseOperand1 = BSON( "$lt" << 0 ); + BSONObj baseOperand2 = BSON( "$gt" << 10 ); + BSONObj baseOperand3 = BSON( "a" << 5 ); + BSONObj match1 = BSON( "a" << -1 ); + BSONObj match2 = BSON( "a" << 11 ); + BSONObj match3 = BSON( "a" << 5 ); + BSONObj notMatch = BSON( "a" << "6" ); + auto_ptr<ComparisonMatchExpression> sub1( new ComparisonMatchExpression() ); + ASSERT( sub1->init( "a", baseOperand1[ "$lt" ] ).isOK() ); + auto_ptr<ComparisonMatchExpression> sub2( new ComparisonMatchExpression() ); + ASSERT( sub2->init( "a", baseOperand2[ "$gt" ] ).isOK() ); + auto_ptr<ComparisonMatchExpression> sub3( new ComparisonMatchExpression() ); + ASSERT( sub3->init( "a", baseOperand3[ "a" ] ).isOK() ); + OwnedPointerVector<MatchMatchExpression> subMatchExpressions; + subMatchExpressions.mutableVector().push_back( sub1.release() ); + subMatchExpressions.mutableVector().push_back( sub2.release() ); + subMatchExpressions.mutableVector().push_back( sub3.release() ); + OrOp orOp; + ASSERT( orOp.init( &subMatchExpressions ).isOK() ); + ASSERT( orOp.matchesSingleElement( match1[ "a" ] ) ); + ASSERT( orOp.matchesSingleElement( match2[ "a" ] ) ); + ASSERT( orOp.matchesSingleElement( match3[ "a" ] ) ); + ASSERT( !orOp.matchesSingleElement( notMatch[ "a" ] ) ); + } + */ + TEST( OrOp, MatchesSingleClause ) { + BSONObj baseOperand = BSON( "$ne" << 5 ); + auto_ptr<ComparisonMatchExpression> eq( new EqualityMatchExpression() ); + ASSERT( eq->init( "a", baseOperand[ "$ne" ] ).isOK() ); + auto_ptr<NotMatchExpression> ne( new NotMatchExpression() ); + ASSERT( ne->init( eq.release() ).isOK() ); + + OrMatchExpression orOp; + orOp.add( ne.release() ); + + ASSERT( orOp.matchesBSON( BSON( "a" << 4 ), NULL ) ); + ASSERT( orOp.matchesBSON( BSON( "a" << BSON_ARRAY( 4 << 6 ) ), NULL ) ); + ASSERT( !orOp.matchesBSON( BSON( "a" << 5 ), NULL ) ); + ASSERT( !orOp.matchesBSON( BSON( "a" << BSON_ARRAY( 4 << 5 ) ), NULL ) ); + } + + TEST( OrOp, MatchesThreeClauses ) { + BSONObj baseOperand1 = BSON( "$gt" << 10 ); + BSONObj baseOperand2 = BSON( "$lt" << 0 ); + BSONObj baseOperand3 = BSON( "b" << 100 ); + auto_ptr<ComparisonMatchExpression> sub1( new GTMatchExpression() ); + ASSERT( sub1->init( "a", baseOperand1[ "$gt" ] ).isOK() ); + auto_ptr<ComparisonMatchExpression> sub2( new LTMatchExpression() ); + ASSERT( sub2->init( "a", baseOperand2[ "$lt" ] ).isOK() ); + auto_ptr<ComparisonMatchExpression> sub3( new EqualityMatchExpression() ); + ASSERT( sub3->init( "b", baseOperand3[ "b" ] ).isOK() ); + + OrMatchExpression orOp; + orOp.add( sub1.release() ); + orOp.add( sub2.release() ); + orOp.add( sub3.release() ); + + ASSERT( orOp.matchesBSON( BSON( "a" << -1 ), NULL ) ); + ASSERT( orOp.matchesBSON( BSON( "a" << 11 ), NULL ) ); + ASSERT( !orOp.matchesBSON( BSON( "a" << 5 ), NULL ) ); + ASSERT( orOp.matchesBSON( BSON( "b" << 100 ), NULL ) ); + ASSERT( !orOp.matchesBSON( BSON( "b" << 101 ), NULL ) ); + ASSERT( !orOp.matchesBSON( BSONObj(), NULL ) ); + ASSERT( orOp.matchesBSON( BSON( "a" << 11 << "b" << 100 ), NULL ) ); + } + + TEST( OrOp, ElemMatchKey ) { + BSONObj baseOperand1 = BSON( "a" << 1 ); + BSONObj baseOperand2 = BSON( "b" << 2 ); + auto_ptr<ComparisonMatchExpression> sub1( new EqualityMatchExpression() ); + ASSERT( sub1->init( "a", baseOperand1[ "a" ] ).isOK() ); + auto_ptr<ComparisonMatchExpression> sub2( new EqualityMatchExpression() ); + ASSERT( sub2->init( "b", baseOperand2[ "b" ] ).isOK() ); + + OrMatchExpression orOp; + orOp.add( sub1.release() ); + orOp.add( sub2.release() ); + + MatchDetails details; + details.requestElemMatchKey(); + ASSERT( !orOp.matchesBSON( BSONObj(), &details ) ); + ASSERT( !details.hasElemMatchKey() ); + ASSERT( !orOp.matchesBSON( BSON( "a" << BSON_ARRAY( 10 ) << "b" << BSON_ARRAY( 10 ) ), + &details ) ); + ASSERT( !details.hasElemMatchKey() ); + ASSERT( orOp.matchesBSON( BSON( "a" << BSON_ARRAY( 1 ) << "b" << BSON_ARRAY( 1 << 2 ) ), + &details ) ); + // The elem match key feature is not implemented for $or. + ASSERT( !details.hasElemMatchKey() ); + } + + /** + TEST( OrOp, MatchesIndexKeyWithoutUnknown ) { + BSONObj baseOperand1 = BSON( "$gt" << 5 ); + BSONObj baseOperand2 = BSON( "$lt" << 1 ); + auto_ptr<ComparisonMatchExpression> sub1( new ComparisonMatchExpression() ); + ASSERT( sub1->init( "a", baseOperand1[ "$gt" ] ).isOK() ); + auto_ptr<ComparisonMatchExpression> sub2( new ComparisonMatchExpression() ); + ASSERT( sub2->init( "a", baseOperand2[ "$lt" ] ).isOK() ); + OwnedPointerVector<MatchMatchExpression> subMatchExpressions; + subMatchExpressions.mutableVector().push_back( sub1.release() ); + subMatchExpressions.mutableVector().push_back( sub2.release() ); + OrOp orOp; + ASSERT( orOp.init( &subMatchExpressions ).isOK() ); + IndexSpec indexSpec( BSON( "a" << 1 ) ); + ASSERT( MatchMatchExpression::PartialMatchResult_False == + orOp.matchesIndexKey( BSON( "" << 3 ), indexSpec ) ); + ASSERT( MatchMatchExpression::PartialMatchResult_True == + orOp.matchesIndexKey( BSON( "" << 0 ), indexSpec ) ); + ASSERT( MatchMatchExpression::PartialMatchResult_True == + orOp.matchesIndexKey( BSON( "" << 6 ), indexSpec ) ); + } + + TEST( OrOp, MatchesIndexKeyWithUnknown ) { + BSONObj baseOperand1 = BSON( "$gt" << 5 ); + BSONObj baseOperand2 = BSON( "$lt" << 1 ); + // This part will return PartialMatchResult_Unknown. + BSONObj baseOperand3 = BSON( "$ne" << 5 ); + auto_ptr<ComparisonMatchExpression> sub1( new ComparisonMatchExpression() ); + ASSERT( sub1->init( "a", baseOperand1[ "$gt" ] ).isOK() ); + auto_ptr<ComparisonMatchExpression> sub2( new ComparisonMatchExpression() ); + ASSERT( sub2->init( "a", baseOperand2[ "$lt" ] ).isOK() ); + auto_ptr<NeOp> sub3( new NeOp() ); + ASSERT( sub3->init( "a", baseOperand3[ "$ne" ] ).isOK() ); + OwnedPointerVector<MatchMatchExpression> subMatchExpressions; + subMatchExpressions.mutableVector().push_back( sub1.release() ); + subMatchExpressions.mutableVector().push_back( sub2.release() ); + subMatchExpressions.mutableVector().push_back( sub3.release() ); + OrOp orOp; + ASSERT( orOp.init( &subMatchExpressions ).isOK() ); + IndexSpec indexSpec( BSON( "a" << 1 ) ); + ASSERT( MatchMatchExpression::PartialMatchResult_Unknown == + orOp.matchesIndexKey( BSON( "" << 3 ), indexSpec ) ); + ASSERT( MatchMatchExpression::PartialMatchResult_True == + orOp.matchesIndexKey( BSON( "" << 0 ), indexSpec ) ); + ASSERT( MatchMatchExpression::PartialMatchResult_True == + orOp.matchesIndexKey( BSON( "" << 6 ), indexSpec ) ); + } + */ + + /** + TEST( NorOp, MatchesElementSingleClause ) { + BSONObj baseOperand = BSON( "$lt" << 5 ); + BSONObj match = BSON( "a" << 5 ); + BSONObj notMatch = BSON( "a" << 4 ); + auto_ptr<ComparisonMatchExpression> lt( new ComparisonMatchExpression() ); + ASSERT( lt->init( "a", baseOperand[ "$lt" ] ).isOK() ); + OwnedPointerVector<MatchMatchExpression> subMatchExpressions; + subMatchExpressions.mutableVector().push_back( lt.release() ); + NorOp norOp; + ASSERT( norOp.init( &subMatchExpressions ).isOK() ); + ASSERT( norOp.matchesSingleElement( match[ "a" ] ) ); + ASSERT( !norOp.matchesSingleElement( notMatch[ "a" ] ) ); + } + */ + + TEST( NorOp, NoClauses ) { + NorMatchExpression norOp; + ASSERT( norOp.matchesBSON( BSONObj(), NULL ) ); + } + /* + TEST( NorOp, MatchesElementThreeClauses ) { + BSONObj baseOperand1 = BSON( "$lt" << 0 ); + BSONObj baseOperand2 = BSON( "$gt" << 10 ); + BSONObj baseOperand3 = BSON( "a" << 5 ); + BSONObj notMatch1 = BSON( "a" << -1 ); + BSONObj notMatch2 = BSON( "a" << 11 ); + BSONObj notMatch3 = BSON( "a" << 5 ); + BSONObj match = BSON( "a" << "6" ); + auto_ptr<ComparisonMatchExpression> sub1( new ComparisonMatchExpression() ); + ASSERT( sub1->init( "a", baseOperand1[ "$lt" ] ).isOK() ); + auto_ptr<ComparisonMatchExpression> sub2( new ComparisonMatchExpression() ); + ASSERT( sub2->init( "a", baseOperand2[ "$gt" ] ).isOK() ); + auto_ptr<ComparisonMatchExpression> sub3( new ComparisonMatchExpression() ); + ASSERT( sub3->init( "a", baseOperand3[ "a" ] ).isOK() ); + OwnedPointerVector<MatchMatchExpression> subMatchExpressions; + subMatchExpressions.mutableVector().push_back( sub1.release() ); + subMatchExpressions.mutableVector().push_back( sub2.release() ); + subMatchExpressions.mutableVector().push_back( sub3.release() ); + NorOp norOp; + ASSERT( norOp.init( &subMatchExpressions ).isOK() ); + ASSERT( !norOp.matchesSingleElement( notMatch1[ "a" ] ) ); + ASSERT( !norOp.matchesSingleElement( notMatch2[ "a" ] ) ); + ASSERT( !norOp.matchesSingleElement( notMatch3[ "a" ] ) ); + ASSERT( norOp.matchesSingleElement( match[ "a" ] ) ); + } + */ + + TEST( NorOp, MatchesSingleClause ) { + BSONObj baseOperand = BSON( "$ne" << 5 ); + auto_ptr<ComparisonMatchExpression> eq( new EqualityMatchExpression() ); + ASSERT( eq->init( "a", baseOperand[ "$ne" ] ).isOK() ); + auto_ptr<NotMatchExpression> ne( new NotMatchExpression() ); + ASSERT( ne->init( eq.release() ).isOK() ); + + NorMatchExpression norOp; + norOp.add( ne.release() ); + + ASSERT( !norOp.matchesBSON( BSON( "a" << 4 ), NULL ) ); + ASSERT( !norOp.matchesBSON( BSON( "a" << BSON_ARRAY( 4 << 6 ) ), NULL ) ); + ASSERT( norOp.matchesBSON( BSON( "a" << 5 ), NULL ) ); + ASSERT( norOp.matchesBSON( BSON( "a" << BSON_ARRAY( 4 << 5 ) ), NULL ) ); + } + + TEST( NorOp, MatchesThreeClauses ) { + BSONObj baseOperand1 = BSON( "$gt" << 10 ); + BSONObj baseOperand2 = BSON( "$lt" << 0 ); + BSONObj baseOperand3 = BSON( "b" << 100 ); + + auto_ptr<ComparisonMatchExpression> sub1( new GTMatchExpression() ); + ASSERT( sub1->init( "a", baseOperand1[ "$gt" ] ).isOK() ); + auto_ptr<ComparisonMatchExpression> sub2( new LTMatchExpression() ); + ASSERT( sub2->init( "a", baseOperand2[ "$lt" ] ).isOK() ); + auto_ptr<ComparisonMatchExpression> sub3( new EqualityMatchExpression() ); + ASSERT( sub3->init( "b", baseOperand3[ "b" ] ).isOK() ); + + NorMatchExpression norOp; + norOp.add( sub1.release() ); + norOp.add( sub2.release() ); + norOp.add( sub3.release() ); + + ASSERT( !norOp.matchesBSON( BSON( "a" << -1 ), NULL ) ); + ASSERT( !norOp.matchesBSON( BSON( "a" << 11 ), NULL ) ); + ASSERT( norOp.matchesBSON( BSON( "a" << 5 ), NULL ) ); + ASSERT( !norOp.matchesBSON( BSON( "b" << 100 ), NULL ) ); + ASSERT( norOp.matchesBSON( BSON( "b" << 101 ), NULL ) ); + ASSERT( norOp.matchesBSON( BSONObj(), NULL ) ); + ASSERT( !norOp.matchesBSON( BSON( "a" << 11 << "b" << 100 ), NULL ) ); + } + + TEST( NorOp, ElemMatchKey ) { + BSONObj baseOperand1 = BSON( "a" << 1 ); + BSONObj baseOperand2 = BSON( "b" << 2 ); + auto_ptr<ComparisonMatchExpression> sub1( new EqualityMatchExpression() ); + ASSERT( sub1->init( "a", baseOperand1[ "a" ] ).isOK() ); + auto_ptr<ComparisonMatchExpression> sub2( new EqualityMatchExpression() ); + ASSERT( sub2->init( "b", baseOperand2[ "b" ] ).isOK() ); + + NorMatchExpression norOp; + norOp.add( sub1.release() ); + norOp.add( sub2.release() ); + + MatchDetails details; + details.requestElemMatchKey(); + ASSERT( !norOp.matchesBSON( BSON( "a" << 1 ), &details ) ); + ASSERT( !details.hasElemMatchKey() ); + ASSERT( !norOp.matchesBSON( BSON( "a" << BSON_ARRAY( 1 ) << "b" << BSON_ARRAY( 10 ) ), + &details ) ); + ASSERT( !details.hasElemMatchKey() ); + ASSERT( norOp.matchesBSON( BSON( "a" << BSON_ARRAY( 3 ) << "b" << BSON_ARRAY( 4 ) ), + &details ) ); + // The elem match key feature is not implemented for $nor. + ASSERT( !details.hasElemMatchKey() ); + } + + + TEST( NorOp, Equivalent ) { + BSONObj baseOperand1 = BSON( "a" << 1 ); + BSONObj baseOperand2 = BSON( "b" << 2 ); + EqualityMatchExpression sub1; + ASSERT( sub1.init( "a", baseOperand1[ "a" ] ).isOK() ); + EqualityMatchExpression sub2; + ASSERT( sub2.init( "b", baseOperand2[ "b" ] ).isOK() ); + + NorMatchExpression e1; + e1.add( sub1.shallowClone() ); + e1.add( sub2.shallowClone() ); + + NorMatchExpression e2; + e2.add( sub1.shallowClone() ); + + ASSERT( e1.equivalent( &e1 ) ); + ASSERT( !e1.equivalent( &e2 ) ); + } + + /** + TEST( NorOp, MatchesIndexKey ) { + BSONObj baseOperand = BSON( "a" << 5 ); + auto_ptr<ComparisonMatchExpression> eq( new ComparisonMatchExpression() ); + ASSERT( eq->init( "a", baseOperand[ "a" ] ).isOK() ); + OwnedPointerVector<MatchMatchExpression> subMatchExpressions; + subMatchExpressions.mutableVector().push_back( eq.release() ); + NorOp norOp; + ASSERT( norOp.init( &subMatchExpressions ).isOK() ); + IndexSpec indexSpec( BSON( "a" << 1 ) ); + BSONObj indexKey = BSON( "" << "7" ); + ASSERT( MatchMatchExpression::PartialMatchResult_Unknown == + norOp.matchesIndexKey( indexKey, indexSpec ) ); + } + */ + +} |
