summaryrefslogtreecommitdiffstats
path: root/searchlib/src/tests/queryeval/queryeval.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'searchlib/src/tests/queryeval/queryeval.cpp')
-rw-r--r--searchlib/src/tests/queryeval/queryeval.cpp691
1 files changed, 691 insertions, 0 deletions
diff --git a/searchlib/src/tests/queryeval/queryeval.cpp b/searchlib/src/tests/queryeval/queryeval.cpp
new file mode 100644
index 00000000000..3a2070a1fd8
--- /dev/null
+++ b/searchlib/src/tests/queryeval/queryeval.cpp
@@ -0,0 +1,691 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#include <vespa/vespalib/testkit/test_kit.h>
+
+#include <vespa/searchlib/test/initrange.h>
+#include <vespa/searchlib/common/bitvectoriterator.h>
+#include <vespa/searchlib/queryeval/andnotsearch.h>
+#include <vespa/searchlib/queryeval/andsearch.h>
+#include <vespa/searchlib/queryeval/booleanmatchiteratorwrapper.h>
+#include <vespa/searchlib/queryeval/nearsearch.h>
+#include <vespa/searchlib/queryeval/orsearch.h>
+#include <vespa/searchlib/queryeval/searchiterator.h>
+#include <vespa/searchlib/queryeval/simpleresult.h>
+#include <vespa/searchlib/queryeval/simplesearch.h>
+#include <vespa/searchlib/queryeval/ranksearch.h>
+#include <vespa/searchlib/queryeval/truesearch.h>
+#include <vespa/searchlib/queryeval/emptysearch.h>
+#include <vespa/searchlib/queryeval/sourceblendersearch.h>
+#include <vespa/searchlib/queryeval/leaf_blueprints.h>
+#include <vespa/searchlib/queryeval/intermediate_blueprints.h>
+#include <vespa/searchlib/attribute/singlenumericattribute.hpp>
+#include <vespa/searchlib/attribute/singlesmallnumericattribute.h>
+#include <vespa/vespalib/test/insertion_operators.h>
+
+#include <vespa/searchlib/fef/fef.h>
+
+using namespace search::queryeval;
+using search::fef::MatchData;
+using search::fef::TermFieldMatchData;
+using search::fef::TermFieldMatchDataArray;
+using search::BitVector;
+using search::BitVectorIterator;
+using search::test::InitRangeVerifier;
+
+//-----------------------------------------------------------------------------
+
+template <typename T, typename V=std::vector<T> >
+class Collect
+{
+private:
+ V _data;
+
+public:
+ Collect &add(const T &t) {
+ _data.push_back(t);
+ return *this;
+ }
+ operator const V &() const { return _data; }
+};
+
+SearchIterator *simple(const std::string &tag) {
+ return &((new SimpleSearch(SimpleResult()))->tag(tag));
+}
+
+Collect<SearchIterator*, MultiSearch::Children> search2(const std::string &t1, const std::string &t2) {
+ return Collect<SearchIterator*, MultiSearch::Children>().add(simple(t1)).add(simple(t2));
+}
+
+
+class ISourceSelectorDummy : public ISourceSelector
+{
+ static SourceStore _sourceStoreDummy;
+
+public:
+ static Iterator::UP
+ makeDummyIterator()
+ {
+ return Iterator::UP(new Iterator(_sourceStoreDummy));
+ }
+};
+
+ISourceSelector::SourceStore ISourceSelectorDummy::_sourceStoreDummy("foo");
+
+ISourceSelector::Iterator::UP selector() {
+ return ISourceSelectorDummy::makeDummyIterator();
+}
+
+//-----------------------------------------------------------------------------
+
+void testMultiSearch(SearchIterator & search) {
+ MultiSearch & ms = dynamic_cast<MultiSearch &>(search);
+ ms.initRange(3, 309);
+ EXPECT_EQUAL(2u, ms.getDocId());
+ EXPECT_EQUAL(309u, ms.getEndId());
+ for (const auto & child : ms.getChildren()) {
+ EXPECT_EQUAL(2u, child->getDocId());
+ EXPECT_EQUAL(309u, child->getEndId());
+ }
+}
+
+TEST("test that OR.andWith is a NOOP") {
+ TermFieldMatchData tfmd;
+ MultiSearch::Children ch;
+ ch.push_back(new TrueSearch(tfmd));
+ ch.push_back(new TrueSearch(tfmd));
+ SearchIterator::UP search(OrSearch::create(ch, true));
+ SearchIterator::UP filter(new TrueSearch(tfmd));
+
+ EXPECT_TRUE(nullptr != search->andWith(std::move(filter), 1).get());
+}
+
+TEST("test that non-strict AND.andWith is a NOOP") {
+ TermFieldMatchData tfmd;
+ MultiSearch::Children ch;
+ ch.push_back(new TrueSearch(tfmd));
+ ch.push_back(new TrueSearch(tfmd));
+ SearchIterator::UP search(AndSearch::create(ch, false));
+ SearchIterator::UP filter(new TrueSearch(tfmd));
+ filter = search->andWith(std::move(filter), 8);
+ EXPECT_TRUE(nullptr != filter.get());
+}
+
+TEST("test that strict AND.andWith steals filter and places it correctly based on estimate") {
+ TermFieldMatchData tfmd;
+ MultiSearch::Children ch;
+ ch.push_back(new TrueSearch(tfmd));
+ ch.push_back(new TrueSearch(tfmd));
+ SearchIterator::UP search(AndSearch::create(ch, true));
+ static_cast<AndSearch &>(*search).estimate(7);
+ SearchIterator::UP filter(new TrueSearch(tfmd));
+ SearchIterator * filterP = filter.get();
+
+ EXPECT_TRUE(nullptr == search->andWith(std::move(filter), 8).get());
+ const MultiSearch::Children & andChildren = static_cast<MultiSearch &>(*search).getChildren();
+ EXPECT_EQUAL(3u, andChildren.size());
+ EXPECT_EQUAL(ch[0], andChildren[0]);
+ EXPECT_EQUAL(filterP, andChildren[1]);
+ EXPECT_EQUAL(ch[1], andChildren[2]);
+
+ SearchIterator::UP filter2(new TrueSearch(tfmd));
+ SearchIterator * filter2P = filter2.get();
+ EXPECT_TRUE(nullptr == search->andWith(std::move(filter2), 6).get());
+ EXPECT_EQUAL(4u, andChildren.size());
+ EXPECT_EQUAL(filter2P, andChildren[0]);
+ EXPECT_EQUAL(ch[0], andChildren[1]);
+ EXPECT_EQUAL(filterP, andChildren[2]);
+ EXPECT_EQUAL(ch[1], andChildren[3]);
+}
+
+class NonStrictTrueSearch : public TrueSearch
+{
+public:
+ NonStrictTrueSearch(TermFieldMatchData & tfmd) : TrueSearch(tfmd) { }
+ Trinary is_strict() const override { return Trinary::False; }
+};
+
+TEST("test that strict AND.andWith does not place non-strict iterator first") {
+ TermFieldMatchData tfmd;
+ MultiSearch::Children ch;
+ ch.push_back(new TrueSearch(tfmd));
+ ch.push_back(new TrueSearch(tfmd));
+ SearchIterator::UP search(AndSearch::create(ch, true));
+ static_cast<AndSearch &>(*search).estimate(7);
+ SearchIterator::UP filter(new NonStrictTrueSearch(tfmd));
+ SearchIterator * filterP = filter.get();
+ EXPECT_TRUE(nullptr == search->andWith(std::move(filter), 6).get());
+ const MultiSearch::Children & andChildren = static_cast<MultiSearch &>(*search).getChildren();
+ EXPECT_EQUAL(3u, andChildren.size());
+ EXPECT_EQUAL(ch[0], andChildren[0]);
+ EXPECT_EQUAL(filterP, andChildren[1]);
+ EXPECT_EQUAL(ch[1], andChildren[2]);
+}
+
+TEST("test that strict rank search forwards to its greedy first child") {
+ TermFieldMatchData tfmd;
+ SearchIterator::UP search(
+ RankSearch::create(
+ Collect<SearchIterator*, MultiSearch::Children>()
+ .add(AndSearch::create(search2("a", "b"), true))
+ .add(new TrueSearch(tfmd)),
+ true)
+ );
+ SearchIterator::UP filter(new TrueSearch(tfmd));
+ EXPECT_TRUE(nullptr == search->andWith(std::move(filter), 8).get());
+}
+
+TEST("test that non-strict rank search does NOT forward to its greedy first child") {
+ TermFieldMatchData tfmd;
+ SearchIterator::UP search(
+ RankSearch::create(
+ Collect<SearchIterator*, MultiSearch::Children>()
+ .add(AndSearch::create(search2("a", "b"), true))
+ .add(new TrueSearch(tfmd)),
+ false)
+ );
+ SearchIterator::UP filter(new TrueSearch(tfmd));
+ EXPECT_TRUE(nullptr != search->andWith(std::move(filter), 8).get());
+}
+
+TEST("test that strict andnot search forwards to its greedy first child") {
+ TermFieldMatchData tfmd;
+ SearchIterator::UP search(
+ AndNotSearch::create(
+ Collect<SearchIterator*, MultiSearch::Children>()
+ .add(AndSearch::create(search2("a", "b"), true))
+ .add(new TrueSearch(tfmd)),
+ true)
+ );
+ SearchIterator::UP filter(new TrueSearch(tfmd));
+ EXPECT_TRUE(nullptr == search->andWith(std::move(filter), 8).get());
+}
+
+TEST("test that non-strict andnot search does NOT forward to its greedy first child") {
+ TermFieldMatchData tfmd;
+ SearchIterator::UP search(
+ AndNotSearch::create(
+ Collect<SearchIterator*, MultiSearch::Children>()
+ .add(AndSearch::create(search2("a", "b"), true))
+ .add(new TrueSearch(tfmd)),
+ false)
+ );
+ SearchIterator::UP filter(new TrueSearch(tfmd));
+ EXPECT_TRUE(nullptr != search->andWith(std::move(filter), 8).get());
+}
+
+TEST("testAnd") {
+ SimpleResult a;
+ SimpleResult b;
+ a.addHit(5).addHit(10).addHit(16).addHit(30);
+ b.addHit(3).addHit(5).addHit(17).addHit(30).addHit(52);
+
+ MatchData::UP md(MatchData::makeTestInstance(0, 100, 10));
+ AndBlueprint *and_b = new AndBlueprint();
+ and_b->addChild(Blueprint::UP(new SimpleBlueprint(a)));
+ and_b->addChild(Blueprint::UP(new SimpleBlueprint(b)));
+ Blueprint::UP bp(and_b);
+ bp->fetchPostings(true);
+ SearchIterator::UP and_ab = bp->createSearch(*md, true);
+
+ EXPECT_TRUE(dynamic_cast<const AndSearch *>(and_ab.get()) != nullptr);
+ EXPECT_EQUAL(4u, dynamic_cast<AndSearch &>(*and_ab).estimate());
+ SimpleResult res;
+ res.search(*and_ab);
+ SimpleResult expect;
+ expect.addHit(5).addHit(30);
+
+ EXPECT_EQUAL(res, expect);
+}
+
+TEST("mutisearch and initRange") {
+}
+
+TEST("testOr") {
+ {
+ SimpleResult a;
+ SimpleResult b;
+ a.addHit(5).addHit(10);
+ b.addHit(5).addHit(17).addHit(30);
+
+ MatchData::UP md(MatchData::makeTestInstance(0, 100, 10));
+ OrBlueprint *or_b = new OrBlueprint();
+ or_b->addChild(Blueprint::UP(new SimpleBlueprint(a)));
+ or_b->addChild(Blueprint::UP(new SimpleBlueprint(b)));
+ Blueprint::UP bp(or_b);
+ bp->fetchPostings(true);
+ SearchIterator::UP or_ab = bp->createSearch(*md, true);
+
+ SimpleResult res;
+ res.search(*or_ab);
+ SimpleResult expect;
+ expect.addHit(5).addHit(10).addHit(17).addHit(30);
+
+ EXPECT_EQUAL(res, expect);
+ }
+ {
+ TermFieldMatchData tfmd;
+ MultiSearch::Children ch;
+ ch.push_back(new TrueSearch(tfmd));
+ ch.push_back(new TrueSearch(tfmd));
+ ch.push_back(new TrueSearch(tfmd));
+ SearchIterator::UP orSearch(OrSearch::create(ch, true));
+ testMultiSearch(*orSearch);
+ }
+}
+
+class TestInsertRemoveSearch : public MultiSearch
+{
+public:
+ TestInsertRemoveSearch(const MultiSearch::Children & children) :
+ MultiSearch(children),
+ _accumRemove(0),
+ _accumInsert(0)
+ { }
+ virtual void onRemove(size_t index) { _accumRemove += index; }
+ virtual void onInsert(size_t index) { _accumInsert += index; }
+ size_t _accumRemove;
+ size_t _accumInsert;
+private:
+ virtual void doSeek(uint32_t docid) { (void) docid; }
+};
+
+TEST("testMultiSearch") {
+ MultiSearch::Children children;
+ children.push_back(new EmptySearch());
+ children.push_back(new EmptySearch());
+ children.push_back(new EmptySearch());
+ TestInsertRemoveSearch ms(children);
+ EXPECT_EQUAL(3u, ms.getChildren().size());
+ EXPECT_EQUAL(children[0], ms.getChildren()[0]);
+ EXPECT_EQUAL(children[1], ms.getChildren()[1]);
+ EXPECT_EQUAL(children[2], ms.getChildren()[2]);
+ EXPECT_EQUAL(0u, ms._accumInsert);
+ EXPECT_EQUAL(0u, ms._accumRemove);
+
+ EXPECT_EQUAL(children[1], ms.remove(1).get());
+ EXPECT_EQUAL(2u, ms.getChildren().size());
+ EXPECT_EQUAL(children[0], ms.getChildren()[0]);
+ EXPECT_EQUAL(children[2], ms.getChildren()[1]);
+ EXPECT_EQUAL(0u, ms._accumInsert);
+ EXPECT_EQUAL(1u, ms._accumRemove);
+
+ children.push_back(new EmptySearch());
+ ms.insert(1, SearchIterator::UP(children.back()));
+ EXPECT_EQUAL(3u, ms.getChildren().size());
+ EXPECT_EQUAL(children[0], ms.getChildren()[0]);
+ EXPECT_EQUAL(children[3], ms.getChildren()[1]);
+ EXPECT_EQUAL(children[2], ms.getChildren()[2]);
+ EXPECT_EQUAL(1u, ms._accumInsert);
+ EXPECT_EQUAL(1u, ms._accumRemove);
+}
+
+class DummySingleValueBitNumericAttributeBlueprint : public SimpleLeafBlueprint
+{
+public:
+ DummySingleValueBitNumericAttributeBlueprint(const SimpleResult & result) :
+ SimpleLeafBlueprint(FieldSpecBaseList()),
+ _a("a"),
+ _sc(),
+ _tfmd()
+ {
+ for (size_t i(0); i < result.getHitCount(); i++) {
+ size_t docId(result.getHit(i));
+ uint32_t curDoc(0);
+ for (_a.addDoc(curDoc); curDoc < docId; _a.addDoc(curDoc));
+ _a.update(docId, 1);
+ }
+ _a.commit();
+ _sc = _a.getSearch(search::QueryTermSimple::UP(new search::QueryTermSimple("1", search::QueryTermSimple::WORD)),
+ search::AttributeVector::SearchContext::Params().useBitVector(true));
+ }
+ virtual SearchIterator::UP
+ createLeafSearch(const TermFieldMatchDataArray &tfmda, bool strict) const
+ {
+ (void) tfmda;
+ return _sc->createIterator(&_tfmd, strict);
+ }
+private:
+ search::SingleValueBitNumericAttribute _a;
+ search::AttributeVector::SearchContext::UP _sc;
+ mutable TermFieldMatchData _tfmd;
+};
+
+
+TEST("testAndNot") {
+ {
+ SimpleResult a;
+ SimpleResult b;
+ a.addHit(5).addHit(10);
+ b.addHit(5).addHit(17).addHit(30);
+
+ MatchData::UP md(MatchData::makeTestInstance(0, 100, 10));
+ AndNotBlueprint *andnot_b = new AndNotBlueprint();
+ andnot_b->addChild(Blueprint::UP(new SimpleBlueprint(a)));
+ andnot_b->addChild(Blueprint::UP(new SimpleBlueprint(b)));
+ Blueprint::UP bp(andnot_b);
+ bp->fetchPostings(true);
+ SearchIterator::UP andnot_ab = bp->createSearch(*md, true);
+
+ SimpleResult res;
+ res.search(*andnot_ab);
+ SimpleResult expect;
+ expect.addHit(10);
+
+ EXPECT_EQUAL(res, expect);
+ }
+ {
+ SimpleResult a;
+ SimpleResult b;
+ a.addHit(1).addHit(5).addHit(10);
+ b.addHit(5).addHit(17).addHit(30);
+
+ MatchData::UP md(MatchData::makeTestInstance(2, 100, 10));
+ AndNotBlueprint *andnot_b = new AndNotBlueprint();
+ andnot_b->addChild(Blueprint::UP(new SimpleBlueprint(a)));
+ andnot_b->addChild(Blueprint::UP(new DummySingleValueBitNumericAttributeBlueprint(b)));
+ Blueprint::UP bp(andnot_b);
+ bp->fetchPostings(true);
+ SearchIterator::UP andnot_ab = bp->createSearch(*md, true);
+ EXPECT_TRUE(dynamic_cast<const OptimizedAndNotForBlackListing *>(andnot_ab.get()) != NULL);
+
+ SimpleResult res;
+ res.search(*andnot_ab);
+ SimpleResult expect;
+ expect.addHit(1).addHit(10);
+
+ EXPECT_EQUAL(res, expect);
+ }
+ {
+ SimpleResult a;
+ SimpleResult b;
+ SimpleResult c;
+ a.addHit(1).addHit(5).addHit(10);
+ b.addHit(5).addHit(17).addHit(30);
+ c.addHit(1).addHit(5).addHit(10).addHit(17).addHit(30);
+
+ MatchData::UP md(MatchData::makeTestInstance(0, 100, 10));
+ AndNotBlueprint *andnot_b = new AndNotBlueprint();
+ andnot_b->addChild(Blueprint::UP(new SimpleBlueprint(a)));
+ andnot_b->addChild(Blueprint::UP(new SimpleBlueprint(b)));
+
+ AndBlueprint *and_b = new AndBlueprint();
+ and_b->addChild(Blueprint::UP(new SimpleBlueprint(c)));
+ and_b->addChild(Blueprint::UP(andnot_b));
+ Blueprint::UP bp(and_b);
+ bp->fetchPostings(true);
+ SearchIterator::UP and_cab = bp->createSearch(*md, true);
+
+ SimpleResult res;
+ res.search(*and_cab);
+ SimpleResult expect;
+ expect.addHit(1).addHit(10);
+
+ EXPECT_EQUAL(res, expect);
+ }
+ {
+ }
+}
+
+TEST("testRank") {
+ {
+ SimpleResult a;
+ SimpleResult b;
+ a.addHit(5).addHit(10).addHit(16).addHit(30);
+ b.addHit(3).addHit(5).addHit(17).addHit(30).addHit(52);
+
+ MatchData::UP md(MatchData::makeTestInstance(0, 100, 10));
+ RankBlueprint *rank_b = new RankBlueprint();
+ rank_b->addChild(Blueprint::UP(new SimpleBlueprint(a)));
+ rank_b->addChild(Blueprint::UP(new SimpleBlueprint(b)));
+ Blueprint::UP bp(rank_b);
+ bp->fetchPostings(true);
+ SearchIterator::UP rank_ab = bp->createSearch(*md, true);
+
+ SimpleResult res;
+ res.search(*rank_ab);
+ SimpleResult expect;
+ expect.addHit(5).addHit(10).addHit(16).addHit(30);
+
+ EXPECT_EQUAL(res, expect);
+ }
+}
+
+TEST("testDump") {
+ typedef SourceBlenderSearch::Child Source;
+ SearchIterator::UP search(
+ AndSearch::create(
+ Collect<SearchIterator*, MultiSearch::Children>()
+ .add(AndNotSearch::create(search2("+", "-"), true))
+ .add(AndSearch::create(search2("and_a", "and_b"), true))
+ .add(new BooleanMatchIteratorWrapper(SearchIterator::UP(simple("wrapped")), TermFieldMatchDataArray()))
+ .add(new NearSearch(search2("near_a", "near_b"),
+ TermFieldMatchDataArray(),
+ 5u, true))
+ .add(new ONearSearch(search2("onear_a", "onear_b"),
+ TermFieldMatchDataArray(), 10, true))
+ .add(OrSearch::create(search2("or_a", "or_b"), false))
+ .add(RankSearch::create(search2("rank_a", "rank_b"),false))
+ .add(SourceBlenderSearch::create(selector(), Collect<Source, SourceBlenderSearch::Children>()
+ .add(Source(simple("blend_a"), 2))
+ .add(Source(simple("blend_b"), 4)), true))
+ , true));
+ vespalib::string sas = search->asString();
+ EXPECT_TRUE(sas.size() > 50);
+ // fprintf(stderr, "%s", search->asString().c_str());
+}
+
+TEST("testFieldSpec") {
+ EXPECT_EQUAL(8u, sizeof(FieldSpecBase));
+ EXPECT_EQUAL(72u, sizeof(FieldSpec));
+}
+
+
+const size_t unpack_child_cnt = 500;
+const size_t max_unpack_size = 31;
+const size_t max_unpack_index = 255;
+
+std::vector<size_t> vectorize(const UnpackInfo &unpack) {
+ std::vector<size_t> list;
+ unpack.each([&](size_t i){list.push_back(i);}, unpack_child_cnt);
+ return list;
+}
+
+std::vector<size_t> fill_vector(size_t begin, size_t end) {
+ std::vector<size_t> list;
+ for (size_t i = begin; i < end; ++i) {
+ list.push_back(i);
+ }
+ return list;
+}
+
+void verify_unpack(const UnpackInfo &unpack, const std::vector<size_t> &expect) {
+ std::vector<size_t> actual = vectorize(unpack);
+ EXPECT_EQUAL(unpack.empty(), expect.empty());
+ EXPECT_EQUAL(unpack.unpackAll(), (expect.size() == unpack_child_cnt));
+ EXPECT_EQUAL(expect, actual);
+ size_t child_idx = 0;
+ for (size_t next_unpack: expect) {
+ while (child_idx < next_unpack) {
+ EXPECT_FALSE(unpack.needUnpack(child_idx++));
+ }
+ EXPECT_TRUE(unpack.needUnpack(child_idx++));
+ }
+}
+
+TEST("require that unpack info has expected memory footprint") {
+ EXPECT_EQUAL(32u, sizeof(UnpackInfo));
+}
+
+TEST("require that unpack info starts out empty") {
+ verify_unpack(UnpackInfo(), {});
+}
+
+TEST("require that unpack info force all unpacks all children") {
+ verify_unpack(UnpackInfo().forceAll(), fill_vector(0, unpack_child_cnt));
+}
+
+TEST("require that adding a large index to unpack info forces unpack all") {
+ UnpackInfo unpack;
+ unpack.add(0);
+ unpack.add(max_unpack_index);
+ verify_unpack(unpack, {0, max_unpack_index});
+ unpack.add(max_unpack_index + 1);
+ verify_unpack(unpack, fill_vector(0, unpack_child_cnt));
+}
+
+TEST("require that adding too many children to unpack info forces unpack all") {
+ UnpackInfo unpack;
+ std::vector<size_t> expect;
+ for (size_t i = 0; i < max_unpack_size; ++i) {
+ unpack.add(i);
+ expect.push_back(i);
+ }
+ verify_unpack(unpack, expect);
+ unpack.add(100);
+ verify_unpack(unpack, fill_vector(0, unpack_child_cnt));
+}
+
+TEST("require that adding normal unpack info indexes works") {
+ UnpackInfo unpack;
+ unpack.add(3).add(5).add(7).add(14).add(50);
+ verify_unpack(unpack, {3,5,7,14,50});
+}
+
+TEST("require that adding unpack info indexes out of order works") {
+ UnpackInfo unpack;
+ unpack.add(5).add(3).add(7).add(50).add(14);
+ verify_unpack(unpack, {3,5,7,14,50});
+}
+
+TEST("require that basic insert remove of unpack info works") {
+ UnpackInfo unpack;
+ unpack.insert(1).insert(3);
+ verify_unpack(unpack, {1, 3});
+ unpack.insert(0);
+ verify_unpack(unpack, {0, 2, 4});
+ unpack.insert(3);
+ verify_unpack(unpack, {0, 2, 3, 5});
+ unpack.remove(1);
+ verify_unpack(unpack, {0, 1, 2, 4});
+ unpack.remove(1);
+ verify_unpack(unpack, {0, 1, 3});
+ unpack.remove(1);
+ verify_unpack(unpack, {0, 2});
+ unpack.remove(2);
+ verify_unpack(unpack, {0});
+ unpack.remove(0);
+ verify_unpack(unpack, {});
+}
+
+TEST("require that inserting too many indexs into unpack info forces unpack all") {
+ for (bool unpack_inserted: {true, false}) {
+ UnpackInfo unpack;
+ for (size_t i = 0; i < max_unpack_size; ++i) {
+ unpack.add(i);
+ }
+ EXPECT_FALSE(unpack.unpackAll());
+ unpack.insert(0, unpack_inserted);
+ if (unpack_inserted) {
+ verify_unpack(unpack, fill_vector(0, unpack_child_cnt));
+ } else {
+ verify_unpack(unpack, fill_vector(1, max_unpack_size + 1));
+ }
+ }
+}
+
+TEST("require that implicitly overflowing indexes during insert in unpack info forces unpack all") {
+ for (bool unpack_inserted: {true, false}) {
+ UnpackInfo unpack;
+ unpack.insert(max_unpack_index);
+ EXPECT_FALSE(unpack.unpackAll());
+ unpack.insert(5, unpack_inserted);
+ verify_unpack(unpack, fill_vector(0, unpack_child_cnt));
+ }
+}
+
+TEST("require that inserting a too high index into unpack info forces unpack all") {
+ for (bool unpack_inserted: {true, false}) {
+ UnpackInfo unpack;
+ for (size_t i = 0; i < 10; ++i) {
+ unpack.add(i);
+ }
+ EXPECT_FALSE(unpack.unpackAll());
+ unpack.insert(max_unpack_index + 1, unpack_inserted);
+ if (unpack_inserted) {
+ verify_unpack(unpack, fill_vector(0, unpack_child_cnt));
+ } else {
+ verify_unpack(unpack, fill_vector(0, 10));
+ }
+ }
+}
+
+TEST("require that we can insert indexes into unpack info that we do not unpack") {
+ UnpackInfo unpack;
+ unpack.add(10).add(20).add(30);
+ verify_unpack(unpack, {10, 20, 30});
+ unpack.insert(5, false).insert(15, false).insert(25, false).insert(35, false);
+ verify_unpack(unpack, {11, 22, 33});
+}
+
+TEST("testTrueSearch") {
+ EXPECT_EQUAL(16u, sizeof(EmptySearch));
+ EXPECT_EQUAL(24u, sizeof(TrueSearch));
+
+ TermFieldMatchData tfmd;
+ TrueSearch t(tfmd);
+ EXPECT_EQUAL(0u, t.getDocId());
+ EXPECT_EQUAL(0u, t.getEndId());
+ t.initRange(7, 10);
+ EXPECT_EQUAL(6u, t.getDocId());
+ EXPECT_EQUAL(10u, t.getEndId());
+ EXPECT_TRUE(t.seek(9));
+ EXPECT_EQUAL(9u, t.getDocId());
+ EXPECT_FALSE(t.isAtEnd());
+ EXPECT_TRUE(t.seek(10));
+ EXPECT_EQUAL(10u, t.getDocId());
+ EXPECT_TRUE(t.isAtEnd());
+ t.resetRange();
+ t.initRange(4, 14);
+ EXPECT_EQUAL(3u, t.getDocId());
+ EXPECT_EQUAL(14u, t.getEndId());
+ EXPECT_FALSE(t.isAtEnd());
+}
+
+TEST("test InitRangeVerifier") {
+ InitRangeVerifier ir;
+ EXPECT_EQUAL(207u, ir.getDocIdLimit());
+ EXPECT_EQUAL(41u, ir.getExpectedDocIds().size());
+ auto inverted = InitRangeVerifier::invert(ir.getExpectedDocIds(), 300);
+ size_t numInverted = 300 - 41 - 1;
+ EXPECT_EQUAL(numInverted, inverted.size());
+ EXPECT_EQUAL(2u, inverted[0]);
+ EXPECT_EQUAL(299u, inverted[numInverted - 1]);
+ ir.verify(*ir.createIterator(ir.getExpectedDocIds(), false));
+ ir.verify(*ir.createIterator(ir.getExpectedDocIds(), true));
+}
+
+TEST("Test multisearch and andsearchstrict iterators adheres to initRange") {
+ InitRangeVerifier ir;
+ ir.verify( AndSearch::create({ ir.createIterator(ir.getExpectedDocIds(), false).release(),
+ ir.createFullIterator().release() }, false));
+
+ ir.verify( AndSearch::create({ ir.createIterator(ir.getExpectedDocIds(), true).release(),
+ ir.createFullIterator().release() }, true));
+}
+
+TEST("Test andnotsearchstrict iterators adheres to initRange") {
+ InitRangeVerifier ir;
+
+ TEST_DO(ir.verify( AndNotSearch::create({ir.createIterator(ir.getExpectedDocIds(), false).release(),
+ ir.createEmptyIterator().release() }, false)));
+ TEST_DO(ir.verify( AndNotSearch::create({ir.createIterator(ir.getExpectedDocIds(), true).release(),
+ ir.createEmptyIterator().release() }, true)));
+
+ auto inverted = InitRangeVerifier::invert(ir.getExpectedDocIds(), ir.getDocIdLimit());
+ TEST_DO(ir.verify( AndNotSearch::create({ir.createFullIterator().release(),
+ ir.createIterator(inverted, false).release() }, false)));
+ TEST_DO(ir.verify( AndNotSearch::create({ir.createFullIterator().release(),
+ ir.createIterator(inverted, false).release() }, true)));
+}
+
+
+TEST_MAIN() { TEST_RUN_ALL(); }