diff options
author | Henning Baldersheim <balder@yahoo-inc.com> | 2024-01-15 10:23:18 +0100 |
---|---|---|
committer | Henning Baldersheim <balder@yahoo-inc.com> | 2024-01-15 09:56:25 +0000 |
commit | d4918f2ce956e316b6ce398f144c53f52e3288da (patch) | |
tree | 6289a1ef92d82b9cc274c1fdd7decbec29bf1cd6 /searchlib/src/tests | |
parent | 48b1bae2a6cdf58a237aa7be59632a06aba86861 (diff) | |
parent | 252fbeed13b8622fbc813620dc3b4e45abc6bbe2 (diff) |
Merge branch 'master' into balder/sliced-parallell-or
Diffstat (limited to 'searchlib/src/tests')
53 files changed, 1547 insertions, 920 deletions
diff --git a/searchlib/src/tests/attribute/bitvector/bitvector_test.cpp b/searchlib/src/tests/attribute/bitvector/bitvector_test.cpp index 181c0fdf110..f612bdda87f 100644 --- a/searchlib/src/tests/attribute/bitvector/bitvector_test.cpp +++ b/searchlib/src/tests/attribute/bitvector/bitvector_test.cpp @@ -7,7 +7,7 @@ #include <vespa/searchlib/common/bitvectoriterator.h> #include <vespa/searchlib/fef/termfieldmatchdata.h> #include <vespa/searchlib/parsequery/parse.h> -#include <vespa/searchlib/queryeval/document_weight_search_iterator.h> +#include <vespa/searchlib/queryeval/docid_with_weight_search_iterator.h> #include <vespa/searchlib/queryeval/executeinfo.h> #include <vespa/searchlib/test/searchiteratorverifier.h> #include <vespa/searchlib/util/randomgenerator.h> @@ -432,7 +432,7 @@ BitVectorTest::test(BasicType bt, CollectionType ct, const vespalib::string &pre const auto* dww = v->as_docid_with_weight_posting_store(); if (dww != nullptr) { auto lres = dww->lookup(getSearchStr<VectorType>(), dww->get_dictionary_snapshot()); - using DWSI = search::queryeval::DocumentWeightSearchIterator; + using DWSI = search::queryeval::DocidWithWeightSearchIterator; TermFieldMatchData md; auto dwsi = std::make_unique<DWSI>(md, *dww, lres); if (!filter) { diff --git a/searchlib/src/tests/attribute/direct_multi_term_blueprint/direct_multi_term_blueprint_test.cpp b/searchlib/src/tests/attribute/direct_multi_term_blueprint/direct_multi_term_blueprint_test.cpp index f2341d0968e..899ddaa3cc0 100644 --- a/searchlib/src/tests/attribute/direct_multi_term_blueprint/direct_multi_term_blueprint_test.cpp +++ b/searchlib/src/tests/attribute/direct_multi_term_blueprint/direct_multi_term_blueprint_test.cpp @@ -3,7 +3,9 @@ #include <vespa/searchlib/attribute/direct_multi_term_blueprint.h> #include <vespa/searchlib/attribute/i_docid_posting_store.h> #include <vespa/searchlib/attribute/i_docid_with_weight_posting_store.h> +#include <vespa/searchlib/attribute/in_term_search.h> #include <vespa/searchlib/attribute/integerbase.h> +#include <vespa/searchlib/attribute/stringbase.h> #include <vespa/searchlib/fef/termfieldmatchdata.h> #include <vespa/searchlib/queryeval/orsearch.h> #include <vespa/searchlib/queryeval/searchiterator.h> @@ -19,13 +21,22 @@ using namespace search::queryeval; using namespace search; using testing::StartsWith; -struct IntegerKey : public IDirectPostingStore::LookupKey { +using LookupKey = IDirectPostingStore::LookupKey; + +struct IntegerKey : public LookupKey { int64_t _value; IntegerKey(int64_t value_in) : _value(value_in) {} vespalib::stringref asString() const override { abort(); } bool asInteger(int64_t& value) const override { value = _value; return true; } }; +struct StringKey : public LookupKey { + vespalib::string _value; + StringKey(int64_t value_in) : _value(std::to_string(value_in)) {} + vespalib::stringref asString() const override { return _value; } + bool asInteger(int64_t&) const override { abort(); } +}; + const vespalib::string field_name = "test"; constexpr uint32_t field_id = 3; uint32_t doc_id_limit = 500; @@ -50,112 +61,153 @@ concat(const Docids& a, const Docids& b) return res; } +template <typename AttributeType, typename DataType> +void +populate_attribute(AttributeType& attr, const std::vector<DataType>& values) +{ + // Values 0 and 1 have btree (short) posting lists. + attr.update(10, values[0]); + attr.update(30, values[1]); + attr.update(31, values[1]); + + // Values 2 and 3 have bitvector posting lists. + // We need at least 128 documents to get bitvector posting list (see PostingStoreBase2::resizeBitVectors()) + for (auto docid : range(100, 128)) { + attr.update(docid, values[2]); + } + for (auto docid : range(300, 128)) { + attr.update(docid, values[3]); + } + attr.commit(true); +} + std::shared_ptr<AttributeVector> -make_attribute(bool field_is_filter, CollectionType col_type) +make_attribute(CollectionType col_type, BasicType type, bool field_is_filter) { - Config cfg(BasicType::INT64, col_type); + Config cfg(type, col_type); cfg.setFastSearch(true); if (field_is_filter) { cfg.setIsFilter(field_is_filter); } uint32_t num_docs = doc_id_limit - 1; auto attr = test::AttributeBuilder(field_name, cfg).docs(num_docs).get(); - IntegerAttribute& real = dynamic_cast<IntegerAttribute&>(*attr); - - // Values 1 and 3 have btree (short) posting lists with weights. - real.update(10, 1); - real.update(30, 3); - real.update(31, 3); - - // Values 100 and 300 have bitvector posting lists. - // We need at least 128 documents to get bitvector posting list (see PostingStoreBase2::resizeBitVectors()) - for (auto docid : range(100, 128)) { - real.update(docid, 100); - } - for (auto docid : range(300, 128)) { - real.update(docid, 300); + if (type == BasicType::STRING) { + populate_attribute<StringAttribute, vespalib::string>(dynamic_cast<StringAttribute&>(*attr), + {"1", "3", "100", "300"}); + } else { + populate_attribute<IntegerAttribute, int64_t>(dynamic_cast<IntegerAttribute&>(*attr), + {1, 3, 100, 300}); } - attr->commit(true); return attr; } void -expect_has_btree_iterator(const IDirectPostingStore& store, int64_t term_value) +expect_has_btree_iterator(const IDirectPostingStore& store, const LookupKey& key) { auto snapshot = store.get_dictionary_snapshot(); - auto res = store.lookup(IntegerKey(term_value), snapshot); + auto res = store.lookup(key, snapshot); EXPECT_TRUE(store.has_btree_iterator(res.posting_idx)); } void -expect_has_bitvector_iterator(const IDirectPostingStore& store, int64_t term_value) +expect_has_bitvector_iterator(const IDirectPostingStore& store, const LookupKey& key) { auto snapshot = store.get_dictionary_snapshot(); - auto res = store.lookup(IntegerKey(term_value), snapshot); + auto res = store.lookup(key, snapshot); EXPECT_TRUE(store.has_bitvector(res.posting_idx)); } +template <typename LookupKeyType> void validate_posting_lists(const IDirectPostingStore& store) { - expect_has_btree_iterator(store, 1); - expect_has_btree_iterator(store, 3); + expect_has_btree_iterator(store, LookupKeyType(1)); + expect_has_btree_iterator(store, LookupKeyType(3)); if (store.has_always_btree_iterator()) { - expect_has_btree_iterator(store, 100); - expect_has_btree_iterator(store, 300); + expect_has_btree_iterator(store, LookupKeyType(100)); + expect_has_btree_iterator(store, LookupKeyType(300)); } - expect_has_bitvector_iterator(store, 100); - expect_has_bitvector_iterator(store, 300); + expect_has_bitvector_iterator(store, LookupKeyType(100)); + expect_has_bitvector_iterator(store, LookupKeyType(300)); } +enum OperatorType { + In, + WSet +}; + struct TestParam { + OperatorType op_type; CollectionType col_type; - TestParam(CollectionType col_type_in) : col_type(col_type_in) {} + BasicType type; + TestParam(OperatorType op_type_in, CollectionType col_type_in, BasicType type_in) + : op_type(op_type_in), col_type(col_type_in), type(type_in) {} ~TestParam() = default; }; std::ostream& operator<<(std::ostream& os, const TestParam& param) { - os << param.col_type.asString(); + os << (param.op_type == OperatorType::In ? "in_" : "wset_") << param.col_type.asString() << "_" << param.type.asString(); return os; } +using SingleInBlueprintType = DirectMultiTermBlueprint<IDocidPostingStore, InTermSearch>; +using MultiInBlueprintType = DirectMultiTermBlueprint<IDocidWithWeightPostingStore, InTermSearch>; +using SingleWSetBlueprintType = DirectMultiTermBlueprint<IDocidPostingStore, WeightedSetTermSearch>; +using MultiWSetBlueprintType = DirectMultiTermBlueprint<IDocidWithWeightPostingStore, WeightedSetTermSearch>; + class DirectMultiTermBlueprintTest : public ::testing::TestWithParam<TestParam> { public: - using SingleValueBlueprintType = DirectMultiTermBlueprint<IDocidPostingStore, WeightedSetTermSearch>; - using MultiValueBlueprintType = DirectMultiTermBlueprint<IDocidWithWeightPostingStore, WeightedSetTermSearch>; std::shared_ptr<AttributeVector> attr; - std::shared_ptr<SingleValueBlueprintType> single_blueprint; - std::shared_ptr<MultiValueBlueprintType> multi_blueprint; - queryeval::ComplexLeafBlueprint* blueprint; + bool in_operator; + bool single_type; + bool integer_type; + std::shared_ptr<ComplexLeafBlueprint> blueprint; Blueprint::HitEstimate estimate; fef::TermFieldMatchData tfmd; fef::TermFieldMatchDataArray tfmda; DirectMultiTermBlueprintTest() : attr(), - single_blueprint(), - multi_blueprint(), + in_operator(true), + single_type(true), + integer_type(true), blueprint(), tfmd(), tfmda() { tfmda.add(&tfmd); } + ~DirectMultiTermBlueprintTest() {} void setup(bool field_is_filter, bool need_term_field_match_data) { - attr = make_attribute(field_is_filter, GetParam().col_type); + attr = make_attribute(GetParam().col_type, GetParam().type, field_is_filter); + in_operator = GetParam().op_type == OperatorType::In; + single_type = GetParam().col_type == CollectionType::SINGLE; + integer_type = GetParam().type != BasicType::STRING; FieldSpec spec(field_name, field_id, fef::TermFieldHandle(), field_is_filter); - if (GetParam().col_type == CollectionType::SINGLE) { - const auto* store = attr->as_docid_posting_store(); - ASSERT_TRUE(store); - validate_posting_lists(*store); - single_blueprint = std::make_shared<SingleValueBlueprintType>(spec, *attr, *store, 2); - blueprint = single_blueprint.get(); + const IDirectPostingStore* store; + if (single_type) { + auto real_store = attr->as_docid_posting_store(); + ASSERT_TRUE(real_store); + if (in_operator) { + blueprint = std::make_shared<SingleInBlueprintType>(spec, *attr, *real_store, 2); + } else { + blueprint = std::make_shared<SingleWSetBlueprintType>(spec, *attr, *real_store, 2); + } + store = real_store; + } else { + auto real_store = attr->as_docid_with_weight_posting_store(); + ASSERT_TRUE(real_store); + if (in_operator) { + blueprint = std::make_shared<MultiInBlueprintType>(spec, *attr, *real_store, 2); + } else { + blueprint = std::make_shared<MultiWSetBlueprintType>(spec, *attr, *real_store, 2); + } + store = real_store; + } + if (integer_type) { + validate_posting_lists<IntegerKey>(*store); } else { - const auto* store = attr->as_docid_with_weight_posting_store(); - ASSERT_TRUE(store); - validate_posting_lists(*store); - multi_blueprint = std::make_shared<MultiValueBlueprintType>(spec, *attr, *store, 2); - blueprint = multi_blueprint.get(); + validate_posting_lists<StringKey>(*store); } blueprint->setDocIdLimit(doc_id_limit); if (need_term_field_match_data) { @@ -164,16 +216,35 @@ public: tfmd.tagAsNotNeeded(); } } + template <typename BlueprintType> + void add_term_helper(BlueprintType& b, int64_t term_value) { + if (integer_type) { + b.addTerm(IntegerKey(term_value), 1, estimate); + } else { + b.addTerm(StringKey(term_value), 1, estimate); + } + } void add_term(int64_t term_value) { - if (single_blueprint) { - single_blueprint->addTerm(IntegerKey(term_value), 1, estimate); + if (single_type) { + if (in_operator) { + add_term_helper(dynamic_cast<SingleInBlueprintType&>(*blueprint), term_value); + } else { + add_term_helper(dynamic_cast<SingleWSetBlueprintType&>(*blueprint), term_value); + } } else { - multi_blueprint->addTerm(IntegerKey(term_value), 1, estimate); + if (in_operator) { + add_term_helper(dynamic_cast<MultiInBlueprintType&>(*blueprint), term_value); + } else { + add_term_helper(dynamic_cast<MultiWSetBlueprintType&>(*blueprint), term_value); + } } } std::unique_ptr<SearchIterator> create_leaf_search() const { return blueprint->createLeafSearch(tfmda, true); } + vespalib::string multi_term_iterator() const { + return in_operator ? "search::attribute::MultiTermOrFilterSearchImpl" : "search::queryeval::WeightedSetTermSearchImpl"; + } }; void @@ -201,30 +272,54 @@ expect_or_child(SearchIterator& itr, size_t child, const vespalib::string& exp_c INSTANTIATE_TEST_SUITE_P(DefaultInstantiation, DirectMultiTermBlueprintTest, - testing::Values(CollectionType::SINGLE, CollectionType::WSET), + testing::Values(TestParam(OperatorType::In, CollectionType::SINGLE, BasicType::INT64), + TestParam(OperatorType::In, CollectionType::SINGLE, BasicType::STRING), + TestParam(OperatorType::In, CollectionType::WSET, BasicType::INT64), + TestParam(OperatorType::In, CollectionType::WSET, BasicType::STRING), + TestParam(OperatorType::WSet, CollectionType::SINGLE, BasicType::INT64), + TestParam(OperatorType::WSet, CollectionType::SINGLE, BasicType::STRING), + TestParam(OperatorType::WSet, CollectionType::WSET, BasicType::INT64), + TestParam(OperatorType::WSet, CollectionType::WSET, BasicType::STRING)), testing::PrintToStringParamName()); -TEST_P(DirectMultiTermBlueprintTest, weight_iterators_used_for_none_filter_field) -{ +TEST_P(DirectMultiTermBlueprintTest, btree_iterators_used_for_none_filter_field) { setup(false, true); add_term(1); add_term(3); auto itr = create_leaf_search(); - EXPECT_THAT(itr->asString(), StartsWith("search::queryeval::WeightedSetTermSearchImpl")); + EXPECT_THAT(itr->asString(), StartsWith(multi_term_iterator())); expect_hits({10, 30, 31}, *itr); } -TEST_P(DirectMultiTermBlueprintTest, weight_iterators_used_instead_of_bitvectors_for_none_filter_field) +TEST_P(DirectMultiTermBlueprintTest, bitvectors_used_instead_of_btree_iterators_for_none_filter_field) +{ + setup(false, true); + if (!in_operator) { + return; + } + add_term(1); + add_term(100); + auto itr = create_leaf_search(); + expect_or_iterator(*itr, 2); + expect_or_child(*itr, 0, "search::BitVectorIteratorStrictT"); + expect_or_child(*itr, 1, multi_term_iterator()); + expect_hits(concat({10}, range(100, 128)), *itr); +} + +TEST_P(DirectMultiTermBlueprintTest, btree_iterators_used_instead_of_bitvectors_for_none_filter_field) { setup(false, true); + if (in_operator) { + return; + } add_term(1); add_term(100); auto itr = create_leaf_search(); - EXPECT_THAT(itr->asString(), StartsWith("search::queryeval::WeightedSetTermSearchImpl")); + EXPECT_THAT(itr->asString(), StartsWith(multi_term_iterator())); expect_hits(concat({10}, range(100, 128)), *itr); } -TEST_P(DirectMultiTermBlueprintTest, bitvectors_and_weight_iterators_used_for_filter_field) +TEST_P(DirectMultiTermBlueprintTest, bitvectors_and_btree_iterators_used_for_filter_field) { setup(true, true); add_term(1); @@ -235,7 +330,7 @@ TEST_P(DirectMultiTermBlueprintTest, bitvectors_and_weight_iterators_used_for_fi expect_or_iterator(*itr, 3); expect_or_child(*itr, 0, "search::BitVectorIteratorStrictT"); expect_or_child(*itr, 1, "search::BitVectorIteratorStrictT"); - expect_or_child(*itr, 2, "search::queryeval::WeightedSetTermSearchImpl"); + expect_or_child(*itr, 2, multi_term_iterator()); expect_hits(concat({10, 30, 31}, concat(range(100, 128), range(300, 128))), *itr); } @@ -251,17 +346,17 @@ TEST_P(DirectMultiTermBlueprintTest, only_bitvectors_used_for_filter_field) expect_hits(concat(range(100, 128), range(300, 128)), *itr); } -TEST_P(DirectMultiTermBlueprintTest, filter_iterator_used_for_filter_field_and_ranking_not_needed) +TEST_P(DirectMultiTermBlueprintTest, or_filter_iterator_used_for_filter_field_when_ranking_not_needed) { setup(true, false); add_term(1); add_term(3); auto itr = create_leaf_search(); - EXPECT_THAT(itr->asString(), StartsWith("search::attribute::DocumentWeightOrFilterSearchImpl")); + EXPECT_THAT(itr->asString(), StartsWith("search::attribute::MultiTermOrFilterSearchImpl")); expect_hits({10, 30, 31}, *itr); } -TEST_P(DirectMultiTermBlueprintTest, bitvectors_and_filter_iterator_used_for_filter_field_and_ranking_not_needed) +TEST_P(DirectMultiTermBlueprintTest, bitvectors_and_or_filter_iterator_used_for_filter_field_when_ranking_not_needed) { setup(true, false); add_term(1); @@ -272,11 +367,11 @@ TEST_P(DirectMultiTermBlueprintTest, bitvectors_and_filter_iterator_used_for_fil expect_or_iterator(*itr, 3); expect_or_child(*itr, 0, "search::BitVectorIteratorStrictT"); expect_or_child(*itr, 1, "search::BitVectorIteratorStrictT"); - expect_or_child(*itr, 2, "search::attribute::DocumentWeightOrFilterSearchImpl"); + expect_or_child(*itr, 2, "search::attribute::MultiTermOrFilterSearchImpl"); expect_hits(concat({10, 30, 31}, concat(range(100, 128), range(300, 128))), *itr); } -TEST_P(DirectMultiTermBlueprintTest, only_bitvectors_used_for_filter_field_and_ranking_not_needed) +TEST_P(DirectMultiTermBlueprintTest, only_bitvectors_used_for_filter_field_when_ranking_not_needed) { setup(true, false); add_term(100); diff --git a/searchlib/src/tests/attribute/direct_posting_store/.gitignore b/searchlib/src/tests/attribute/direct_posting_store/.gitignore new file mode 100644 index 00000000000..5516bc721c7 --- /dev/null +++ b/searchlib/src/tests/attribute/direct_posting_store/.gitignore @@ -0,0 +1 @@ +searchlib_direct_posting_store_test_app diff --git a/searchlib/src/tests/attribute/direct_posting_store/CMakeLists.txt b/searchlib/src/tests/attribute/direct_posting_store/CMakeLists.txt new file mode 100644 index 00000000000..3c8e76bc9b2 --- /dev/null +++ b/searchlib/src/tests/attribute/direct_posting_store/CMakeLists.txt @@ -0,0 +1,10 @@ +# Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(searchlib_direct_posting_store_test_app TEST + SOURCES + direct_posting_store_test.cpp + DEPENDS + searchlib + searchlib_test + GTest::GTest +) +vespa_add_test(NAME searchlib_direct_posting_store_test_app COMMAND searchlib_direct_posting_store_test_app) diff --git a/searchlib/src/tests/attribute/direct_posting_store/direct_posting_store_test.cpp b/searchlib/src/tests/attribute/direct_posting_store/direct_posting_store_test.cpp new file mode 100644 index 00000000000..c1e12580559 --- /dev/null +++ b/searchlib/src/tests/attribute/direct_posting_store/direct_posting_store_test.cpp @@ -0,0 +1,297 @@ +// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#include <vespa/searchcommon/attribute/config.h> +#include <vespa/searchlib/attribute/attribute.h> +#include <vespa/searchlib/attribute/attribute_read_guard.h> +#include <vespa/searchlib/attribute/attributefactory.h> +#include <vespa/searchlib/attribute/attributeguard.h> +#include <vespa/searchlib/attribute/attributememorysavetarget.h> +#include <vespa/searchlib/attribute/i_docid_posting_store.h> +#include <vespa/searchlib/attribute/i_docid_with_weight_posting_store.h> +#include <vespa/searchlib/index/dummyfileheadercontext.h> +#include <vespa/searchlib/queryeval/docid_with_weight_search_iterator.h> +#define ENABLE_GTEST_MIGRATION +#include <vespa/searchlib/test/searchiteratorverifier.h> +#include <vespa/searchlib/util/randomgenerator.h> +#include <vespa/vespalib/gtest/gtest.h> +#include <vespa/vespalib/test/insertion_operators.h> + +#include <vespa/log/log.h> +LOG_SETUP("direct_posting_store_test"); + +using namespace search; +using namespace search::attribute; + +AttributeVector::SP make_attribute(BasicType type, CollectionType collection, bool fast_search) { + Config cfg(type, collection); + cfg.setFastSearch(fast_search); + return AttributeFactory::createAttribute("my_attribute", cfg); +} + +void add_docs(AttributeVector::SP attr_ptr, size_t limit = 1000) { + AttributeVector::DocId docid; + for (size_t i = 0; i < limit; ++i) { + attr_ptr->addDoc(docid); + } + attr_ptr->commit(); + ASSERT_EQ((limit - 1), docid); +} + +template <typename ATTR, typename KEY> +void set_doc(ATTR *attr, uint32_t docid, KEY key, int32_t weight) { + attr->clearDoc(docid); + if (attr->getCollectionType() == CollectionType::SINGLE) { + attr->update(docid, key); + } else { + attr->append(docid, key, weight); + } + attr->commit(); +} + +void populate_long(AttributeVector::SP attr_ptr) { + IntegerAttribute *attr = static_cast<IntegerAttribute *>(attr_ptr.get()); + set_doc(attr, 1, int64_t(111), 20); + set_doc(attr, 5, int64_t(111), 5); + set_doc(attr, 7, int64_t(111), 10); +} + +void populate_string(AttributeVector::SP attr_ptr) { + StringAttribute *attr = static_cast<StringAttribute *>(attr_ptr.get()); + set_doc(attr, 1, "foo", 20); + set_doc(attr, 5, "foo", 5); + set_doc(attr, 7, "foo", 10); +} + +struct TestParam { + CollectionType col_type; + BasicType type; + const char* valid_term; + const char* invalid_term; + TestParam(CollectionType col_type_in, BasicType type_in, + const char* valid_term_in, const char* invalid_term_in) + : col_type(col_type_in), type(type_in), valid_term(valid_term_in), invalid_term(invalid_term_in) {} + ~TestParam() {} +}; + +std::ostream& operator<<(std::ostream& os, const TestParam& param) +{ + os << param.col_type.asString() << "_" << param.type.asString(); + return os; +} + +struct DirectPostingStoreTest : public ::testing::TestWithParam<TestParam> { + AttributeVector::SP attr; + bool has_weight; + const IDirectPostingStore* api; + + const IDirectPostingStore* extract_api() { + if (has_weight) { + return attr->as_docid_with_weight_posting_store(); + } else { + return attr->as_docid_posting_store(); + } + } + + DirectPostingStoreTest() + : attr(make_attribute(GetParam().type, GetParam().col_type, true)), + has_weight(GetParam().col_type != CollectionType::SINGLE), + api(extract_api()) + { + assert(api != nullptr); + add_docs(attr); + if (GetParam().type == BasicType::STRING) { + populate_string(attr); + } else { + populate_long(attr); + } + } + ~DirectPostingStoreTest() {} +}; + +void expect_docid_posting_store(BasicType type, CollectionType col_type, bool fast_search) { + EXPECT_TRUE(make_attribute(type, col_type, fast_search)->as_docid_posting_store() != nullptr); +} + +void expect_not_docid_posting_store(BasicType type, CollectionType col_type, bool fast_search) { + EXPECT_TRUE(make_attribute(type, col_type, fast_search)->as_docid_posting_store() == nullptr); +} + +void expect_docid_with_weight_posting_store(BasicType type, CollectionType col_type, bool fast_search) { + EXPECT_TRUE(make_attribute(type, col_type, fast_search)->as_docid_with_weight_posting_store() != nullptr); +} + +void expect_not_docid_with_weight_posting_store(BasicType type, CollectionType col_type, bool fast_search) { + EXPECT_TRUE(make_attribute(type, col_type, fast_search)->as_docid_with_weight_posting_store() == nullptr); +} + +TEST(DirectPostingStoreApiTest, attributes_support_IDocidPostingStore_interface) { + expect_docid_posting_store(BasicType::INT8, CollectionType::SINGLE, true); + expect_docid_posting_store(BasicType::INT16, CollectionType::SINGLE, true); + expect_docid_posting_store(BasicType::INT32, CollectionType::SINGLE, true); + expect_docid_posting_store(BasicType::INT64, CollectionType::SINGLE, true); + expect_docid_posting_store(BasicType::STRING, CollectionType::SINGLE, true); +} + +TEST(DirectPostingStoreApiTest, attributes_do_not_support_IDocidPostingStore_interface) { + expect_not_docid_posting_store(BasicType::BOOL, CollectionType::SINGLE, true); + expect_not_docid_posting_store(BasicType::FLOAT, CollectionType::SINGLE, true); + expect_not_docid_posting_store(BasicType::DOUBLE, CollectionType::SINGLE, true); + expect_not_docid_posting_store(BasicType::INT64, CollectionType::SINGLE, false); + expect_not_docid_posting_store(BasicType::STRING, CollectionType::SINGLE, false); +} + +TEST(DirectPostingStoreApiTest, attributes_support_IDocidWithWeightPostingStore_interface) { + expect_docid_with_weight_posting_store(BasicType::INT64, CollectionType::WSET, true); + expect_docid_with_weight_posting_store(BasicType::STRING, CollectionType::WSET, true); +} + +TEST(DirectPostingStoreApiTest, attributes_do_not_support_IDocidWithWeightPostingStore_interface) { + expect_not_docid_with_weight_posting_store(BasicType::INT64, CollectionType::SINGLE, false); + expect_not_docid_with_weight_posting_store(BasicType::INT64, CollectionType::ARRAY, false); + expect_not_docid_with_weight_posting_store(BasicType::INT64, CollectionType::WSET, false); + expect_not_docid_with_weight_posting_store(BasicType::INT64, CollectionType::SINGLE, true); + expect_not_docid_with_weight_posting_store(BasicType::INT64, CollectionType::ARRAY, true); + expect_not_docid_with_weight_posting_store(BasicType::STRING, CollectionType::SINGLE, false); + expect_not_docid_with_weight_posting_store(BasicType::STRING, CollectionType::ARRAY, false); + expect_not_docid_with_weight_posting_store(BasicType::STRING, CollectionType::WSET, false); + expect_not_docid_with_weight_posting_store(BasicType::STRING, CollectionType::SINGLE, true); + expect_not_docid_with_weight_posting_store(BasicType::STRING, CollectionType::ARRAY, true); + expect_not_docid_with_weight_posting_store(BasicType::INT32, CollectionType::WSET, true); + expect_not_docid_with_weight_posting_store(BasicType::DOUBLE, CollectionType::WSET, true); +} + +void verify_valid_lookup(IDirectPostingStore::LookupResult result, bool has_weight) { + EXPECT_TRUE(result.posting_idx.valid()); + EXPECT_EQ(3u, result.posting_size); + EXPECT_EQ(has_weight ? 5 : 1, result.min_weight); + EXPECT_EQ(has_weight ? 20 : 1, result.max_weight); +} + +void verify_invalid_lookup(IDirectPostingStore::LookupResult result) { + EXPECT_FALSE(result.posting_idx.valid()); + EXPECT_EQ(0u, result.posting_size); + EXPECT_EQ(0, result.min_weight); + EXPECT_EQ(0, result.max_weight); +} + +INSTANTIATE_TEST_SUITE_P(DefaultInstantiation, + DirectPostingStoreTest, + testing::Values(TestParam(CollectionType::SINGLE, BasicType::INT64, "111", "222"), + TestParam(CollectionType::WSET, BasicType::INT64, "111", "222"), + TestParam(CollectionType::SINGLE, BasicType::STRING, "foo", "bar"), + TestParam(CollectionType::WSET, BasicType::STRING, "foo", "bar")), + testing::PrintToStringParamName()); + +TEST_P(DirectPostingStoreTest, lookup_works_correctly) { + verify_valid_lookup(api->lookup(GetParam().valid_term, api->get_dictionary_snapshot()), has_weight); + verify_invalid_lookup(api->lookup(GetParam().invalid_term, api->get_dictionary_snapshot())); +} + +template <typename DirectPostingStoreType, bool has_weight> +void verify_posting(const IDirectPostingStore& api, const vespalib::string& term) { + auto result = api.lookup(term, api.get_dictionary_snapshot()); + ASSERT_TRUE(result.posting_idx.valid()); + std::vector<typename DirectPostingStoreType::IteratorType> itr_store; + auto& real = dynamic_cast<const DirectPostingStoreType&>(api); + real.create(result.posting_idx, itr_store); + ASSERT_EQ(1u, itr_store.size()); + { + auto& itr = itr_store[0]; + if (itr.valid() && itr.getKey() < 1) { + itr.linearSeek(1); + } + ASSERT_TRUE(itr.valid()); + EXPECT_EQ(1u, itr.getKey()); // docid + if constexpr (has_weight) { + EXPECT_EQ(20, itr.getData()); // weight + } + itr.linearSeek(2); + ASSERT_TRUE(itr.valid()); + EXPECT_EQ(5u, itr.getKey()); // docid + if constexpr (has_weight) { + EXPECT_EQ(5, itr.getData()); // weight + } + itr.linearSeek(6); + ASSERT_TRUE(itr.valid()); + EXPECT_EQ(7u, itr.getKey()); // docid + if constexpr (has_weight) { + EXPECT_EQ(10, itr.getData()); // weight + } + itr.linearSeek(8); + EXPECT_FALSE(itr.valid()); + } +} + +TEST_P(DirectPostingStoreTest, iterators_are_created_correctly) { + if (has_weight) { + verify_posting<IDocidWithWeightPostingStore, true>(*api, GetParam().valid_term); + } else { + verify_posting<IDocidPostingStore, false>(*api, GetParam().valid_term); + } +} + +TEST_P(DirectPostingStoreTest, collect_folded_works) +{ + if (GetParam().type == BasicType::STRING) { + auto* sa = static_cast<StringAttribute*>(attr.get()); + set_doc(sa, 2, "bar", 30); + attr->commit(); + set_doc(sa, 3, "FOO", 30); + attr->commit(); + auto snapshot = api->get_dictionary_snapshot(); + auto lookup = api->lookup(GetParam().valid_term, snapshot); + std::vector<vespalib::string> folded; + std::function<void(vespalib::datastore::EntryRef)> save_folded = [&folded,sa](vespalib::datastore::EntryRef enum_idx) { folded.emplace_back(sa->getFromEnum(enum_idx.ref())); }; + api->collect_folded(lookup.enum_idx, snapshot, save_folded); + std::vector<vespalib::string> expected_folded{"FOO", "foo"}; + EXPECT_EQ(expected_folded, folded); + } else { + auto* ia = dynamic_cast<IntegerAttributeTemplate<int64_t>*>(attr.get()); + set_doc(ia, 2, int64_t(112), 30); + attr->commit(); + auto snapshot = api->get_dictionary_snapshot(); + auto lookup = api->lookup(GetParam().valid_term, snapshot); + std::vector<int64_t> folded; + std::function<void(vespalib::datastore::EntryRef)> save_folded = [&folded, ia]( + vespalib::datastore::EntryRef enum_idx) { folded.emplace_back(ia->getFromEnum(enum_idx.ref())); }; + api->collect_folded(lookup.enum_idx, snapshot, save_folded); + std::vector<int64_t> expected_folded{int64_t(111)}; + EXPECT_EQ(expected_folded, folded); + } +} + +class Verifier : public search::test::SearchIteratorVerifier { +public: + Verifier(); + ~Verifier(); + SearchIterator::UP create(bool strict) const override { + (void) strict; + const auto* api = _attr->as_docid_with_weight_posting_store(); + assert(api != nullptr); + auto dict_entry = api->lookup("123", api->get_dictionary_snapshot()); + assert(dict_entry.posting_idx.valid()); + return std::make_unique<queryeval::DocidWithWeightSearchIterator>(_tfmd, *api, dict_entry); + } +private: + mutable fef::TermFieldMatchData _tfmd; + AttributeVector::SP _attr; +}; + +Verifier::Verifier() + : _attr(make_attribute(BasicType::INT64, CollectionType::WSET, true)) +{ + add_docs(_attr, getDocIdLimit()); + auto docids = getExpectedDocIds(); + auto* int_attr = static_cast<IntegerAttribute*>(_attr.get()); + for (auto docid : docids) { + set_doc(int_attr, docid, int64_t(123), 1); + } +} +Verifier::~Verifier() {} + +TEST(VerifierTest, verify_document_weight_search_iterator) { + Verifier verifier; + verifier.verify(); +} + +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/searchlib/src/tests/attribute/document_weight_iterator/.gitignore b/searchlib/src/tests/attribute/document_weight_iterator/.gitignore deleted file mode 100644 index 08cae9a48df..00000000000 --- a/searchlib/src/tests/attribute/document_weight_iterator/.gitignore +++ /dev/null @@ -1 +0,0 @@ -searchlib_document_weight_iterator_test_app diff --git a/searchlib/src/tests/attribute/document_weight_iterator/CMakeLists.txt b/searchlib/src/tests/attribute/document_weight_iterator/CMakeLists.txt deleted file mode 100644 index 4cb480068e3..00000000000 --- a/searchlib/src/tests/attribute/document_weight_iterator/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -vespa_add_executable(searchlib_document_weight_iterator_test_app TEST - SOURCES - document_weight_iterator_test.cpp - DEPENDS - searchlib - searchlib_test -) -vespa_add_test(NAME searchlib_document_weight_iterator_test_app COMMAND searchlib_document_weight_iterator_test_app) diff --git a/searchlib/src/tests/attribute/document_weight_iterator/document_weight_iterator_test.cpp b/searchlib/src/tests/attribute/document_weight_iterator/document_weight_iterator_test.cpp deleted file mode 100644 index 28416d09d6f..00000000000 --- a/searchlib/src/tests/attribute/document_weight_iterator/document_weight_iterator_test.cpp +++ /dev/null @@ -1,226 +0,0 @@ -// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. - -#include <vespa/searchcommon/attribute/config.h> -#include <vespa/searchlib/attribute/attribute.h> -#include <vespa/searchlib/attribute/attribute_read_guard.h> -#include <vespa/searchlib/attribute/attributefactory.h> -#include <vespa/searchlib/attribute/attributeguard.h> -#include <vespa/searchlib/attribute/attributememorysavetarget.h> -#include <vespa/searchlib/attribute/i_docid_with_weight_posting_store.h> -#include <vespa/searchlib/index/dummyfileheadercontext.h> -#include <vespa/searchlib/queryeval/document_weight_search_iterator.h> -#include <vespa/searchlib/test/searchiteratorverifier.h> -#include <vespa/searchlib/util/randomgenerator.h> -#include <vespa/vespalib/test/insertion_operators.h> -#include <vespa/vespalib/testkit/test_kit.h> - -#include <vespa/log/log.h> -LOG_SETUP("document_weight_iterator_test"); - -using namespace search; -using namespace search::attribute; - -AttributeVector::SP make_attribute(BasicType type, CollectionType collection, bool fast_search) { - Config cfg(type, collection); - cfg.setFastSearch(fast_search); - return AttributeFactory::createAttribute("my_attribute", cfg); -} - -void add_docs(AttributeVector::SP attr_ptr, size_t limit = 1000) { - AttributeVector::DocId docid; - for (size_t i = 0; i < limit; ++i) { - attr_ptr->addDoc(docid); - } - attr_ptr->commit(); - ASSERT_EQUAL((limit - 1), docid); -} - -template <typename ATTR, typename KEY> -void set_doc(ATTR *attr, uint32_t docid, KEY key, int32_t weight) { - attr->clearDoc(docid); - attr->append(docid, key, weight); - attr->commit(); -} - -void populate_long(AttributeVector::SP attr_ptr) { - IntegerAttribute *attr = static_cast<IntegerAttribute *>(attr_ptr.get()); - set_doc(attr, 1, int64_t(111), 20); - set_doc(attr, 5, int64_t(111), 5); - set_doc(attr, 7, int64_t(111), 10); -} - -void populate_string(AttributeVector::SP attr_ptr) { - StringAttribute *attr = static_cast<StringAttribute *>(attr_ptr.get()); - set_doc(attr, 1, "foo", 20); - set_doc(attr, 5, "foo", 5); - set_doc(attr, 7, "foo", 10); -} - -struct LongFixture { - AttributeVector::SP attr; - const IDocidWithWeightPostingStore *api; - LongFixture() : attr(make_attribute(BasicType::INT64, CollectionType::WSET, true)), - api(attr->as_docid_with_weight_posting_store()) - { - ASSERT_TRUE(api != nullptr); - add_docs(attr); - populate_long(attr); - } -}; - -struct StringFixture { - AttributeVector::SP attr; - const IDocidWithWeightPostingStore *api; - StringFixture() : attr(make_attribute(BasicType::STRING, CollectionType::WSET, true)), - api(attr->as_docid_with_weight_posting_store()) - { - ASSERT_TRUE(api != nullptr); - add_docs(attr); - populate_string(attr); - } -}; - -TEST("require that appropriate attributes support the document weight attribute interface") { - EXPECT_TRUE(make_attribute(BasicType::INT64, CollectionType::WSET, true)->as_docid_with_weight_posting_store() != nullptr); - EXPECT_TRUE(make_attribute(BasicType::STRING, CollectionType::WSET, true)->as_docid_with_weight_posting_store() != nullptr); -} - -TEST("require that inappropriate attributes do not support the document weight attribute interface") { - EXPECT_TRUE(make_attribute(BasicType::INT64, CollectionType::SINGLE, false)->as_docid_with_weight_posting_store() == nullptr); - EXPECT_TRUE(make_attribute(BasicType::INT64, CollectionType::ARRAY, false)->as_docid_with_weight_posting_store() == nullptr); - EXPECT_TRUE(make_attribute(BasicType::INT64, CollectionType::WSET, false)->as_docid_with_weight_posting_store() == nullptr); - EXPECT_TRUE(make_attribute(BasicType::INT64, CollectionType::SINGLE, true)->as_docid_with_weight_posting_store() == nullptr); - EXPECT_TRUE(make_attribute(BasicType::INT64, CollectionType::ARRAY, true)->as_docid_with_weight_posting_store() == nullptr); - EXPECT_TRUE(make_attribute(BasicType::STRING, CollectionType::SINGLE, false)->as_docid_with_weight_posting_store() == nullptr); - EXPECT_TRUE(make_attribute(BasicType::STRING, CollectionType::ARRAY, false)->as_docid_with_weight_posting_store() == nullptr); - EXPECT_TRUE(make_attribute(BasicType::STRING, CollectionType::WSET, false)->as_docid_with_weight_posting_store() == nullptr); - EXPECT_TRUE(make_attribute(BasicType::STRING, CollectionType::SINGLE, true)->as_docid_with_weight_posting_store() == nullptr); - EXPECT_TRUE(make_attribute(BasicType::STRING, CollectionType::ARRAY, true)->as_docid_with_weight_posting_store() == nullptr); - EXPECT_TRUE(make_attribute(BasicType::INT32, CollectionType::WSET, true)->as_docid_with_weight_posting_store() == nullptr); - EXPECT_TRUE(make_attribute(BasicType::DOUBLE, CollectionType::WSET, true)->as_docid_with_weight_posting_store() == nullptr); -} - -void verify_valid_lookup(IDirectPostingStore::LookupResult result) { - EXPECT_TRUE(result.posting_idx.valid()); - EXPECT_EQUAL(3u, result.posting_size); - EXPECT_EQUAL(5, result.min_weight); - EXPECT_EQUAL(20, result.max_weight); -} - -void verify_invalid_lookup(IDirectPostingStore::LookupResult result) { - EXPECT_FALSE(result.posting_idx.valid()); - EXPECT_EQUAL(0u, result.posting_size); - EXPECT_EQUAL(0, result.min_weight); - EXPECT_EQUAL(0, result.max_weight); -} - -TEST_F("require that integer lookup works correctly", LongFixture) { - verify_valid_lookup(f1.api->lookup("111", f1.api->get_dictionary_snapshot())); - verify_invalid_lookup(f1.api->lookup("222", f1.api->get_dictionary_snapshot())); -} - -TEST_F("require string lookup works correctly", StringFixture) { - verify_valid_lookup(f1.api->lookup("foo", f1.api->get_dictionary_snapshot())); - verify_invalid_lookup(f1.api->lookup("bar", f1.api->get_dictionary_snapshot())); -} - -void verify_posting(const IDocidWithWeightPostingStore &api, const char *term) { - auto result = api.lookup(term, api.get_dictionary_snapshot()); - ASSERT_TRUE(result.posting_idx.valid()); - std::vector<DocidWithWeightIterator> itr_store; - api.create(result.posting_idx, itr_store); - ASSERT_EQUAL(1u, itr_store.size()); - { - DocidWithWeightIterator &itr = itr_store[0]; - if (itr.valid() && itr.getKey() < 1) { - itr.linearSeek(1); - } - ASSERT_TRUE(itr.valid()); - EXPECT_EQUAL(1u, itr.getKey()); // docid - EXPECT_EQUAL(20, itr.getData()); // weight - itr.linearSeek(2); - ASSERT_TRUE(itr.valid()); - EXPECT_EQUAL(5u, itr.getKey()); // docid - EXPECT_EQUAL(5, itr.getData()); // weight - itr.linearSeek(6); - ASSERT_TRUE(itr.valid()); - EXPECT_EQUAL(7u, itr.getKey()); // docid - EXPECT_EQUAL(10, itr.getData()); // weight - itr.linearSeek(8); - EXPECT_FALSE(itr.valid()); - } -} - -TEST_F("require that integer iterators are created correctly", LongFixture) { - verify_posting(*f1.api, "111"); -} - -TEST_F("require that string iterators are created correctly", StringFixture) { - verify_posting(*f1.api, "foo"); -} - -TEST_F("require that collect_folded works for string", StringFixture) -{ - StringAttribute *attr = static_cast<StringAttribute *>(f1.attr.get()); - set_doc(attr, 2, "bar", 30); - attr->commit(); - set_doc(attr, 3, "FOO", 30); - attr->commit(); - auto dictionary_snapshot = f1.api->get_dictionary_snapshot(); - auto lookup1 = f1.api->lookup("foo", dictionary_snapshot); - std::vector<vespalib::string> folded; - std::function<void(vespalib::datastore::EntryRef)> save_folded = [&folded,attr](vespalib::datastore::EntryRef enum_idx) { folded.emplace_back(attr->getFromEnum(enum_idx.ref())); }; - f1.api->collect_folded(lookup1.enum_idx, dictionary_snapshot, save_folded); - std::vector<vespalib::string> expected_folded{"FOO", "foo"}; - EXPECT_EQUAL(expected_folded, folded); -} - -TEST_F("require that collect_folded works for integers", LongFixture) -{ - IntegerAttributeTemplate<int64_t> *attr = dynamic_cast<IntegerAttributeTemplate<int64_t> *>(f1.attr.get()); - set_doc(attr, 2, int64_t(112), 30); - attr->commit(); - auto dictionary_snapshot = f1.api->get_dictionary_snapshot(); - auto lookup1 = f1.api->lookup("111", dictionary_snapshot); - std::vector<int64_t> folded; - std::function<void(vespalib::datastore::EntryRef)> save_folded = [&folded,attr](vespalib::datastore::EntryRef enum_idx) { folded.emplace_back(attr->getFromEnum(enum_idx.ref())); }; - f1.api->collect_folded(lookup1.enum_idx, dictionary_snapshot, save_folded); - std::vector<int64_t> expected_folded{int64_t(111)}; - EXPECT_EQUAL(expected_folded, folded); -} - -class Verifier : public search::test::SearchIteratorVerifier { -public: - Verifier(); - ~Verifier(); - SearchIterator::UP create(bool strict) const override { - (void) strict; - const auto* api = _attr->as_docid_with_weight_posting_store(); - ASSERT_TRUE(api != nullptr); - auto dict_entry = api->lookup("123", api->get_dictionary_snapshot()); - ASSERT_TRUE(dict_entry.posting_idx.valid()); - return std::make_unique<queryeval::DocumentWeightSearchIterator>(_tfmd, *api, dict_entry); - } -private: - mutable fef::TermFieldMatchData _tfmd; - AttributeVector::SP _attr; -}; - -Verifier::Verifier() - : _attr(make_attribute(BasicType::INT64, CollectionType::WSET, true)) -{ - add_docs(_attr, getDocIdLimit()); - auto docids = getExpectedDocIds(); - IntegerAttribute *int_attr = static_cast<IntegerAttribute *>(_attr.get()); - for (auto docid: docids) { - set_doc(int_attr, docid, int64_t(123), 1); - } -} -Verifier::~Verifier() {} - -TEST("verify document weight search iterator") { - Verifier verifier; - verifier.verify(); -} - -TEST_MAIN() { TEST_RUN_ALL(); } diff --git a/searchlib/src/tests/attribute/document_weight_or_filter_search/CMakeLists.txt b/searchlib/src/tests/attribute/document_weight_or_filter_search/CMakeLists.txt deleted file mode 100644 index b2f86a9ddec..00000000000 --- a/searchlib/src/tests/attribute/document_weight_or_filter_search/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -vespa_add_executable(searchlib_document_weight_or_filter_search_test_app TEST - SOURCES - document_weight_or_filter_search_test.cpp - DEPENDS - searchlib - searchlib_test - GTest::GTest -) -vespa_add_test(NAME searchlib_document_weight_or_filter_search_test_app COMMAND searchlib_document_weight_or_filter_search_test_app) diff --git a/searchlib/src/tests/attribute/multi_term_or_filter_search/CMakeLists.txt b/searchlib/src/tests/attribute/multi_term_or_filter_search/CMakeLists.txt new file mode 100644 index 00000000000..4ec5d849ad3 --- /dev/null +++ b/searchlib/src/tests/attribute/multi_term_or_filter_search/CMakeLists.txt @@ -0,0 +1,10 @@ +# Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(searchlib_multi_term_or_filter_search_test_app TEST + SOURCES + multi_term_or_filter_search_test.cpp + DEPENDS + searchlib + searchlib_test + GTest::GTest +) +vespa_add_test(NAME searchlib_multi_term_or_filter_search_test_app COMMAND searchlib_multi_term_or_filter_search_test_app) diff --git a/searchlib/src/tests/attribute/document_weight_or_filter_search/document_weight_or_filter_search_test.cpp b/searchlib/src/tests/attribute/multi_term_or_filter_search/multi_term_or_filter_search_test.cpp index ae4812b5437..552a128c518 100644 --- a/searchlib/src/tests/attribute/document_weight_or_filter_search/document_weight_or_filter_search_test.cpp +++ b/searchlib/src/tests/attribute/multi_term_or_filter_search/multi_term_or_filter_search_test.cpp @@ -1,30 +1,34 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -#include <vespa/vespalib/gtest/gtest.h> #include <vespa/searchlib/attribute/i_direct_posting_store.h> -#include <vespa/searchlib/attribute/document_weight_or_filter_search.h> -#include <vespa/searchlib/queryeval/searchiterator.h> +#include <vespa/searchlib/attribute/multi_term_or_filter_search.h> #include <vespa/searchlib/common/bitvector.h> +#include <vespa/searchlib/fef/termfieldmatchdata.h> +#include <vespa/searchlib/queryeval/searchiterator.h> +#include <vespa/vespalib/gtest/gtest.h> #define ENABLE_GTEST_MIGRATION #include <vespa/searchlib/test/searchiteratorverifier.h> using PostingList = search::attribute::PostingListTraits<int32_t>::PostingStoreBase; using Iterator = search::attribute::PostingListTraits<int32_t>::const_iterator; using KeyData = PostingList::KeyDataType; + using search::BitVector; -using search::attribute::DocumentWeightOrFilterSearch; +using search::attribute::MultiTermOrFilterSearch; +using search::fef::TermFieldMatchData; using search::queryeval::SearchIterator; using vespalib::datastore::EntryRef; -class DocumentWeightOrFilterSearchTest : public ::testing::Test { +class MultiTermOrFilterSearchTest : public ::testing::Test { PostingList _postings; + mutable TermFieldMatchData _tfmd; vespalib::GenerationHandler _gens; std::vector<EntryRef> _trees; uint32_t _range_start; uint32_t _range_end; public: - DocumentWeightOrFilterSearchTest(); - ~DocumentWeightOrFilterSearchTest() override; + MultiTermOrFilterSearchTest(); + ~MultiTermOrFilterSearchTest() override; void inc_generation(); size_t num_trees() const { return _trees.size(); } Iterator get_tree(size_t idx) const { @@ -62,7 +66,7 @@ public: for (size_t i = 0; i < num_trees(); ++i) { iterators.emplace_back(get_tree(i)); } - auto result = DocumentWeightOrFilterSearch::create(std::move(iterators)); + auto result = MultiTermOrFilterSearch::create(std::move(iterators), _tfmd); result->initRange(_range_start, _range_end); return result; }; @@ -73,6 +77,8 @@ public: while (doc_id < _range_end) { if (iterator.seek(doc_id)) { result.emplace_back(doc_id); + iterator.unpack(doc_id); + EXPECT_EQ(doc_id, _tfmd.getDocId()); ++doc_id; } else { doc_id = std::max(doc_id + 1, iterator.getDocId()); @@ -121,7 +127,7 @@ public: } }; -DocumentWeightOrFilterSearchTest::DocumentWeightOrFilterSearchTest() +MultiTermOrFilterSearchTest::MultiTermOrFilterSearchTest() : _postings(true), _gens(), _range_start(1), @@ -129,7 +135,7 @@ DocumentWeightOrFilterSearchTest::DocumentWeightOrFilterSearchTest() { } -DocumentWeightOrFilterSearchTest::~DocumentWeightOrFilterSearchTest() +MultiTermOrFilterSearchTest::~MultiTermOrFilterSearchTest() { for (auto& tree : _trees) { _postings.clear(tree); @@ -140,7 +146,7 @@ DocumentWeightOrFilterSearchTest::~DocumentWeightOrFilterSearchTest() } void -DocumentWeightOrFilterSearchTest::inc_generation() +MultiTermOrFilterSearchTest::inc_generation() { _postings.freeze(); _postings.assign_generation(_gens.getCurrentGeneration()); @@ -148,19 +154,19 @@ DocumentWeightOrFilterSearchTest::inc_generation() _postings.reclaim_memory(_gens.get_oldest_used_generation()); } -TEST_F(DocumentWeightOrFilterSearchTest, daat_or) +TEST_F(MultiTermOrFilterSearchTest, daat_or) { make_sample_data(); expect_result(eval_daat(*make_iterator()), { 3, 10, 11, 14, 17, 20 }); } -TEST_F(DocumentWeightOrFilterSearchTest, taat_get_hits) +TEST_F(MultiTermOrFilterSearchTest, taat_get_hits) { make_sample_data(); expect_result(frombv(*make_iterator()->get_hits(get_range_start())), { 3, 10, 11, 14, 17, 20 }); } -TEST_F(DocumentWeightOrFilterSearchTest, taat_or_hits_into) +TEST_F(MultiTermOrFilterSearchTest, taat_or_hits_into) { make_sample_data(); auto bv = tobv({13, 14}); @@ -168,7 +174,7 @@ TEST_F(DocumentWeightOrFilterSearchTest, taat_or_hits_into) expect_result(frombv(*bv), { 3, 10, 11, 13, 14, 17, 20 }); } -TEST_F(DocumentWeightOrFilterSearchTest, taat_and_hits_into) +TEST_F(MultiTermOrFilterSearchTest, taat_and_hits_into) { make_sample_data(); auto bv = tobv({13, 14}); @@ -176,21 +182,21 @@ TEST_F(DocumentWeightOrFilterSearchTest, taat_and_hits_into) expect_result(frombv(*bv), { 14 }); } -TEST_F(DocumentWeightOrFilterSearchTest, daat_or_ranged) +TEST_F(MultiTermOrFilterSearchTest, daat_or_ranged) { make_sample_data(); set_range(4, 15); expect_result(eval_daat(*make_iterator()), {10, 11, 14 }); } -TEST_F(DocumentWeightOrFilterSearchTest, taat_get_hits_ranged) +TEST_F(MultiTermOrFilterSearchTest, taat_get_hits_ranged) { make_sample_data(); set_range(4, 15); expect_result(frombv(*make_iterator()->get_hits(get_range_start())), { 10, 11, 14 }); } -TEST_F(DocumentWeightOrFilterSearchTest, taat_or_hits_into_ranged) +TEST_F(MultiTermOrFilterSearchTest, taat_or_hits_into_ranged) { make_sample_data(); set_range(4, 15); @@ -199,7 +205,7 @@ TEST_F(DocumentWeightOrFilterSearchTest, taat_or_hits_into_ranged) expect_result(frombv(*bv), { 10, 11, 13, 14 }); } -TEST_F(DocumentWeightOrFilterSearchTest, taat_and_hits_into_ranged) +TEST_F(MultiTermOrFilterSearchTest, taat_and_hits_into_ranged) { make_sample_data(); set_range(4, 15); @@ -211,9 +217,9 @@ TEST_F(DocumentWeightOrFilterSearchTest, taat_and_hits_into_ranged) namespace { class Verifier : public search::test::SearchIteratorVerifier { - DocumentWeightOrFilterSearchTest &_test; + MultiTermOrFilterSearchTest &_test; public: - Verifier(DocumentWeightOrFilterSearchTest &test, int num_trees) + Verifier(MultiTermOrFilterSearchTest &test, int num_trees) : _test(test) { std::vector<std::vector<uint32_t>> trees(num_trees); @@ -239,7 +245,7 @@ public: }; -TEST_F(DocumentWeightOrFilterSearchTest, iterator_conformance) +TEST_F(MultiTermOrFilterSearchTest, iterator_conformance) { { Verifier verifier(*this, 1); diff --git a/searchlib/src/tests/attribute/searchable/attribute_searchable_adapter_test.cpp b/searchlib/src/tests/attribute/searchable/attribute_searchable_adapter_test.cpp index 8831bd1ec75..ecc03ac54c5 100644 --- a/searchlib/src/tests/attribute/searchable/attribute_searchable_adapter_test.cpp +++ b/searchlib/src/tests/attribute/searchable/attribute_searchable_adapter_test.cpp @@ -488,11 +488,11 @@ TEST("require that direct attribute iterators work") { EXPECT_TRUE(result.has_minmax); EXPECT_EQUAL(100, result.min_weight); EXPECT_EQUAL(1000, result.max_weight); - EXPECT_TRUE(result.iterator_dump.find("DocumentWeightSearchIterator") != vespalib::string::npos); + EXPECT_TRUE(result.iterator_dump.find("DocidWithWeightSearchIterator") != vespalib::string::npos); } else { EXPECT_EQUAL(num_docs, result.est_hits); EXPECT_FALSE(result.has_minmax); - EXPECT_TRUE(result.iterator_dump.find("DocumentWeightSearchIterator") == vespalib::string::npos); + EXPECT_TRUE(result.iterator_dump.find("DocidWithWeightSearchIterator") == vespalib::string::npos); } ASSERT_EQUAL(3u, result.hits.size()); EXPECT_FALSE(result.est_empty); @@ -513,7 +513,7 @@ TEST("require that single weighted set turns filter on filter fields") { SimpleStringTerm node("foo", "", 0, Weight(1)); Result result = do_search(attribute_manager, node, strict); EXPECT_EQUAL(3u, result.est_hits); - EXPECT_TRUE(result.iterator_dump.find("DocumentWeightSearchIterator") == vespalib::string::npos); + EXPECT_TRUE(result.iterator_dump.find("DocidWithWeightSearchIterator") == vespalib::string::npos); EXPECT_TRUE(result.iterator_dump.find("FilterAttributePostingListIteratorT") != vespalib::string::npos); ASSERT_EQUAL(3u, result.hits.size()); EXPECT_FALSE(result.est_empty); diff --git a/searchlib/src/tests/attribute/searchcontext/searchcontext_test.cpp b/searchlib/src/tests/attribute/searchcontext/searchcontext_test.cpp index 6e334fffa75..741a86b0beb 100644 --- a/searchlib/src/tests/attribute/searchcontext/searchcontext_test.cpp +++ b/searchlib/src/tests/attribute/searchcontext/searchcontext_test.cpp @@ -468,7 +468,7 @@ template <typename V, typename T> ResultSetPtr SearchContextTest::performSearch(const V & vec, const T & term) { - return performSearch(search::queryeval::ExecuteInfo::TRUE, vec, term, TermType::WORD); + return performSearch(queryeval::ExecuteInfo::TRUE, vec, term, TermType::WORD); } template <typename V, typename T> @@ -503,7 +503,7 @@ void SearchContextTest::performSearch(const V & vec, const vespalib::string & term, const DocSet & expected, TermType termType) { - performSearch(search::queryeval::ExecuteInfo::TRUE, vec, term, expected, termType); + performSearch(queryeval::ExecuteInfo::TRUE, vec, term, expected, termType); } void @@ -1113,7 +1113,7 @@ SearchContextTest::performRangeSearch(const VectorType & vec, const vespalib::st { for (size_t num_threads : {1,3}) { vespalib::SimpleThreadBundle thread_bundle(num_threads); - auto executeInfo = search::queryeval::ExecuteInfo::create(true, 1.0, nullptr, thread_bundle, true, true); + auto executeInfo = queryeval::ExecuteInfo::create(true, 1.0, vespalib::Doom::never(), thread_bundle); performSearch(executeInfo, vec, term, expected, TermType::WORD); } } diff --git a/searchlib/src/tests/attribute/stringattribute/stringattribute_test.cpp b/searchlib/src/tests/attribute/stringattribute/stringattribute_test.cpp index 1beb2b1e501..1bfb9fb41f9 100644 --- a/searchlib/src/tests/attribute/stringattribute/stringattribute_test.cpp +++ b/searchlib/src/tests/attribute/stringattribute/stringattribute_test.cpp @@ -1,5 +1,6 @@ // 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/searchcommon/attribute/config.h> #include <vespa/searchlib/attribute/enumstore.h> #include <vespa/searchlib/attribute/singlestringattribute.h> #include <vespa/searchlib/attribute/singlestringpostattribute.h> @@ -8,7 +9,6 @@ #include <vespa/searchlib/attribute/enumstore.hpp> #include <vespa/searchlib/attribute/single_string_enum_search_context.h> -#include <vespa/searchlib/attribute/multistringpostattribute.hpp> #include <vespa/log/log.h> LOG_SETUP("stringattribute_test"); diff --git a/searchlib/src/tests/attribute/tensorattribute/tensorattribute_test.cpp b/searchlib/src/tests/attribute/tensorattribute/tensorattribute_test.cpp index 81862b74eb2..b1b2235165f 100644 --- a/searchlib/src/tests/attribute/tensorattribute/tensorattribute_test.cpp +++ b/searchlib/src/tests/attribute/tensorattribute/tensorattribute_test.cpp @@ -7,7 +7,6 @@ #include <vespa/searchlib/tensor/dense_tensor_attribute.h> #include <vespa/searchlib/tensor/direct_tensor_attribute.h> #include <vespa/searchlib/tensor/doc_vector_access.h> -#include <vespa/searchlib/tensor/distance_functions.h> #include <vespa/searchlib/tensor/hnsw_index.h> #include <vespa/searchlib/tensor/mips_distance_transform.h> #include <vespa/searchlib/tensor/nearest_neighbor_index.h> @@ -25,7 +24,6 @@ #include <vespa/vespalib/testkit/test_kit.h> #include <vespa/vespalib/util/mmap_file_allocator_factory.h> #include <vespa/searchlib/util/bufferwriter.h> -#include <vespa/vespalib/util/fake_doom.h> #include <vespa/vespalib/util/threadstackexecutor.h> #include <vespa/document/base/exceptions.h> #include <vespa/eval/eval/fast_value.h> @@ -132,7 +130,7 @@ private: int _index_value; public: - MockIndexSaver(int index_value) : _index_value(index_value) {} + explicit MockIndexSaver(int index_value) noexcept : _index_value(index_value) {} void save(search::BufferWriter& writer) const override { writer.write(&_index_value, sizeof(int)); writer.flush(); @@ -158,7 +156,7 @@ public: class MockPrepareResult : public PrepareResult { public: uint32_t docid; - MockPrepareResult(uint32_t docid_in) : docid(docid_in) {} + explicit MockPrepareResult(uint32_t docid_in) noexcept : docid(docid_in) {} }; class MockNearestNeighborIndex : public NearestNeighborIndex { @@ -177,7 +175,7 @@ private: int _index_value; public: - MockNearestNeighborIndex(const DocVectorAccess& vectors) + explicit MockNearestNeighborIndex(const DocVectorAccess& vectors) : _vectors(vectors), _adds(), _removes(), @@ -279,11 +277,11 @@ public: } vespalib::MemoryUsage update_stat(const CompactionStrategy&) override { ++_memory_usage_cnt; - return vespalib::MemoryUsage(); + return {}; } vespalib::MemoryUsage memory_usage() const override { ++_memory_usage_cnt; - return vespalib::MemoryUsage(); + return {}; } void populate_address_space_usage(AddressSpaceUsage&) const override {} void get_state(const vespalib::slime::Inserter&) const override {} @@ -293,7 +291,7 @@ public: if (_index_value != 0) { return std::make_unique<MockIndexSaver>(_index_value); } - return std::unique_ptr<NearestNeighborIndexSaver>(); + return {}; } std::unique_ptr<NearestNeighborIndexLoader> make_loader(FastOS_FileInterface& file, const vespalib::GenericHeader& header) override { (void) header; @@ -310,7 +308,7 @@ public: (void) explore_k; (void) doom; (void) distance_threshold; - return std::vector<Neighbor>(); + return {}; } std::vector<Neighbor> find_top_k_with_filter(uint32_t k, const search::tensor::BoundDistanceFunction &df, @@ -324,7 +322,7 @@ public: (void) filter; (void) doom; (void) distance_threshold; - return std::vector<Neighbor>(); + return {}; } search::tensor::DistanceFunctionFactory &distance_function_factory() const override { @@ -427,7 +425,7 @@ struct Fixture { FixtureTraits _traits; vespalib::string _mmap_allocator_base_dir; - Fixture(const vespalib::string &typeSpec, FixtureTraits traits = FixtureTraits()); + explicit Fixture(const vespalib::string &typeSpec, FixtureTraits traits = FixtureTraits()); ~Fixture(); @@ -589,7 +587,7 @@ struct Fixture { } TensorSpec expEmptyDenseTensor() const { - return TensorSpec(denseSpec); + return {denseSpec}; } vespalib::string expEmptyDenseTensorSpec() const { @@ -1296,12 +1294,10 @@ template <typename ParentT> class NearestNeighborBlueprintFixtureBase : public ParentT { private: std::unique_ptr<Value> _query_tensor; - vespalib::FakeDoom _no_doom; public: NearestNeighborBlueprintFixtureBase() - : _query_tensor(), - _no_doom() + : _query_tensor() { this->set_tensor(1, vec_2d(1, 1)); this->set_tensor(2, vec_2d(2, 2)); @@ -1329,7 +1325,7 @@ public: std::make_unique<DistanceCalculator>(this->as_dense_tensor(), create_query_tensor(vec_2d(17, 42))), 3, approximate, 5, 100100.25, - global_filter_lower_limit, 1.0, target_hits_max_adjustment_factor, _no_doom.get_doom()); + global_filter_lower_limit, 1.0, target_hits_max_adjustment_factor, vespalib::Doom::never()); EXPECT_EQUAL(11u, bp->getState().estimate().estHits); EXPECT_EQUAL(100100.25 * 100100.25, bp->get_distance_threshold()); return bp; diff --git a/searchlib/src/tests/common/bitvector/bitvector_test.cpp b/searchlib/src/tests/common/bitvector/bitvector_test.cpp index 2ac9fb738f8..758f44cdba2 100644 --- a/searchlib/src/tests/common/bitvector/bitvector_test.cpp +++ b/searchlib/src/tests/common/bitvector/bitvector_test.cpp @@ -646,45 +646,45 @@ TEST("requireThatGrowWorks") EXPECT_EQUAL(4u, v.writer().countTrueBits()); EXPECT_EQUAL(200u, v.reader().size()); - EXPECT_EQUAL(1023u, v.writer().capacity()); + EXPECT_EQUAL(2047u, v.writer().capacity()); EXPECT_TRUE(assertBV("[7,39,71,103]", v.reader())); EXPECT_EQUAL(4u, v.writer().countTrueBits()); - EXPECT_TRUE(v.reserve(1024)); + EXPECT_TRUE(v.reserve(2048u)); EXPECT_EQUAL(200u, v.reader().size()); - EXPECT_EQUAL(2047u, v.writer().capacity()); + EXPECT_EQUAL(4095u, v.writer().capacity()); EXPECT_TRUE(assertBV("[7,39,71,103]", v.reader())); EXPECT_EQUAL(4u, v.writer().countTrueBits()); EXPECT_FALSE(v.extend(202)); EXPECT_EQUAL(202u, v.reader().size()); - EXPECT_EQUAL(2047u, v.writer().capacity()); + EXPECT_EQUAL(4095u, v.writer().capacity()); EXPECT_TRUE(assertBV("[7,39,71,103]", v.reader())); EXPECT_EQUAL(4u, v.writer().countTrueBits()); EXPECT_FALSE(v.shrink(200)); EXPECT_EQUAL(200u, v.reader().size()); - EXPECT_EQUAL(2047u, v.writer().capacity()); + EXPECT_EQUAL(4095u, v.writer().capacity()); EXPECT_TRUE(assertBV("[7,39,71,103]", v.reader())); EXPECT_EQUAL(4u, v.writer().countTrueBits()); - EXPECT_FALSE(v.reserve(2047)); + EXPECT_FALSE(v.reserve(4095u)); EXPECT_EQUAL(200u, v.reader().size()); - EXPECT_EQUAL(2047u, v.writer().capacity()); + EXPECT_EQUAL(4095u, v.writer().capacity()); EXPECT_TRUE(assertBV("[7,39,71,103]", v.reader())); EXPECT_EQUAL(4u, v.writer().countTrueBits()); EXPECT_FALSE(v.shrink(202)); EXPECT_EQUAL(202u, v.reader().size()); - EXPECT_EQUAL(2047u, v.writer().capacity()); + EXPECT_EQUAL(4095u, v.writer().capacity()); EXPECT_TRUE(assertBV("[7,39,71,103]", v.reader())); EXPECT_EQUAL(4u, v.writer().countTrueBits()); EXPECT_FALSE(v.shrink(100)); EXPECT_EQUAL(100u, v.reader().size()); - EXPECT_EQUAL(2047u, v.writer().capacity()); + EXPECT_EQUAL(4095u, v.writer().capacity()); EXPECT_TRUE(assertBV("[7,39,71]", v.reader())); EXPECT_EQUAL(3u, v.writer().countTrueBits()); v.writer().invalidateCachedCount(); - EXPECT_TRUE(v.reserve(3100)); + EXPECT_TRUE(v.reserve(5100u)); EXPECT_EQUAL(100u, v.reader().size()); - EXPECT_EQUAL(4095u, v.writer().capacity()); + EXPECT_EQUAL(6143u, v.writer().capacity()); EXPECT_EQUAL(3u, v.writer().countTrueBits()); g.assign_generation(1); @@ -701,9 +701,9 @@ TEST("require that growable bit vectors keeps memory allocator") EXPECT_EQUAL(AllocStats(1, 0), stats); v.writer().resize(1); // DO NOT TRY THIS AT HOME EXPECT_EQUAL(AllocStats(2, 1), stats); - v.reserve(2000); + v.reserve(2048); EXPECT_EQUAL(AllocStats(3, 1), stats); - v.extend(4000); + v.extend(5000); EXPECT_EQUAL(AllocStats(4, 1), stats); v.shrink(200); EXPECT_EQUAL(AllocStats(4, 1), stats); diff --git a/searchlib/src/tests/features/CMakeLists.txt b/searchlib/src/tests/features/CMakeLists.txt index 9d2ed02f5dd..ea2410734b5 100644 --- a/searchlib/src/tests/features/CMakeLists.txt +++ b/searchlib/src/tests/features/CMakeLists.txt @@ -17,5 +17,6 @@ vespa_add_executable(searchlib_featurebenchmark_app featurebenchmark.cpp DEPENDS searchlib + searchlib_test ) vespa_add_test(NAME searchlib_featurebenchmark_app COMMAND searchlib_featurebenchmark_app BENCHMARK) diff --git a/searchlib/src/tests/features/beta/CMakeLists.txt b/searchlib/src/tests/features/beta/CMakeLists.txt index 543982c549c..db45f02d898 100644 --- a/searchlib/src/tests/features/beta/CMakeLists.txt +++ b/searchlib/src/tests/features/beta/CMakeLists.txt @@ -4,6 +4,7 @@ vespa_add_executable(searchlib_beta_features_test_app TEST beta_features_test.cpp DEPENDS searchlib + searchlib_test ) vespa_add_test( NAME searchlib_beta_features_test_app diff --git a/searchlib/src/tests/features/beta/beta_features_test.cpp b/searchlib/src/tests/features/beta/beta_features_test.cpp index e0f57a6cad1..8413cfde47f 100644 --- a/searchlib/src/tests/features/beta/beta_features_test.cpp +++ b/searchlib/src/tests/features/beta/beta_features_test.cpp @@ -14,7 +14,7 @@ #include <vespa/searchlib/features/utils.h> #include <vespa/searchlib/fef/test/plugin/setup.h> #include <vespa/vespalib/util/rand48.h> -#include <vespa/searchlib/fef/test/ftlib.h> +#include <vespa/searchlib/test/ft_test_app.h> #include <vespa/vespalib/util/stringfmt.h> using namespace search::features; diff --git a/searchlib/src/tests/features/bm25/bm25_test.cpp b/searchlib/src/tests/features/bm25/bm25_test.cpp index 8abd3d104b9..233c0ec09f3 100644 --- a/searchlib/src/tests/features/bm25/bm25_test.cpp +++ b/searchlib/src/tests/features/bm25/bm25_test.cpp @@ -4,9 +4,9 @@ #include <vespa/searchlib/features/setup.h> #include <vespa/searchlib/fef/blueprintfactory.h> #include <vespa/searchlib/fef/test/dummy_dependency_handler.h> -#include <vespa/searchlib/fef/test/ftlib.h> #include <vespa/searchlib/fef/test/indexenvironment.h> #include <vespa/searchlib/fef/test/indexenvironmentbuilder.h> +#include <vespa/searchlib/test/ft_test_app.h> #include <vespa/vespalib/gtest/gtest.h> using namespace search::features; diff --git a/searchlib/src/tests/features/element_completeness/CMakeLists.txt b/searchlib/src/tests/features/element_completeness/CMakeLists.txt index 327bb691819..046b061b884 100644 --- a/searchlib/src/tests/features/element_completeness/CMakeLists.txt +++ b/searchlib/src/tests/features/element_completeness/CMakeLists.txt @@ -4,5 +4,6 @@ vespa_add_executable(searchlib_element_completeness_test_app TEST element_completeness_test.cpp DEPENDS searchlib + searchlib_test ) vespa_add_test(NAME searchlib_element_completeness_test_app COMMAND searchlib_element_completeness_test_app) diff --git a/searchlib/src/tests/features/element_completeness/element_completeness_test.cpp b/searchlib/src/tests/features/element_completeness/element_completeness_test.cpp index 3b2a5035d1a..ff210035502 100644 --- a/searchlib/src/tests/features/element_completeness/element_completeness_test.cpp +++ b/searchlib/src/tests/features/element_completeness/element_completeness_test.cpp @@ -5,8 +5,8 @@ #include <vespa/searchlib/fef/test/indexenvironmentbuilder.h> #include <vespa/searchlib/fef/test/queryenvironment.h> #include <vespa/searchlib/features/element_completeness_feature.h> -#include <vespa/searchlib/fef/test/ftlib.h> #include <vespa/searchlib/fef/test/dummy_dependency_handler.h> +#include <vespa/searchlib/test/ft_test_app.h> #include <vespa/vespalib/util/stringfmt.h> using namespace search::fef; diff --git a/searchlib/src/tests/features/element_similarity_feature/CMakeLists.txt b/searchlib/src/tests/features/element_similarity_feature/CMakeLists.txt index 921e4bab04e..748556b0fcd 100644 --- a/searchlib/src/tests/features/element_similarity_feature/CMakeLists.txt +++ b/searchlib/src/tests/features/element_similarity_feature/CMakeLists.txt @@ -4,5 +4,6 @@ vespa_add_executable(searchlib_element_similarity_feature_test_app TEST element_similarity_feature_test.cpp DEPENDS searchlib + searchlib_test ) vespa_add_test(NAME searchlib_element_similarity_feature_test_app COMMAND searchlib_element_similarity_feature_test_app) diff --git a/searchlib/src/tests/features/element_similarity_feature/element_similarity_feature_test.cpp b/searchlib/src/tests/features/element_similarity_feature/element_similarity_feature_test.cpp index 3aedb3c51ed..1eda660d2ec 100644 --- a/searchlib/src/tests/features/element_similarity_feature/element_similarity_feature_test.cpp +++ b/searchlib/src/tests/features/element_similarity_feature/element_similarity_feature_test.cpp @@ -5,7 +5,7 @@ #include <vespa/searchlib/fef/test/indexenvironmentbuilder.h> #include <vespa/searchlib/fef/test/queryenvironment.h> #include <vespa/searchlib/features/element_similarity_feature.h> -#include <vespa/searchlib/fef/test/ftlib.h> +#include <vespa/searchlib/test/ft_test_app.h> #include <initializer_list> #include <vespa/searchlib/fef/test/dummy_dependency_handler.h> #include <vespa/vespalib/util/stringfmt.h> diff --git a/searchlib/src/tests/features/euclidean_distance/CMakeLists.txt b/searchlib/src/tests/features/euclidean_distance/CMakeLists.txt index 6af6a9095ac..df55b8f834c 100644 --- a/searchlib/src/tests/features/euclidean_distance/CMakeLists.txt +++ b/searchlib/src/tests/features/euclidean_distance/CMakeLists.txt @@ -4,5 +4,6 @@ vespa_add_executable(searchlib_euclidean_distance_test_app TEST euclidean_distance_test.cpp DEPENDS searchlib + searchlib_test ) vespa_add_test(NAME searchlib_euclidean_distance_test_app COMMAND searchlib_euclidean_distance_test_app) diff --git a/searchlib/src/tests/features/euclidean_distance/euclidean_distance_test.cpp b/searchlib/src/tests/features/euclidean_distance/euclidean_distance_test.cpp index d327253731d..3bc61a77c55 100644 --- a/searchlib/src/tests/features/euclidean_distance/euclidean_distance_test.cpp +++ b/searchlib/src/tests/features/euclidean_distance/euclidean_distance_test.cpp @@ -1,16 +1,16 @@ // 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/searchcommon/attribute/config.h> #include <vespa/searchlib/attribute/attributefactory.h> #include <vespa/searchlib/attribute/attributevector.h> #include <vespa/searchlib/attribute/integerbase.h> #include <vespa/searchlib/attribute/floatbase.h> #include <vespa/searchlib/features/setup.h> #include <vespa/searchlib/fef/test/indexenvironment.h> -#include <vespa/searchlib/fef/test/ftlib.h> #include <vespa/searchlib/features/euclidean_distance_feature.h> #include <vespa/searchlib/fef/fef.h> -#include <vespa/searchcommon/attribute/config.h> +#include <vespa/searchlib/test/ft_test_app.h> using search::feature_t; diff --git a/searchlib/src/tests/features/featurebenchmark.cpp b/searchlib/src/tests/features/featurebenchmark.cpp index e151b47a0c9..9c3d4943d65 100644 --- a/searchlib/src/tests/features/featurebenchmark.cpp +++ b/searchlib/src/tests/features/featurebenchmark.cpp @@ -11,7 +11,7 @@ #include <vespa/searchlib/fef/functiontablefactory.h> #include <vespa/searchlib/fef/test/plugin/setup.h> #include <vespa/vespalib/util/stringfmt.h> -#include <vespa/searchlib/fef/test/ftlib.h> +#include <vespa/searchlib/test/ft_test_app.h> #include <vespa/searchcommon/attribute/config.h> #include <fstream> diff --git a/searchlib/src/tests/features/internal_max_reduce_prod_join_feature/CMakeLists.txt b/searchlib/src/tests/features/internal_max_reduce_prod_join_feature/CMakeLists.txt index 217af473987..e7fc3126e2f 100644 --- a/searchlib/src/tests/features/internal_max_reduce_prod_join_feature/CMakeLists.txt +++ b/searchlib/src/tests/features/internal_max_reduce_prod_join_feature/CMakeLists.txt @@ -4,5 +4,6 @@ vespa_add_executable(searchlib_internal_max_reduce_prod_join_feature_test_app TE internal_max_reduce_prod_join_feature_test.cpp DEPENDS searchlib + searchlib_test ) vespa_add_test(NAME searchlib_internal_max_reduce_prod_join_feature_test_app COMMAND searchlib_internal_max_reduce_prod_join_feature_test_app) diff --git a/searchlib/src/tests/features/internal_max_reduce_prod_join_feature/internal_max_reduce_prod_join_feature_test.cpp b/searchlib/src/tests/features/internal_max_reduce_prod_join_feature/internal_max_reduce_prod_join_feature_test.cpp index 852827244bc..7611296c641 100644 --- a/searchlib/src/tests/features/internal_max_reduce_prod_join_feature/internal_max_reduce_prod_join_feature_test.cpp +++ b/searchlib/src/tests/features/internal_max_reduce_prod_join_feature/internal_max_reduce_prod_join_feature_test.cpp @@ -2,11 +2,11 @@ #include <vespa/vespalib/testkit/test_kit.h> +#include <vespa/searchcommon/attribute/config.h> +#include <vespa/searchlib/attribute/attribute.h> #include <vespa/searchlib/attribute/attributefactory.h> -#include <vespa/searchlib/fef/test/ftlib.h> #include <vespa/searchlib/features/internal_max_reduce_prod_join_feature.h> -#include <vespa/searchlib/attribute/attribute.h> -#include <vespa/searchcommon/attribute/config.h> +#include <vespa/searchlib/test/ft_test_app.h> using search::feature_t; using namespace search::fef; diff --git a/searchlib/src/tests/features/prod_features_test.h b/searchlib/src/tests/features/prod_features_test.h index 94c4e496dd2..aeadf23be80 100644 --- a/searchlib/src/tests/features/prod_features_test.h +++ b/searchlib/src/tests/features/prod_features_test.h @@ -4,7 +4,7 @@ #include <vespa/searchlib/features/distancetopathfeature.h> #include <vespa/searchlib/features/termdistancefeature.h> -#include <vespa/searchlib/fef/test/ftlib.h> +#include <vespa/searchlib/test/ft_test_app.h> class Test : public FtTestApp { diff --git a/searchlib/src/tests/features/tensor/tensor_test.cpp b/searchlib/src/tests/features/tensor/tensor_test.cpp index 96a53d98865..fe4464bad72 100644 --- a/searchlib/src/tests/features/tensor/tensor_test.cpp +++ b/searchlib/src/tests/features/tensor/tensor_test.cpp @@ -1,21 +1,21 @@ // 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/eval/eval/function.h> +#include <vespa/eval/eval/simple_value.h> +#include <vespa/eval/eval/tensor_spec.h> +#include <vespa/eval/eval/value.h> +#include <vespa/eval/eval/value_codec.h> +#include <vespa/eval/eval/test/value_compare.h> +#include <vespa/searchcommon/attribute/config.h> #include <vespa/searchlib/attribute/attributefactory.h> #include <vespa/searchlib/attribute/attributevector.h> #include <vespa/searchlib/features/setup.h> #include <vespa/searchlib/fef/fef.h> -#include <vespa/searchlib/fef/test/ftlib.h> #include <vespa/searchlib/fef/test/indexenvironment.h> #include <vespa/searchlib/tensor/tensor_attribute.h> #include <vespa/searchlib/tensor/direct_tensor_attribute.h> -#include <vespa/searchcommon/attribute/config.h> -#include <vespa/eval/eval/function.h> -#include <vespa/eval/eval/simple_value.h> -#include <vespa/eval/eval/tensor_spec.h> -#include <vespa/eval/eval/value.h> -#include <vespa/eval/eval/value_codec.h> -#include <vespa/eval/eval/test/value_compare.h> +#include <vespa/searchlib/test/ft_test_app.h> #include <vespa/vespalib/objects/nbostream.h> using search::feature_t; diff --git a/searchlib/src/tests/features/tensor_from_labels/CMakeLists.txt b/searchlib/src/tests/features/tensor_from_labels/CMakeLists.txt index 186ecf38c9e..3ecceffd422 100644 --- a/searchlib/src/tests/features/tensor_from_labels/CMakeLists.txt +++ b/searchlib/src/tests/features/tensor_from_labels/CMakeLists.txt @@ -4,5 +4,6 @@ vespa_add_executable(searchlib_tensor_from_labels_test_app TEST tensor_from_labels_test.cpp DEPENDS searchlib + searchlib_test ) vespa_add_test(NAME searchlib_tensor_from_labels_test_app COMMAND searchlib_tensor_from_labels_test_app) diff --git a/searchlib/src/tests/features/tensor_from_labels/tensor_from_labels_test.cpp b/searchlib/src/tests/features/tensor_from_labels/tensor_from_labels_test.cpp index 20cfa4d84c8..f241398539a 100644 --- a/searchlib/src/tests/features/tensor_from_labels/tensor_from_labels_test.cpp +++ b/searchlib/src/tests/features/tensor_from_labels/tensor_from_labels_test.cpp @@ -8,8 +8,8 @@ #include <vespa/searchlib/features/setup.h> #include <vespa/searchlib/features/tensor_from_labels_feature.h> #include <vespa/searchlib/fef/fef.h> -#include <vespa/searchlib/fef/test/ftlib.h> #include <vespa/searchlib/fef/test/indexenvironment.h> +#include <vespa/searchlib/test/ft_test_app.h> #include <vespa/searchcommon/attribute/config.h> #include <vespa/eval/eval/function.h> #include <vespa/eval/eval/simple_value.h> diff --git a/searchlib/src/tests/features/tensor_from_weighted_set/CMakeLists.txt b/searchlib/src/tests/features/tensor_from_weighted_set/CMakeLists.txt index bf93e8923b5..b5322c1a64c 100644 --- a/searchlib/src/tests/features/tensor_from_weighted_set/CMakeLists.txt +++ b/searchlib/src/tests/features/tensor_from_weighted_set/CMakeLists.txt @@ -4,5 +4,6 @@ vespa_add_executable(searchlib_tensor_from_weighted_set_test_app TEST tensor_from_weighted_set_test.cpp DEPENDS searchlib + searchlib_test ) vespa_add_test(NAME searchlib_tensor_from_weighted_set_test_app COMMAND searchlib_tensor_from_weighted_set_test_app) diff --git a/searchlib/src/tests/features/tensor_from_weighted_set/tensor_from_weighted_set_test.cpp b/searchlib/src/tests/features/tensor_from_weighted_set/tensor_from_weighted_set_test.cpp index db734387288..9c8f231051e 100644 --- a/searchlib/src/tests/features/tensor_from_weighted_set/tensor_from_weighted_set_test.cpp +++ b/searchlib/src/tests/features/tensor_from_weighted_set/tensor_from_weighted_set_test.cpp @@ -1,6 +1,12 @@ // 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/eval/eval/function.h> +#include <vespa/eval/eval/simple_value.h> +#include <vespa/eval/eval/tensor_spec.h> +#include <vespa/eval/eval/value.h> +#include <vespa/eval/eval/test/value_compare.h> +#include <vespa/searchcommon/attribute/config.h> #include <vespa/searchlib/attribute/attributefactory.h> #include <vespa/searchlib/attribute/attributevector.h> #include <vespa/searchlib/attribute/integerbase.h> @@ -8,14 +14,8 @@ #include <vespa/searchlib/features/setup.h> #include <vespa/searchlib/features/tensor_from_weighted_set_feature.h> #include <vespa/searchlib/fef/fef.h> -#include <vespa/searchlib/fef/test/ftlib.h> #include <vespa/searchlib/fef/test/indexenvironment.h> -#include <vespa/searchcommon/attribute/config.h> -#include <vespa/eval/eval/function.h> -#include <vespa/eval/eval/simple_value.h> -#include <vespa/eval/eval/tensor_spec.h> -#include <vespa/eval/eval/value.h> -#include <vespa/eval/eval/test/value_compare.h> +#include <vespa/searchlib/test/ft_test_app.h> using search::feature_t; using namespace search::fef; diff --git a/searchlib/src/tests/features/text_similarity_feature/CMakeLists.txt b/searchlib/src/tests/features/text_similarity_feature/CMakeLists.txt index 363619ce4fb..cfa715af516 100644 --- a/searchlib/src/tests/features/text_similarity_feature/CMakeLists.txt +++ b/searchlib/src/tests/features/text_similarity_feature/CMakeLists.txt @@ -4,5 +4,6 @@ vespa_add_executable(searchlib_text_similarity_feature_test_app TEST text_similarity_feature_test.cpp DEPENDS searchlib + searchlib_test ) vespa_add_test(NAME searchlib_text_similarity_feature_test_app COMMAND searchlib_text_similarity_feature_test_app) diff --git a/searchlib/src/tests/features/text_similarity_feature/text_similarity_feature_test.cpp b/searchlib/src/tests/features/text_similarity_feature/text_similarity_feature_test.cpp index 03734b15d64..cf0660282f2 100644 --- a/searchlib/src/tests/features/text_similarity_feature/text_similarity_feature_test.cpp +++ b/searchlib/src/tests/features/text_similarity_feature/text_similarity_feature_test.cpp @@ -1,14 +1,14 @@ // 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/features/setup.h> +#include <vespa/searchlib/fef/test/dummy_dependency_handler.h> #include <vespa/searchlib/fef/test/indexenvironment.h> #include <vespa/searchlib/fef/test/indexenvironmentbuilder.h> #include <vespa/searchlib/fef/test/queryenvironment.h> #include <vespa/searchlib/features/text_similarity_feature.h> -#include <vespa/searchlib/fef/test/ftlib.h> -#include <initializer_list> -#include <vespa/searchlib/fef/test/dummy_dependency_handler.h> +#include <vespa/searchlib/test/ft_test_app.h> #include <vespa/vespalib/util/stringfmt.h> +#include <initializer_list> using namespace search::fef; using namespace search::fef::test; diff --git a/searchlib/src/tests/nativerank/CMakeLists.txt b/searchlib/src/tests/nativerank/CMakeLists.txt index 20fdc0c1245..2a46dd54904 100644 --- a/searchlib/src/tests/nativerank/CMakeLists.txt +++ b/searchlib/src/tests/nativerank/CMakeLists.txt @@ -4,6 +4,7 @@ vespa_add_executable(searchlib_nativerank_test_app TEST nativerank_test.cpp DEPENDS searchlib + searchlib_test ) vespa_add_test( NAME searchlib_nativerank_test_app diff --git a/searchlib/src/tests/nativerank/nativerank_test.cpp b/searchlib/src/tests/nativerank/nativerank_test.cpp index bc9c579a597..69234071a34 100644 --- a/searchlib/src/tests/nativerank/nativerank_test.cpp +++ b/searchlib/src/tests/nativerank/nativerank_test.cpp @@ -10,8 +10,8 @@ #include <vespa/searchlib/fef/functiontablefactory.h> #include <vespa/searchlib/fef/test/plugin/setup.h> #include <vespa/vespalib/util/stringfmt.h> -#include <vespa/searchlib/fef/test/ftlib.h> #include <vespa/searchlib/fef/test/dummy_dependency_handler.h> +#include <vespa/searchlib/test/ft_test_app.h> #include <vespa/log/log.h> LOG_SETUP("nativerank_test"); diff --git a/searchlib/src/tests/query/streaming_query_test.cpp b/searchlib/src/tests/query/streaming_query_test.cpp index 306456518b7..7c4b7555158 100644 --- a/searchlib/src/tests/query/streaming_query_test.cpp +++ b/searchlib/src/tests/query/streaming_query_test.cpp @@ -6,6 +6,7 @@ #include <vespa/searchlib/query/streaming/in_term.h> #include <vespa/searchlib/query/streaming/query.h> #include <vespa/searchlib/query/streaming/nearest_neighbor_query_node.h> +#include <vespa/searchlib/query/streaming/wand_term.h> #include <vespa/searchlib/query/tree/querybuilder.h> #include <vespa/searchlib/query/tree/simplequery.h> #include <vespa/searchlib/query/tree/stackdumpcreator.h> @@ -27,6 +28,7 @@ void assertHit(const Hit & h, size_t expWordpos, size_t expContext, int32_t weig EXPECT_EQ(h.weight(), weight); } + TEST(StreamingQueryTest, test_query_language) { QueryNodeResultFactory factory; @@ -38,7 +40,7 @@ TEST(StreamingQueryTest, test_query_language) EXPECT_TRUE(q.getAsIntegerTerm(ia, ib)); EXPECT_EQ(ia, 7); EXPECT_EQ(ib, 7); - EXPECT_TRUE(q.getAsDoubleTerm(da, db)); + EXPECT_TRUE(q.getAsFloatTerm(da, db)); EXPECT_EQ(da, 7); EXPECT_EQ(db, 7); } @@ -48,15 +50,24 @@ TEST(StreamingQueryTest, test_query_language) EXPECT_TRUE(q.getAsIntegerTerm(ia, ib)); EXPECT_EQ(ia, -7); EXPECT_EQ(ib, -7); - EXPECT_TRUE(q.getAsDoubleTerm(da, db)); + EXPECT_TRUE(q.getAsFloatTerm(da, db)); EXPECT_EQ(da, -7); EXPECT_EQ(db, -7); } + { + QueryTerm q(factory.create(), "+7", "index", TermType::WORD); + EXPECT_TRUE(q.getAsIntegerTerm(ia, ib)); + EXPECT_EQ(ia, 7); + EXPECT_EQ(ib, 7); + EXPECT_TRUE(q.getAsFloatTerm(da, db)); + EXPECT_EQ(da, 7); + EXPECT_EQ(db, 7); + } { QueryTerm q(factory.create(), "7.5", "index", TermType::WORD); EXPECT_TRUE(!q.getAsIntegerTerm(ia, ib)); - EXPECT_TRUE(q.getAsDoubleTerm(da, db)); + EXPECT_TRUE(q.getAsFloatTerm(da, db)); EXPECT_EQ(da, 7.5); EXPECT_EQ(db, 7.5); } @@ -64,7 +75,7 @@ TEST(StreamingQueryTest, test_query_language) { QueryTerm q(factory.create(), "-7.5", "index", TermType::WORD); EXPECT_TRUE(!q.getAsIntegerTerm(ia, ib)); - EXPECT_TRUE(q.getAsDoubleTerm(da, db)); + EXPECT_TRUE(q.getAsFloatTerm(da, db)); EXPECT_EQ(da, -7.5); EXPECT_EQ(db, -7.5); } @@ -74,8 +85,8 @@ TEST(StreamingQueryTest, test_query_language) EXPECT_TRUE(q.getAsIntegerTerm(ia, ib)); EXPECT_EQ(ia, std::numeric_limits<int64_t>::min()); EXPECT_EQ(ib, 6); - EXPECT_TRUE(q.getAsDoubleTerm(da, db)); - EXPECT_EQ(da, -std::numeric_limits<double>::max()); + EXPECT_TRUE(q.getAsFloatTerm(da, db)); + EXPECT_EQ(da, -std::numeric_limits<double>::infinity()); EXPECT_LT(db, 7); EXPECT_GT(db, 6.99); } @@ -85,8 +96,8 @@ TEST(StreamingQueryTest, test_query_language) EXPECT_TRUE(q.getAsIntegerTerm(ia, ib)); EXPECT_EQ(ia, std::numeric_limits<int64_t>::min()); EXPECT_EQ(ib, 7); - EXPECT_TRUE(q.getAsDoubleTerm(da, db)); - EXPECT_EQ(da, -std::numeric_limits<double>::max()); + EXPECT_TRUE(q.getAsFloatTerm(da, db)); + EXPECT_EQ(da, -std::numeric_limits<double>::infinity()); EXPECT_EQ(db, 7); } @@ -95,10 +106,10 @@ TEST(StreamingQueryTest, test_query_language) EXPECT_TRUE(q.getAsIntegerTerm(ia, ib)); EXPECT_EQ(ia, 8); EXPECT_EQ(ib, std::numeric_limits<int64_t>::max()); - EXPECT_TRUE(q.getAsDoubleTerm(da, db)); + EXPECT_TRUE(q.getAsFloatTerm(da, db)); EXPECT_GT(da, 7); EXPECT_LT(da, 7.01); - EXPECT_EQ(db, std::numeric_limits<double>::max()); + EXPECT_EQ(db, std::numeric_limits<double>::infinity()); } { @@ -106,9 +117,9 @@ TEST(StreamingQueryTest, test_query_language) EXPECT_TRUE(q.getAsIntegerTerm(ia, ib)); EXPECT_EQ(ia, 7); EXPECT_EQ(ib, std::numeric_limits<int64_t>::max()); - EXPECT_TRUE(q.getAsDoubleTerm(da, db)); + EXPECT_TRUE(q.getAsFloatTerm(da, db)); EXPECT_EQ(da, 7); - EXPECT_EQ(db, std::numeric_limits<double>::max()); + EXPECT_EQ(db, std::numeric_limits<double>::infinity()); } { @@ -116,7 +127,7 @@ TEST(StreamingQueryTest, test_query_language) EXPECT_TRUE(q.getAsIntegerTerm(ia, ib)); EXPECT_EQ(ia, -7); EXPECT_EQ(ib, 7); - EXPECT_TRUE(q.getAsDoubleTerm(da, db)); + EXPECT_TRUE(q.getAsFloatTerm(da, db)); EXPECT_EQ(da, -7); EXPECT_EQ(db, 7); } @@ -126,7 +137,7 @@ TEST(StreamingQueryTest, test_query_language) EXPECT_FALSE(q.getAsIntegerTerm(ia, ib)); // This is dubious and perhaps a regression. EXPECT_EQ(ia, std::numeric_limits<int64_t>::min()); EXPECT_EQ(ib, std::numeric_limits<int64_t>::max()); - EXPECT_TRUE(q.getAsDoubleTerm(da, db)); + EXPECT_TRUE(q.getAsFloatTerm(da, db)); EXPECT_EQ(da, -7.1); EXPECT_EQ(db, 7.1); } @@ -136,7 +147,7 @@ TEST(StreamingQueryTest, test_query_language) EXPECT_FALSE(q.getAsIntegerTerm(ia, ib)); // This is dubious and perhaps a regression. EXPECT_EQ(ia, std::numeric_limits<int64_t>::min()); EXPECT_EQ(ib, std::numeric_limits<int64_t>::max()); - EXPECT_TRUE(q.getAsDoubleTerm(da, db)); + EXPECT_TRUE(q.getAsFloatTerm(da, db)); EXPECT_EQ(da, 500.0); EXPECT_EQ(db, std::numeric_limits<double>::max()); } @@ -147,8 +158,8 @@ TEST(StreamingQueryTest, test_query_language) EXPECT_TRUE(q.getAsIntegerTerm(ia, ib)); EXPECT_EQ(ia, -6); EXPECT_EQ(ib, 7); - EXPECT_TRUE(q.getAsDoubleTerm(da, db)); - EXPECT_EQ(da, std::nextafterf(minusSeven, seven)); + EXPECT_TRUE(q.getAsFloatTerm(da, db)); + EXPECT_EQ(da, std::nextafter(minusSeven, seven)); EXPECT_EQ(db, seven); } @@ -157,9 +168,9 @@ TEST(StreamingQueryTest, test_query_language) EXPECT_TRUE(q.getAsIntegerTerm(ia, ib)); EXPECT_EQ(ia, -6); EXPECT_EQ(ib, 6); - EXPECT_TRUE(q.getAsDoubleTerm(da, db)); - EXPECT_EQ(da, std::nextafterf(minusSeven, seven)); - EXPECT_EQ(db, std::nextafterf(seven, minusSeven)); + EXPECT_TRUE(q.getAsFloatTerm(da, db)); + EXPECT_EQ(da, std::nextafter(minusSeven, seven)); + EXPECT_EQ(db, std::nextafter(seven, minusSeven)); } { @@ -174,9 +185,9 @@ TEST(StreamingQueryTest, test_query_language) EXPECT_TRUE(q.getAsIntegerTerm(ia, ib)); EXPECT_EQ(ia, -7); EXPECT_EQ(ib, 6); - EXPECT_TRUE(q.getAsDoubleTerm(da, db)); + EXPECT_TRUE(q.getAsFloatTerm(da, db)); EXPECT_EQ(da, minusSeven); - EXPECT_EQ(db, std::nextafterf(seven, minusSeven)); + EXPECT_EQ(db, std::nextafter(seven, minusSeven)); } { @@ -184,8 +195,8 @@ TEST(StreamingQueryTest, test_query_language) EXPECT_TRUE(q.getAsIntegerTerm(ia, ib)); EXPECT_EQ(ia, std::numeric_limits<int64_t>::min()); EXPECT_EQ(ib, -8); - EXPECT_TRUE(q.getAsDoubleTerm(da, db)); - EXPECT_EQ(da, -std::numeric_limits<double>::max()); + EXPECT_TRUE(q.getAsFloatTerm(da, db)); + EXPECT_EQ(da, -std::numeric_limits<double>::infinity()); EXPECT_LT(db, -7); EXPECT_GT(db, -7.01); } @@ -195,8 +206,8 @@ TEST(StreamingQueryTest, test_query_language) EXPECT_TRUE(q.getAsIntegerTerm(ia, ib)); EXPECT_EQ(ia, std::numeric_limits<int64_t>::min()); EXPECT_EQ(ib, -7); - EXPECT_TRUE(q.getAsDoubleTerm(da, db)); - EXPECT_EQ(da, -std::numeric_limits<double>::max()); + EXPECT_TRUE(q.getAsFloatTerm(da, db)); + EXPECT_EQ(da, -std::numeric_limits<double>::infinity()); EXPECT_EQ(db, -7); } @@ -205,8 +216,8 @@ TEST(StreamingQueryTest, test_query_language) EXPECT_TRUE(q.getAsIntegerTerm(ia, ib)); EXPECT_EQ(ia, std::numeric_limits<int64_t>::min()); EXPECT_EQ(ib, -7); - EXPECT_TRUE(q.getAsDoubleTerm(da, db)); - EXPECT_EQ(da, -std::numeric_limits<double>::max()); + EXPECT_TRUE(q.getAsFloatTerm(da, db)); + EXPECT_EQ(da, -std::numeric_limits<double>::infinity()); EXPECT_EQ(db, -7); } @@ -215,10 +226,10 @@ TEST(StreamingQueryTest, test_query_language) EXPECT_TRUE(q.getAsIntegerTerm(ia, ib)); EXPECT_EQ(ia, -6); EXPECT_EQ(ib, std::numeric_limits<int64_t>::max()); - EXPECT_TRUE(q.getAsDoubleTerm(da, db)); + EXPECT_TRUE(q.getAsFloatTerm(da, db)); EXPECT_GT(da, -7); EXPECT_LT(da, -6.99); - EXPECT_EQ(db, std::numeric_limits<double>::max()); + EXPECT_EQ(db, std::numeric_limits<double>::infinity()); } { @@ -226,9 +237,9 @@ TEST(StreamingQueryTest, test_query_language) EXPECT_TRUE(q.getAsIntegerTerm(ia, ib)); EXPECT_EQ(ia, -7); EXPECT_EQ(ib, std::numeric_limits<int64_t>::max()); - EXPECT_TRUE(q.getAsDoubleTerm(da, db)); + EXPECT_TRUE(q.getAsFloatTerm(da, db)); EXPECT_EQ(da, -7); - EXPECT_EQ(db, std::numeric_limits<double>::max()); + EXPECT_EQ(db, std::numeric_limits<double>::infinity()); } { @@ -236,15 +247,15 @@ TEST(StreamingQueryTest, test_query_language) EXPECT_TRUE(q.getAsIntegerTerm(ia, ib)); EXPECT_EQ(ia, -7); EXPECT_EQ(ib, std::numeric_limits<int64_t>::max()); - EXPECT_TRUE(q.getAsDoubleTerm(da, db)); + EXPECT_TRUE(q.getAsFloatTerm(da, db)); EXPECT_EQ(da, -7); - EXPECT_EQ(db, std::numeric_limits<double>::max()); + EXPECT_EQ(db, std::numeric_limits<double>::infinity()); } { QueryTerm q(factory.create(), "a", "index", TermType::WORD); EXPECT_TRUE(!q.getAsIntegerTerm(ia, ib)); - EXPECT_TRUE(!q.getAsDoubleTerm(da, db)); + EXPECT_TRUE(!q.getAsFloatTerm(da, db)); } { @@ -287,7 +298,10 @@ TEST(StreamingQueryTest, test_query_language) class AllowRewrite : public QueryNodeResultFactory { public: - virtual bool getRewriteFloatTerms() const override { return true; } + explicit AllowRewrite(vespalib::stringref index) noexcept : _allowedIndex(index) {} + bool allow_float_terms_rewrite(vespalib::stringref index) const noexcept override { return index == _allowedIndex; } +private: + vespalib::string _allowedIndex; }; const char TERM_UNIQ = static_cast<char>(ParseItem::ITEM_TERM) | static_cast<char>(ParseItem::IF_UNIQUEID); @@ -297,12 +311,12 @@ TEST(StreamingQueryTest, e_is_not_rewritten_even_if_allowed) const char term[6] = {TERM_UNIQ, 3, 1, 'c', 1, 'e'}; vespalib::stringref stackDump(term, sizeof(term)); EXPECT_EQ(6u, stackDump.size()); - AllowRewrite allowRewrite; + AllowRewrite allowRewrite("c"); const Query q(allowRewrite, stackDump); EXPECT_TRUE(q.valid()); const QueryNode & root = q.getRoot(); EXPECT_TRUE(dynamic_cast<const QueryTerm *>(&root) != nullptr); - const QueryTerm & qt = static_cast<const QueryTerm &>(root); + const auto & qt = static_cast<const QueryTerm &>(root); EXPECT_EQ("c", qt.index()); EXPECT_EQ(vespalib::stringref("e"), qt.getTerm()); EXPECT_EQ(3u, qt.uniqueId()); @@ -313,12 +327,12 @@ TEST(StreamingQueryTest, onedot0e_is_not_rewritten_by_default) const char term[9] = {TERM_UNIQ, 3, 1, 'c', 4, '1', '.', '0', 'e'}; vespalib::stringref stackDump(term, sizeof(term)); EXPECT_EQ(9u, stackDump.size()); - QueryNodeResultFactory empty; + AllowRewrite empty("nix"); const Query q(empty, stackDump); EXPECT_TRUE(q.valid()); const QueryNode & root = q.getRoot(); EXPECT_TRUE(dynamic_cast<const QueryTerm *>(&root) != nullptr); - const QueryTerm & qt = static_cast<const QueryTerm &>(root); + const auto & qt = static_cast<const QueryTerm &>(root); EXPECT_EQ("c", qt.index()); EXPECT_EQ(vespalib::stringref("1.0e"), qt.getTerm()); EXPECT_EQ(3u, qt.uniqueId()); @@ -329,34 +343,34 @@ TEST(StreamingQueryTest, onedot0e_is_rewritten_if_allowed_too) const char term[9] = {TERM_UNIQ, 3, 1, 'c', 4, '1', '.', '0', 'e'}; vespalib::stringref stackDump(term, sizeof(term)); EXPECT_EQ(9u, stackDump.size()); - AllowRewrite empty; + AllowRewrite empty("c"); const Query q(empty, stackDump); EXPECT_TRUE(q.valid()); const QueryNode & root = q.getRoot(); EXPECT_TRUE(dynamic_cast<const EquivQueryNode *>(&root) != nullptr); - const EquivQueryNode & equiv = static_cast<const EquivQueryNode &>(root); + const auto & equiv = static_cast<const EquivQueryNode &>(root); EXPECT_EQ(2u, equiv.size()); EXPECT_TRUE(dynamic_cast<const QueryTerm *>(equiv[0].get()) != nullptr); { - const QueryTerm & qt = static_cast<const QueryTerm &>(*equiv[0]); + const auto & qt = static_cast<const QueryTerm &>(*equiv[0]); EXPECT_EQ("c", qt.index()); EXPECT_EQ(vespalib::stringref("1.0e"), qt.getTerm()); EXPECT_EQ(3u, qt.uniqueId()); } EXPECT_TRUE(dynamic_cast<const PhraseQueryNode *>(equiv[1].get()) != nullptr); { - const PhraseQueryNode & phrase = static_cast<const PhraseQueryNode &>(*equiv[1]); + const auto & phrase = static_cast<const PhraseQueryNode &>(*equiv[1]); EXPECT_EQ(2u, phrase.size()); EXPECT_TRUE(dynamic_cast<const QueryTerm *>(phrase[0].get()) != nullptr); { - const QueryTerm & qt = static_cast<const QueryTerm &>(*phrase[0]); + const auto & qt = static_cast<const QueryTerm &>(*phrase[0]); EXPECT_EQ("c", qt.index()); EXPECT_EQ(vespalib::stringref("1"), qt.getTerm()); EXPECT_EQ(0u, qt.uniqueId()); } EXPECT_TRUE(dynamic_cast<const QueryTerm *>(phrase[1].get()) != nullptr); { - const QueryTerm & qt = static_cast<const QueryTerm &>(*phrase[1]); + const auto & qt = static_cast<const QueryTerm &>(*phrase[1]); EXPECT_EQ("c", qt.index()); EXPECT_EQ(vespalib::stringref("0e"), qt.getTerm()); EXPECT_EQ(0u, qt.uniqueId()); @@ -460,7 +474,7 @@ TEST(StreamingQueryTest, test_phrase_evaluate) terms[1]->add(1, 5, 0, 1); terms[2]->add(0, 5, 0, 1); HitList hits; - PhraseQueryNode * p = static_cast<PhraseQueryNode *>(phrases[0]); + auto * p = static_cast<PhraseQueryNode *>(phrases[0]); p->evaluateHits(hits); ASSERT_EQ(3u, hits.size()); EXPECT_EQ(hits[0].wordpos(), 2u); @@ -522,6 +536,7 @@ void assertInt64Range(const std::string &term, bool expAdjusted, int64_t expLow, EXPECT_EQ(expHigh, (int64_t)res.high); } + TEST(StreamingQueryTest, require_that_int8_limits_are_enforced) { //std::numeric_limits<int8_t>::min() -> -128 @@ -607,6 +622,20 @@ TEST(StreamingQueryTest, require_that_we_can_take_floating_point_values_in_range assertInt64Range("[1.7976931348623157E308;-1.7976931348623157E308]", false, std::numeric_limits<int64_t>::max(), std::numeric_limits<int64_t>::min()); } +void assertIllegalRangeQueries(const QueryTermSimple & qt) { + QueryTermSimple::RangeResult<int64_t> ires = qt.getRange<int64_t>(); + EXPECT_EQ(false, ires.valid); + QueryTermSimple::RangeResult<double> fres = qt.getRange<double>(); + EXPECT_EQ(false, fres.valid); +} + +TEST(StreamingQueryTest, require_safe_parsing_of_illegal_ranges) { + // The 2 below are created when naively splitting numeric terms by dot. + // T=A.B => T EQUIV PHRASE(A, B) + assertIllegalRangeQueries(QueryTermSimple("[1", TermType::WORD)); + assertIllegalRangeQueries(QueryTermSimple(".1;2.1]", TermType::WORD)); +} + TEST(StreamingQueryTest, require_that_we_handle_empty_range_as_expected) { assertInt64Range("[1;1]", false, 1, 1); @@ -627,11 +656,11 @@ TEST(StreamingQueryTest, require_that_ascending_range_can_be_specified_with_limi QueryTerm ascending_query(eqnr.create(), "[;;500]", "index", TermType::WORD); EXPECT_TRUE(ascending_query.getAsIntegerTerm(low_integer, high_integer)); - EXPECT_TRUE(ascending_query.getAsDoubleTerm(low_double, high_double)); + EXPECT_TRUE(ascending_query.getAsFloatTerm(low_double, high_double)); EXPECT_EQ(std::numeric_limits<int64_t>::min(), low_integer); EXPECT_EQ(std::numeric_limits<int64_t>::max(), high_integer); - EXPECT_EQ(-std::numeric_limits<double>::max(), low_double); - EXPECT_EQ(std::numeric_limits<double>::max(), high_double); + EXPECT_EQ(-std::numeric_limits<double>::infinity(), low_double); + EXPECT_EQ(std::numeric_limits<double>::infinity(), high_double); EXPECT_EQ(500, ascending_query.getRangeLimit()); } @@ -646,11 +675,11 @@ TEST(StreamingQueryTest, require_that_descending_range_can_be_specified_with_lim QueryTerm descending_query(eqnr.create(), "[;;-500]", "index", TermType::WORD); EXPECT_TRUE(descending_query.getAsIntegerTerm(low_integer, high_integer)); - EXPECT_TRUE(descending_query.getAsDoubleTerm(low_double, high_double)); + EXPECT_TRUE(descending_query.getAsFloatTerm(low_double, high_double)); EXPECT_EQ(std::numeric_limits<int64_t>::min(), low_integer); EXPECT_EQ(std::numeric_limits<int64_t>::max(), high_integer); - EXPECT_EQ(-std::numeric_limits<double>::max(), low_double); - EXPECT_EQ(std::numeric_limits<double>::max(), high_double); + EXPECT_EQ(-std::numeric_limits<double>::infinity(), low_double); + EXPECT_EQ(std::numeric_limits<double>::infinity(), high_double); EXPECT_EQ(-500, descending_query.getRangeLimit()); } @@ -735,7 +764,7 @@ TEST(StreamingQueryTest, require_that_incorrectly_specified_diversity_can_be_par TEST(StreamingQueryTest, require_that_we_do_not_break_the_stack_on_bad_query) { - QueryTermSimple term("<form><iframe+	 +src=\\\"javascript:alert(1)\\\" 	;>", TermType::WORD); + QueryTermSimple term(R"(<form><iframe+	 +src=\"javascript:alert(1)\" 	;>)", TermType::WORD); EXPECT_FALSE(term.isValid()); } @@ -744,7 +773,7 @@ TEST(StreamingQueryTest, a_unhandled_sameElement_stack) const char * stack = "\022\002\026xyz_abcdefghij_xyzxyzxQ\001\vxxxxxx_name\034xxxxxx_xxxx_xxxxxxx_xxxxxxxxE\002\005delta\b<0.00393"; vespalib::stringref stackDump(stack); EXPECT_EQ(85u, stackDump.size()); - AllowRewrite empty; + AllowRewrite empty(""); const Query q(empty, stackDump); EXPECT_TRUE(q.valid()); const QueryNode & root = q.getRoot(); @@ -778,7 +807,7 @@ TEST(StreamingQueryTest, test_same_element_evaluate) vespalib::string stackDump = StackDumpCreator::create(*node); QueryNodeResultFactory empty; Query q(empty, stackDump); - SameElementQueryNode * sameElem = dynamic_cast<SameElementQueryNode *>(&q.getRoot()); + auto * sameElem = dynamic_cast<SameElementQueryNode *>(&q.getRoot()); EXPECT_TRUE(sameElem != nullptr); EXPECT_EQ("field", sameElem->getIndex()); EXPECT_EQ(3u, sameElem->size()); @@ -878,7 +907,7 @@ TEST(StreamingQueryTest, test_in_term) { auto term_vector = std::make_unique<StringTermVector>(1); term_vector->addTerm("7"); - search::streaming::InTerm term({}, "index", std::move(term_vector)); + search::streaming::InTerm term({}, "index", std::move(term_vector), Normalizing::NONE); SimpleTermData td; td.addField(10); td.addField(11); @@ -929,6 +958,68 @@ TEST(StreamingQueryTest, dot_product_term) EXPECT_EQ(-17 * 27 + 9 * 2, tmd1->getRawScore()); } +namespace { + +constexpr double exp_wand_score_field_12 = 13 * 27 + 4 * 2; +constexpr double exp_wand_score_field_11 = 17 * 27 + 9 * 2; + +void +check_wand_term(double limit, const vespalib::string& label) +{ + SCOPED_TRACE(label); + search::streaming::WandTerm term({}, "index", 2); + term.add_term(std::make_unique<QueryTerm>(std::unique_ptr<QueryNodeResultBase>(), "7", "", QueryTermSimple::Type::WORD)); + term.get_terms().back()->setWeight(Weight(27)); + term.add_term(std::make_unique<QueryTerm>(std::unique_ptr<QueryNodeResultBase>(), "9", "", QueryTermSimple::Type::WORD)); + term.get_terms().back()->setWeight(Weight(2)); + EXPECT_EQ(2, term.get_terms().size()); + term.set_score_threshold(limit); + SimpleTermData td; + /* + * Search in fields 10, 11 and 12 (cf. fieldset in schema). + * Fields 11 and 12 have content for doc containing the keys. + * Fields 10 and 12 have valid handles and can be used for ranking. + * Field 11 does not have a valid handle, thus no associated match data. + */ + td.addField(10); + td.addField(11); + td.addField(12); + td.lookupField(10)->setHandle(0); + td.lookupField(12)->setHandle(1); + EXPECT_FALSE(term.evaluate()); + auto& q0 = *term.get_terms()[0]; + q0.add(0, 11, 0, 17); + q0.add(0, 12, 0, 13); + auto& q1 = *term.get_terms()[1]; + q1.add(0, 11, 0, 9); + q1.add(0, 12, 0, 4); + EXPECT_EQ(limit < exp_wand_score_field_11, term.evaluate()); + MatchData md(MatchData::params().numTermFields(2)); + term.unpack_match_data(23, td, md); + auto tmd0 = md.resolveTermField(0); + EXPECT_NE(23, tmd0->getDocId()); + auto tmd1 = md.resolveTermField(1); + if (limit < exp_wand_score_field_12) { + EXPECT_EQ(23, tmd1->getDocId()); + EXPECT_EQ(exp_wand_score_field_12, tmd1->getRawScore()); + } else { + EXPECT_NE(23, tmd1->getDocId()); + } +} + +} + +TEST(StreamingQueryTest, wand_term) +{ + check_wand_term(0.0, "no limit"); + check_wand_term(exp_wand_score_field_12 - 1, "score above limit"); + check_wand_term(exp_wand_score_field_12, "score at limit"); + check_wand_term(exp_wand_score_field_12 + 1, "score below limit"); + check_wand_term(exp_wand_score_field_11 - 1, "hidden score above limit"); + check_wand_term(exp_wand_score_field_11, "hidden score at limit"); + check_wand_term(exp_wand_score_field_11 + 1, "hidden score below limit"); +} + TEST(StreamingQueryTest, control_the_size_of_query_terms) { EXPECT_EQ(112u, sizeof(QueryTermSimple)); 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() diff --git a/searchlib/src/tests/sortspec/multilevelsort_test.cpp b/searchlib/src/tests/sortspec/multilevelsort_test.cpp index 2d0456e13fc..f3bf363645e 100644 --- a/searchlib/src/tests/sortspec/multilevelsort_test.cpp +++ b/searchlib/src/tests/sortspec/multilevelsort_test.cpp @@ -8,7 +8,6 @@ #include <vespa/searchlib/attribute/attributemanager.h> #include <vespa/searchlib/uca/ucaconverter.h> #include <vespa/searchcommon/attribute/config.h> -#include <vespa/vespalib/util/testclock.h> #include <vespa/vespalib/testkit/testapp.h> #include <type_traits> #include <cinttypes> @@ -242,10 +241,8 @@ MultilevelSortTest::sortAndCheck(const std::vector<Spec> &specs, uint32_t num, hits.emplace_back(i, getRandomValue<uint32_t>()); } - vespalib::TestClock clock; - vespalib::Doom doom(clock.clock(), vespalib::steady_time::max()); search::uca::UcaConverterFactory ucaFactory; - FastS_SortSpec sorter("no-metastore", 7, doom, ucaFactory); + FastS_SortSpec sorter("no-metastore", 7, vespalib::Doom::never(), ucaFactory); // init sorter with sort data for (const auto & spec : specs) { AttributeGuard ag; @@ -384,10 +381,8 @@ TEST("require that all sort methods behave the same") } TEST("test that [docid] translates to [lid][paritionid]") { - vespalib::TestClock clock; - vespalib::Doom doom(clock.clock(), vespalib::steady_time::max()); search::uca::UcaConverterFactory ucaFactory; - FastS_SortSpec asc("no-metastore", 7, doom, ucaFactory); + FastS_SortSpec asc("no-metastore", 7, vespalib::Doom::never(), ucaFactory); RankedHit hits[2] = {RankedHit(91, 0.0), RankedHit(3, 2.0)}; search::AttributeManager mgr; search::AttributeContext ac(mgr); @@ -404,7 +399,7 @@ TEST("test that [docid] translates to [lid][paritionid]") { EXPECT_EQUAL(6u, sr2.second); EXPECT_EQUAL(0, memcmp(SECOND_ASC, sr2.first, 6)); - FastS_SortSpec desc("no-metastore", 7, doom, ucaFactory); + FastS_SortSpec desc("no-metastore", 7, vespalib::Doom::never(), ucaFactory); desc.Init("-[docid]", ac); desc.initWithoutSorting(hits, 2); sr1 = desc.getSortRef(0); @@ -416,10 +411,8 @@ TEST("test that [docid] translates to [lid][paritionid]") { } TEST("test that [docid] uses attribute when one exists") { - vespalib::TestClock clock; - vespalib::Doom doom(clock.clock(), vespalib::steady_time::max()); search::uca::UcaConverterFactory ucaFactory; - FastS_SortSpec asc("metastore", 7, doom, ucaFactory); + FastS_SortSpec asc("metastore", 7, vespalib::Doom::never(), ucaFactory); RankedHit hits[2] = {RankedHit(91, 0.0), RankedHit(3, 2.0)}; Config cfg(BasicType::INT64, CollectionType::SINGLE); auto metastore = AttributeFactory::createAttribute("metastore", cfg); @@ -445,7 +438,7 @@ TEST("test that [docid] uses attribute when one exists") { EXPECT_EQUAL(8u, sr2.second); EXPECT_EQUAL(0, memcmp(SECOND_ASC, sr2.first, 8)); - FastS_SortSpec desc("metastore", 7, doom, ucaFactory); + FastS_SortSpec desc("metastore", 7, vespalib::Doom::never(), ucaFactory); desc.Init("-[docid]", ac); desc.initWithoutSorting(hits, 2); sr1 = desc.getSortRef(0); diff --git a/searchlib/src/tests/tensor/hnsw_index/hnsw_index_test.cpp b/searchlib/src/tests/tensor/hnsw_index/hnsw_index_test.cpp index 74d4600a079..da58dd749ba 100644 --- a/searchlib/src/tests/tensor/hnsw_index/hnsw_index_test.cpp +++ b/searchlib/src/tests/tensor/hnsw_index/hnsw_index_test.cpp @@ -106,7 +106,7 @@ public: .set(7, {3, 5}).set(8, {0, 3}).set(9, {4, 5}); } - ~HnswIndexTest() {} + ~HnswIndexTest() override {} auto dff() { return search::tensor::make_distance_function_factory( @@ -135,7 +135,7 @@ public: gen_handler.incGeneration(); index->reclaim_memory(gen_handler.get_oldest_used_generation()); } - void set_filter(std::vector<uint32_t> docids) { + void set_filter(const std::vector<uint32_t>& docids) { uint32_t sz = 10; global_filter = GlobalFilter::create(docids, sz); } @@ -168,7 +168,7 @@ public: ASSERT_EQ(exp_levels.size(), act_node.size()); EXPECT_EQ(exp_levels, act_node.levels()); } - void expect_top_3_by_docid(const vespalib::string& label, std::vector<float> qv, std::vector<uint32_t> exp) { + void expect_top_3_by_docid(const vespalib::string& label, std::vector<float> qv, const std::vector<uint32_t>& exp) { SCOPED_TRACE(label); uint32_t k = 3; uint32_t explore_k = 100; @@ -794,7 +794,7 @@ class MyGlobalFilter : public GlobalFilter { std::shared_ptr<GlobalFilter> _filter; mutable uint32_t _max_docid; public: - MyGlobalFilter(std::shared_ptr<GlobalFilter> filter) noexcept + explicit MyGlobalFilter(std::shared_ptr<GlobalFilter> filter) noexcept : _filter(std::move(filter)), _max_docid(0) { @@ -845,7 +845,7 @@ TEST_F(HnswMultiIndexTest, duplicate_docid_is_removed) global_filter = filter; this->expect_top_3_by_docid("{2,2}", {2, 2}, {1, 2}); EXPECT_EQ(2, filter->max_docid()); -}; +} TEST_F(HnswMultiIndexTest, docid_with_empty_tensor_can_be_removed) { @@ -904,10 +904,10 @@ TEST(LevelGeneratorTest, gives_various_levels) } hist[l]++; } - for (uint32_t l = 0; l < hist.size(); ++l) { + for (unsigned int l : hist) { double expected = left * 0.75; - EXPECT_TRUE(hist[l] < expected*1.01 + 100); - EXPECT_TRUE(hist[l] > expected*0.99 - 100); + EXPECT_TRUE(l < expected*1.01 + 100); + EXPECT_TRUE(l > expected*0.99 - 100); left *= 0.25; } EXPECT_TRUE(hist.size() < 14); |