Repository: vespa-engine/vespa
File: searchlib/src/tests/queryeval/blueprint/intermediate_blueprints_test.cpp (C++)

Code before:
    search::fef::TermFieldHandle idxth22 = subLayout.allocTermField(2);
    search::fef::TermFieldHandle idxth1 = subLayout.allocTermField(1);
    search::fef::MatchDataLayout mdl;
    Blueprint::UP top_up(
            ap((new EquivBlueprint(fields, std::move(subLayout)))->
               addTerm(index.getIndex().createBlueprint(requestContext,
                                                        FieldSpec("f2", 2, idxth22, true),
                                                        makeTerm("w2"), mdl),
                       1.0).
               addTerm(index.getIndex().createBlueprint(requestContext,
                                                        FieldSpec("f1", 1, idxth1),
                                                        makeTerm("w1"), mdl),
                       1.0).
               addTerm(index.getIndex().createBlueprint(requestContext,
                                                        FieldSpec("f2", 2, idxth21), makeTerm("w2"), mdl),
                       1.0)));
    EXPECT_TRUE(mdl.empty());
    MatchData::UP md = MatchData::makeTestInstance(100, 10);
    top_up->basic_plan(true, 1000);
    top_up->fetchPostings(ExecuteInfo::FULL);
    SearchIterator::UP search = top_up->createSearch(*md);
    EXPECT_EQ(strict_equiv_name, normalize_class_name(search->getClassName()));
    {
        const auto & e = dynamic_cast<const MultiSearch &>(*search);
        EXPECT_EQ(strict_bitvector_iterator_class_name, e.getChildren()[0]->getClassName());
        EXPECT_PRED1(is_disk_index_iterator, e.getChildren()[1]->getClassName());
        EXPECT_PRED1(is_disk_index_iterator, e.getChildren()[2]->getClassName());
    }

    md->resolveTermField(12)->tagAsNotNeeded();
    search = top_up->createSearch(*md);
    EXPECT_EQ(strict_equiv_name, normalize_class_name(search->getClassName()));
    {
        const auto & e = dynamic_cast<const MultiSearch &>(*search);
        EXPECT_EQ(strict_bitvector_iterator_class_name, e.getChildren()[0]->getClassName());
        EXPECT_PRED1(is_disk_index_iterator, e.getChildren()[1]->getClassName());
        EXPECT_PRED1(is_disk_index_iterator, e.getChildren()[2]->getClassName());
    }
}

TEST(IntermediateBlueprintsTest, require_that_unpack_optimization_is_not_overruled_by_equiv) {
    FieldSpecBaseList fields;
    fields.add(FieldSpecBase(1, 1));
    fields.add(FieldSpecBase(2, 2));
    fields.add(FieldSpecBase(3, 3));
    search::fef::MatchDataLayout subLayout;
    search::fef::TermFieldHandle idxth1 = subLayout.allocTermField(1);
    search::fef::TermFieldHandle idxth2 = subLayout.allocTermField(2);
    search::fef::TermFieldHandle idxth3 = subLayout.allocTermField(3);
    Blueprint::UP top_up(
            ap((new EquivBlueprint(fields, std::move(subLayout)))->

Review comment (suggestion):
If you want to get extra fancy you could consider replacing the explicit predicate class with a gMock [`MATCHER`](https://google.github.io/googletest/reference/matchers.html) macro. Something like (assuming the string constants are defined at file scope):
```c++
using namespace ::testing;

MATCHER(IsIdiskIndexIterator, "") {
    return ExplainMatchResult(AnyOf(_rare_word_iterator, _word_iterator), arg, result_listener);
}

...

EXPECT_THAT(e.getChildren()[1]->getClassName(), IsDiskIndexIterator());
```
Caveat: this is off the top of my head, not actually compiled etc etc.


Code after:
            ap((new EquivBlueprint(fields, std::move(subLayout)))->
               addTerm(index.getIndex().createBlueprint(requestContext,
                                                        FieldSpec("f2", 2, idxth22, true),
                                                        makeTerm("w2"), mdl),
                       1.0).
               addTerm(index.getIndex().createBlueprint(requestContext,
                                                        FieldSpec("f1", 1, idxth1),
                                                        makeTerm("w1"), mdl),
                       1.0).
               addTerm(index.getIndex().createBlueprint(requestContext,
                                                        FieldSpec("f2", 2, idxth21), makeTerm("w2"), mdl),
                       1.0)));
    EXPECT_TRUE(mdl.empty());
    MatchData::UP md = MatchData::makeTestInstance(100, 10);
    top_up->basic_plan(true, 1000);
    top_up->fetchPostings(ExecuteInfo::FULL);
    SearchIterator::UP search = top_up->createSearch(*md);
    EXPECT_EQ(strict_equiv_name, normalize_class_name(search->getClassName()));
    {
        const auto & e = dynamic_cast<const MultiSearch &>(*search);
        EXPECT_EQ(strict_bitvector_iterator_class_name, e.getChildren()[0]->getClassName());
        EXPECT_THAT(e.getChildren()[1]->getClassName(), IsDiskIndexIterator());
        EXPECT_THAT(e.getChildren()[2]->getClassName(), IsDiskIndexIterator());
    }

    md->resolveTermField(12)->tagAsNotNeeded();
    search = top_up->createSearch(*md);
    EXPECT_EQ(strict_equiv_name, normalize_class_name(search->getClassName()));
    {
        const auto & e = dynamic_cast<const MultiSearch &>(*search);
        EXPECT_EQ(strict_bitvector_iterator_class_name, e.getChildren()[0]->getClassName());
        EXPECT_THAT(e.getChildren()[1]->getClassName(), IsDiskIndexIterator());
        EXPECT_THAT(e.getChildren()[2]->getClassName(), IsDiskIndexIterator());
    }
}

TEST(IntermediateBlueprintsTest, require_that_unpack_optimization_is_not_overruled_by_equiv) {
    FieldSpecBaseList fields;
    fields.add(FieldSpecBase(1, 1));
    fields.add(FieldSpecBase(2, 2));
    fields.add(FieldSpecBase(3, 3));
    search::fef::MatchDataLayout subLayout;
    search::fef::TermFieldHandle idxth1 = subLayout.allocTermField(1);
    search::fef::TermFieldHandle idxth2 = subLayout.allocTermField(2);
    search::fef::TermFieldHandle idxth3 = subLayout.allocTermField(3);
    Blueprint::UP top_up(
            ap((new EquivBlueprint(fields, std::move(subLayout)))->
               addTerm(ap((new OrBlueprint())->
                          addChild(ap(MyLeafSpec(20).addField(1,idxth1).create())).
                          addChild(ap(MyLeafSpec(20).addField(2,idxth2).create())).
                          addChild(ap(MyLeafSpec(10).addField(3,idxth3).create()))),