From 18caeab025d968d6d908027cc268182fdbc43dbd Mon Sep 17 00:00:00 2001 From: Yuri Gorshenin Date: Tue, 17 Oct 2017 15:16:26 +0300 Subject: [PATCH] [search] Usage of CitiesBoundaries in LocalityFinder. --- indexer/index.hpp | 6 +++ search/cities_boundaries_table.cpp | 19 +++++-- search/cities_boundaries_table.hpp | 15 +++++- search/city_finder.hpp | 8 ++- search/engine.cpp | 8 +++ search/engine.hpp | 6 +++ search/locality_finder.cpp | 42 ++++++++++----- search/locality_finder.hpp | 22 +++++--- search/processor.cpp | 7 ++- search/processor.hpp | 3 ++ search/ranker.cpp | 10 ++-- search/ranker.hpp | 6 ++- search/search_integration_tests/helpers.cpp | 5 ++ search/search_integration_tests/helpers.hpp | 9 +++- .../pre_ranker_test.cpp | 15 +++--- .../processor_test.cpp | 53 ++++++++++++++++++- search/search_tests/locality_finder_test.cpp | 7 ++- .../search_tests/locality_selector_test.cpp | 20 +++---- .../test_results_matching.cpp | 8 +++ .../test_results_matching.hpp | 2 + .../test_search_engine.hpp | 4 +- 21 files changed, 217 insertions(+), 58 deletions(-) diff --git a/indexer/index.hpp b/indexer/index.hpp index 0f1f55e685..f32538d0d4 100644 --- a/indexer/index.hpp +++ b/indexer/index.hpp @@ -232,6 +232,12 @@ public: ForEachInIntervals(implFunctor, covering::FullCover, m2::RectD::GetInfiniteRect(), scale); } + template + void ReadFeature(F && f, FeatureID const & feature) const + { + return ReadFeatures(forward(f), {feature}); + } + // "features" must be sorted using FeatureID::operator< as predicate. template void ReadFeatures(F && f, std::vector const & features) const diff --git a/search/cities_boundaries_table.cpp b/search/cities_boundaries_table.cpp index 1fceb47481..97ef366bb5 100644 --- a/search/cities_boundaries_table.cpp +++ b/search/cities_boundaries_table.cpp @@ -30,14 +30,15 @@ bool CitiesBoundariesTable::Boundaries::HasPoint(m2::PointD const & p) const } // CitiesBoundariesTable --------------------------------------------------------------------------- -bool CitiesBoundariesTable::Load(Index const & index) +bool CitiesBoundariesTable::Load() { - auto handle = FindWorld(index); + auto handle = FindWorld(m_index); if (!handle.IsAlive()) - { - LOG(LERROR, ("Can't find world map file")); return false; - } + + // Skip if table was already loaded from this file. + if (handle.GetId() == m_mwmId) + return true; MwmContext context(move(handle)); auto const localities = CategoriesCache(LocalitiesSource{}, my::Cancellable{}).Get(context); @@ -73,6 +74,7 @@ bool CitiesBoundariesTable::Load(Index const & index) return false; } + m_mwmId = context.GetId(); m_table.clear(); m_eps = precision; size_t boundary = 0; @@ -85,6 +87,13 @@ bool CitiesBoundariesTable::Load(Index const & index) return true; } +bool CitiesBoundariesTable::Get(FeatureID const & fid, Boundaries & bs) const +{ + if (fid.m_mwmId != m_mwmId) + return false; + return Get(fid.m_index, bs); +} + bool CitiesBoundariesTable::Get(uint32_t fid, Boundaries & bs) const { auto const it = m_table.find(fid); diff --git a/search/cities_boundaries_table.hpp b/search/cities_boundaries_table.hpp index 1c5b29c337..dc4498f443 100644 --- a/search/cities_boundaries_table.hpp +++ b/search/cities_boundaries_table.hpp @@ -1,6 +1,7 @@ #pragma once #include "indexer/city_boundary.hpp" +#include "indexer/feature_decl.hpp" #include "geometry/point2d.hpp" @@ -11,6 +12,11 @@ class Index; +namespace feature +{ +struct FeatureID; +} + namespace search { class CitiesBoundariesTable @@ -40,12 +46,19 @@ public: double m_eps = 0.0; }; - bool Load(Index const & index); + CitiesBoundariesTable(Index const & index) : m_index(index) {} + bool Load(); + + bool Has(FeatureID const & fid) const { return fid.m_mwmId == m_mwmId && Has(fid.m_index); } bool Has(uint32_t fid) const { return m_table.find(fid) != m_table.end(); } + + bool Get(FeatureID const & fid, Boundaries & bs) const; bool Get(uint32_t fid, Boundaries & bs) const; private: + Index const & m_index; + MwmSet::MwmId m_mwmId; std::unordered_map> m_table; double m_eps = 0.0; }; diff --git a/search/city_finder.hpp b/search/city_finder.hpp index 4b94c59944..6656c276f1 100644 --- a/search/city_finder.hpp +++ b/search/city_finder.hpp @@ -14,8 +14,13 @@ namespace search class CityFinder { public: + // TODO (@milchakov): consider to reuse locality finder from search + // engine. Otherwise, CityFinder won't benefit from approximated + // cities boundaries. explicit CityFinder(Index const & index) - : m_unusedCache(m_cancellable), m_finder(index, m_unusedCache) + : m_unusedBoundaries(index) + , m_unusedCache(m_cancellable) + , m_finder(index, m_unusedBoundaries, m_unusedCache) { } @@ -29,6 +34,7 @@ public: private: my::Cancellable m_cancellable; + search::CitiesBoundariesTable m_unusedBoundaries; search::VillagesCache m_unusedCache; search::LocalityFinder m_finder; }; diff --git a/search/engine.cpp b/search/engine.cpp index fcc27412d0..99ac9f380c 100644 --- a/search/engine.cpp +++ b/search/engine.cpp @@ -110,6 +110,8 @@ Engine::Engine(Index & index, CategoriesHolder const & categories, m_threads.reserve(params.m_numThreads); for (size_t i = 0; i < params.m_numThreads; ++i) m_threads.emplace_back(&Engine::MainLoop, this, ref(m_contexts[i])); + + LoadCitiesBoundaries(); } Engine::~Engine() @@ -150,6 +152,12 @@ void Engine::ClearCaches() }); } +void Engine::LoadCitiesBoundaries() +{ + PostMessage(Message::TYPE_BROADCAST, + [this](Processor & processor) { processor.LoadCitiesBoundaries(); }); +} + void Engine::MainLoop(Context & context) { while (true) diff --git a/search/engine.hpp b/search/engine.hpp index b6aff07fe1..779db4f474 100644 --- a/search/engine.hpp +++ b/search/engine.hpp @@ -106,6 +106,10 @@ public: // Posts request to clear caches to the queue. void ClearCaches(); + // Posts request to reload cities boundaries tables. Must be used + // for testing only. + void LoadCitiesBoundariesForTesting() { return LoadCitiesBoundaries(); } + private: struct Message { @@ -140,6 +144,8 @@ private: unique_ptr m_processor; }; + void LoadCitiesBoundaries(); + // *ALL* following methods are executed on the m_threads threads. // This method executes tasks from a common pool (|tasks|) in a FIFO diff --git a/search/locality_finder.cpp b/search/locality_finder.cpp index 13f0d24f13..5d2ffbaef6 100644 --- a/search/locality_finder.cpp +++ b/search/locality_finder.cpp @@ -57,9 +57,11 @@ private: class LocalitiesLoader { public: - LocalitiesLoader(MwmContext const & ctx, Filter const & filter, LocalityFinder::Holder & holder, + LocalitiesLoader(MwmContext const & ctx, CitiesBoundariesTable const & boundaries, + Filter const & filter, LocalityFinder::Holder & holder, map> & loadedIds) : m_ctx(ctx) + , m_boundaries(boundaries) , m_filter(filter) , m_holder(holder) , m_loadedIds(loadedIds[m_ctx.GetId()]) @@ -99,12 +101,16 @@ public: auto const names = ft.GetNames(); auto const center = ft.GetCenter(); - m_holder.Add(LocalityItem(names, center, population)); + CitiesBoundariesTable::Boundaries boundaries; + m_boundaries.Get(FeatureID(m_ctx.GetId(), id), boundaries); + + m_holder.Add(LocalityItem(names, center, boundaries, population)); m_loadedIds.insert(id); } private: MwmContext const & m_ctx; + CitiesBoundariesTable const & m_boundaries; Filter const & m_filter; LocalityFinder::Holder & m_holder; @@ -114,8 +120,8 @@ private: // LocalityItem ------------------------------------------------------------------------------------ LocalityItem::LocalityItem(StringUtf8Multilang const & names, m2::PointD const & center, - uint64_t population) - : m_names(names), m_center(center), m_population(population) + Boundaries const & boundaries, uint64_t population) + : m_names(names), m_center(center), m_boundaries(boundaries), m_population(population) { } @@ -130,19 +136,27 @@ string DebugPrint(LocalityItem const & item) // LocalitySelector -------------------------------------------------------------------------------- LocalitySelector::LocalitySelector(m2::PointD const & p) : m_p(p) {} - void LocalitySelector::operator()(LocalityItem const & item) { + auto const inside = item.m_boundaries.HasPoint(m_p); + // TODO (@y, @m): replace this naive score by p-values on // multivariate Gaussian. double const distance = MercatorBounds::DistanceOnEarth(item.m_center, m_p); double const score = ftypes::GetPopulationByRadius(distance) / static_cast(item.m_population); - if (score < m_bestScore) + + if (!inside && m_inside) + return; + + ASSERT(inside || !m_inside, ()); + + if ((inside && !m_inside) || (score < m_score)) { - m_bestScore = score; - m_bestLocality = &item; + m_inside = inside; + m_score = score; + m_locality = &item; } } @@ -189,8 +203,10 @@ void LocalityFinder::Holder::Clear() } // LocalityFinder ---------------------------------------------------------------------------------- -LocalityFinder::LocalityFinder(Index const & index, VillagesCache & villagesCache) +LocalityFinder::LocalityFinder(Index const & index, CitiesBoundariesTable const & boundariesTable, + VillagesCache & villagesCache) : m_index(index) + , m_boundariesTable(boundariesTable) , m_villagesCache(villagesCache) , m_cities(kMaxCityRadiusMeters) , m_villages(kMaxVillageRadiusMeters) @@ -228,7 +244,8 @@ void LocalityFinder::LoadVicinity(m2::PointD const & p, bool loadCities, bool lo m_ranks = make_unique(); MwmContext ctx(move(handle)); - ctx.ForEachIndex(crect, LocalitiesLoader(ctx, CityFilter(*m_ranks), m_cities, m_loadedIds)); + ctx.ForEachIndex(crect, LocalitiesLoader(ctx, m_boundariesTable, CityFilter(*m_ranks), + m_cities, m_loadedIds)); } m_cities.SetCovered(p); @@ -243,8 +260,9 @@ void LocalityFinder::LoadVicinity(m2::PointD const & p, bool loadCities, bool lo return; MwmContext ctx(move(handle)); - ctx.ForEachIndex(vrect, LocalitiesLoader(ctx, VillageFilter(ctx, m_villagesCache), m_villages, - m_loadedIds)); + ctx.ForEachIndex(vrect, + LocalitiesLoader(ctx, m_boundariesTable, VillageFilter(ctx, m_villagesCache), + m_villages, m_loadedIds)); }); m_villages.SetCovered(p); diff --git a/search/locality_finder.hpp b/search/locality_finder.hpp index 7a6de185d5..7177986309 100644 --- a/search/locality_finder.hpp +++ b/search/locality_finder.hpp @@ -1,5 +1,7 @@ #pragma once +#include "search/cities_boundaries_table.hpp" + #include "indexer/mwm_set.hpp" #include "indexer/rank_table.hpp" @@ -26,7 +28,10 @@ class VillagesCache; struct LocalityItem { - LocalityItem(StringUtf8Multilang const & names, m2::PointD const & center, uint64_t population); + using Boundaries = CitiesBoundariesTable::Boundaries; + + LocalityItem(StringUtf8Multilang const & names, m2::PointD const & center, + Boundaries const & boundaries, uint64_t population); bool GetName(int8_t lang, string & name) const { return m_names.GetString(lang, name); } @@ -37,6 +42,7 @@ struct LocalityItem StringUtf8Multilang m_names; m2::PointD m_center; + Boundaries m_boundaries; uint64_t m_population; }; @@ -52,16 +58,18 @@ public: template bool WithBestLocality(Fn && fn) const { - if (!m_bestLocality) + if (!m_locality) return false; - fn(*m_bestLocality); + fn(*m_locality); return true; } private: m2::PointD const m_p; - double m_bestScore = std::numeric_limits::max(); - LocalityItem const * m_bestLocality = nullptr; + + bool m_inside = false; + double m_score = std::numeric_limits::max(); + LocalityItem const * m_locality = nullptr; }; class LocalityFinder @@ -91,7 +99,8 @@ public: DISALLOW_COPY_AND_MOVE(Holder); }; - LocalityFinder(Index const & index, VillagesCache & villagesCache); + LocalityFinder(Index const & index, CitiesBoundariesTable const & boundaries, + VillagesCache & villagesCache); template bool GetLocality(m2::PointD const & p, Fn && fn) @@ -116,6 +125,7 @@ private: void UpdateMaps(); Index const & m_index; + CitiesBoundariesTable const & m_boundariesTable; VillagesCache & m_villagesCache; Holder m_cities; diff --git a/search/processor.cpp b/search/processor.cpp index eb1f25acef..2f4d1a78ec 100644 --- a/search/processor.cpp +++ b/search/processor.cpp @@ -183,8 +183,9 @@ Processor::Processor(Index const & index, CategoriesHolder const & categories, , m_suggestsEnabled(true) , m_viewportSearch(false) , m_villagesCache(static_cast(*this)) - , m_ranker(index, infoGetter, m_emitter, categories, suggests, m_villagesCache, - static_cast(*this)) + , m_citiesBoundaries(index) + , m_ranker(index, m_citiesBoundaries, infoGetter, m_emitter, categories, suggests, + m_villagesCache, static_cast(*this)) , m_preRanker(index, m_ranker, kPreResultsCount) , m_geocoder(index, infoGetter, m_preRanker, m_villagesCache, static_cast(*this)) @@ -390,6 +391,8 @@ void Processor::SetViewportByIndex(m2::RectD const & viewport, size_t idx, bool void Processor::ClearCache(size_t ind) { m_viewport[ind].MakeEmpty(); } +void Processor::LoadCitiesBoundaries() { m_citiesBoundaries.Load(); } + Locales Processor::GetCategoryLocales() const { static int8_t const enLocaleCode = CategoriesHolder::MapLocaleToInteger("en"); diff --git a/search/processor.hpp b/search/processor.hpp index 96310054a8..f7f8360caa 100644 --- a/search/processor.hpp +++ b/search/processor.hpp @@ -1,6 +1,7 @@ #pragma once #include "search/categories_cache.hpp" #include "search/categories_set.hpp" +#include "search/cities_boundaries_table.hpp" #include "search/emitter.hpp" #include "search/geocoder.hpp" #include "search/hotels_filter.hpp" @@ -111,6 +112,7 @@ public: void InitEmitter(); void ClearCaches(); + void LoadCitiesBoundaries(); protected: enum ViewportID @@ -180,6 +182,7 @@ protected: bool m_viewportSearch; VillagesCache m_villagesCache; + CitiesBoundariesTable m_citiesBoundaries; Emitter m_emitter; Ranker m_ranker; diff --git a/search/ranker.cpp b/search/ranker.cpp index a7e83cc001..63e4afb33e 100644 --- a/search/ranker.cpp +++ b/search/ranker.cpp @@ -319,13 +319,13 @@ public: // static size_t const Ranker::kBatchSize = 10; -Ranker::Ranker(Index const & index, storage::CountryInfoGetter const & infoGetter, - Emitter & emitter, CategoriesHolder const & categories, - vector const & suggests, VillagesCache & villagesCache, - my::Cancellable const & cancellable) +Ranker::Ranker(Index const & index, CitiesBoundariesTable const & boundariesTable, + storage::CountryInfoGetter const & infoGetter, Emitter & emitter, + CategoriesHolder const & categories, vector const & suggests, + VillagesCache & villagesCache, my::Cancellable const & cancellable) : m_reverseGeocoder(index) , m_cancellable(cancellable) - , m_localities(index, villagesCache) + , m_localities(index, boundariesTable, villagesCache) , m_index(index) , m_infoGetter(infoGetter) , m_emitter(emitter) diff --git a/search/ranker.hpp b/search/ranker.hpp index d045ba61a8..b369f8e777 100644 --- a/search/ranker.hpp +++ b/search/ranker.hpp @@ -35,9 +35,10 @@ class CountryInfoGetter; namespace search { -class VillagesCache; +class CitiesBoundariesTable; class Emitter; class PreResult2Maker; +class VillagesCache; class Ranker { @@ -71,7 +72,8 @@ public: static size_t const kBatchSize; - Ranker(Index const & index, storage::CountryInfoGetter const & infoGetter, Emitter & emitter, + Ranker(Index const & index, CitiesBoundariesTable const & boundariesTable, + storage::CountryInfoGetter const & infoGetter, Emitter & emitter, CategoriesHolder const & categories, vector const & suggests, VillagesCache & villagesCache, my::Cancellable const & cancellable); virtual ~Ranker() = default; diff --git a/search/search_integration_tests/helpers.cpp b/search/search_integration_tests/helpers.cpp index 758394801f..3606fda4d5 100644 --- a/search/search_integration_tests/helpers.cpp +++ b/search/search_integration_tests/helpers.cpp @@ -79,6 +79,11 @@ bool SearchTest::ResultsMatch(SearchParams const & params, TRules const & rules) return ResultsMatch(request.Results(), rules); } +bool SearchTest::ResultMatches(search::Result const & result, TRule const & rule) +{ + return tests_support::ResultMatches(m_engine, rule, result); +} + unique_ptr SearchTest::MakeRequest( string const & query, string const & locale /* = "en" */) { diff --git a/search/search_integration_tests/helpers.hpp b/search/search_integration_tests/helpers.hpp index f42579f4f7..a6074a6a3d 100644 --- a/search/search_integration_tests/helpers.hpp +++ b/search/search_integration_tests/helpers.hpp @@ -39,7 +39,8 @@ public: class SearchTest : public TestWithClassificator { public: - using TRules = vector>; + using TRule = shared_ptr; + using TRules = vector; SearchTest(); @@ -83,7 +84,9 @@ public: template MwmSet::MwmId BuildWorld(TBuildFn && fn) { - return BuildMwm("testWorld", feature::DataHeader::world, forward(fn)); + auto const id = BuildMwm("testWorld", feature::DataHeader::world, forward(fn)); + m_engine.LoadCitiesBoundaries(); + return id; } template @@ -113,6 +116,8 @@ public: bool ResultsMatch(SearchParams const & params, TRules const & rules); + bool ResultMatches(search::Result const & result, TRule const & rule); + unique_ptr MakeRequest(string const & query, string const & locale = "en"); diff --git a/search/search_integration_tests/pre_ranker_test.cpp b/search/search_integration_tests/pre_ranker_test.cpp index ae8049d901..2e86d3941b 100644 --- a/search/search_integration_tests/pre_ranker_test.cpp +++ b/search/search_integration_tests/pre_ranker_test.cpp @@ -1,6 +1,7 @@ #include "testing/testing.hpp" #include "search/categories_cache.hpp" +#include "search/cities_boundaries_table.hpp" #include "search/emitter.hpp" #include "search/intermediate_result.hpp" #include "search/model.hpp" @@ -44,11 +45,11 @@ namespace class TestRanker : public Ranker { public: - TestRanker(TestSearchEngine & engine, Emitter & emitter, vector const & suggests, - VillagesCache & villagesCache, my::Cancellable const & cancellable, - vector & results) - : Ranker(static_cast(engine), engine.GetCountryInfoGetter(), emitter, - GetDefaultCategories(), suggests, villagesCache, cancellable) + TestRanker(TestSearchEngine & engine, CitiesBoundariesTable const & boundariesTable, + Emitter & emitter, vector const & suggests, VillagesCache & villagesCache, + my::Cancellable const & cancellable, vector & results) + : Ranker(static_cast(engine), boundariesTable, engine.GetCountryInfoGetter(), + emitter, GetDefaultCategories(), suggests, villagesCache, cancellable) , m_results(results) { } @@ -113,8 +114,10 @@ UNIT_CLASS_TEST(PreRankerTest, Smoke) vector results; Emitter emitter; + CitiesBoundariesTable boundariesTable(m_engine); VillagesCache villagesCache(m_cancellable); - TestRanker ranker(m_engine, emitter, m_suggests, villagesCache, m_cancellable, results); + TestRanker ranker(m_engine, boundariesTable, emitter, m_suggests, villagesCache, m_cancellable, + results); PreRanker preRanker(m_engine, ranker, pois.size()); PreRanker::Params params; diff --git a/search/search_integration_tests/processor_test.cpp b/search/search_integration_tests/processor_test.cpp index 1b72825f0a..1b2ac83208 100644 --- a/search/search_integration_tests/processor_test.cpp +++ b/search/search_integration_tests/processor_test.cpp @@ -1113,8 +1113,8 @@ UNIT_CLASS_TEST(ProcessorTest, CityBoundaryLoad) TEST(ResultsMatch("moscow", "en", rules), ()); } - CitiesBoundariesTable table; - TEST(table.Load(m_engine), ()); + CitiesBoundariesTable table(m_engine); + TEST(table.Load(), ()); TEST(table.Has(0 /* fid */), ()); TEST(!table.Has(10 /* fid */), ()); @@ -1129,5 +1129,54 @@ UNIT_CLASS_TEST(ProcessorTest, CityBoundaryLoad) TEST(!boundaries.HasPoint(m2::PointD(0.6, 0.6)), ()); TEST(!boundaries.HasPoint(m2::PointD(-1, 0.5)), ()); } + +UNIT_CLASS_TEST(ProcessorTest, CityBoundarySmoke) +{ + TestCity moscow(vector({m2::PointD(0, 0), m2::PointD(0.5, 0), m2::PointD(0.5, 0.5), + m2::PointD(0, 0.5)}), + "Москва", "ru", 100 /* rank */); + TestCity khimki(vector({m2::PointD(0.25, 0.5), m2::PointD(0.5, 0.5), + m2::PointD(0.5, 0.75), m2::PointD(0.25, 0.75)}), + "Химки", "ru", 50 /* rank */); + + TestPOI cafeMoscow(m2::PointD(0.49, 0.49), "Москвичка", "ru"); + cafeMoscow.SetTypes({{"amenity", "cafe"}, {"internet_access", "wlan"}}); + + TestPOI cafeKhimki(m2::PointD(0.49, 0.51), "Химичка", "ru"); + cafeKhimki.SetTypes({{"amenity", "cafe"}, {"internet_access", "wlan"}}); + + BuildWorld([&](TestMwmBuilder & builder) { + builder.Add(moscow); + builder.Add(khimki); + }); + + auto countryId = BuildCountry("Россия" /* countryName */, [&](TestMwmBuilder & builder) { + builder.Add(cafeMoscow); + builder.Add(cafeKhimki); + }); + + SetViewport(m2::RectD(m2::PointD(-1.0, -1.0), m2::PointD(1.0, 1.0))); + + { + auto request = MakeRequest("кафе", "ru"); + auto const & results = request->Results(); + + TRules rules{ExactMatch(countryId, cafeMoscow), ExactMatch(countryId, cafeKhimki)}; + TEST(ResultsMatch(results, rules), ()); + + for (auto const & result : results) + { + if (ResultMatches(result, ExactMatch(countryId, cafeMoscow))) + { + TEST_EQUAL(result.GetAddress(), "Москва, Россия", ()); + } + else + { + TEST(ResultMatches(result, ExactMatch(countryId, cafeKhimki)), ()); + TEST_EQUAL(result.GetAddress(), "Химки, Россия", ()); + } + } + } +} } // namespace } // namespace search diff --git a/search/search_tests/locality_finder_test.cpp b/search/search_tests/locality_finder_test.cpp index c36deb012b..e069d74eac 100644 --- a/search/search_tests/locality_finder_test.cpp +++ b/search/search_tests/locality_finder_test.cpp @@ -29,12 +29,16 @@ class LocalityFinderTest : public TestWithClassificator my::Cancellable m_cancellable; search::VillagesCache m_villagesCache; + search::CitiesBoundariesTable m_boundariesTable; search::LocalityFinder m_finder; m2::RectD m_worldRect; public: - LocalityFinderTest() : m_villagesCache(m_cancellable), m_finder(m_index, m_villagesCache) + LocalityFinderTest() + : m_villagesCache(m_cancellable) + , m_boundariesTable(m_index) + , m_finder(m_index, m_boundariesTable, m_villagesCache) { m_worldFile = platform::LocalCountryFile::MakeForTesting("World"); @@ -47,6 +51,7 @@ public: TEST(id.IsAlive(), ()); m_worldRect = id.GetInfo()->m_limitRect; + m_boundariesTable.Load(); } catch (RootException const & ex) { diff --git a/search/search_tests/locality_selector_test.cpp b/search/search_tests/locality_selector_test.cpp index e23f27c24a..76a93fa550 100644 --- a/search/search_tests/locality_selector_test.cpp +++ b/search/search_tests/locality_selector_test.cpp @@ -18,7 +18,7 @@ StringUtf8Multilang ToMultilang(string const & name) struct City { City(string const & name, m2::PointD const & center, uint64_t population) - : m_item(ToMultilang(name), center, population) + : m_item(ToMultilang(name), center, {} /* boundaries */, population) { } @@ -37,18 +37,14 @@ string GetMatchedCity(m2::PointD const & point, vector const & cities) return name; } -// TODO (@y): this test fails for now. Need to uncomment it as soon as -// locality finder will be fixed. -// -// UNIT_TEST(LocalitySelector_Test1) -// { -// auto const name = GetMatchedCity( -// m2::PointD(-97.56345, 26.79672), -// {{"Matamoros", m2::PointD(-97.50665, 26.79718), 10000}, +UNIT_TEST(LocalitySelector_Test1) +{ + auto const name = GetMatchedCity(m2::PointD(-97.56345, 26.79672), + {{"Matamoros", m2::PointD(-97.50665, 26.79718), 918536}, -// {"Brownsville", m2::PointD(-97.48910, 26.84558), 180663}}); -// TEST_EQUAL(name, "Matamoros", ()); -// } + {"Brownsville", m2::PointD(-97.48910, 26.84558), 180663}}); + TEST_EQUAL(name, "Matamoros", ()); +} UNIT_TEST(LocalitySelector_Test2) { diff --git a/search/search_tests_support/test_results_matching.cpp b/search/search_tests_support/test_results_matching.cpp index ccbfa55b7f..386ff118d1 100644 --- a/search/search_tests_support/test_results_matching.cpp +++ b/search/search_tests_support/test_results_matching.cpp @@ -99,6 +99,14 @@ bool MatchResults(Index const & index, vector> rules, return false; } +bool ResultMatches(Index const & index, shared_ptr rule, + search::Result const & result) +{ + bool matches = false; + index.ReadFeature([&](FeatureType & ft) { matches = rule->Matches(ft); }, result.GetFeatureID()); + return matches; +} + string DebugPrint(MatchingRule const & rule) { return rule.ToString(); } } // namespace tests_support } // namespace search diff --git a/search/search_tests_support/test_results_matching.hpp b/search/search_tests_support/test_results_matching.hpp index 3a776d48ca..54b351b348 100644 --- a/search/search_tests_support/test_results_matching.hpp +++ b/search/search_tests_support/test_results_matching.hpp @@ -74,6 +74,8 @@ shared_ptr AlternativesMatch(TArgs &&... args) bool MatchResults(Index const & index, vector> rules, vector const & actual); +bool ResultMatches(Index const & index, shared_ptr rule, + search::Result const & result); string DebugPrint(MatchingRule const & rule); } // namespace tests_support diff --git a/search/search_tests_support/test_search_engine.hpp b/search/search_tests_support/test_search_engine.hpp index b363413d4f..58955383bd 100644 --- a/search/search_tests_support/test_search_engine.hpp +++ b/search/search_tests_support/test_search_engine.hpp @@ -31,7 +31,9 @@ public: TestSearchEngine(unique_ptr<::search::ProcessorFactory> factory, Engine::Params const & params); ~TestSearchEngine() override; - inline void SetLocale(string const & locale) { m_engine.SetLocale(locale); } + void SetLocale(string const & locale) { m_engine.SetLocale(locale); } + + void LoadCitiesBoundaries() { m_engine.LoadCitiesBoundariesForTesting(); } weak_ptr Search(search::SearchParams const & params, m2::RectD const & viewport);