diff options
author | Yuri Gorshenin <y@maps.me> | 2016-08-22 13:47:56 +0300 |
---|---|---|
committer | Yuri Gorshenin <y@maps.me> | 2016-08-26 16:21:13 +0300 |
commit | afc3d20264e8fcd99dc3cd465ce1770d0b3246d0 (patch) | |
tree | 67d2bcd855340555d742181e467cc987bd70a332 /search | |
parent | 336c137d59c12d0de9fd292bcf3db9b453670567 (diff) |
[search] Added matching of edited features by type.
Diffstat (limited to 'search')
-rw-r--r-- | search/categories_set.hpp | 69 | ||||
-rw-r--r-- | search/geocoder.cpp | 90 | ||||
-rw-r--r-- | search/geocoder.hpp | 6 | ||||
-rw-r--r-- | search/processor.cpp | 7 | ||||
-rw-r--r-- | search/query_params.cpp | 79 | ||||
-rw-r--r-- | search/query_params.hpp | 43 | ||||
-rw-r--r-- | search/retrieval.cpp | 54 | ||||
-rw-r--r-- | search/search.pro | 1 | ||||
-rw-r--r-- | search/search_integration_tests/helpers.cpp | 2 | ||||
-rw-r--r-- | search/search_integration_tests/helpers.hpp | 16 | ||||
-rw-r--r-- | search/search_integration_tests/search_edited_features_test.cpp | 64 | ||||
-rw-r--r-- | search/search_integration_tests/search_integration_tests.pro | 7 | ||||
-rw-r--r-- | search/token_slice.cpp | 2 |
13 files changed, 257 insertions, 183 deletions
diff --git a/search/categories_set.hpp b/search/categories_set.hpp new file mode 100644 index 0000000000..343d1c40b9 --- /dev/null +++ b/search/categories_set.hpp @@ -0,0 +1,69 @@ +#pragma once + +#include "indexer/classificator.hpp" +#include "indexer/search_string_utils.hpp" + +#include "base/macros.hpp" +#include "base/stl_helpers.hpp" +#include "base/string_utils.hpp" + +#include "std/algorithm.hpp" +#include "std/cstdint.hpp" +#include "std/vector.hpp" + +namespace search +{ +struct Category +{ + Category(strings::UniString const & key, uint32_t type) : m_key(key), m_type(type) {} + + bool operator==(Category const & rhs) const { return m_key == rhs.m_key && m_type == rhs.m_type; } + + bool operator<(Category const & rhs) const + { + if (m_key != rhs.m_key) + return m_key < rhs.m_key; + return m_type < rhs.m_type; + } + + strings::UniString m_key; + uint32_t m_type = 0; +}; + +class CategoriesSet +{ +public: + template <typename TTypesList> + CategoriesSet(TTypesList const & typesList) + { + auto const & classificator = classif(); + + auto addCategory = [&](uint32_t type) { + uint32_t const index = classificator.GetIndexForType(type); + m_categories.emplace_back(FeatureTypeToString(index), type); + }; + + typesList.ForEachType(addCategory); + + my::SortUnique(m_categories); + } + + template <typename TFn> + void ForEach(TFn && fn) const + { + for_each(m_categories.cbegin(), m_categories.cend(), forward<TFn>(fn)); + } + + bool HasKey(strings::UniString const & key) const + { + auto const it = + lower_bound(m_categories.cbegin(), m_categories.cend(), Category(key, 0 /* type */)); + return it != m_categories.cend() && it->m_key == key; + } + +private: + vector<Category> m_categories; + + DISALLOW_COPY_AND_MOVE(CategoriesSet); +}; +} // namespace search diff --git a/search/geocoder.cpp b/search/geocoder.cpp index cea3c3f4f9..f66d5136ea 100644 --- a/search/geocoder.cpp +++ b/search/geocoder.cpp @@ -170,46 +170,6 @@ private: LazyRankTable m_ranks; }; -class StreetCategories -{ -public: - static StreetCategories const & Instance() - { - static StreetCategories const instance; - return instance; - } - - template <typename TFn> - void ForEach(TFn && fn) const - { - for_each(m_categories.cbegin(), m_categories.cend(), forward<TFn>(fn)); - } - - bool Contains(strings::UniString const & category) const - { - return binary_search(m_categories.cbegin(), m_categories.cend(), category); - } - - vector<strings::UniString> const & GetCategories() const { return m_categories; } - -private: - StreetCategories() - { - auto const & classificator = classif(); - auto addCategory = [&](uint32_t type) - { - uint32_t const index = classificator.GetIndexForType(type); - m_categories.push_back(FeatureTypeToString(index)); - }; - ftypes::IsStreetChecker::Instance().ForEachType(addCategory); - sort(m_categories.begin(), m_categories.end()); - } - - vector<strings::UniString> m_categories; - - DISALLOW_COPY_AND_MOVE(StreetCategories); -}; - void JoinQueryTokens(QueryParams const & params, size_t curToken, size_t endToken, strings::UniString const & sep, strings::UniString & res) { @@ -245,22 +205,6 @@ WARN_UNUSED_RESULT bool GetAffiliationName(FeatureType const & ft, string & affi return false; } -// todo(@m) Refactor at least here, or even at indexer/ftypes_matcher.hpp. -vector<strings::UniString> GetVillageCategories() -{ - vector<strings::UniString> categories; - - auto const & classificator = classif(); - auto addCategory = [&](uint32_t type) - { - uint32_t const index = classificator.GetIndexForType(type); - categories.push_back(FeatureTypeToString(index)); - }; - ftypes::IsVillageChecker::Instance().ForEachType(addCategory); - - return categories; -} - bool HasSearchIndex(MwmValue const & value) { return value.m_cont.IsExist(SEARCH_INDEX_FILE_TAG); } bool HasGeometryIndex(MwmValue & value) { return value.m_cont.IsExist(INDEX_FILE_TAG); } @@ -418,6 +362,8 @@ Geocoder::Geocoder(Index const & index, storage::CountryInfoGetter const & infoG : m_index(index) , m_infoGetter(infoGetter) , m_cancellable(cancellable) + , m_streets(ftypes::IsStreetChecker::Instance()) + , m_villages(ftypes::IsVillageChecker::Instance()) , m_model(SearchModel::Instance()) , m_pivotRectsCache(kPivotRectsCacheSize, m_cancellable, Processor::kMaxViewportRadiusM) , m_localityRectsCache(kLocalityRectsCacheSize, m_cancellable) @@ -462,9 +408,7 @@ void Geocoder::SetParams(Params const & params) { auto b = synonyms.begin(); auto e = synonyms.end(); - auto const & categories = StreetCategories::Instance(); - synonyms.erase(remove_if(b + 1, e, bind(&StreetCategories::Contains, cref(categories), _1)), - e); + synonyms.erase(remove_if(b + 1, e, bind(&CategoriesSet::HasKey, cref(m_streets), _1)), e); } } @@ -639,6 +583,7 @@ void Geocoder::PrepareRetrievalParams(size_t curToken, size_t endToken) m_retrievalParams.m_tokens.clear(); m_retrievalParams.m_prefixTokens.clear(); + m_retrievalParams.m_types.clear(); // TODO (@y): possibly it's not cheap to copy vectors of strings. // Profile it, and in case of serious performance loss, refactor @@ -649,6 +594,8 @@ void Geocoder::PrepareRetrievalParams(size_t curToken, size_t endToken) m_retrievalParams.m_tokens.push_back(m_params.m_tokens[i]); else m_retrievalParams.m_prefixTokens = m_params.m_prefixTokens; + + m_retrievalParams.m_types.push_back(m_params.m_types[i]); } } @@ -1413,24 +1360,29 @@ void Geocoder::MatchUnclassified(BaseContext & ctx, size_t curToken) allFeatures.ForEach(emitUnclassified); } -CBV Geocoder::LoadCategories(MwmContext & context, vector<strings::UniString> const & categories) +CBV Geocoder::LoadCategories(MwmContext & context, CategoriesSet const & categories) { ASSERT(context.m_handle.IsAlive(), ()); ASSERT(HasSearchIndex(context.m_value), ()); m_retrievalParams.m_tokens.resize(1); m_retrievalParams.m_tokens[0].resize(1); + m_retrievalParams.m_prefixTokens.clear(); + m_retrievalParams.m_types.resize(1); + m_retrievalParams.m_types[0].resize(1); + vector<CBV> cbvs; - for_each(categories.begin(), categories.end(), [&](strings::UniString const & category) - { - m_retrievalParams.m_tokens[0][0] = category; - CBV cbv(RetrieveAddressFeatures(context, m_cancellable, m_retrievalParams)); - if (!cbv.IsEmpty()) - cbvs.push_back(move(cbv)); - }); + categories.ForEach([&](Category const & category) { + m_retrievalParams.m_tokens[0][0] = category.m_key; + m_retrievalParams.m_types[0][0] = category.m_type; + + CBV cbv(RetrieveAddressFeatures(context, m_cancellable, m_retrievalParams)); + if (!cbv.IsEmpty()) + cbvs.push_back(move(cbv)); + }); UniteCBVs(cbvs); if (cbvs.empty()) @@ -1449,7 +1401,7 @@ CBV Geocoder::LoadStreets(MwmContext & context) if (it != m_streetsCache.cend()) return it->second; - auto streets = LoadCategories(context, StreetCategories::Instance().GetCategories()); + auto streets = LoadCategories(context, m_streets); m_streetsCache[mwmId] = streets; return streets; } @@ -1458,7 +1410,7 @@ CBV Geocoder::LoadVillages(MwmContext & context) { if (!context.m_handle.IsAlive() || !HasSearchIndex(context.m_value)) return CBV(); - return LoadCategories(context, GetVillageCategories()); + return LoadCategories(context, m_villages); } CBV Geocoder::RetrievePostcodeFeatures(MwmContext const & context, TokenSlice const & slice) diff --git a/search/geocoder.hpp b/search/geocoder.hpp index f74105f157..715e4250a3 100644 --- a/search/geocoder.hpp +++ b/search/geocoder.hpp @@ -1,6 +1,7 @@ #pragma once #include "search/cancel_exception.hpp" +#include "search/categories_set.hpp" #include "search/features_layer.hpp" #include "search/features_layer_path_finder.hpp" #include "search/geocoder_context.hpp" @@ -256,7 +257,7 @@ private: // UNCLASSIFIED objects that match to all currently unused tokens. void MatchUnclassified(BaseContext & ctx, size_t curToken); - CBV LoadCategories(MwmContext & context, vector<strings::UniString> const & categories); + CBV LoadCategories(MwmContext & context, CategoriesSet const & categories); CBV LoadStreets(MwmContext & context); @@ -279,6 +280,9 @@ private: my::Cancellable const & m_cancellable; + CategoriesSet m_streets; + CategoriesSet m_villages; + // Geocoder params. Params m_params; diff --git a/search/processor.cpp b/search/processor.cpp index 7f19f6ba7e..c23de90ece 100644 --- a/search/processor.cpp +++ b/search/processor.cpp @@ -627,7 +627,9 @@ void Processor::InitParams(QueryParams & params) for (size_t i = 0; i < tokensCount; ++i) params.m_tokens[i].push_back(m_tokens[i]); - params.m_isCategorySynonym.assign(tokensCount + (m_prefix.empty() ? 0 : 1), false); + params.m_types.resize(tokensCount + (m_prefix.empty() ? 0 : 1)); + for (auto & types : params.m_types) + types.clear(); // Add names of categories (and synonyms). Classificator const & c = classif(); @@ -635,9 +637,10 @@ void Processor::InitParams(QueryParams & params) { QueryParams::TSynonymsVector & v = params.GetTokens(i); + params.m_types[i].push_back(t); + uint32_t const index = c.GetIndexForType(t); v.push_back(FeatureTypeToString(index)); - params.m_isCategorySynonym[i] = true; // v2-version MWM has raw classificator types in search index prefix, so // do the hack: add synonyms for old convention if needed. diff --git a/search/query_params.cpp b/search/query_params.cpp index 8762b356ff..c5aa8b9bee 100644 --- a/search/query_params.cpp +++ b/search/query_params.cpp @@ -1,9 +1,6 @@ #include "search/query_params.hpp" #include "indexer/feature_impl.hpp" -#include "indexer/scales.hpp" - -#include "base/assert.hpp" #include "std/algorithm.hpp" @@ -11,6 +8,7 @@ namespace search { namespace { +// TODO (@y, @m): reuse this class in search::Processor. class DoAddStreetSynonyms { public: @@ -57,79 +55,44 @@ private: }; } // namespace -QueryParams::QueryParams() : m_scale(scales::GetUpperScale()) {} - void QueryParams::Clear() { m_tokens.clear(); m_prefixTokens.clear(); - m_isCategorySynonym.clear(); + m_types.clear(); m_langs.clear(); m_scale = scales::GetUpperScale(); } -void QueryParams::EraseTokens(vector<size_t> & eraseInds) +bool QueryParams::IsCategorySynonym(size_t i) const { - eraseInds.erase(unique(eraseInds.begin(), eraseInds.end()), eraseInds.end()); - ASSERT(is_sorted(eraseInds.begin(), eraseInds.end()), ()); - - // fill temporary vector - vector<TSynonymsVector> newTokens; - - size_t skipI = 0; - size_t const count = m_tokens.size(); - size_t const eraseCount = eraseInds.size(); - for (size_t i = 0; i < count; ++i) - { - if (skipI < eraseCount && eraseInds[skipI] == i) - ++skipI; - else - newTokens.push_back(move(m_tokens[i])); - } - - // assign to m_tokens - newTokens.swap(m_tokens); - - if (skipI < eraseCount) - { - // it means that we need to skip prefix tokens - ASSERT_EQUAL(skipI + 1, eraseCount, (eraseInds)); - ASSERT_EQUAL(eraseInds[skipI], count, (eraseInds)); - m_prefixTokens.clear(); - } + ASSERT_LESS(i, GetNumTokens(), ()); + return !m_types[i].empty(); } -void QueryParams::ProcessAddressTokens() +bool QueryParams::IsPrefixToken(size_t i) const { - // Erases all number tokens. - // Assumes that USA street name numbers are end with "st, nd, rd, th" suffixes. - vector<size_t> toErase; - ForEachToken([&toErase](QueryParams::TString const & s, size_t i) - { - if (feature::IsNumber(s)) - toErase.push_back(i); - }); - EraseTokens(toErase); - - // Adds synonyms for N, NE, NW, etc. - ForEachToken(DoAddStreetSynonyms(*this)); + ASSERT_LESS(i, GetNumTokens(), ()); + return i == m_tokens.size(); } QueryParams::TSynonymsVector const & QueryParams::GetTokens(size_t i) const { - ASSERT_LESS_OR_EQUAL(i, m_tokens.size(), ()); + ASSERT_LESS(i, GetNumTokens(), ()); return i < m_tokens.size() ? m_tokens[i] : m_prefixTokens; } QueryParams::TSynonymsVector & QueryParams::GetTokens(size_t i) { - ASSERT_LESS_OR_EQUAL(i, m_tokens.size(), ()); + ASSERT_LESS(i, GetNumTokens(), ()); return i < m_tokens.size() ? m_tokens[i] : m_prefixTokens; } bool QueryParams::IsNumberTokens(size_t start, size_t end) const { ASSERT_LESS(start, end, ()); + ASSERT_LESS_OR_EQUAL(end, GetNumTokens(), ()); + for (; start != end; ++start) { bool number = false; @@ -148,24 +111,6 @@ bool QueryParams::IsNumberTokens(size_t start, size_t end) const return true; } -template <class ToDo> -void QueryParams::ForEachToken(ToDo && toDo) -{ - size_t const count = m_tokens.size(); - for (size_t i = 0; i < count; ++i) - { - ASSERT(!m_tokens[i].empty(), ()); - ASSERT(!m_tokens[i].front().empty(), ()); - toDo(m_tokens[i].front(), i); - } - - if (!m_prefixTokens.empty()) - { - ASSERT(!m_prefixTokens.front().empty(), ()); - toDo(m_prefixTokens.front(), count); - } -} - string DebugPrint(search::QueryParams const & params) { ostringstream os; diff --git a/search/query_params.hpp b/search/query_params.hpp index 2f00bc6c34..4d537a7a8e 100644 --- a/search/query_params.hpp +++ b/search/query_params.hpp @@ -1,5 +1,8 @@ #pragma once +#include "indexer/scales.hpp" + +#include "base/assert.hpp" #include "base/string_utils.hpp" #include "std/cstdint.hpp" @@ -14,39 +17,33 @@ struct QueryParams using TSynonymsVector = vector<TString>; using TLangsSet = unordered_set<int8_t>; - vector<TSynonymsVector> m_tokens; - TSynonymsVector m_prefixTokens; - vector<bool> m_isCategorySynonym; + QueryParams() = default; - TLangsSet m_langs; - int m_scale; + inline size_t GetNumTokens() const + { + return m_prefixTokens.empty() ? m_tokens.size() : m_tokens.size() + 1; + } - QueryParams(); + inline bool IsEmpty() const { return GetNumTokens() == 0; } + inline bool IsLangExist(int8_t lang) const { return m_langs.count(lang) != 0; } void Clear(); - /// @param[in] eraseInds Sorted vector of token's indexes. - void EraseTokens(vector<size_t> & eraseInds); - - void ProcessAddressTokens(); - - inline bool IsEmpty() const { return (m_tokens.empty() && m_prefixTokens.empty()); } - inline bool CanSuggest() const { return (m_tokens.empty() && !m_prefixTokens.empty()); } - inline bool IsLangExist(int8_t l) const { return (m_langs.count(l) > 0); } - + bool IsCategorySynonym(size_t i) const; + bool IsPrefixToken(size_t i) const; TSynonymsVector const & GetTokens(size_t i) const; TSynonymsVector & GetTokens(size_t i); - inline size_t GetNumTokens() const - { - return m_prefixTokens.empty() ? m_tokens.size() : m_tokens.size() + 1; - } - /// @return true if all tokens in [start, end) range has number synonym. + // Returns true if all tokens in [start, end) range has intergral + // synonyms. bool IsNumberTokens(size_t start, size_t end) const; -private: - template <class ToDo> - void ForEachToken(ToDo && toDo); + vector<TSynonymsVector> m_tokens; + TSynonymsVector m_prefixTokens; + vector<vector<uint32_t>> m_types; + + TLangsSet m_langs; + int m_scale = scales::GetUpperScale(); }; string DebugPrint(search::QueryParams const & params); diff --git a/search/retrieval.cpp b/search/retrieval.cpp index 87051e731b..4f77bf35d5 100644 --- a/search/retrieval.cpp +++ b/search/retrieval.cpp @@ -10,6 +10,7 @@ #include "indexer/feature.hpp" #include "indexer/feature_algo.hpp" +#include "indexer/feature_data.hpp" #include "indexer/index.hpp" #include "indexer/osm_editor.hpp" #include "indexer/scales.hpp" @@ -106,7 +107,8 @@ unique_ptr<coding::CompressedBitVector> SortFeaturesAndBuildCBV(vector<uint64_t> return coding::CompressedBitVectorBuilder::FromBitPositions(move(features)); } -/// Check that any from first matches any from second. +// Checks that any from the |second| matches any from the |first|. In +// ambiguous case when |second| is empty, returns true. template <class TComp, class T> bool IsFirstMatchesSecond(vector<T> const & first, vector<T> const & second, TComp const & comp) { @@ -124,34 +126,54 @@ bool IsFirstMatchesSecond(vector<T> const & first, vector<T> const & second, TCo return false; } -bool MatchFeatureByName(FeatureType const & ft, QueryParams const & params) +bool MatchFeatureByNameAndType(FeatureType const & ft, QueryParams const & params) { using namespace strings; + auto const prefixMatch = [](UniString const & s1, UniString const & s2) { + return StartsWith(s1, s2); + }; + + auto const fullMatch = [](UniString const & s1, UniString const & s2) { return s1 == s2; }; + + feature::TypesHolder th(ft); + bool matched = false; ft.ForEachName([&](int8_t lang, string const & utf8Name) { - if (utf8Name.empty() || params.m_langs.count(lang) == 0) - return true; + if (utf8Name.empty() || !params.IsLangExist(lang)) + return true /* continue ForEachName */; vector<UniString> nameTokens; NormalizeAndTokenizeString(utf8Name, nameTokens, Delimiters()); - auto const matchPrefix = [](UniString const & s1, UniString const & s2) + for (size_t i = 0; i < params.GetNumTokens(); ++i) { - return StartsWith(s1, s2); - }; - if (!IsFirstMatchesSecond(nameTokens, params.m_prefixTokens, matchPrefix)) - return true; - - for (auto const & synonyms : params.m_tokens) - { - if (!IsFirstMatchesSecond(nameTokens, synonyms, equal_to<UniString>())) - return true; + bool const isPrefix = params.IsPrefixToken(i); + auto const & syms = params.GetTokens(i); + + if (!IsFirstMatchesSecond(nameTokens, syms, isPrefix ? prefixMatch : fullMatch)) + { + // Checks types in case of names mismatch. + auto const & types = params.m_types[i]; + bool typeMatched = false; + + for (auto const type : types) + { + if (th.Has(type)) + { + typeMatched = true; + break; + } + } + + if (!typeMatched) + return true /* continue ForEachName */; + } } matched = true; - return false; + return false /* break ForEachName */; }); return matched; @@ -211,7 +233,7 @@ unique_ptr<coding::CompressedBitVector> RetrieveAddressFeaturesImpl( collector); }); holder.ForEachModifiedOrCreated([&](FeatureType & ft, uint64_t index) { - if (MatchFeatureByName(ft, params)) + if (MatchFeatureByNameAndType(ft, params)) features.push_back(index); }); return SortFeaturesAndBuildCBV(move(features)); diff --git a/search/search.pro b/search/search.pro index 4fe9079e2d..da1ee701ea 100644 --- a/search/search.pro +++ b/search/search.pro @@ -12,6 +12,7 @@ HEADERS += \ algos.hpp \ approximate_string_match.hpp \ cancel_exception.hpp \ + categories_set.hpp \ cbv.hpp \ common.hpp \ displayed_categories.hpp \ diff --git a/search/search_integration_tests/helpers.cpp b/search/search_integration_tests/helpers.cpp index 1aa205d0b0..79768d0f2d 100644 --- a/search/search_integration_tests/helpers.cpp +++ b/search/search_integration_tests/helpers.cpp @@ -4,6 +4,7 @@ #include "search/search_tests_support/test_search_request.hpp" #include "indexer/classificator_loader.hpp" +#include "indexer/indexer_tests_support/helpers.hpp" #include "indexer/map_style.hpp" #include "indexer/map_style_reader.hpp" #include "indexer/scales.hpp" @@ -26,6 +27,7 @@ SearchTest::SearchTest() , m_engine(make_unique<storage::CountryInfoGetterForTesting>(), make_unique<ProcessorFactory>(), Engine::Params()) { + indexer::tests_support::SetUpEditorForTesting(m_engine); } SearchTest::~SearchTest() diff --git a/search/search_integration_tests/helpers.hpp b/search/search_integration_tests/helpers.hpp index 3dfafe85d5..0160bbfe7f 100644 --- a/search/search_integration_tests/helpers.hpp +++ b/search/search_integration_tests/helpers.hpp @@ -8,6 +8,10 @@ #include "storage/country_decl.hpp" #include "storage/country_info_getter.hpp" +#include "indexer/feature.hpp" +#include "indexer/feature_decl.hpp" +#include "indexer/index.hpp" +#include "indexer/indexer_tests_support/helpers.hpp" #include "indexer/mwm_set.hpp" #include "geometry/rect2d.hpp" @@ -16,7 +20,7 @@ #include "platform/local_country_file.hpp" #include "platform/local_country_file_utils.hpp" -#include "base/logging.hpp" +#include "base/assert.hpp" #include "std/unique_ptr.hpp" #include "std/vector.hpp" @@ -37,6 +41,7 @@ public: using TRules = vector<shared_ptr<tests_support::MatchingRule>>; SearchTest(); + ~SearchTest(); // Registers country in internal records. Note that physical country @@ -86,6 +91,15 @@ public: return BuildMwm(name, feature::DataHeader::country, forward<TBuildFn>(fn)); } + template <typename TEditorFn> + void EditFeature(FeatureID const & id, TEditorFn && fn) + { + Index::FeaturesLoaderGuard loader(m_engine, id.m_mwmId); + FeatureType ft; + CHECK(loader.GetFeatureByIndex(id.m_index, ft), ()); + indexer::tests_support::EditFeature(ft, forward<TEditorFn>(fn)); + } + inline void SetViewport(m2::RectD const & viewport) { m_viewport = viewport; } bool ResultsMatch(string const & query, TRules const & rules); diff --git a/search/search_integration_tests/search_edited_features_test.cpp b/search/search_integration_tests/search_edited_features_test.cpp new file mode 100644 index 0000000000..5f8d70eb6a --- /dev/null +++ b/search/search_integration_tests/search_edited_features_test.cpp @@ -0,0 +1,64 @@ +#include "testing/testing.hpp" + +#include "generator/generator_tests_support/test_feature.hpp" + +#include "search/search_integration_tests/helpers.hpp" +#include "search/search_tests_support/test_results_matching.hpp" + +#include "indexer/editable_map_object.hpp" + +#include "geometry/point2d.hpp" + +#include "coding/multilang_utf8_string.hpp" + +#include "std/shared_ptr.hpp" + +using namespace generator::tests_support; +using namespace search::tests_support; +using namespace search; + +using TRules = vector<shared_ptr<MatchingRule>>; + +namespace +{ +class SearchEditedFeaturesTest : public SearchTest +{ +}; + +UNIT_CLASS_TEST(SearchEditedFeaturesTest, Smoke) +{ + TestCity city(m2::PointD(0, 0), "Quahog", "default", 100 /* rank */); + TestPOI cafe(m2::PointD(0, 0), "Bar", "default"); + + BuildWorld([&](TestMwmBuilder & builder) { builder.Add(city); }); + + auto const id = BuildCountry("Wonderland", [&](TestMwmBuilder & builder) { builder.Add(cafe); }); + + FeatureID cafeId(id, 0 /* index */); + + { + TRules const rules = {ExactMatch(id, cafe)}; + + TEST(ResultsMatch("Bar", rules), ()); + TEST(ResultsMatch("Drunken", TRules{}), ()); + + EditFeature(cafeId, [](osm::EditableMapObject & emo) { + emo.SetName("The Drunken Clam", StringUtf8Multilang::kEnglishCode); + }); + + TEST(ResultsMatch("Bar", rules), ()); + TEST(ResultsMatch("Drunken", rules), ()); + } + + { + TRules const rules = {ExactMatch(id, cafe)}; + + TEST(ResultsMatch("Wifi", TRules{}), ()); + + EditFeature(cafeId, [](osm::EditableMapObject & emo) { emo.SetInternet(osm::Internet::Wlan); }); + + TEST(ResultsMatch("Wifi", rules), ()); + TEST(ResultsMatch("wifi bar quahog", rules), ()); + } +} +} // namespace diff --git a/search/search_integration_tests/search_integration_tests.pro b/search/search_integration_tests/search_integration_tests.pro index e8ae629a85..1d2165831f 100644 --- a/search/search_integration_tests/search_integration_tests.pro +++ b/search/search_integration_tests/search_integration_tests.pro @@ -7,9 +7,9 @@ TEMPLATE = app ROOT_DIR = ../.. -DEPENDENCIES = search_tests_support generator_tests_support generator routing search storage \ - stats_client indexer platform editor geometry coding base tess2 protobuf \ - tomcrypt jansson succinct pugixml opening_hours +DEPENDENCIES = generator_tests_support search_tests_support indexer_tests_support generator \ + routing search storage stats_client indexer platform editor geometry coding base \ + tess2 protobuf tomcrypt jansson succinct pugixml opening_hours include($$ROOT_DIR/common.pri) @@ -25,6 +25,7 @@ SOURCES += \ interactive_search_test.cpp \ pre_ranker_test.cpp \ processor_test.cpp \ + search_edited_features_test.cpp \ smoke_test.cpp \ HEADERS += \ diff --git a/search/token_slice.cpp b/search/token_slice.cpp index 6705b884fe..33ab649498 100644 --- a/search/token_slice.cpp +++ b/search/token_slice.cpp @@ -51,7 +51,7 @@ TokenSliceNoCategories::TokenSliceNoCategories(QueryParams const & params, size_ m_indexes.reserve(endToken - startToken); for (size_t i = startToken; i < endToken; ++i) { - if (!m_params.m_isCategorySynonym[i]) + if (!m_params.IsCategorySynonym(i)) m_indexes.push_back(i); } } |