diff options
Diffstat (limited to 'searchlib/src/tests/queryeval')
11 files changed, 805 insertions, 441 deletions
diff --git a/searchlib/src/tests/queryeval/blueprint/blueprint_test.cpp b/searchlib/src/tests/queryeval/blueprint/blueprint_test.cpp index 20cf2008e4b..f800e124bdc 100644 --- a/searchlib/src/tests/queryeval/blueprint/blueprint_test.cpp +++ b/searchlib/src/tests/queryeval/blueprint/blueprint_test.cpp @@ -1,6 +1,7 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include "mysearch.h" #include <vespa/vespalib/testkit/testapp.h> +#include <vespa/searchlib/queryeval/flow.h> #include <vespa/searchlib/queryeval/blueprint.h> #include <vespa/searchlib/queryeval/intermediate_blueprints.h> #include <vespa/vespalib/objects/objectdumper.h> @@ -22,8 +23,12 @@ class MyOr : public IntermediateBlueprint { private: public: - double calculate_cost() const final { return 1.0; } - double calculate_relative_estimate() const final { return 0.5; } + double calculate_cost() const final { + return cost_of(get_children(), OrFlow()); + } + double calculate_relative_estimate() const final { + return estimate_of(get_children(), OrFlow()); + } HitEstimate combine(const std::vector<HitEstimate> &data) const override { return max(data); } @@ -32,7 +37,7 @@ public: return mixChildrenFields(); } - void sort(Children &children) const override { + void sort(Children &children, bool) const override { std::sort(children.begin(), children.end(), TieredGreaterEstimate()); } @@ -440,7 +445,8 @@ TEST_F("testChildAndNotCollapsing", Fixture) ) ); TEST_DO(f.check_not_equal(*sorted, *unsorted)); - unsorted = Blueprint::optimize(std::move(unsorted)); + unsorted->setDocIdLimit(1000); + unsorted = Blueprint::optimize(std::move(unsorted), true); TEST_DO(f.check_equal(*sorted, *unsorted)); } @@ -479,7 +485,8 @@ TEST_F("testChildAndCollapsing", Fixture) ); TEST_DO(f.check_not_equal(*sorted, *unsorted)); - unsorted = Blueprint::optimize(std::move(unsorted)); + unsorted->setDocIdLimit(1000); + unsorted = Blueprint::optimize(std::move(unsorted), true); TEST_DO(f.check_equal(*sorted, *unsorted)); } @@ -517,7 +524,8 @@ TEST_F("testChildOrCollapsing", Fixture) .add(MyLeafSpec(1).addField(2, 42).create()) ); TEST_DO(f.check_not_equal(*sorted, *unsorted)); - unsorted = Blueprint::optimize(std::move(unsorted)); + unsorted->setDocIdLimit(1000); + unsorted = Blueprint::optimize(std::move(unsorted), true); TEST_DO(f.check_equal(*sorted, *unsorted)); } @@ -560,7 +568,8 @@ TEST_F("testChildSorting", Fixture) ); TEST_DO(f.check_not_equal(*sorted, *unsorted)); - unsorted = Blueprint::optimize(std::move(unsorted)); + unsorted->setDocIdLimit(1000); + unsorted = Blueprint::optimize(std::move(unsorted), true); TEST_DO(f.check_equal(*sorted, *unsorted)); } @@ -646,6 +655,7 @@ getExpectedBlueprint() " tree_size: 2\n" " allow_termwise_eval: false\n" " }\n" + " cost: 1\n" " sourceId: 4294967295\n" " docid_limit: 0\n" " children: std::vector {\n" @@ -666,6 +676,7 @@ getExpectedBlueprint() " tree_size: 1\n" " allow_termwise_eval: true\n" " }\n" + " cost: 1\n" " sourceId: 4294967295\n" " docid_limit: 0\n" " }\n" @@ -696,6 +707,7 @@ getExpectedSlimeBlueprint() { " tree_size: 2," " allow_termwise_eval: false" " }," + " cost: 1.0," " sourceId: 4294967295," " docid_limit: 0," " children: {" @@ -721,6 +733,7 @@ getExpectedSlimeBlueprint() { " tree_size: 1," " allow_termwise_eval: true" " }," + " cost: 1.0," " sourceId: 4294967295," " docid_limit: 0" " }" diff --git a/searchlib/src/tests/queryeval/blueprint/intermediate_blueprints_test.cpp b/searchlib/src/tests/queryeval/blueprint/intermediate_blueprints_test.cpp index e24e91c2f1d..ab1c004c721 100644 --- a/searchlib/src/tests/queryeval/blueprint/intermediate_blueprints_test.cpp +++ b/searchlib/src/tests/queryeval/blueprint/intermediate_blueprints_test.cpp @@ -14,6 +14,11 @@ #include <vespa/searchlib/test/diskindex/testdiskindex.h> #include <vespa/searchlib/query/tree/simplequery.h> #include <vespa/searchlib/common/bitvectoriterator.h> +#include <vespa/vespalib/util/overload.h> +#include <vespa/vespalib/util/approx.h> +#include <vespa/vespalib/data/simple_buffer.h> +#include <vespa/vespalib/data/slime/slime.h> +#include <vespa/vespalib/data/slime/inserter.h> #include <filesystem> #include <vespa/log/log.h> @@ -24,6 +29,11 @@ using namespace search::fef; using namespace search::query; using search::BitVector; using BlueprintVector = std::vector<std::unique_ptr<Blueprint>>; +using vespalib::Slime; +using vespalib::slime::Inspector; +using vespalib::slime::SlimeInserter; +using vespalib::make_string_short::fmt; +using Path = std::vector<std::variant<size_t,vespalib::stringref>>; struct InvalidSelector : ISourceSelector { InvalidSelector() : ISourceSelector(Source()) {} @@ -66,7 +76,8 @@ void check_sort_order(IntermediateBlueprint &self, BlueprintVector children, std for (const auto & child: children) { unordered.push_back(child.get()); } - self.sort(children); + // TODO: sort by cost (requires both setDocIdLimit and optimize to be called) + self.sort(children, false); for (size_t i = 0; i < children.size(); ++i) { EXPECT_EQUAL(children[i].get(), unordered[order[i]]); } @@ -120,7 +131,7 @@ TEST("test AndNot Blueprint") { template <typename BP> void optimize(std::unique_ptr<BP> &ref) { - auto optimized = Blueprint::optimize(std::move(ref)); + auto optimized = Blueprint::optimize(std::move(ref), true); ref.reset(dynamic_cast<BP*>(optimized.get())); ASSERT_TRUE(ref); optimized.release(); @@ -132,8 +143,8 @@ TEST("test And propagates updated histestimate") { bp->addChild(ap(MyLeafSpec(20).create<RememberExecuteInfo>()->setSourceId(2))); bp->addChild(ap(MyLeafSpec(200).create<RememberExecuteInfo>()->setSourceId(2))); bp->addChild(ap(MyLeafSpec(2000).create<RememberExecuteInfo>()->setSourceId(2))); - optimize(bp); bp->setDocIdLimit(5000); + optimize(bp); bp->fetchPostings(ExecuteInfo::TRUE); EXPECT_EQUAL(3u, bp->childCnt()); for (uint32_t i = 0; i < bp->childCnt(); i++) { @@ -152,8 +163,8 @@ TEST("test Or propagates updated histestimate") { bp->addChild(ap(MyLeafSpec(2000).create<RememberExecuteInfo>()->setSourceId(2))); bp->addChild(ap(MyLeafSpec(800).create<RememberExecuteInfo>()->setSourceId(2))); bp->addChild(ap(MyLeafSpec(20).create<RememberExecuteInfo>()->setSourceId(2))); - optimize(bp); bp->setDocIdLimit(5000); + optimize(bp); bp->fetchPostings(ExecuteInfo::TRUE); EXPECT_EQUAL(4u, bp->childCnt()); for (uint32_t i = 0; i < bp->childCnt(); i++) { @@ -480,13 +491,71 @@ struct SourceBlenderTestFixture { void addChildrenForSimpleSBTest(IntermediateBlueprint & parent); }; +vespalib::string path_to_str(const Path &path) { + size_t cnt = 0; + vespalib::string str("["); + for (const auto &item: path) { + if (cnt++ > 0) { + str.append(","); + } + std::visit(vespalib::overload{ + [&str](size_t value)noexcept{ str.append(fmt("%zu", value)); }, + [&str](vespalib::stringref value)noexcept{ str.append(value); }}, item); + } + str.append("]"); + return str; +} + +vespalib::string to_str(const Inspector &value) { + if (!value.valid()) { + return "<missing>"; + } + vespalib::SimpleBuffer buf; + vespalib::slime::JsonFormat::encode(value, buf, true); + return buf.get().make_string(); +} + +void compare(const Blueprint &bp1, const Blueprint &bp2, bool expect_eq) { + auto cmp_hook = [expect_eq](const auto &path, const auto &a, const auto &b) { + if (!path.empty() && std::holds_alternative<vespalib::stringref>(path.back())) { + vespalib::stringref field = std::get<vespalib::stringref>(path.back()); + if (field == "cost") { + return true; + } + if (field == "relative_estimate") { + double a_val = a.asDouble(); + double b_val = b.asDouble(); + if (a_val != 0.0 && b_val != 0.0 && vespalib::approx_equal(a_val, b_val)) { + return true; + } + } + } + if (expect_eq) { + fprintf(stderr, " mismatch at %s: %s vs %s\n", path_to_str(path).c_str(), + to_str(a).c_str(), to_str(b).c_str()); + } + return false; + }; + Slime a; + Slime b; + bp1.asSlime(SlimeInserter(a)); + bp2.asSlime(SlimeInserter(b)); + if (expect_eq) { + EXPECT_TRUE(vespalib::slime::are_equal(a.get(), b.get(), cmp_hook)); + } else { + EXPECT_FALSE(vespalib::slime::are_equal(a.get(), b.get(), cmp_hook)); + } +} + void -optimize_and_compare(Blueprint::UP top, Blueprint::UP expect) { - EXPECT_NOT_EQUAL(expect->asString(), top->asString()); - top = Blueprint::optimize(std::move(top)); - EXPECT_EQUAL(expect->asString(), top->asString()); - expect = Blueprint::optimize(std::move(expect)); - EXPECT_EQUAL(expect->asString(), top->asString()); +optimize_and_compare(Blueprint::UP top, Blueprint::UP expect, bool sort_by_cost = true) { + top->setDocIdLimit(1000); + expect->setDocIdLimit(1000); + TEST_DO(compare(*top, *expect, false)); + top = Blueprint::optimize(std::move(top), sort_by_cost); + TEST_DO(compare(*top, *expect, true)); + expect = Blueprint::optimize(std::move(expect), sort_by_cost); + TEST_DO(compare(*expect, *top, true)); } void SourceBlenderTestFixture::addChildrenForSBTest(IntermediateBlueprint & parent) { @@ -612,11 +681,11 @@ TEST("test empty root node optimization and safeness") { //------------------------------------------------------------------------- auto expect_up = std::make_unique<EmptyBlueprint>(); - EXPECT_EQUAL(expect_up->asString(), Blueprint::optimize(std::move(top1))->asString()); - EXPECT_EQUAL(expect_up->asString(), Blueprint::optimize(std::move(top2))->asString()); - EXPECT_EQUAL(expect_up->asString(), Blueprint::optimize(std::move(top3))->asString()); - EXPECT_EQUAL(expect_up->asString(), Blueprint::optimize(std::move(top4))->asString()); - EXPECT_EQUAL(expect_up->asString(), Blueprint::optimize(std::move(top5))->asString()); + EXPECT_EQUAL(expect_up->asString(), Blueprint::optimize(std::move(top1), true)->asString()); + EXPECT_EQUAL(expect_up->asString(), Blueprint::optimize(std::move(top2), true)->asString()); + EXPECT_EQUAL(expect_up->asString(), Blueprint::optimize(std::move(top3), true)->asString()); + EXPECT_EQUAL(expect_up->asString(), Blueprint::optimize(std::move(top4), true)->asString()); + EXPECT_EQUAL(expect_up->asString(), Blueprint::optimize(std::move(top5), true)->asString()); } TEST("and with one empty child is optimized away") { @@ -624,7 +693,7 @@ TEST("and with one empty child is optimized away") { Blueprint::UP top = ap((new SourceBlenderBlueprint(*selector))-> addChild(ap(MyLeafSpec(10).create())). addChild(addLeafs(std::make_unique<AndBlueprint>(), {{0, true}, 10, 20}))); - top = Blueprint::optimize(std::move(top)); + top = Blueprint::optimize(std::move(top), true); Blueprint::UP expect_up(ap((new SourceBlenderBlueprint(*selector))-> addChild(ap(MyLeafSpec(10).create())). addChild(std::make_unique<EmptyBlueprint>()))); @@ -716,6 +785,22 @@ TEST("AND_NOT AND AND_NOT collapsing") { optimize_and_compare(std::move(top), std::move(expect)); } +TEST("AND_NOT AND AND_NOT AND nested collapsing") { + Blueprint::UP top = make::ANDNOT() + .add(make::AND() + .add(make::ANDNOT() + .add(make::AND().leafs({1,2})) + .leafs({5,6})) + .add(make::ANDNOT() + .add(make::AND().leafs({3,4})) + .leafs({8,9}))) + .leaf(7); + Blueprint::UP expect = make::ANDNOT() + .add(make::AND().leafs({1,2,3,4})) + .leafs({9,8,7,6,5}); + optimize_and_compare(std::move(top), std::move(expect)); +} + TEST("AND_NOT AND AND_NOT collapsing into full source blender optimization") { InvalidSelector sel; Blueprint::UP top = @@ -783,8 +868,8 @@ TEST("require that replaced blueprints retain source id") { addChild(ap(MyLeafSpec(30).create()->setSourceId(55))))); Blueprint::UP expect2_up(ap(MyLeafSpec(30).create()->setSourceId(42))); //------------------------------------------------------------------------- - top1_up = Blueprint::optimize(std::move(top1_up)); - top2_up = Blueprint::optimize(std::move(top2_up)); + top1_up = Blueprint::optimize(std::move(top1_up), true); + top2_up = Blueprint::optimize(std::move(top2_up), true); EXPECT_EQUAL(expect1_up->asString(), top1_up->asString()); EXPECT_EQUAL(expect2_up->asString(), top2_up->asString()); EXPECT_EQUAL(13u, top1_up->getSourceId()); @@ -1103,8 +1188,8 @@ TEST("require that children of near are not optimized") { auto expect_up = ap((new NearBlueprint(10))-> addChild(addLeafs(std::make_unique<OrBlueprint>(), {20, {0, true}})). addChild(addLeafs(std::make_unique<OrBlueprint>(), {{0, true}, 30}))); - top_up = Blueprint::optimize(std::move(top_up)); - EXPECT_EQUAL(expect_up->asString(), top_up->asString()); + top_up = Blueprint::optimize(std::move(top_up), true); + TEST_DO(compare(*top_up, *expect_up, true)); } TEST("require that children of onear are not optimized") { @@ -1114,27 +1199,27 @@ TEST("require that children of onear are not optimized") { auto expect_up = ap((new ONearBlueprint(10))-> addChild(addLeafs(std::make_unique<OrBlueprint>(), {20, {0, true}})). addChild(addLeafs(std::make_unique<OrBlueprint>(), {{0, true}, 30}))); - top_up = Blueprint::optimize(std::move(top_up)); - EXPECT_EQUAL(expect_up->asString(), top_up->asString()); + top_up = Blueprint::optimize(std::move(top_up), true); + TEST_DO(compare(*top_up, *expect_up, true)); } TEST("require that ANDNOT without children is optimized to empty search") { Blueprint::UP top_up = std::make_unique<AndNotBlueprint>(); auto expect_up = std::make_unique<EmptyBlueprint>(); - top_up = Blueprint::optimize(std::move(top_up)); + top_up = Blueprint::optimize(std::move(top_up), true); EXPECT_EQUAL(expect_up->asString(), top_up->asString()); } TEST("require that highest cost tier sorts last for OR") { Blueprint::UP top = addLeafsWithCostTier(std::make_unique<OrBlueprint>(), {{50, 1}, {30, 3}, {20, 2}, {10, 1}}); Blueprint::UP expect = addLeafsWithCostTier(std::make_unique<OrBlueprint>(), {{50, 1}, {10, 1}, {20, 2}, {30, 3}}); - optimize_and_compare(std::move(top), std::move(expect)); + optimize_and_compare(std::move(top), std::move(expect), false); } TEST("require that highest cost tier sorts last for AND") { Blueprint::UP top = addLeafsWithCostTier(std::make_unique<AndBlueprint>(), {{10, 1}, {20, 3}, {30, 2}, {50, 1}}); Blueprint::UP expect = addLeafsWithCostTier(std::make_unique<AndBlueprint>(), {{10, 1}, {50, 1}, {30, 2}, {20, 3}}); - optimize_and_compare(std::move(top), std::move(expect)); + optimize_and_compare(std::move(top), std::move(expect), false); } template<typename BP> @@ -1251,7 +1336,7 @@ void verify_cost(make &&mk, double expect) { .cost(1.2).leaf(300) .cost(1.3).leaf(500); bp->setDocIdLimit(1000); - bp = Blueprint::optimize(std::move(bp)); + bp = Blueprint::optimize(std::move(bp), true); EXPECT_EQUAL(bp->cost(), expect); } diff --git a/searchlib/src/tests/queryeval/filter_search/filter_search_test.cpp b/searchlib/src/tests/queryeval/filter_search/filter_search_test.cpp index f910ff5be1b..1180206279d 100644 --- a/searchlib/src/tests/queryeval/filter_search/filter_search_test.cpp +++ b/searchlib/src/tests/queryeval/filter_search/filter_search_test.cpp @@ -48,7 +48,7 @@ concept ChildCollector = requires(T a, std::unique_ptr<Blueprint> bp) { // inherit Blueprint to capture the default filter factory struct DefaultBlueprint : Blueprint { double calculate_relative_estimate() const override { abort(); } - void optimize(Blueprint* &, OptimizePass) override { abort(); } + void optimize(Blueprint* &, OptimizePass, bool) override { abort(); } const State &getState() const override { abort(); } void fetchPostings(const ExecuteInfo &) override { abort(); } void freeze() override { abort(); } diff --git a/searchlib/src/tests/queryeval/flow/CMakeLists.txt b/searchlib/src/tests/queryeval/flow/CMakeLists.txt new file mode 100644 index 00000000000..70658d36f21 --- /dev/null +++ b/searchlib/src/tests/queryeval/flow/CMakeLists.txt @@ -0,0 +1,9 @@ +# Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(searchlib_queryeval_flow_test_app TEST + SOURCES + queryeval_flow_test.cpp + DEPENDS + searchlib + GTest::GTest +) +vespa_add_test(NAME searchlib_queryeval_flow_test_app COMMAND searchlib_queryeval_flow_test_app) diff --git a/searchlib/src/tests/queryeval/flow/queryeval_flow_test.cpp b/searchlib/src/tests/queryeval/flow/queryeval_flow_test.cpp new file mode 100644 index 00000000000..ceda30f169a --- /dev/null +++ b/searchlib/src/tests/queryeval/flow/queryeval_flow_test.cpp @@ -0,0 +1,117 @@ +// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#include <vespa/searchlib/queryeval/flow.h> +#include <vespa/vespalib/gtest/gtest.h> +#include <vector> +#include <random> + +using search::queryeval::AndFlow; +using search::queryeval::OrFlow; + +struct Item { + double rel_est; + double cost; + Item(double rel_est_in, double cost_in) noexcept + : rel_est(rel_est_in), cost(cost_in) {} + static void sort_for_and(std::vector<Item> &data) { + std::sort(data.begin(), data.end(), [](const Item &a, const Item &b) noexcept { + return (1.0 - a.rel_est) / a.cost > (1.0 - b.rel_est) / b.cost; + }); + } + static void sort_for_or(std::vector<Item> &data) { + std::sort(data.begin(), data.end(), [](const Item &a, const Item &b) noexcept { + return a.rel_est / a.cost > b.rel_est / b.cost; + }); + } + static double cost_of(const std::vector<Item> &data, auto flow) { + double cost = 0.0; + for (const Item &item: data) { + cost += flow.flow() * item.cost; + flow.add(item.rel_est); + } + return cost; + } + static double cost_of_and(const std::vector<Item> &data) { return cost_of(data, AndFlow()); } + static double cost_of_or(const std::vector<Item> &data) { return cost_of(data, OrFlow()); } +}; + +std::vector<Item> gen_data(size_t size) { + static std::mt19937 gen; + static std::uniform_real_distribution<double> rel_est(0.1, 0.9); + static std::uniform_real_distribution<double> cost(1.0, 10.0); + std::vector<Item> result; + result.reserve(size); + for (size_t i = 0; i < size; ++i) { + result.emplace_back(rel_est(gen), cost(gen)); + } + return result; +} + +template <typename T, typename F> +void each_perm(std::vector<T> &data, size_t k, F fun) { + if (k <= 1) { + fun(const_cast<const std::vector<T> &>(data)); + } else { + each_perm(data, k-1, fun); + for (size_t i = 0; i < k-1; ++i) { + if (k & 1) { + std::swap(data[0], data[k-1]); + } else { + std::swap(data[i], data[k-1]); + } + each_perm(data, k-1, fun); + } + } +} + +template <typename T, typename F> +void each_perm(std::vector<T> &data, F fun) { + each_perm(data, data.size(), fun); +} + +TEST(FlowTest, perm_test) { + std::set<std::vector<int>> seen; + std::vector<int> data = {1,2,3,4,5}; + auto hook = [&](const std::vector<int> &perm) { + EXPECT_EQ(perm.size(), 5); + seen.insert(perm); + }; + each_perm(data, hook); + EXPECT_EQ(seen.size(), 120); +} + +TEST(FlowTest, optimal_and_flow) { + for (size_t i = 0; i < 256; ++i) { + auto data = gen_data(7); + Item::sort_for_and(data); + double min_cost = Item::cost_of_and(data); + double max_cost = 0.0; + auto check = [min_cost,&max_cost](const std::vector<Item> &my_data) noexcept { + double my_cost = Item::cost_of_and(my_data); + EXPECT_LE(min_cost, my_cost); + max_cost = std::max(max_cost, my_cost); + }; + each_perm(data, check); + fprintf(stderr, " and cost(%zu): min: %g, max: %g, factor: %g\n", + i, min_cost, max_cost, max_cost / min_cost); + } +} + +TEST(FlowTest, optimal_or_flow) { + for (size_t i = 0; i < 256; ++i) { + auto data = gen_data(7); + Item::sort_for_or(data); + double min_cost = Item::cost_of_or(data); + double max_cost = 0.0; + auto check = [min_cost,&max_cost](const std::vector<Item> &my_data) noexcept { + double my_cost = Item::cost_of_or(my_data); + EXPECT_LE(min_cost, my_cost); + max_cost = std::max(max_cost, my_cost); + }; + each_perm(data, check); + fprintf(stderr, " or cost(%zu): min: %g, max: %g, factor: %g\n", + i, min_cost, max_cost, max_cost / min_cost); + } +} + +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/searchlib/src/tests/queryeval/parallel_weak_and/parallel_weak_and_test.cpp b/searchlib/src/tests/queryeval/parallel_weak_and/parallel_weak_and_test.cpp index 2a59a578ec9..aa6d922f23f 100644 --- a/searchlib/src/tests/queryeval/parallel_weak_and/parallel_weak_and_test.cpp +++ b/searchlib/src/tests/queryeval/parallel_weak_and/parallel_weak_and_test.cpp @@ -1,6 +1,6 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include <vespa/searchlib/query/tree/simplequery.h> -#include <vespa/searchlib/queryeval/document_weight_search_iterator.h> +#include <vespa/searchlib/queryeval/docid_with_weight_search_iterator.h> #include <vespa/searchlib/queryeval/fake_requestcontext.h> #include <vespa/searchlib/queryeval/fake_searchable.h> #include <vespa/searchlib/queryeval/simpleresult.h> @@ -10,8 +10,9 @@ #include <vespa/searchlib/queryeval/wand/parallel_weak_and_blueprint.h> #include <vespa/searchlib/queryeval/wand/parallel_weak_and_search.h> #include <vespa/searchlib/test/document_weight_attribute_helper.h> +#define ENABLE_GTEST_MIGRATION #include <vespa/searchlib/test/weightedchildrenverifiers.h> -#include <vespa/vespalib/testkit/test_kit.h> +#include <vespa/vespalib/gtest/gtest.h> using namespace search::query; using namespace search::queryeval; @@ -284,89 +285,101 @@ struct AlgoExhaustPastFixture : public FixtureBase }; -TEST_F("require that algorithm prunes bad hits after enough good ones are obtained", AlgoSimpleFixture) +TEST(ParallelWeakAndTest, require_that_algorithm_prunes_bad_hits_after_enough_good_ones_are_obtained) { + AlgoSimpleFixture f; FakeResult expect = FakeResult() .doc(1).score(1 * 1 + 4 * 1) .doc(2).score(1 * 2) .doc(3).score(1 * 3 + 4 * 3) .doc(5).score(1 * 5 + 4 * 5); - EXPECT_EQUAL(expect, f.result); + EXPECT_EQ(expect, f.result); } -TEST_F("require that algorithm uses subsearches as expected", AlgoSimpleFixture) { - EXPECT_EQUAL(SearchHistory() - .seek("PWAND", 1).seek("B", 1).step("B", 1).unpack("B", 1).step("PWAND", 1) - .unpack("PWAND", 1).seek("A", 1).step("A", 1).unpack("A", 1) - .seek("PWAND", 2).seek("B", 2).step("B", 3).seek("A", 2).step("A", 2).unpack("A", 2).step("PWAND", 2) - .unpack("PWAND", 2) - .seek("PWAND", 3).unpack("B", 3).step("PWAND", 3) - .unpack("PWAND", 3).seek("A", 3).step("A", 3).unpack("A", 3) - .seek("PWAND", 4).seek("B", 4).step("B", 5).seek("A", 4).step("A", 4).unpack("A", 4).unpack("B", 5).step("PWAND", 5) - .unpack("PWAND", 5).seek("A", 5).step("A", 5).unpack("A", 5) - .seek("PWAND", 6).seek("B", 6).step("B", search::endDocId).step("PWAND", search::endDocId), - f.spec.getHistory()); +TEST(ParallelWeakAndTest, require_that_algorithm_uses_subsearches_as_expected) +{ + AlgoSimpleFixture f; + EXPECT_EQ(SearchHistory() + .seek("PWAND", 1).seek("B", 1).step("B", 1).unpack("B", 1).step("PWAND", 1) + .unpack("PWAND", 1).seek("A", 1).step("A", 1).unpack("A", 1) + .seek("PWAND", 2).seek("B", 2).step("B", 3).seek("A", 2).step("A", 2).unpack("A", 2).step("PWAND", 2) + .unpack("PWAND", 2) + .seek("PWAND", 3).unpack("B", 3).step("PWAND", 3) + .unpack("PWAND", 3).seek("A", 3).step("A", 3).unpack("A", 3) + .seek("PWAND", 4).seek("B", 4).step("B", 5).seek("A", 4).step("A", 4).unpack("A", 4).unpack("B", 5).step("PWAND", 5) + .unpack("PWAND", 5).seek("A", 5).step("A", 5).unpack("A", 5) + .seek("PWAND", 6).seek("B", 6).step("B", search::endDocId).step("PWAND", search::endDocId), + f.spec.getHistory()); } -TEST_F("require that algorithm considers documents in the right order", AlgoAdvancedFixture) +TEST(ParallelWeakAndTest, require_that_algorithm_considers_documents_in_the_right_order) { - EXPECT_EQUAL(SimpleResult() - .addHit(1).addHit(2).addHit(3).addHit(4).addHit(5) - .addHit(11).addHit(12).addHit(13).addHit(14).addHit(15) - .addHit(111).addHit(112).addHit(113).addHit(114).addHit(115), asSimpleResult(f.result)); + AlgoAdvancedFixture f; + EXPECT_EQ(SimpleResult() + .addHit(1).addHit(2).addHit(3).addHit(4).addHit(5) + .addHit(11).addHit(12).addHit(13).addHit(14).addHit(15) + .addHit(111).addHit(112).addHit(113).addHit(114).addHit(115), asSimpleResult(f.result)); } -TEST_F("require that algorithm take initial docid for subsearches into account", AlgoSubsearchFixture) +TEST(ParallelWeakAndTest, require_that_algorithm_take_initial_docid_for_subsearches_into_account) { - EXPECT_EQUAL(FakeResult().doc(10).score(20), f.result); - EXPECT_EQUAL(SearchHistory().seek("PWAND", 1).unpack("B", 10).step("PWAND", 10).unpack("PWAND", 10) - .seek("PWAND", 11).seek("B", 11).step("B", search::endDocId).step("PWAND", search::endDocId), - f.spec.getHistory()); + AlgoSubsearchFixture f; + EXPECT_EQ(FakeResult().doc(10).score(20), f.result); + EXPECT_EQ(SearchHistory().seek("PWAND", 1).unpack("B", 10).step("PWAND", 10).unpack("PWAND", 10) + .seek("PWAND", 11).seek("B", 11).step("B", search::endDocId).step("PWAND", search::endDocId), + f.spec.getHistory()); } -TEST_F("require that algorithm uses first match when two matches have same score", AlgoSameScoreFixture) +TEST(ParallelWeakAndTest, require_that_algorithm_uses_first_match_when_two_matches_have_same_score) { - EXPECT_EQUAL(FakeResult().doc(1).score(100), f.result); + AlgoSameScoreFixture f; + EXPECT_EQ(FakeResult().doc(1).score(100), f.result); } -TEST_F("require that algorithm uses initial score threshold (all hits greater)", AlgoScoreThresholdFixture(29)) +TEST(ParallelWeakAndTest, require_that_algorithm_uses_initial_score_threshold_case_all_hits_greater) { - EXPECT_EQUAL(FakeResult() - .doc(1).score(1 * 10 + 2 * 20) - .doc(2).score(1 * 30) - .doc(3).score(2 * 40), f.result); + AlgoScoreThresholdFixture f(29); + EXPECT_EQ(FakeResult() + .doc(1).score(1 * 10 + 2 * 20) + .doc(2).score(1 * 30) + .doc(3).score(2 * 40), f.result); } -TEST_F("require that algorithm uses initial score threshold (2 hits greater)", AlgoScoreThresholdFixture(30)) +TEST(ParallelWeakAndTest, require_that_algorithm_uses_initial_score_threshold_case_2_hits_greater) { - EXPECT_EQUAL(FakeResult() - .doc(1).score(1 * 10 + 2 * 20) - .doc(3).score(2 * 40), f.result); + AlgoScoreThresholdFixture f(30); + EXPECT_EQ(FakeResult() + .doc(1).score(1 * 10 + 2 * 20) + .doc(3).score(2 * 40), f.result); } -TEST_F("require that algorithm uses initial score threshold (1 hit greater)", AlgoScoreThresholdFixture(50)) +TEST(ParallelWeakAndTest, require_that_algorithm_uses_initial_score_threshold_case_1_hit_greater) { - EXPECT_EQUAL(FakeResult() - .doc(3).score(2 * 40), f.result); + AlgoScoreThresholdFixture f(50); + EXPECT_EQ(FakeResult() + .doc(3).score(2 * 40), f.result); } -TEST_F("require that algorithm uses initial score threshold (0 hits greater)", AlgoScoreThresholdFixture(80)) +TEST(ParallelWeakAndTest, require_that_algorithm_uses_initial_score_threshold_case_0_hits_greater) { - EXPECT_EQUAL(FakeResult(), f.result); + AlgoScoreThresholdFixture f(80); + EXPECT_EQ(FakeResult(), f.result); } -TEST_F("require that algorithm handle large scores", AlgoLargeScoresFixture(60000L * 70000L)) +TEST(ParallelWeakAndTest, require_that_algorithm_handles_large_scores) { - EXPECT_EQUAL(FakeResult() - .doc(1).score(60000L * 60000L + 70000L * 80000L) - .doc(3).score(70000L * 90000L), f.result); + AlgoLargeScoresFixture f(60000L * 70000L); + EXPECT_EQ(FakeResult() + .doc(1).score(60000L * 60000L + 70000L * 80000L) + .doc(3).score(70000L * 90000L), f.result); } -TEST_F("require that algorithm steps all present terms when past is empty", AlgoExhaustPastFixture(25)) +TEST(ParallelWeakAndTest, require_that_algorithm_steps_all_present_terms_when_past_is_empty) { - EXPECT_EQUAL(FakeResult() - .doc(3).score(40) - .doc(5).score(30), f.result); + AlgoExhaustPastFixture f(25); + EXPECT_EQ(FakeResult() + .doc(3).score(40) + .doc(5).score(30), f.result); } struct HeapFixture @@ -380,14 +393,15 @@ struct HeapFixture } }; -TEST_F("require that scores are collected in batches before adjusting heap", HeapFixture) +TEST(ParallelWeakAndTest, require_that_scores_are_collected_in_batches_before_adjusting_heap) { - EXPECT_EQUAL(SimpleResult().addHit(1).addHit(2).addHit(3).addHit(4).addHit(5).addHit(6), - f.result); - EXPECT_EQUAL(ScoresHistory().add(Scores().add(1).add(2)) - .add(Scores().add(3).add(4)) - .add(Scores().add(5).add(6)), - f.spec.heap.history); + HeapFixture f; + EXPECT_EQ(SimpleResult().addHit(1).addHit(2).addHit(3).addHit(4).addHit(5).addHit(6), + f.result); + EXPECT_EQ(ScoresHistory().add(Scores().add(1).add(2)) + .add(Scores().add(3).add(4)) + .add(Scores().add(5).add(6)), + f.spec.heap.history); } @@ -400,13 +414,14 @@ struct SearchFixture : public FixtureBase } }; -TEST_F("require that dot product score is calculated", SearchFixture) +TEST(ParallelWeakAndTest, require_that_dot_product_score_is_calculated) { + SearchFixture f; FakeResult expect = FakeResult() .doc(1).score(1 * 10 + 2 * 20) .doc(2).score(1 * 30) .doc(3).score(2 * 40); - EXPECT_EQUAL(expect, f.result); + EXPECT_EQ(expect, f.result); } @@ -452,8 +467,9 @@ struct BlueprintHitsFixture : public BlueprintFixtureBase bool maxScoreFirst() { SearchIterator::UP itr = iterator(); const ParallelWeakAndSearch *wand = dynamic_cast<ParallelWeakAndSearch*>(itr.get()); - ASSERT_EQUAL(2u, wand->get_num_terms()); - return (wand->get_term_weight(0) == 20); + bool failed = false; + EXPECT_EQ(2u, wand->get_num_terms()) << (failed = true, ""); + return failed ? false : (wand->get_term_weight(0) == 20); } }; @@ -468,8 +484,11 @@ struct ThresholdBoostFixture : public FixtureBase SearchIterator::UP si(spec.create()); result = doSearch(*si, spec.rootMatchData); } + ~ThresholdBoostFixture(); }; +ThresholdBoostFixture::~ThresholdBoostFixture() = default; + struct BlueprintFixture : public BlueprintFixtureBase { BlueprintFixture() : BlueprintFixtureBase() { @@ -497,89 +516,99 @@ struct BlueprintAsStringFixture : public BlueprintFixtureBase }; -TEST_F("require that hit estimate is calculated", BlueprintFixture) +TEST(ParallelWeakAndTest, require_that_hit_estimate_is_calculated) { + BlueprintFixture f; Node::UP term = f.spec.createNode(); Blueprint::UP bp = f.blueprint(*term); - EXPECT_EQUAL(4u, bp->getState().estimate().estHits); + EXPECT_EQ(4u, bp->getState().estimate().estHits); } -TEST_F("require that blueprint picks up docid limit", BlueprintFixture) +TEST(ParallelWeakAndTest, require_that_blueprint_picks_up_docid_limit) { + BlueprintFixture f; Node::UP term = f.spec.createNode(57, 67, 77.7); Blueprint::UP bp = f.blueprint(*term); const ParallelWeakAndBlueprint * pbp = dynamic_cast<const ParallelWeakAndBlueprint *>(bp.get()); - EXPECT_EQUAL(0u, pbp->get_docid_limit()); + EXPECT_EQ(0u, pbp->get_docid_limit()); bp->setDocIdLimit(1000); - EXPECT_EQUAL(1000u, pbp->get_docid_limit()); + EXPECT_EQ(1000u, pbp->get_docid_limit()); } -TEST_F("require that scores to track, score threshold and threshold boost factor is passed down from query node to blueprint", BlueprintFixture) +TEST(ParallelWeakAndTest, require_that_scores_to_track_score_threshold_and_threshold_boost_factor_is_passed_down_from_query_node_to_blueprint) { + BlueprintFixture f; Node::UP term = f.spec.createNode(57, 67, 77.7); Blueprint::UP bp = f.blueprint(*term); const ParallelWeakAndBlueprint * pbp = dynamic_cast<const ParallelWeakAndBlueprint *>(bp.get()); - EXPECT_EQUAL(57u, pbp->getScores().getScoresToTrack()); - EXPECT_EQUAL(67u, pbp->getScoreThreshold()); - EXPECT_EQUAL(77.7, pbp->getThresholdBoostFactor()); + EXPECT_EQ(57u, pbp->getScores().getScoresToTrack()); + EXPECT_EQ(67u, pbp->getScoreThreshold()); + EXPECT_EQ(77.7, pbp->getThresholdBoostFactor()); } -TEST_F("require that search iterator is correctly setup and executed", BlueprintFixture) +TEST(ParallelWeakAndTest, require_that_search_iterator_is_correctly_setup_and_executed) { + BlueprintFixture f; FakeResult expect = FakeResult() .doc(1).score(1 * 10 + 2 * 20) .doc(2).score(1 * 30) .doc(3).score(2 * 40); - EXPECT_EQUAL(expect, f.search()); + EXPECT_EQ(expect, f.search()); } -TEST_F("require that initial score threshold can be specified (1 hit greater)", BlueprintFixture) +TEST(ParallelWeakAndTest, require_that_initial_score_threshold_can_be_specified_case_1_hit_greater) { + BlueprintFixture f; Node::UP term = f.spec.createNode(3, 50); - EXPECT_EQUAL(FakeResult() - .doc(3).score(2 * 40), f.search(*term)); + EXPECT_EQ(FakeResult() + .doc(3).score(2 * 40), f.search(*term)); } -TEST_F("require that large scores are handled", BlueprintLargeScoresFixture) +TEST(ParallelWeakAndTest, require_that_large_scores_are_handled) { + BlueprintLargeScoresFixture f; Node::UP term = f.spec.createNode(3, 60000L * 70000L); - EXPECT_EQUAL(FakeResult() - .doc(1).score(60000L * 60000L + 70000L * 80000L) - .doc(3).score(70000L * 90000L), f.search(*term)); + EXPECT_EQ(FakeResult() + .doc(1).score(60000L * 60000L + 70000L * 80000L) + .doc(3).score(70000L * 90000L), f.search(*term)); } -TEST_F("require that docid limit is propagated to search iterator", BlueprintFixture()) +TEST(ParallelWeakAndTest, require_that_docid_limit_is_propagated_to_search_iterator) { + BlueprintFixture f1; f1.spec.docIdLimit = 4050; SearchIterator::UP itr = f1.iterator(); const ParallelWeakAndSearch *wand = dynamic_cast<ParallelWeakAndSearch*>(itr.get()); - EXPECT_EQUAL(4050u, wand->getMatchParams().docIdLimit); + EXPECT_EQ(4050u, wand->getMatchParams().docIdLimit); } -TEST_FFF("require that terms are sorted for maximum skipping", - BlueprintHitsFixture(50, 50, 100), - BlueprintHitsFixture(60, 50, 100), - BlueprintHitsFixture(80, 50, 100)) +TEST(ParallelWeakAndTest, require_that_terms_are_sorted_for_maximum_skipping) { + BlueprintHitsFixture f1(50, 50, 100); + BlueprintHitsFixture f2(60, 50, 100); + BlueprintHitsFixture f3(80, 50, 100); EXPECT_TRUE(f1.maxScoreFirst()); EXPECT_TRUE(f2.maxScoreFirst()); EXPECT_FALSE(f3.maxScoreFirst()); } -TEST_FF("require that threshold boosting works as expected", ThresholdBoostFixture(1.0), ThresholdBoostFixture(2.0)) -{ - EXPECT_EQUAL(FakeResult() - .doc(1).score(1000) - .doc(2).score(2000) - .doc(3).score(3000) - .doc(4).score(4200), f1.result); - EXPECT_EQUAL(FakeResult() - .doc(2).score(2000) - .doc(4).score(4200), f2.result); +TEST(ParallelWeakAndTest, require_that_threshold_boosting_works_as_expected) +{ + ThresholdBoostFixture f1(1.0); + ThresholdBoostFixture f2(2.0); + EXPECT_EQ(FakeResult() + .doc(1).score(1000) + .doc(2).score(2000) + .doc(3).score(3000) + .doc(4).score(4200), f1.result); + EXPECT_EQ(FakeResult() + .doc(2).score(2000) + .doc(4).score(4200), f2.result); } -TEST_F("require that asString() on blueprint works", BlueprintAsStringFixture) +TEST(ParallelWeakAndTest, require_that_asString_on_blueprint_works) { + BlueprintAsStringFixture f; Node::UP term = f.spec.createNode(57, 67); Blueprint::UP bp = f.blueprint(*term); vespalib::string expStr = "search::queryeval::ParallelWeakAndBlueprint {\n" @@ -599,6 +628,7 @@ TEST_F("require that asString() on blueprint works", BlueprintAsStringFixture) " tree_size: 2\n" " allow_termwise_eval: false\n" " }\n" + " cost: 1\n" " sourceId: 4294967295\n" " docid_limit: 0\n" " _weights: std::vector {\n" @@ -622,12 +652,13 @@ TEST_F("require that asString() on blueprint works", BlueprintAsStringFixture) " tree_size: 1\n" " allow_termwise_eval: true\n" " }\n" + " cost: 1\n" " sourceId: 4294967295\n" " docid_limit: 0\n" " }\n" " }\n" "}\n"; - EXPECT_EQUAL(expStr, bp->asString()); + EXPECT_EQ(expStr, bp->asString()); } using MatchParams = ParallelWeakAndSearch::MatchParams; @@ -659,7 +690,7 @@ SearchIterator::UP create_wand(bool use_dww, assert(childrenMatchData->getNumTermFields() == dict_entries.size()); wand::Terms terms; for (size_t i = 0; i < dict_entries.size(); ++i) { - terms.push_back(wand::Term(new DocumentWeightSearchIterator(*(childrenMatchData->resolveTermField(handles[i])), attr, dict_entries[i]), + terms.push_back(wand::Term(new DocidWithWeightSearchIterator(*(childrenMatchData->resolveTermField(handles[i])), attr, dict_entries[i]), weights[i], dict_entries[i].posting_size, childrenMatchData->resolveTermField(handles[i]))); @@ -684,11 +715,12 @@ private: mutable DummyHeap _dummy_heap; }; -TEST("verify search iterator conformance") { +TEST(ParallelWeakAndTest, verify_search_iterator_conformance) +{ for (bool use_dww: {false, true}) { Verifier verifier(use_dww); verifier.verify(); } } -TEST_MAIN() { TEST_RUN_ALL(); } +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/searchlib/src/tests/queryeval/queryeval_test.cpp b/searchlib/src/tests/queryeval/queryeval_test.cpp index a403f7a7c23..3fabb45a7ff 100644 --- a/searchlib/src/tests/queryeval/queryeval_test.cpp +++ b/searchlib/src/tests/queryeval/queryeval_test.cpp @@ -1,7 +1,7 @@ // Copyright Vespa.ai. 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/vespalib/regex/regex.h> +#define ENABLE_GTEST_MIGRATION #include <vespa/searchlib/test/initrange.h> #include <vespa/searchlib/queryeval/andnotsearch.h> #include <vespa/searchlib/queryeval/andsearch.h> @@ -19,9 +19,9 @@ #include <vespa/searchlib/query/query_term_simple.h> #include <vespa/searchlib/attribute/singleboolattribute.h> #include <vespa/searchcommon/common/growstrategy.h> -#include <vespa/vespalib/test/insertion_operators.h> #include <vespa/searchlib/fef/fef.h> #include <vespa/vespalib/data/slime/slime.h> +#include <vespa/vespalib/gtest/gtest.h> #include <vespa/log/log.h> LOG_SETUP("query_eval_test"); @@ -87,15 +87,16 @@ std::unique_ptr<sourceselector::Iterator> selector() { void testMultiSearch(SearchIterator & search) { auto & ms = dynamic_cast<MultiSearch &>(search); ms.initRange(3, 309); - EXPECT_EQUAL(2u, ms.getDocId()); - EXPECT_EQUAL(309u, ms.getEndId()); + EXPECT_EQ(2u, ms.getDocId()); + EXPECT_EQ(309u, ms.getEndId()); for (const auto & child : ms.getChildren()) { - EXPECT_EQUAL(2u, child->getDocId()); - EXPECT_EQUAL(309u, child->getEndId()); + EXPECT_EQ(2u, child->getDocId()); + EXPECT_EQ(309u, child->getEndId()); } } -TEST("test that OR.andWith is a NOOP") { +TEST(QueryEvalTest, test_that_or_andwith_is_a_noop) +{ TermFieldMatchData tfmd; MultiSearch::Children ch; ch.emplace_back(new TrueSearch(tfmd)); @@ -106,7 +107,8 @@ TEST("test that OR.andWith is a NOOP") { EXPECT_TRUE(search->andWith(std::move(filter), 1)); } -TEST("test that non-strict AND.andWith is a NOOP") { +TEST(QueryEvalTest, test_that_non_strict_and_andwidth_is_a_noop) +{ TermFieldMatchData tfmd; MultiSearch::Children ch; ch.emplace_back(new TrueSearch(tfmd)); @@ -117,7 +119,8 @@ TEST("test that non-strict AND.andWith is a NOOP") { EXPECT_TRUE(filter); } -TEST("test that strict AND.andWith steals filter and places it correctly based on estimate") { +TEST(QueryEvalTest, test_that_strict_and_andwidth_steals_filter_and_places_it_correctly_based_on_estimate) +{ TermFieldMatchData tfmd; std::vector<SearchIterator *> ch; ch.emplace_back(new TrueSearch(tfmd)); @@ -129,19 +132,19 @@ TEST("test that strict AND.andWith steals filter and places it correctly based o EXPECT_TRUE(nullptr == search->andWith(std::move(filter), 8).get()); const auto & andChildren = dynamic_cast<MultiSearch &>(*search).getChildren(); - EXPECT_EQUAL(3u, andChildren.size()); - EXPECT_EQUAL(ch[0], andChildren[0].get()); - EXPECT_EQUAL(filterP, andChildren[1].get()); - EXPECT_EQUAL(ch[1], andChildren[2].get()); + EXPECT_EQ(3u, andChildren.size()); + EXPECT_EQ(ch[0], andChildren[0].get()); + EXPECT_EQ(filterP, andChildren[1].get()); + EXPECT_EQ(ch[1], andChildren[2].get()); auto filter2 = std::make_unique<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].get()); - EXPECT_EQUAL(ch[0], andChildren[1].get()); - EXPECT_EQUAL(filterP, andChildren[2].get()); - EXPECT_EQUAL(ch[1], andChildren[3].get()); + EXPECT_EQ(4u, andChildren.size()); + EXPECT_EQ(filter2P, andChildren[0].get()); + EXPECT_EQ(ch[0], andChildren[1].get()); + EXPECT_EQ(filterP, andChildren[2].get()); + EXPECT_EQ(ch[1], andChildren[3].get()); } class NonStrictTrueSearch : public TrueSearch @@ -151,7 +154,8 @@ public: [[nodiscard]] Trinary is_strict() const override { return Trinary::False; } }; -TEST("test that strict AND.andWith does not place non-strict iterator first") { +TEST(QueryEvalTest, test_that_strict_and_andwidth_does_not_place_non_strict_iterator_first) +{ TermFieldMatchData tfmd; std::vector<SearchIterator *> ch; ch.emplace_back(new TrueSearch(tfmd)); @@ -162,34 +166,38 @@ TEST("test that strict AND.andWith does not place non-strict iterator first") { SearchIterator * filterP = filter.get(); EXPECT_TRUE(nullptr == search->andWith(std::move(filter), 6).get()); const auto & andChildren = dynamic_cast<MultiSearch &>(*search).getChildren(); - EXPECT_EQUAL(3u, andChildren.size()); - EXPECT_EQUAL(ch[0], andChildren[0].get()); - EXPECT_EQUAL(filterP, andChildren[1].get()); - EXPECT_EQUAL(ch[1], andChildren[2].get()); + EXPECT_EQ(3u, andChildren.size()); + EXPECT_EQ(ch[0], andChildren[0].get()); + EXPECT_EQ(filterP, andChildren[1].get()); + EXPECT_EQ(ch[1], andChildren[2].get()); } -TEST("test that strict rank search forwards to its greedy first child") { +TEST(QueryEvalTest, test_that_strict_rank_search_forwards_to_its_greedy_first_child) +{ TermFieldMatchData tfmd; SearchIterator::UP search = RankSearch::create({ AndSearch::create(search2("a", "b"), true), new TrueSearch(tfmd) }, true); auto filter = std::make_unique<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") { +TEST(QueryEvalTest, test_that_non_strict_rank_search_does_not_forward_to_its_greedy_first_child) +{ TermFieldMatchData tfmd; SearchIterator::UP search = RankSearch::create({ AndSearch::create(search2("a", "b"), true), new TrueSearch(tfmd) }, false); auto filter = std::make_unique<TrueSearch>(tfmd); EXPECT_TRUE(nullptr != search->andWith(std::move(filter), 8).get()); } -TEST("test that strict andnot search forwards to its greedy first child") { +TEST(QueryEvalTest, test_that_strict_andnot_search_forwards_to_its_greedy_first_child) +{ TermFieldMatchData tfmd; SearchIterator::UP search = AndNotSearch::create({ AndSearch::create(search2("a", "b"), true), new TrueSearch(tfmd) }, true); auto filter = std::make_unique<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") { +TEST(QueryEvalTest, test_that_non_strict_andnot_search_does_not_forward_to_its_greedy_first_child) +{ TermFieldMatchData tfmd; SearchIterator::UP search = AndNotSearch::create({ AndSearch::create(search2("a", "b"), true), new TrueSearch(tfmd) }, false); auto filter = std::make_unique<TrueSearch>(tfmd); @@ -199,13 +207,10 @@ TEST("test that non-strict andnot search does NOT forward to its greedy first ch void expect_match(std::string input, std::string regexp) { using vespalib::Regex; Regex pattern = Regex::from_pattern(regexp, Regex::Options::DotMatchesNewline); - if (! EXPECT_TRUE(pattern.partial_match(input))) { - fprintf(stderr, "no match for pattern: >>>%s<<< in input:\n>>>\n%s\n<<<\n", - regexp.c_str(), input.c_str()); - } + EXPECT_TRUE(pattern.partial_match(input)) << "no match for pattern: >>>" << regexp << "<<< in input: >>>\n" << input << "<<<"; } -TEST("testAnd") { +TEST(QueryEvalTest, test_and) { SimpleResult a; SimpleResult b; a.addHit(5).addHit(10).addHit(16).addHit(30); @@ -219,17 +224,17 @@ TEST("testAnd") { SearchIterator::UP and_ab = and_b->createSearch(*md, true); EXPECT_TRUE(dynamic_cast<const AndSearch *>(and_ab.get()) != nullptr); - EXPECT_EQUAL(4u, dynamic_cast<AndSearch &>(*and_ab).estimate()); + EXPECT_EQ(4u, dynamic_cast<AndSearch &>(*and_ab).estimate()); SimpleResult res; res.search(*and_ab); SimpleResult expect; expect.addHit(5).addHit(30); - EXPECT_EQUAL(res, expect); + EXPECT_EQ(res, expect); SearchIterator::UP filter_ab = and_b->createFilterSearch(true, upper_bound); SimpleResult filter_res; filter_res.search(*filter_ab); - EXPECT_EQUAL(res, expect); + EXPECT_EQ(res, expect); std::string dump = filter_ab->asString(); expect_match(dump, "upper"); expect_match(dump, "AndSearchStrict.*NoUnpack.*SimpleSearch.*upper.*SimpleSearch.*upper"); @@ -239,10 +244,8 @@ TEST("testAnd") { expect_match(dump, "AndSearchNoStrict.*NoUnpack.*SimpleSearch.*lower.*SimpleSearch.*lower"); } -TEST("mutisearch and initRange") { -} - -TEST("testOr") { +TEST(QueryEvalTest, test_or) +{ { SimpleResult a; SimpleResult b; @@ -260,12 +263,12 @@ TEST("testOr") { res.search(*or_ab); SimpleResult expect; expect.addHit(5).addHit(10).addHit(17).addHit(30); - EXPECT_EQUAL(res, expect); + EXPECT_EQ(res, expect); SearchIterator::UP filter_ab = or_b->createFilterSearch(true, upper_bound); SimpleResult filter_res; filter_res.search(*filter_ab); - EXPECT_EQUAL(res, expect); + EXPECT_EQ(res, expect); std::string dump = filter_ab->asString(); expect_match(dump, "upper"); expect_match(dump, "OrLikeSearch.true.*NoUnpack.*SimpleSearch.*upper.*SimpleSearch.*upper"); @@ -305,34 +308,35 @@ struct MultiSearchRemoveTest { static SearchIterator::UP remove(MultiSearch &ms, size_t idx) { return ms.remove(idx); } }; -TEST("testMultiSearch") { +TEST(QueryEvalTest, test_multi_search) +{ std::vector<SearchIterator *> orig; orig.emplace_back(new EmptySearch()); orig.emplace_back(new EmptySearch()); orig.emplace_back(new EmptySearch()); TestInsertRemoveSearch ms({orig[0], orig[1], orig[2]}); - EXPECT_EQUAL(3u, ms.getChildren().size()); - EXPECT_EQUAL(orig[0], ms.getChildren()[0].get()); - EXPECT_EQUAL(orig[1], ms.getChildren()[1].get()); - EXPECT_EQUAL(orig[2], ms.getChildren()[2].get()); - EXPECT_EQUAL(0u, ms._accumInsert); - EXPECT_EQUAL(0u, ms._accumRemove); - - EXPECT_EQUAL(orig[1], MultiSearchRemoveTest::remove(ms, 1).get()); - EXPECT_EQUAL(2u, ms.getChildren().size()); - EXPECT_EQUAL(orig[0], ms.getChildren()[0].get()); - EXPECT_EQUAL(orig[2], ms.getChildren()[1].get()); - EXPECT_EQUAL(0u, ms._accumInsert); - EXPECT_EQUAL(1u, ms._accumRemove); + EXPECT_EQ(3u, ms.getChildren().size()); + EXPECT_EQ(orig[0], ms.getChildren()[0].get()); + EXPECT_EQ(orig[1], ms.getChildren()[1].get()); + EXPECT_EQ(orig[2], ms.getChildren()[2].get()); + EXPECT_EQ(0u, ms._accumInsert); + EXPECT_EQ(0u, ms._accumRemove); + + EXPECT_EQ(orig[1], MultiSearchRemoveTest::remove(ms, 1).get()); + EXPECT_EQ(2u, ms.getChildren().size()); + EXPECT_EQ(orig[0], ms.getChildren()[0].get()); + EXPECT_EQ(orig[2], ms.getChildren()[1].get()); + EXPECT_EQ(0u, ms._accumInsert); + EXPECT_EQ(1u, ms._accumRemove); orig.emplace_back(new EmptySearch()); ms.insert(1, SearchIterator::UP(orig.back())); - EXPECT_EQUAL(3u, ms.getChildren().size()); - EXPECT_EQUAL(orig[0], ms.getChildren()[0].get()); - EXPECT_EQUAL(orig[3], ms.getChildren()[1].get()); - EXPECT_EQUAL(orig[2], ms.getChildren()[2].get()); - EXPECT_EQUAL(1u, ms._accumInsert); - EXPECT_EQUAL(1u, ms._accumRemove); + EXPECT_EQ(3u, ms.getChildren().size()); + EXPECT_EQ(orig[0], ms.getChildren()[0].get()); + EXPECT_EQ(orig[3], ms.getChildren()[1].get()); + EXPECT_EQ(orig[2], ms.getChildren()[2].get()); + EXPECT_EQ(1u, ms._accumInsert); + EXPECT_EQ(1u, ms._accumRemove); } class DummySingleValueBitNumericAttributeBlueprint : public SimpleLeafBlueprint @@ -370,7 +374,8 @@ private: }; -TEST("testAndNot") { +TEST(QueryEvalTest, test_andnot) +{ { SimpleResult a; SimpleResult b; @@ -388,12 +393,12 @@ TEST("testAndNot") { res.search(*andnot_ab); SimpleResult expect; expect.addHit(10); - EXPECT_EQUAL(res, expect); + EXPECT_EQ(res, expect); SearchIterator::UP filter_ab = andnot_b->createFilterSearch(true, upper_bound); SimpleResult filter_res; filter_res.search(*filter_ab); - EXPECT_EQUAL(res, expect); + EXPECT_EQ(res, expect); std::string dump = filter_ab->asString(); expect_match(dump, "upper"); expect_match(dump, "AndNotSearch.*SimpleSearch.*<strict,upper>.*SimpleSearch.*<nostrict,lower>"); @@ -420,7 +425,7 @@ TEST("testAndNot") { SimpleResult expect; expect.addHit(1).addHit(10); - EXPECT_EQUAL(res, expect); + EXPECT_EQ(res, expect); } { SimpleResult a; @@ -446,13 +451,14 @@ TEST("testAndNot") { SimpleResult expect; expect.addHit(1).addHit(10); - EXPECT_EQUAL(res, expect); + EXPECT_EQ(res, expect); } { } } -TEST("testRank") { +TEST(QueryEvalTest, test_rank) +{ { SimpleResult a; SimpleResult b; @@ -471,7 +477,7 @@ TEST("testRank") { SimpleResult expect; expect.addHit(5).addHit(10).addHit(16).addHit(30); - EXPECT_EQUAL(res, expect); + EXPECT_EQ(res, expect); } } @@ -600,7 +606,8 @@ getExpectedSlime() { "}"; } -TEST("testDump") { +TEST(QueryEvalTest, test_dump) +{ using SBChild = SourceBlenderSearch::Child; SearchIterator::UP search = AndSearch::create( { @@ -622,13 +629,13 @@ TEST("testDump") { auto s = slime.toString(); vespalib::Slime expectedSlime; vespalib::slime::JsonFormat::decode(getExpectedSlime(), expectedSlime); - EXPECT_EQUAL(expectedSlime, slime); + EXPECT_EQ(expectedSlime, slime); // fprintf(stderr, "%s", search->asString().c_str()); } -TEST("testFieldSpec") { - EXPECT_EQUAL(8u, sizeof(FieldSpecBase)); - EXPECT_EQUAL(72u, sizeof(FieldSpec)); +TEST(QueryEvalTest, test_field_spec) { + EXPECT_EQ(8u, sizeof(FieldSpecBase)); + EXPECT_EQ(72u, sizeof(FieldSpec)); } @@ -652,9 +659,9 @@ std::vector<size_t> fill_vector(size_t begin, size_t end) { 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); + EXPECT_EQ(unpack.empty(), expect.empty()); + EXPECT_EQ(unpack.unpackAll(), (expect.size() == unpack_child_cnt)); + EXPECT_EQ(expect, actual); size_t child_idx = 0; for (size_t next_unpack: expect) { while (child_idx < next_unpack) { @@ -664,19 +671,23 @@ void verify_unpack(const UnpackInfo &unpack, const std::vector<size_t> &expect) } } -TEST("require that unpack info has expected memory footprint") { - EXPECT_EQUAL(32u, sizeof(UnpackInfo)); +TEST(QueryEvalTest, require_that_unpack_info_has_expected_memory_footprint) +{ + EXPECT_EQ(32u, sizeof(UnpackInfo)); } -TEST("require that unpack info starts out empty") { +TEST(QueryEvalTest, require_that_unpack_info_starts_out_empty) +{ verify_unpack(UnpackInfo(), {}); } -TEST("require that unpack info force all unpacks all children") { +TEST(QueryEvalTest, 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") { +TEST(QueryEvalTest, require_that_adding_a_large_index_to_unpack_info_forces_unpack_all) +{ UnpackInfo unpack; unpack.add(0); unpack.add(max_unpack_index); @@ -685,7 +696,8 @@ TEST("require that adding a large index to unpack info forces unpack all") { verify_unpack(unpack, fill_vector(0, unpack_child_cnt)); } -TEST("require that adding too many children to unpack info forces unpack all") { +TEST(QueryEvalTest, 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) { @@ -697,19 +709,22 @@ TEST("require that adding too many children to unpack info forces unpack all") { verify_unpack(unpack, fill_vector(0, unpack_child_cnt)); } -TEST("require that adding normal unpack info indexes works") { +TEST(QueryEvalTest, 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") { +TEST(QueryEvalTest, 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") { +TEST(QueryEvalTest, require_that_basic_insert_remove_of_unpack_info_works) +{ UnpackInfo unpack; unpack.insert(1).insert(3); verify_unpack(unpack, {1, 3}); @@ -729,7 +744,8 @@ TEST("require that basic insert remove of unpack info works") { verify_unpack(unpack, {}); } -TEST("require that inserting too many indexs into unpack info forces unpack all") { +TEST(QueryEvalTest, require_that_inserting_too_many_indexes_into_unpack_info_forces_unpack_all) +{ for (bool unpack_inserted: {true, false}) { UnpackInfo unpack; for (size_t i = 0; i < max_unpack_size; ++i) { @@ -745,7 +761,8 @@ TEST("require that inserting too many indexs into unpack info forces unpack all" } } -TEST("require that implicitly overflowing indexes during insert in unpack info forces unpack all") { +TEST(QueryEvalTest, 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); @@ -755,7 +772,8 @@ TEST("require that implicitly overflowing indexes during insert in unpack info f } } -TEST("require that inserting a too high index into unpack info forces unpack all") { +TEST(QueryEvalTest, 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) { @@ -771,7 +789,7 @@ TEST("require that inserting a too high index into unpack info forces unpack all } } -TEST("require that we can insert indexes into unpack info that we do not unpack") { +TEST(QueryEvalTest, 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}); @@ -779,65 +797,85 @@ TEST("require that we can insert indexes into unpack info that we do not unpack" verify_unpack(unpack, {11, 22, 33}); } -TEST("testTrueSearch") { - EXPECT_EQUAL(16u, sizeof(EmptySearch)); - EXPECT_EQUAL(24u, sizeof(TrueSearch)); +TEST(QueryEvalTest, test_true_search) +{ + EXPECT_EQ(16u, sizeof(EmptySearch)); + EXPECT_EQ(24u, sizeof(TrueSearch)); TermFieldMatchData tfmd; TrueSearch t(tfmd); - EXPECT_EQUAL(0u, t.getDocId()); - EXPECT_EQUAL(0u, t.getEndId()); + EXPECT_EQ(0u, t.getDocId()); + EXPECT_EQ(0u, t.getEndId()); t.initRange(7, 10); - EXPECT_EQUAL(6u, t.getDocId()); - EXPECT_EQUAL(10u, t.getEndId()); + EXPECT_EQ(6u, t.getDocId()); + EXPECT_EQ(10u, t.getEndId()); EXPECT_TRUE(t.seek(9)); - EXPECT_EQUAL(9u, t.getDocId()); + EXPECT_EQ(9u, t.getDocId()); EXPECT_FALSE(t.isAtEnd()); EXPECT_TRUE(t.seek(10)); - EXPECT_EQUAL(10u, t.getDocId()); + EXPECT_EQ(10u, t.getDocId()); EXPECT_TRUE(t.isAtEnd()); t.initRange(4, 14); - EXPECT_EQUAL(3u, t.getDocId()); - EXPECT_EQUAL(14u, t.getEndId()); + EXPECT_EQ(3u, t.getDocId()); + EXPECT_EQ(14u, t.getEndId()); EXPECT_FALSE(t.isAtEnd()); } -TEST("test InitRangeVerifier") { +TEST(QueryEvalTest, test_init_range_verifier) +{ InitRangeVerifier ir; - EXPECT_EQUAL(207u, ir.getDocIdLimit()); - EXPECT_EQUAL(41u, ir.getExpectedDocIds().size()); + EXPECT_EQ(207u, ir.getDocIdLimit()); + EXPECT_EQ(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]); + EXPECT_EQ(numInverted, inverted.size()); + EXPECT_EQ(2u, inverted[0]); + EXPECT_EQ(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") { +TEST(QueryEvalTest, test_multisearch_and_andsearchstrict_iterators_adheres_to_init_range) +{ InitRangeVerifier ir; - ir.verify( AndSearch::create({ ir.createIterator(ir.getExpectedDocIds(), false), - ir.createFullIterator() }, false)); - - ir.verify( AndSearch::create({ ir.createIterator(ir.getExpectedDocIds(), true), - ir.createFullIterator() }, true)); + { + SCOPED_TRACE("non-strict"); + ir.verify( AndSearch::create({ ir.createIterator(ir.getExpectedDocIds(), false), + ir.createFullIterator() }, false)); + } + { + SCOPED_TRACE("strict"); + ir.verify( AndSearch::create({ ir.createIterator(ir.getExpectedDocIds(), true), + ir.createFullIterator() }, true)); + } } -TEST("Test andnotsearchstrict iterators adheres to initRange") { +TEST(QueryEvalTest, test_andnotsearchstrict_iterators_adheres_to_init_range) { InitRangeVerifier ir; - - TEST_DO(ir.verify( AndNotSearch::create({ir.createIterator(ir.getExpectedDocIds(), false), - ir.createEmptyIterator() }, false))); - TEST_DO(ir.verify( AndNotSearch::create({ir.createIterator(ir.getExpectedDocIds(), true), - ir.createEmptyIterator() }, true))); + + { + SCOPED_TRACE("non-strict"); + ir.verify( AndNotSearch::create({ir.createIterator(ir.getExpectedDocIds(), false), + ir.createEmptyIterator() }, false)); + } + { + SCOPED_TRACE("strict"); + ir.verify( AndNotSearch::create({ir.createIterator(ir.getExpectedDocIds(), true), + ir.createEmptyIterator() }, true)); + } auto inverted = InitRangeVerifier::invert(ir.getExpectedDocIds(), ir.getDocIdLimit()); - TEST_DO(ir.verify( AndNotSearch::create({ir.createFullIterator(), - ir.createIterator(inverted, false) }, false))); - TEST_DO(ir.verify( AndNotSearch::create({ir.createFullIterator(), - ir.createIterator(inverted, false) }, true))); + { + SCOPED_TRACE("non-strict full"); + ir.verify( AndNotSearch::create({ir.createFullIterator(), + ir.createIterator(inverted, false) }, false)); + } + { + SCOPED_TRACE("strict full"); + ir.verify( AndNotSearch::create({ir.createFullIterator(), + ir.createIterator(inverted, false) }, true)); + } } -TEST_MAIN() { TEST_RUN_ALL(); } +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/searchlib/src/tests/queryeval/same_element/same_element_test.cpp b/searchlib/src/tests/queryeval/same_element/same_element_test.cpp index d05e6c8e4f4..7c535e5d3d5 100644 --- a/searchlib/src/tests/queryeval/same_element/same_element_test.cpp +++ b/searchlib/src/tests/queryeval/same_element/same_element_test.cpp @@ -46,7 +46,7 @@ std::unique_ptr<SameElementBlueprint> make_blueprint(const std::vector<FakeResul } Blueprint::UP finalize(Blueprint::UP bp, bool strict) { - Blueprint::UP result = Blueprint::optimize(std::move(bp)); + Blueprint::UP result = Blueprint::optimize(std::move(bp), true); result->fetchPostings(ExecuteInfo::createForTest(strict)); result->freeze(); return result; diff --git a/searchlib/src/tests/queryeval/termwise_eval/termwise_eval_test.cpp b/searchlib/src/tests/queryeval/termwise_eval/termwise_eval_test.cpp index 3ca35221c50..3a10ed6df53 100644 --- a/searchlib/src/tests/queryeval/termwise_eval/termwise_eval_test.cpp +++ b/searchlib/src/tests/queryeval/termwise_eval/termwise_eval_test.cpp @@ -1,5 +1,4 @@ // Copyright Vespa.ai. 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/vespalib/util/stringfmt.h> #include <vespa/searchlib/queryeval/searchiterator.h> #include <vespa/searchlib/queryeval/andnotsearch.h> @@ -8,11 +7,12 @@ #include <vespa/searchlib/queryeval/termwise_search.h> #include <vespa/searchlib/queryeval/intermediate_blueprints.h> #include <vespa/searchlib/queryeval/termwise_blueprint_helper.h> -#include <vespa/vespalib/test/insertion_operators.h> +#define ENABLE_GTEST_MIGRATION #include <vespa/searchlib/test/searchiteratorverifier.h> #include <vespa/searchlib/common/bitvectoriterator.h> #include <vespa/searchlib/fef/matchdata.h> #include <vespa/vespalib/objects/visit.hpp> +#include <vespa/vespalib/gtest/gtest.h> using namespace vespalib; using namespace search; @@ -192,7 +192,10 @@ std::vector<uint32_t> make_expect(uint32_t begin, uint32_t end) { return expect; } -void verify(const std::vector<uint32_t> &expect, SearchIterator &search, uint32_t begin, uint32_t end) { +void +verify(const std::vector<uint32_t> &expect, SearchIterator &search, uint32_t begin, uint32_t end, const vespalib::string& label) +{ + SCOPED_TRACE(label); std::vector<uint32_t> actual; search.initRange(begin, end); for (uint32_t docid = begin; docid < end; ++docid) { @@ -200,7 +203,7 @@ void verify(const std::vector<uint32_t> &expect, SearchIterator &search, uint32_ actual.push_back(docid); } } - EXPECT_EQUAL(expect, actual); + EXPECT_EQ(expect, actual); } //----------------------------------------------------------------------------- @@ -213,95 +216,107 @@ MatchData::UP make_match_data() { //----------------------------------------------------------------------------- -TEST("require that pseudo term produces correct results") { - TEST_DO(verify({1,2,3,4,5}, *UP(TERM({1,2,3,4,5}, true)), 1, 6)); - TEST_DO(verify({1,2,3,4,5}, *UP(TERM({1,2,3,4,5}, false)), 1, 6)); - TEST_DO(verify({3,4,5}, *UP(TERM({1,2,3,4,5}, true)), 3, 6)); - TEST_DO(verify({3,4,5}, *UP(TERM({1,2,3,4,5}, false)), 3, 6)); - TEST_DO(verify({1,2,3}, *UP(TERM({1,2,3,4,5}, true)), 1, 4)); - TEST_DO(verify({1,2,3}, *UP(TERM({1,2,3,4,5}, false)), 1, 4)); +TEST(TermwiseEvalTest, require_that_pseudo_term_produces_correct_results) +{ + verify({1,2,3,4,5}, *UP(TERM({1,2,3,4,5}, true)), 1, 6, "strict full"); + verify({1,2,3,4,5}, *UP(TERM({1,2,3,4,5}, false)), 1, 6, "non-strict full"); + verify({3,4,5}, *UP(TERM({1,2,3,4,5}, true)), 3, 6, "strict last"); + verify({3,4,5}, *UP(TERM({1,2,3,4,5}, false)), 3, 6, "non-strict last"); + verify({1,2,3}, *UP(TERM({1,2,3,4,5}, true)), 1, 4, "strict first"); + verify({1,2,3}, *UP(TERM({1,2,3,4,5}, false)), 1, 4, "non-strict first"); } -TEST("require that normal search gives expected results") { +TEST(TermwiseEvalTest, require_that_normal_search_gives_expected_results) +{ auto search = make_search(true); - TEST_DO(verify(make_expect(1, 10), *search, 1, 10)); + verify(make_expect(1, 10), *search, 1, 10, "strict normal"); } -TEST("require that filter search gives expected results") { +TEST(TermwiseEvalTest, require_that_filter_search_gives_expected_results) +{ auto search = make_filter_search(true); - TEST_DO(verify(make_expect(1, 10), *search, 1, 10)); + verify(make_expect(1, 10), *search, 1, 10, "strict filter"); } -TEST("require that termwise AND/OR search produces appropriate results") { +TEST(TermwiseEvalTest, require_that_termwise_and_or_or_search_produces_appropriate_results) +{ for (uint32_t begin: {1, 2, 5}) { for (uint32_t end: {6, 7, 10}) { for (bool strict_search: {true, false}) { for (bool strict_wrapper: {true, false}) { - TEST_STATE(make_string("begin: %u, end: %u, strict_search: %s, strict_wrapper: %s", - begin, end, strict_search ? "true" : "false", - strict_wrapper ? "true" : "false").c_str()); + auto label = make_string("begin: %u, end: %u, strict_search: %s, strict_wrapper: %s", + begin, end, strict_search ? "true" : "false", + strict_wrapper ? "true" : "false"); auto search = make_termwise(make_search(strict_search), strict_wrapper); - TEST_DO(verify(make_expect(begin, end), *search, begin, end)); + verify(make_expect(begin, end), *search, begin, end, label); } } } } } -TEST("require that termwise filter search produces appropriate results") { +TEST(TermwiseEvalTest, require_that_termwise_filter_search_produces_appropriate_results) +{ for (uint32_t begin: {1, 2, 5}) { for (uint32_t end: {6, 7, 10}) { for (bool strict_search: {true, false}) { for (bool strict_wrapper: {true, false}) { - TEST_STATE(make_string("begin: %u, end: %u, strict_search: %s, strict_wrapper: %s", - begin, end, strict_search ? "true" : "false", - strict_wrapper ? "true" : "false").c_str()); + auto label = make_string("begin: %u, end: %u, strict_search: %s, strict_wrapper: %s", + begin, end, strict_search ? "true" : "false", + strict_wrapper ? "true" : "false"); auto search = make_termwise(make_filter_search(strict_search), strict_wrapper); - TEST_DO(verify(make_expect(begin, end), *search, begin, end)); + verify(make_expect(begin, end), *search, begin, end, label); } } } } } -TEST("require that termwise ANDNOT with single term works") { - TEST_DO(verify({2,3,4}, *make_termwise(ANDNOT({ TERM({1,2,3,4,5}, true) }, true), true), 2, 5)); +TEST(TermwiseEvalTest, require_that_termwise_andnot_with_single_term_works) +{ + verify({2,3,4}, *make_termwise(ANDNOT({ TERM({1,2,3,4,5}, true) }, true), true), 2, 5, "termwise andnot"); } -TEST("require that pseudo term is rewindable") { +TEST(TermwiseEvalTest, require_that_pseudo_term_is_rewindable) +{ auto search = UP(TERM({1,2,3,4,5}, true)); - TEST_DO(verify({3,4,5}, *search, 3, 6)); - TEST_DO(verify({1,2,3,4}, *search, 1, 5)); + verify({3,4,5}, *search, 3, 6, "pseudo term end"); + verify({1,2,3,4}, *search, 1, 5, "pseudo term rewound to start"); } -TEST("require that termwise wrapper is rewindable") { +TEST(TermwiseEvalTest, require_that_termwise_wrapper_is_rewindable) +{ auto search = make_termwise(make_search(true), true); - TEST_DO(verify(make_expect(3, 7), *search, 3, 7)); - TEST_DO(verify(make_expect(1, 5), *search, 1, 5)); + verify(make_expect(3, 7), *search, 3, 7, "termwise wrapper end"); + verify(make_expect(1, 5), *search, 1, 5, "termwise wrapper rewound to start"); } //----------------------------------------------------------------------------- -TEST("require that leaf blueprints allow termwise evaluation by default") { +TEST(TermwiseEvalTest, require_that_leaf_blueprints_allow_termwise_evaluation_by_default) +{ MyBlueprint bp({}); EXPECT_TRUE(bp.getState().allow_termwise_eval()); } -TEST("require that leaf blueprints can enable/disable termwise evaluation") { +TEST(TermwiseEvalTest, require_that_leaf_blueprints_can_enable_and_disable_termwise_evaluation) +{ MyBlueprint enable({}, true); MyBlueprint disable({}, false); EXPECT_TRUE(enable.getState().allow_termwise_eval()); EXPECT_FALSE(disable.getState().allow_termwise_eval()); } -TEST("require that intermediate blueprints disallow termwise evaluation by default") { +TEST(TermwiseEvalTest, require_that_intermediate_blueprints_disallow_termwise_evaluation_by_default) +{ MyOr bp(false); bp.addChild(UP(new MyBlueprint({}, true))); bp.addChild(UP(new MyBlueprint({}, true))); EXPECT_FALSE(bp.getState().allow_termwise_eval()); } -TEST("require that intermediate blueprints can enable/disable termwise evaluation") { +TEST(TermwiseEvalTest, require_that_intermediate_blueprints_can_enable_and_disable_termwise_evaluation) +{ MyOr enable(true, true); enable.addChild(UP(new MyBlueprint({}, true))); enable.addChild(UP(new MyBlueprint({}, true))); @@ -312,7 +327,8 @@ TEST("require that intermediate blueprints can enable/disable termwise evaluatio EXPECT_FALSE(disable.getState().allow_termwise_eval()); } -TEST("require that intermediate blueprints cannot be termwise unless all its children are termwise") { +TEST(TermwiseEvalTest, require_that_intermediate_blueprints_cannot_be_termwise_unless_all_its_children_are_termwise) +{ MyOr bp(true, true); bp.addChild(UP(new MyBlueprint({}, true))); bp.addChild(UP(new MyBlueprint({}, false))); @@ -321,27 +337,30 @@ TEST("require that intermediate blueprints cannot be termwise unless all its chi //----------------------------------------------------------------------------- -TEST("require that leafs have tree size 1") { +TEST(TermwiseEvalTest, require_that_leafs_have_tree_size_1) +{ MyBlueprint bp({}); - EXPECT_EQUAL(1u, bp.getState().tree_size()); + EXPECT_EQ(1u, bp.getState().tree_size()); } -TEST("require that tree size is accumulated correctly by intermediate nodes") { +TEST(TermwiseEvalTest, require_that_tree_size_is_accumulated_correctly_by_intermediate_nodes) +{ MyOr bp(false); - EXPECT_EQUAL(1u, bp.getState().tree_size()); + EXPECT_EQ(1u, bp.getState().tree_size()); bp.addChild(UP(new MyBlueprint({}))); bp.addChild(UP(new MyBlueprint({}))); - EXPECT_EQUAL(3u, bp.getState().tree_size()); + EXPECT_EQ(3u, bp.getState().tree_size()); auto child = UP(new MyOr(false)); child->addChild(UP(new MyBlueprint({}))); child->addChild(UP(new MyBlueprint({}))); bp.addChild(std::move(child)); - EXPECT_EQUAL(6u, bp.getState().tree_size()); + EXPECT_EQ(6u, bp.getState().tree_size()); } //----------------------------------------------------------------------------- -TEST("require that any blueprint node can obtain the root") { +TEST(TermwiseEvalTest, require_that_any_blueprint_node_can_obtain_the_root) +{ MyOr bp(false); bp.addChild(UP(new MyBlueprint({1,2,3}))); bp.addChild(UP(new MyBlueprint({1,2,3,4,5,6}))); @@ -354,35 +373,38 @@ TEST("require that any blueprint node can obtain the root") { //----------------------------------------------------------------------------- -TEST("require that match data keeps track of the termwise limit") { +TEST(TermwiseEvalTest, require_that_match_data_keeps_track_of_the_termwise_limit) +{ auto md = make_match_data(); - EXPECT_EQUAL(1.0, md->get_termwise_limit()); + EXPECT_EQ(1.0, md->get_termwise_limit()); md->set_termwise_limit(0.03); - EXPECT_EQUAL(0.03, md->get_termwise_limit()); + EXPECT_EQ(0.03, md->get_termwise_limit()); } //----------------------------------------------------------------------------- -TEST("require that terwise test search string dump is detailed enough") { - EXPECT_EQUAL(make_termwise(OR({ TERM({1,2,3}, true), TERM({2,3}, true), TERM({3}, true) }, true), true)->asString(), - make_termwise(OR({ TERM({1,2,3}, true), TERM({2,3}, true), TERM({3}, true) }, true), true)->asString()); +TEST(TermwiseEvalTest, require_that_terwise_test_search_string_dump_is_detailed_enough) +{ + EXPECT_EQ(make_termwise(OR({ TERM({1,2,3}, true), TERM({2,3}, true), TERM({3}, true) }, true), true)->asString(), + make_termwise(OR({ TERM({1,2,3}, true), TERM({2,3}, true), TERM({3}, true) }, true), true)->asString()); - EXPECT_NOT_EQUAL(make_termwise(OR({ TERM({1,2,3}, true), TERM({2,3}, true), TERM({3}, true) }, true), true)->asString(), - make_termwise(OR({ TERM({1,2,3}, true), TERM({2,3}, false), TERM({3}, true) }, true), true)->asString()); + EXPECT_NE(make_termwise(OR({ TERM({1,2,3}, true), TERM({2,3}, true), TERM({3}, true) }, true), true)->asString(), + make_termwise(OR({ TERM({1,2,3}, true), TERM({2,3}, false), TERM({3}, true) }, true), true)->asString()); - EXPECT_NOT_EQUAL(make_termwise(OR({ TERM({1,2,3}, true), TERM({2,3}, true), TERM({3}, true) }, true), true)->asString(), - make_termwise(OR({ TERM({1,2,3}, true), TERM({2,3}, true), TERM({3}, true) }, false), true)->asString()); + EXPECT_NE(make_termwise(OR({ TERM({1,2,3}, true), TERM({2,3}, true), TERM({3}, true) }, true), true)->asString(), + make_termwise(OR({ TERM({1,2,3}, true), TERM({2,3}, true), TERM({3}, true) }, false), true)->asString()); - EXPECT_NOT_EQUAL(make_termwise(OR({ TERM({1,2,3}, true), TERM({2,3}, true), TERM({3}, true) }, true), true)->asString(), - make_termwise(OR({ TERM({1,2,3}, true), TERM({2,3}, true), TERM({3}, true) }, true), false)->asString()); + EXPECT_NE(make_termwise(OR({ TERM({1,2,3}, true), TERM({2,3}, true), TERM({3}, true) }, true), true)->asString(), + make_termwise(OR({ TERM({1,2,3}, true), TERM({2,3}, true), TERM({3}, true) }, true), false)->asString()); - EXPECT_NOT_EQUAL(make_termwise(OR({ TERM({1,2,3}, true), TERM({2,3}, true), TERM({3}, true) }, true), true)->asString(), - make_termwise(OR({ TERM({1,2,3}, true), TERM({3}, true), TERM({2,3}, true) }, true), true)->asString()); + EXPECT_NE(make_termwise(OR({ TERM({1,2,3}, true), TERM({2,3}, true), TERM({3}, true) }, true), true)->asString(), + make_termwise(OR({ TERM({1,2,3}, true), TERM({3}, true), TERM({2,3}, true) }, true), true)->asString()); } //----------------------------------------------------------------------------- -TEST("require that basic termwise evaluation works") { +TEST(TermwiseEvalTest, require_that_basic_termwise_evaluation_works) +{ auto md = make_match_data(); md->set_termwise_limit(0.0); md->resolveTermField(1)->tagAsNotNeeded(); @@ -391,12 +413,13 @@ TEST("require that basic termwise evaluation works") { my_or.addChild(UP(new MyBlueprint({1}, true, 1))); my_or.addChild(UP(new MyBlueprint({2}, true, 2))); for (bool strict: {true, false}) { - EXPECT_EQUAL(my_or.createSearch(*md, strict)->asString(), - make_termwise(OR({ TERM({1}, strict), TERM({2}, strict) }, strict), strict)->asString()); + EXPECT_EQ(my_or.createSearch(*md, strict)->asString(), + make_termwise(OR({ TERM({1}, strict), TERM({2}, strict) }, strict), strict)->asString()); } } -TEST("require that the hit rate must be high enough for termwise evaluation to be activated") { +TEST(TermwiseEvalTest, require_that_the_hit_rate_must_be_high_enough_for_termwise_evaluation_to_be_activated) +{ auto md = make_match_data(); md->set_termwise_limit(1.0); // <- md->resolveTermField(1)->tagAsNotNeeded(); @@ -409,7 +432,8 @@ TEST("require that the hit rate must be high enough for termwise evaluation to b } } -TEST("require that enough unranked termwise terms are present for termwise evaluation to be activated") { +TEST(TermwiseEvalTest, require_that_enough_unranked_termwise_terms_are_present_for_termwise_evaluation_to_be_activated) +{ auto md = make_match_data(); md->set_termwise_limit(0.0); md->resolveTermField(1)->tagAsNotNeeded(); @@ -423,29 +447,31 @@ TEST("require that enough unranked termwise terms are present for termwise evalu } } -TEST("require that termwise evaluation can be multi-level, but not duplicated") { +TEST(TermwiseEvalTest, require_that_termwise_evaluation_can_be_multi_level_but_not_duplicated) +{ auto md = make_match_data(); md->set_termwise_limit(0.0); md->resolveTermField(1)->tagAsNotNeeded(); md->resolveTermField(2)->tagAsNotNeeded(); md->resolveTermField(3)->tagAsNotNeeded(); OrBlueprint my_or; - my_or.addChild(UP(new MyBlueprint({1}, true, 1))); + my_or.addChild(UP(new MyBlueprint({1}, true, 1))); auto child = UP(new OrBlueprint()); child->addChild(UP(new MyBlueprint({2}, true, 2))); child->addChild(UP(new MyBlueprint({3}, true, 3))); my_or.addChild(std::move(child)); for (bool strict: {true, false}) { - EXPECT_EQUAL(my_or.createSearch(*md, strict)->asString(), - make_termwise(OR({ TERM({1}, strict), - ORz({ TERM({2}, strict), TERM({3}, strict) }, strict) }, - strict), strict)->asString()); + EXPECT_EQ(my_or.createSearch(*md, strict)->asString(), + make_termwise(OR({ TERM({1}, strict), + ORz({ TERM({2}, strict), TERM({3}, strict) }, strict) }, + strict), strict)->asString()); } } //----------------------------------------------------------------------------- -TEST("require that OR can be completely termwise") { +TEST(TermwiseEvalTest, require_that_or_can_be_completely_termwise) +{ auto md = make_match_data(); md->set_termwise_limit(0.0); md->resolveTermField(1)->tagAsNotNeeded(); @@ -454,12 +480,13 @@ TEST("require that OR can be completely termwise") { my_or.addChild(UP(new MyBlueprint({1}, true, 1))); my_or.addChild(UP(new MyBlueprint({2}, true, 2))); for (bool strict: {true, false}) { - EXPECT_EQUAL(my_or.createSearch(*md, strict)->asString(), - make_termwise(OR({ TERM({1}, strict), TERM({2}, strict) }, strict), strict)->asString()); + EXPECT_EQ(my_or.createSearch(*md, strict)->asString(), + make_termwise(OR({ TERM({1}, strict), TERM({2}, strict) }, strict), strict)->asString()); } } -TEST("require that OR can be partially termwise") { +TEST(TermwiseEvalTest, require_that_or_can_be_partially_termwise) +{ auto md = make_match_data(); md->set_termwise_limit(0.0); md->resolveTermField(1)->tagAsNotNeeded(); @@ -469,13 +496,14 @@ TEST("require that OR can be partially termwise") { my_or.addChild(UP(new MyBlueprint({2}, true, 2))); my_or.addChild(UP(new MyBlueprint({3}, true, 3))); for (bool strict: {true, false}) { - EXPECT_EQUAL(my_or.createSearch(*md, strict)->asString(), - ORs({ make_termwise(OR({ TERM({1}, strict), TERM({3}, strict) }, strict), strict), + EXPECT_EQ(my_or.createSearch(*md, strict)->asString(), + ORs({ make_termwise(OR({ TERM({1}, strict), TERM({3}, strict) }, strict), strict), TERM({2}, strict) }, strict)->asString()); } } -TEST("require that OR puts termwise subquery at the right place") { +TEST(TermwiseEvalTest, require_that_or_puts_termwise_subquery_at_the_right_place) +{ auto md = make_match_data(); md->set_termwise_limit(0.0); md->resolveTermField(2)->tagAsNotNeeded(); @@ -485,14 +513,15 @@ TEST("require that OR puts termwise subquery at the right place") { my_or.addChild(UP(new MyBlueprint({2}, true, 2))); my_or.addChild(UP(new MyBlueprint({3}, true, 3))); for (bool strict: {true, false}) { - EXPECT_EQUAL(my_or.createSearch(*md, strict)->asString(), - ORs({ TERM({1}, strict), - make_termwise(OR({ TERM({2}, strict), TERM({3}, strict) }, strict), - strict) }, strict)->asString()); + EXPECT_EQ(my_or.createSearch(*md, strict)->asString(), + ORs({ TERM({1}, strict), + make_termwise(OR({ TERM({2}, strict), TERM({3}, strict) }, strict), + strict) }, strict)->asString()); } } -TEST("require that OR can use termwise eval also when having non-termwise children") { +TEST(TermwiseEvalTest, require_that_or_can_use_termwise_eval_also_when_having_non_termwise_children) +{ auto md = make_match_data(); md->set_termwise_limit(0.0); md->resolveTermField(1)->tagAsNotNeeded(); @@ -503,17 +532,18 @@ TEST("require that OR can use termwise eval also when having non-termwise childr my_or.addChild(UP(new MyBlueprint({2}, true, 2))); my_or.addChild(UP(new MyBlueprint({3}, true, 3))); for (bool strict: {true, false}) { - EXPECT_EQUAL(my_or.createSearch(*md, strict)->asString(), - ORz({ TERM({1}, strict), - make_termwise(OR({ TERM({2}, strict), TERM({3}, strict) }, strict), - strict)}, - strict)->asString()); + EXPECT_EQ(my_or.createSearch(*md, strict)->asString(), + ORz({ TERM({1}, strict), + make_termwise(OR({ TERM({2}, strict), TERM({3}, strict) }, strict), + strict)}, + strict)->asString()); } } //----------------------------------------------------------------------------- -TEST("require that AND can be completely termwise") { +TEST(TermwiseEvalTest, require_that_and_can_be_completely_termwise) +{ auto md = make_match_data(); md->set_termwise_limit(0.0); md->resolveTermField(1)->tagAsNotNeeded(); @@ -522,12 +552,13 @@ TEST("require that AND can be completely termwise") { my_and.addChild(UP(new MyBlueprint({1}, true, 1))); my_and.addChild(UP(new MyBlueprint({2}, true, 2))); for (bool strict: {true, false}) { - EXPECT_EQUAL(my_and.createSearch(*md, strict)->asString(), - make_termwise(AND({ TERM({1}, strict), TERM({2}, false) }, strict), strict)->asString()); + EXPECT_EQ(my_and.createSearch(*md, strict)->asString(), + make_termwise(AND({ TERM({1}, strict), TERM({2}, false) }, strict), strict)->asString()); } } -TEST("require that AND can be partially termwise") { +TEST(TermwiseEvalTest, require_that_and_can_be_partially_termwise) +{ auto md = make_match_data(); md->set_termwise_limit(0.0); md->resolveTermField(1)->tagAsNotNeeded(); @@ -537,7 +568,7 @@ TEST("require that AND can be partially termwise") { my_and.addChild(UP(new MyBlueprint({2}, true, 2))); my_and.addChild(UP(new MyBlueprint({3}, true, 3))); for (bool strict: {true, false}) { - EXPECT_EQUAL(my_and.createSearch(*md, strict)->asString(), + EXPECT_EQ(my_and.createSearch(*md, strict)->asString(), ANDs({ make_termwise(AND({ TERM({1}, strict), TERM({3}, false) }, strict), strict), @@ -545,7 +576,8 @@ TEST("require that AND can be partially termwise") { } } -TEST("require that AND puts termwise subquery at the right place") { +TEST(TermwiseEvalTest, require_that_and_puts_termwise_subquery_at_the_right_place) +{ auto md = make_match_data(); md->set_termwise_limit(0.0); md->resolveTermField(2)->tagAsNotNeeded(); @@ -555,14 +587,15 @@ TEST("require that AND puts termwise subquery at the right place") { my_and.addChild(UP(new MyBlueprint({2}, true, 2))); my_and.addChild(UP(new MyBlueprint({3}, true, 3))); for (bool strict: {true, false}) { - EXPECT_EQUAL(my_and.createSearch(*md, strict)->asString(), + EXPECT_EQ(my_and.createSearch(*md, strict)->asString(), ANDs({ TERM({1}, strict), make_termwise(AND({ TERM({2}, false), TERM({3}, false) }, false), false) }, strict)->asString()); } } -TEST("require that AND can use termwise eval also when having non-termwise children") { +TEST(TermwiseEvalTest, require_that_and_can_use_termwise_eval_also_when_having_non_termwise_children) +{ auto md = make_match_data(); md->set_termwise_limit(0.0); md->resolveTermField(1)->tagAsNotNeeded(); @@ -573,7 +606,7 @@ TEST("require that AND can use termwise eval also when having non-termwise child my_and.addChild(UP(new MyBlueprint({2}, true, 2))); my_and.addChild(UP(new MyBlueprint({3}, true, 3))); for (bool strict: {true, false}) { - EXPECT_EQUAL(my_and.createSearch(*md, strict)->asString(), + EXPECT_EQ(my_and.createSearch(*md, strict)->asString(), ANDz({ TERM({1}, strict), make_termwise(AND({ TERM({2}, false), TERM({3}, false) }, false), false) }, strict)->asString()); @@ -582,7 +615,8 @@ TEST("require that AND can use termwise eval also when having non-termwise child //----------------------------------------------------------------------------- -TEST("require that ANDNOT can be completely termwise") { +TEST(TermwiseEvalTest, require_that_andnot_can_be_completely_termwise) +{ auto md = make_match_data(); md->set_termwise_limit(0.0); md->resolveTermField(1)->tagAsNotNeeded(); @@ -590,13 +624,14 @@ TEST("require that ANDNOT can be completely termwise") { my_andnot.addChild(UP(new MyBlueprint({1}, true, 1))); my_andnot.addChild(UP(new MyBlueprint({2}, true, 2))); for (bool strict: {true, false}) { - EXPECT_EQUAL(my_andnot.createSearch(*md, strict)->asString(), + EXPECT_EQ(my_andnot.createSearch(*md, strict)->asString(), make_termwise(ANDNOT({ TERM({1}, strict), TERM({2}, false) }, strict), strict)->asString()); } } -TEST("require that ANDNOT can be partially termwise") { +TEST(TermwiseEvalTest, require_that_andnot_can_be_partially_termwise) +{ auto md = make_match_data(); md->set_termwise_limit(0.0); AndNotBlueprint my_andnot; @@ -604,14 +639,15 @@ TEST("require that ANDNOT can be partially termwise") { my_andnot.addChild(UP(new MyBlueprint({2}, true, 2))); my_andnot.addChild(UP(new MyBlueprint({3}, true, 3))); for (bool strict: {true, false}) { - EXPECT_EQUAL(my_andnot.createSearch(*md, strict)->asString(), + EXPECT_EQ(my_andnot.createSearch(*md, strict)->asString(), ANDNOT({ TERM({1}, strict), make_termwise(OR({ TERM({2}, false), TERM({3}, false) }, false), false) }, strict)->asString()); } } -TEST("require that ANDNOT can be partially termwise with first child being termwise") { +TEST(TermwiseEvalTest, require_that_andnot_can_be_partially_termwise_with_first_child_being_termwise) +{ auto md = make_match_data(); md->set_termwise_limit(0.0); md->resolveTermField(1)->tagAsNotNeeded(); @@ -620,7 +656,7 @@ TEST("require that ANDNOT can be partially termwise with first child being termw my_andnot.addChild(UP(new MyBlueprint({2}, false, 2))); my_andnot.addChild(UP(new MyBlueprint({3}, true, 3))); for (bool strict: {true, false}) { - EXPECT_EQUAL(my_andnot.createSearch(*md, strict)->asString(), + EXPECT_EQ(my_andnot.createSearch(*md, strict)->asString(), ANDNOT({ make_termwise(ANDNOT({ TERM({1}, strict), TERM({3}, false) }, strict), strict), TERM({2}, false) }, strict)->asString()); @@ -629,7 +665,8 @@ TEST("require that ANDNOT can be partially termwise with first child being termw //----------------------------------------------------------------------------- -TEST("require that termwise blueprint helper calculates unpack info correctly") { +TEST(TermwiseEvalTest, require_that_termwise_blueprint_helper_calculates_unpack_info_correctly) +{ OrBlueprint my_or; my_or.addChild(UP(new MyBlueprint({1}, false, 1))); // termwise not allowed my_or.addChild(UP(new MyBlueprint({2}, false, 2))); // termwise not allowed and ranked @@ -641,9 +678,9 @@ TEST("require that termwise blueprint helper calculates unpack info correctly") unpack.add(1); unpack.add(3); TermwiseBlueprintHelper helper(my_or, std::move(dummy_searches), unpack); - EXPECT_EQUAL(helper.get_result().size(), 3u); - EXPECT_EQUAL(helper.get_termwise_children().size(), 2u); - EXPECT_EQUAL(helper.first_termwise, 2u); + EXPECT_EQ(helper.get_result().size(), 3u); + EXPECT_EQ(helper.get_termwise_children().size(), 2u); + EXPECT_EQ(helper.first_termwise, 2u); EXPECT_TRUE(!helper.termwise_unpack.needUnpack(0)); EXPECT_TRUE(helper.termwise_unpack.needUnpack(1)); EXPECT_TRUE(!helper.termwise_unpack.needUnpack(2)); @@ -658,11 +695,12 @@ public: return make_termwise(createIterator(getExpectedDocIds(), strict), strict); } }; -TEST("test terwise adheres to search iterator requirements.") { +TEST(TermwiseEvalTest, test_termwise_adheres_to_search_iterator_requirements) +{ Verifier verifier; verifier.verify(); } //----------------------------------------------------------------------------- -TEST_MAIN() { TEST_RUN_ALL(); } +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/searchlib/src/tests/queryeval/weak_and/weak_and_test.cpp b/searchlib/src/tests/queryeval/weak_and/weak_and_test.cpp index 1054980e4ec..9409b2b26c4 100644 --- a/searchlib/src/tests/queryeval/weak_and/weak_and_test.cpp +++ b/searchlib/src/tests/queryeval/weak_and/weak_and_test.cpp @@ -1,5 +1,4 @@ // Copyright Vespa.ai. 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/queryeval/fake_search.h> #include <vespa/searchlib/queryeval/wand/weak_and_search.h> #include <vespa/searchlib/queryeval/simpleresult.h> @@ -7,7 +6,9 @@ #include <vespa/searchlib/queryeval/test/eagerchild.h> #include <vespa/searchlib/queryeval/test/leafspec.h> #include <vespa/searchlib/queryeval/test/wandspec.h> +#define ENABLE_GTEST_MIGRATION #include <vespa/searchlib/test/weightedchildrenverifiers.h> +#include <vespa/vespalib/gtest/gtest.h> using namespace search::fef; using namespace search::queryeval; @@ -60,32 +61,39 @@ struct WeightOrder { } // namespace <unnamed> -TEST_F("require that wand prunes bad hits after enough good ones are obtained", SimpleWandFixture) { - EXPECT_EQUAL(SimpleResult().addHit(1).addHit(2).addHit(3).addHit(5), f.hits); +TEST(WeakAndTest, require_that_wand_prunes_bad_hits_after_enough_good_ones_are_obtained) +{ + SimpleWandFixture f; + EXPECT_EQ(SimpleResult().addHit(1).addHit(2).addHit(3).addHit(5), f.hits); } -TEST_F("require that wand uses subsearches as expected", SimpleWandFixture) { - EXPECT_EQUAL(History() - .seek("WAND", 1).seek("bar", 1).step("bar", 1).step("WAND", 1) - .unpack("WAND", 1).seek("foo", 1).step("foo", 1).unpack("bar", 1).unpack("foo", 1) - .seek("WAND", 2).seek("bar", 2).step("bar", 3).seek("foo", 2).step("foo", 2).step("WAND", 2) - .unpack("WAND", 2).unpack("foo", 2) - .seek("WAND", 3).step("WAND", 3) - .unpack("WAND", 3).seek("foo", 3).step("foo", 3).unpack("bar", 3).unpack("foo", 3) - .seek("WAND", 4).seek("bar", 4).step("bar", 5).seek("foo", 5).step("foo", 5).step("WAND", 5) - .unpack("WAND", 5).unpack("bar", 5).unpack("foo", 5) - .seek("WAND", 6).seek("bar", 6).step("bar", search::endDocId).step("WAND", search::endDocId), - f.spec.getHistory()); +TEST(WeakAndTest, require_that_wand_uses_subsearches_as_expected) +{ + SimpleWandFixture f; + EXPECT_EQ(History() + .seek("WAND", 1).seek("bar", 1).step("bar", 1).step("WAND", 1) + .unpack("WAND", 1).seek("foo", 1).step("foo", 1).unpack("bar", 1).unpack("foo", 1) + .seek("WAND", 2).seek("bar", 2).step("bar", 3).seek("foo", 2).step("foo", 2).step("WAND", 2) + .unpack("WAND", 2).unpack("foo", 2) + .seek("WAND", 3).step("WAND", 3) + .unpack("WAND", 3).seek("foo", 3).step("foo", 3).unpack("bar", 3).unpack("foo", 3) + .seek("WAND", 4).seek("bar", 4).step("bar", 5).seek("foo", 5).step("foo", 5).step("WAND", 5) + .unpack("WAND", 5).unpack("bar", 5).unpack("foo", 5) + .seek("WAND", 6).seek("bar", 6).step("bar", search::endDocId).step("WAND", search::endDocId), + f.spec.getHistory()); } -TEST_F("require that documents are considered in the right order", AdvancedWandFixture) { - EXPECT_EQUAL(SimpleResult() - .addHit(1).addHit(2).addHit(3).addHit(4).addHit(5) - .addHit(11).addHit(12).addHit(13).addHit(14).addHit(15) - .addHit(111).addHit(112).addHit(113).addHit(114).addHit(115), f.hits); +TEST(WeakAndTest, require_that_documents_are_considered_in_the_right_order) +{ + AdvancedWandFixture f; + EXPECT_EQ(SimpleResult() + .addHit(1).addHit(2).addHit(3).addHit(4).addHit(5) + .addHit(11).addHit(12).addHit(13).addHit(14).addHit(15) + .addHit(111).addHit(112).addHit(113).addHit(114).addHit(115), f.hits); } -TEST("require that initial docid for subsearches are taken into account") { +TEST(WeakAndTest, require_that_initial_docid_for_subsearches_are_taken_into_account) +{ History history; wand::Terms terms; terms.push_back(wand::Term(new TrackedSearch("foo", history, new EagerChild(search::endDocId)), 100, 1)); @@ -93,10 +101,10 @@ TEST("require that initial docid for subsearches are taken into account") { SearchIterator::UP search(new TrackedSearch("WAND", history, WeakAndSearch::create(terms, 2, true))); SimpleResult hits; hits.search(*search); - EXPECT_EQUAL(SimpleResult().addHit(10), hits); - EXPECT_EQUAL(History().seek("WAND", 1).step("WAND", 10).unpack("WAND", 10).unpack("bar", 10) - .seek("WAND", 11).seek("bar", 11).step("bar", search::endDocId).step("WAND", search::endDocId), - history); + EXPECT_EQ(SimpleResult().addHit(10), hits); + EXPECT_EQ(History().seek("WAND", 1).step("WAND", 10).unpack("WAND", 10).unpack("bar", 10) + .seek("WAND", 11).seek("bar", 11).step("bar", search::endDocId).step("WAND", search::endDocId), + history); } class IteratorChildrenVerifier : public search::test::IteratorChildrenVerifier { @@ -111,9 +119,10 @@ private: } }; -TEST("verify search iterator conformance") { +TEST(WeakAndTest, verify_search_iterator_conformance) +{ IteratorChildrenVerifier verifier; verifier.verify(); } -TEST_MAIN() { TEST_RUN_ALL(); } +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/searchlib/src/tests/queryeval/weighted_set_term/weighted_set_term_test.cpp b/searchlib/src/tests/queryeval/weighted_set_term/weighted_set_term_test.cpp index 5faead1175e..24d62f66714 100644 --- a/searchlib/src/tests/queryeval/weighted_set_term/weighted_set_term_test.cpp +++ b/searchlib/src/tests/queryeval/weighted_set_term/weighted_set_term_test.cpp @@ -1,6 +1,5 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -#include <vespa/vespalib/testkit/testapp.h> #include <vespa/searchlib/queryeval/weighted_set_term_search.h> #include <vespa/searchlib/query/tree/simplequery.h> @@ -11,7 +10,9 @@ #include <vespa/searchlib/queryeval/emptysearch.h> #include <vespa/searchlib/queryeval/fake_searchable.h> #include <vespa/searchlib/queryeval/fake_requestcontext.h> +#define ENABLE_GTEST_MIGRATION #include <vespa/searchlib/test/weightedchildrenverifiers.h> +#include <vespa/vespalib/gtest/gtest.h> using namespace search; using namespace search::query; @@ -112,8 +113,9 @@ WS::WS() term_is_not_needed(false) { MatchData::UP tmp = layout.createMatchData(); - ASSERT_TRUE(tmp->resolveTermField(handle)->getFieldId() == fieldId); + assert(tmp->resolveTermField(handle)->getFieldId() == fieldId); } + WS::~WS() = default; struct MockSearch : public SearchIterator { @@ -143,8 +145,11 @@ struct MockFixture { weights.push_back(1); search = WeightedSetTermSearch::create(children, tfmd, false, weights, {}); } + ~MockFixture(); }; +MockFixture::~MockFixture() = default; + } // namespace <unnamed> void run_simple(bool field_is_filter, bool term_is_not_needed, bool singleTerm) @@ -179,42 +184,50 @@ void run_simple(bool field_is_filter, bool term_is_not_needed, bool singleTerm) EXPECT_TRUE(ws.isGenericSearch(index, "multi-field", true)); EXPECT_TRUE(ws.isGenericSearch(index, "multi-field", false)); - EXPECT_EQUAL(expect, ws.search(index, "field", true)); - EXPECT_EQUAL(expect, ws.search(index, "field", false)); - EXPECT_EQUAL(expect, ws.search(index, "multi-field", true)); - EXPECT_EQUAL(expect, ws.search(index, "multi-field", false)); + EXPECT_EQ(expect, ws.search(index, "field", true)); + EXPECT_EQ(expect, ws.search(index, "field", false)); + EXPECT_EQ(expect, ws.search(index, "multi-field", true)); + EXPECT_EQ(expect, ws.search(index, "multi-field", false)); } -TEST("testSimple") { - TEST_DO(run_simple(false, false, false)); +TEST(WeightedSetTermTest, test_simple) +{ + run_simple(false, false, false); } -TEST("testSimple filter field") { - TEST_DO(run_simple(true, false, false)); +TEST(WeightedSetTermTest, test_simple_filter_field) +{ + run_simple(true, false, false); } -TEST("testSimple unranked") { - TEST_DO(run_simple(false, true, false)); +TEST(WeightedSetTermTest, test_simple_unranked) +{ + run_simple(false, true, false); } -TEST("testSimple unranked filter filed") { - TEST_DO(run_simple(true, true, false)); +TEST(WeightedSetTermTest, test_simple_unranked_filter_field) +{ + run_simple(true, true, false); } -TEST("testSimple single") { - TEST_DO(run_simple(false, false, true)); +TEST(WeightedSetTermTest, test_simple_single) +{ + run_simple(false, false, true); } -TEST("testSimple single filter field") { - TEST_DO(run_simple(true, false, true)); +TEST(WeightedSetTermTest, test_simple_single_filter_field) +{ + run_simple(true, false, true); } -TEST("testSimple single unranked") { - TEST_DO(run_simple(false, true, true)); +TEST(WeightedSetTermTest, test_simple_single_unranked) +{ + run_simple(false, true, true); } -TEST("testSimple single unranked filter field") { - TEST_DO(run_simple(true, true, true)); +TEST(WeightedSetTermTest, test_simple_single_unranked_filter_field) +{ + run_simple(true, true, true); } void run_multi(bool field_is_filter, bool term_is_not_needed) @@ -240,46 +253,53 @@ void run_multi(bool field_is_filter, bool term_is_not_needed) EXPECT_TRUE(ws.isGenericSearch(index, "multi-field", true)); EXPECT_TRUE(ws.isGenericSearch(index, "multi-field", false)); - EXPECT_EQUAL(expect, ws.search(index, "multi-field", true)); - EXPECT_EQUAL(expect, ws.search(index, "multi-field", false)); + EXPECT_EQ(expect, ws.search(index, "multi-field", true)); + EXPECT_EQ(expect, ws.search(index, "multi-field", false)); } -TEST("testMulti") { - TEST_DO(run_multi(false, false)); +TEST(WeightedSetTermTest, test_multi) +{ + run_multi(false, false); } -TEST("testMulti filter field") { - TEST_DO(run_multi(true, false)); +TEST(WeightedSetTermTest, test_multi_filter_field) +{ + run_multi(true, false); } -TEST("testMulti unranked") { - TEST_DO(run_multi(false, true)); +TEST(WeightedSetTermTest, test_multi_unranked) +{ + run_multi(false, true); } -TEST_F("test Eager Empty Child", MockFixture(search::endDocId)) { +TEST(WeightedSetTermTest, test_eager_empty_child) +{ + MockFixture f1(search::endDocId); MockSearch *mock = f1.mock; SearchIterator &search = *f1.search; search.initFullRange(); - EXPECT_EQUAL(search.beginId(), search.getDocId()); + EXPECT_EQ(search.beginId(), search.getDocId()); EXPECT_TRUE(!search.seek(1)); EXPECT_TRUE(search.isAtEnd()); - EXPECT_EQUAL(0, mock->seekCnt); + EXPECT_EQ(0, mock->seekCnt); } -TEST_F("test Eager Matching Child", MockFixture(5)) { +TEST(WeightedSetTermTest, test_eager_matching_child) +{ + MockFixture f1(5); MockSearch *mock = f1.mock; SearchIterator &search = *f1.search; search.initFullRange(); - EXPECT_EQUAL(search.beginId(), search.getDocId()); + EXPECT_EQ(search.beginId(), search.getDocId()); EXPECT_TRUE(!search.seek(3)); - EXPECT_EQUAL(5u, search.getDocId()); - EXPECT_EQUAL(0, mock->seekCnt); + EXPECT_EQ(5u, search.getDocId()); + EXPECT_EQ(0, mock->seekCnt); EXPECT_TRUE(search.seek(5)); - EXPECT_EQUAL(5u, search.getDocId()); - EXPECT_EQUAL(0, mock->seekCnt); + EXPECT_EQ(5u, search.getDocId()); + EXPECT_EQ(0, mock->seekCnt); EXPECT_TRUE(!search.seek(7)); EXPECT_TRUE(search.isAtEnd()); - EXPECT_EQUAL(1, mock->seekCnt); + EXPECT_EQ(1, mock->seekCnt); } class IteratorChildrenVerifier : public search::test::IteratorChildrenVerifier { @@ -296,12 +316,14 @@ private: } }; -TEST("verify search iterator conformance with search iterator children") { +TEST(WeightedSetTermTest, verify_search_iterator_conformance_with_search_iterator_children) +{ IteratorChildrenVerifier verifier; verifier.verify(); } -TEST("verify search iterator conformance with document weight iterator children") { +TEST(WeightedSetTermTest, verify_search_iterator_conformance_with_document_weight_iterator_children) +{ WeightIteratorChildrenVerifier verifier; verifier.verify(); } @@ -312,12 +334,12 @@ struct VerifyMatchData { MyBlueprint(VerifyMatchData &vmd_in, FieldSpecBase spec_in) : SimpleLeafBlueprint(spec_in), vmd(vmd_in) {} [[nodiscard]] SearchIterator::UP createLeafSearch(const fef::TermFieldMatchDataArray &tfmda, bool) const override { - EXPECT_EQUAL(tfmda.size(), 1u); + EXPECT_EQ(tfmda.size(), 1u); EXPECT_TRUE(tfmda[0] != nullptr); if (vmd.child_tfmd == nullptr) { vmd.child_tfmd = tfmda[0]; } else { - EXPECT_EQUAL(vmd.child_tfmd, tfmda[0]); + EXPECT_EQ(vmd.child_tfmd, tfmda[0]); } ++vmd.child_cnt; return std::make_unique<EmptySearch>(); @@ -333,7 +355,8 @@ struct VerifyMatchData { } }; -TEST("require that children get a common (yet separate) term field match data") { +TEST(WeightedSetTermTest, require_that_children_get_a_common_yet_separate_term_field_match_data) +{ VerifyMatchData vmd; MatchDataLayout layout; auto top_handle = layout.allocTermField(42); @@ -347,9 +370,9 @@ TEST("require that children get a common (yet separate) term field match data") auto match_data = layout.createMatchData(); auto search = blueprint.createSearch(*match_data, true); auto top_tfmd = match_data->resolveTermField(top_handle); - EXPECT_EQUAL(vmd.child_cnt, 5u); + EXPECT_EQ(vmd.child_cnt, 5u); EXPECT_TRUE(vmd.child_tfmd != nullptr); - EXPECT_NOT_EQUAL(top_tfmd, vmd.child_tfmd); + EXPECT_NE(top_tfmd, vmd.child_tfmd); } -TEST_MAIN() { TEST_RUN_ALL(); } +GTEST_MAIN_RUN_ALL_TESTS() |