/*
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" );
    unique_ptr<ComparisonMatchExpression> sub1( new ComparisonMatchExpression() );
    ASSERT( sub1->init( "a", baseOperand1[ "$lt" ] ).isOK() );
    unique_ptr<ComparisonMatchExpression> sub2( new ComparisonMatchExpression() );
    ASSERT( sub2->init( "a", baseOperand2[ "$gt" ] ).isOK() );
    unique_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);
    unique_ptr<ComparisonMatchExpression> eq(new EqualityMatchExpression());
    ASSERT(eq->init("a", baseOperand["$ne"]).isOK());
    unique_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);
    const CollatorInterface* collator = nullptr;
    unique_ptr<ComparisonMatchExpression> sub1(new GTMatchExpression(collator));
    ASSERT(sub1->init("a", baseOperand1["$gt"]).isOK());
    unique_ptr<ComparisonMatchExpression> sub2(new LTMatchExpression(collator));
    ASSERT(sub2->init("a", baseOperand2["$lt"]).isOK());
    unique_ptr<ComparisonMatchExpression> sub3(new EqualityMatchExpression(collator));
    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);
    unique_ptr<ComparisonMatchExpression> sub1(new EqualityMatchExpression());
    ASSERT(sub1->init("a", baseOperand1["a"]).isOK());
    unique_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, NoClauses) {
    OrMatchExpression orOp;
    ASSERT(!orOp.matchesBSON(BSONObj(), NULL));
}