Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mapsme/omim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'search/search_integration_tests/processor_test.cpp')
-rw-r--r--search/search_integration_tests/processor_test.cpp550
1 files changed, 550 insertions, 0 deletions
diff --git a/search/search_integration_tests/processor_test.cpp b/search/search_integration_tests/processor_test.cpp
new file mode 100644
index 0000000000..4d81c982d9
--- /dev/null
+++ b/search/search_integration_tests/processor_test.cpp
@@ -0,0 +1,550 @@
+#include "testing/testing.hpp"
+
+#include "search/retrieval.hpp"
+#include "search/search_integration_tests/helpers.hpp"
+#include "search/search_tests_support/test_results_matching.hpp"
+#include "search/search_tests_support/test_search_request.hpp"
+#include "search/v2/token_slice.hpp"
+
+#include "generator/generator_tests_support/test_feature.hpp"
+#include "generator/generator_tests_support/test_mwm_builder.hpp"
+
+#include "indexer/feature.hpp"
+#include "indexer/index.hpp"
+
+#include "geometry/point2d.hpp"
+#include "geometry/rect2d.hpp"
+
+#include "base/math.hpp"
+
+#include "std/shared_ptr.hpp"
+#include "std/vector.hpp"
+
+using namespace generator::tests_support;
+using namespace search::tests_support;
+using namespace search::v2;
+
+using TRules = vector<shared_ptr<MatchingRule>>;
+
+namespace search
+{
+namespace
+{
+class ProcessorTest : public SearchTest
+{
+public:
+ unique_ptr<TestSearchRequest> MakeRequest(string const & query)
+ {
+ SearchParams params;
+ params.m_query = query;
+ params.m_inputLocale = "en";
+ params.SetMode(Mode::Everywhere);
+ params.SetSuggestsEnabled(false);
+
+ auto request = make_unique<TestSearchRequest>(m_engine, params, m_viewport);
+ request->Wait();
+ return request;
+ }
+
+ bool MatchResults(vector<shared_ptr<MatchingRule>> rules,
+ vector<search::Result> const & actual) const
+ {
+ return ::MatchResults(m_engine, rules, actual);
+ }
+};
+
+UNIT_CLASS_TEST(ProcessorTest, Smoke)
+{
+ string const countryName = "Wonderland";
+ TestCountry wonderlandCountry(m2::PointD(10, 10), countryName, "en");
+
+ TestCity losAlamosCity(m2::PointD(10, 10), "Los Alamos", "en", 100 /* rank */);
+ TestCity mskCity(m2::PointD(0, 0), "Moscow", "en", 100 /* rank */);
+ TestVillage longPondVillage(m2::PointD(15, 15), "Long Pond Village", "en", 10 /* rank */);
+ TestStreet feynmanStreet(
+ vector<m2::PointD>{m2::PointD(9.999, 9.999), m2::PointD(10, 10), m2::PointD(10.001, 10.001)},
+ "Feynman street", "en");
+ TestStreet bohrStreet1(
+ vector<m2::PointD>{m2::PointD(9.999, 10.001), m2::PointD(10, 10), m2::PointD(10.001, 9.999)},
+ "Bohr street", "en");
+ TestStreet bohrStreet2(vector<m2::PointD>{m2::PointD(10.001, 9.999), m2::PointD(10.002, 9.998)},
+ "Bohr street", "en");
+ TestStreet bohrStreet3(vector<m2::PointD>{m2::PointD(10.002, 9.998), m2::PointD(10.003, 9.997)},
+ "Bohr street", "en");
+ TestStreet firstAprilStreet(vector<m2::PointD>{m2::PointD(14.998, 15), m2::PointD(15.002, 15)},
+ "1st April street", "en");
+
+ TestBuilding feynmanHouse(m2::PointD(10, 10), "Feynman house", "1 unit 1", feynmanStreet, "en");
+ TestBuilding bohrHouse(m2::PointD(10, 10), "Bohr house", "1 unit 1", bohrStreet1, "en");
+ TestBuilding hilbertHouse(
+ vector<m2::PointD>{
+ {10.0005, 10.0005}, {10.0006, 10.0005}, {10.0006, 10.0006}, {10.0005, 10.0006}},
+ "Hilbert house", "1 unit 2", bohrStreet1, "en");
+ TestBuilding descartesHouse(m2::PointD(10, 10), "Descartes house", "2", "en");
+ TestBuilding bornHouse(m2::PointD(14.999, 15), "Born house", "8", firstAprilStreet, "en");
+
+ TestPOI busStop(m2::PointD(0, 0), "Bus stop", "en");
+ TestPOI tramStop(m2::PointD(0.0001, 0.0001), "Tram stop", "en");
+ TestPOI quantumTeleport1(m2::PointD(0.0002, 0.0002), "Quantum teleport 1", "en");
+
+ TestPOI quantumTeleport2(m2::PointD(10, 10), "Quantum teleport 2", "en");
+ quantumTeleport2.SetHouseNumber("3");
+ quantumTeleport2.SetStreet(feynmanStreet);
+
+ TestPOI quantumCafe(m2::PointD(-0.0002, -0.0002), "Quantum cafe", "en");
+ TestPOI lantern1(m2::PointD(10.0005, 10.0005), "lantern 1", "en");
+ TestPOI lantern2(m2::PointD(10.0006, 10.0005), "lantern 2", "en");
+
+ BuildWorld([&](TestMwmBuilder & builder)
+ {
+ builder.Add(wonderlandCountry);
+ builder.Add(losAlamosCity);
+ builder.Add(mskCity);
+ });
+ auto wonderlandId = BuildCountry(countryName, [&](TestMwmBuilder & builder)
+ {
+ builder.Add(losAlamosCity);
+ builder.Add(mskCity);
+ builder.Add(longPondVillage);
+
+ builder.Add(feynmanStreet);
+ builder.Add(bohrStreet1);
+ builder.Add(bohrStreet2);
+ builder.Add(bohrStreet3);
+ builder.Add(firstAprilStreet);
+
+ builder.Add(feynmanHouse);
+ builder.Add(bohrHouse);
+ builder.Add(hilbertHouse);
+ builder.Add(descartesHouse);
+ builder.Add(bornHouse);
+
+ builder.Add(busStop);
+ builder.Add(tramStop);
+ builder.Add(quantumTeleport1);
+ builder.Add(quantumTeleport2);
+ builder.Add(quantumCafe);
+ builder.Add(lantern1);
+ builder.Add(lantern2);
+ });
+
+ SetViewport(m2::RectD(m2::PointD(-1.0, -1.0), m2::PointD(1.0, 1.0)));
+ {
+ TRules rules = {ExactMatch(wonderlandId, busStop)};
+ TEST(ResultsMatch("Bus stop", rules), ());
+ }
+ {
+ TRules rules = {ExactMatch(wonderlandId, quantumCafe),
+ ExactMatch(wonderlandId, quantumTeleport1),
+ ExactMatch(wonderlandId, quantumTeleport2)};
+ TEST(ResultsMatch("quantum", rules), ());
+ }
+ {
+ TRules rules = {ExactMatch(wonderlandId, quantumCafe),
+ ExactMatch(wonderlandId, quantumTeleport1)};
+ TEST(ResultsMatch("quantum Moscow ", rules), ());
+ }
+ {
+ TEST(ResultsMatch(" ", TRules()), ());
+ }
+ {
+ TRules rules = {ExactMatch(wonderlandId, quantumTeleport2)};
+ TEST(ResultsMatch("teleport feynman street", rules), ());
+ }
+ {
+ TRules rules = {ExactMatch(wonderlandId, quantumTeleport2)};
+ TEST(ResultsMatch("feynman street 3", rules), ());
+ }
+ {
+ TRules rules = {ExactMatch(wonderlandId, feynmanHouse), ExactMatch(wonderlandId, lantern1)};
+ TEST(ResultsMatch("feynman street 1", rules), ());
+ }
+ {
+ TRules rules = {ExactMatch(wonderlandId, bohrHouse), ExactMatch(wonderlandId, hilbertHouse),
+ ExactMatch(wonderlandId, lantern1)};
+ TEST(ResultsMatch("bohr street 1", rules), ());
+ }
+ {
+ TEST(ResultsMatch("bohr street 1 unit 3", TRules()), ());
+ }
+ {
+ TRules rules = {ExactMatch(wonderlandId, lantern1), ExactMatch(wonderlandId, lantern2)};
+ TEST(ResultsMatch("bohr street 1 lantern ", rules), ());
+ }
+ {
+ TRules rules = {ExactMatch(wonderlandId, feynmanHouse)};
+ TEST(ResultsMatch("wonderland los alamos feynman 1 unit 1 ", rules), ());
+ }
+ {
+ // It's possible to find Descartes house by name.
+ TRules rules = {ExactMatch(wonderlandId, descartesHouse)};
+ TEST(ResultsMatch("Los Alamos Descartes", rules), ());
+ }
+ {
+ // It's not possible to find Descartes house by house number,
+ // because it doesn't belong to Los Alamos streets. But it still
+ // exists.
+ TRules rules = {ExactMatch(wonderlandId, lantern2), ExactMatch(wonderlandId, quantumTeleport2)};
+ TEST(ResultsMatch("Los Alamos 2", rules), ());
+ }
+ {
+ TRules rules = {ExactMatch(wonderlandId, bornHouse)};
+ TEST(ResultsMatch("long pond 1st april street 8", rules), ());
+ }
+}
+
+UNIT_CLASS_TEST(ProcessorTest, SearchInWorld)
+{
+ string const countryName = "Wonderland";
+ TestCountry wonderland(m2::PointD(0, 0), countryName, "en");
+ TestCity losAlamos(m2::PointD(0, 0), "Los Alamos", "en", 100 /* rank */);
+
+ auto testWorldId = BuildWorld([&](TestMwmBuilder & builder)
+ {
+ builder.Add(wonderland);
+ builder.Add(losAlamos);
+ });
+ RegisterCountry(countryName, m2::RectD(m2::PointD(-1.0, -1.0), m2::PointD(1.0, 1.0)));
+
+ SetViewport(m2::RectD(m2::PointD(-1.0, -1.0), m2::PointD(-0.5, -0.5)));
+ {
+ TRules rules = {ExactMatch(testWorldId, losAlamos)};
+ TEST(ResultsMatch("Los Alamos", rules), ());
+ }
+ {
+ TRules rules = {ExactMatch(testWorldId, wonderland)};
+ TEST(ResultsMatch("Wonderland", rules), ());
+ }
+ {
+ TRules rules = {ExactMatch(testWorldId, losAlamos)};
+ TEST(ResultsMatch("Wonderland Los Alamos", rules), ());
+ }
+}
+
+UNIT_CLASS_TEST(ProcessorTest, SearchByName)
+{
+ string const countryName = "Wonderland";
+ TestCity london(m2::PointD(1, 1), "London", "en", 100 /* rank */);
+ TestPark hydePark(vector<m2::PointD>{m2::PointD(0.5, 0.5), m2::PointD(1.5, 0.5),
+ m2::PointD(1.5, 1.5), m2::PointD(0.5, 1.5)},
+ "Hyde Park", "en");
+ TestPOI cafe(m2::PointD(1.0, 1.0), "London Cafe", "en");
+
+ auto worldId = BuildWorld([&](TestMwmBuilder & builder)
+ {
+ builder.Add(london);
+ });
+ auto wonderlandId = BuildCountry(countryName, [&](TestMwmBuilder & builder)
+ {
+ builder.Add(hydePark);
+ builder.Add(cafe);
+ });
+
+ SetViewport(m2::RectD(m2::PointD(-1.0, -1.0), m2::PointD(-0.9, -0.9)));
+ {
+ TRules rules = {ExactMatch(wonderlandId, hydePark)};
+ TEST(ResultsMatch("hyde park", rules), ());
+ TEST(ResultsMatch("london hyde park", rules), ());
+ TEST(ResultsMatch("hyde london park", TRules()), ());
+ }
+
+ SetViewport(m2::RectD(m2::PointD(0.5, 0.5), m2::PointD(1.5, 1.5)));
+ {
+ TRules rules = {ExactMatch(worldId, london)};
+ TEST(ResultsMatch("london", Mode::World, rules), ());
+ }
+ {
+ TRules rules = {ExactMatch(worldId, london), ExactMatch(wonderlandId, cafe)};
+ TEST(ResultsMatch("london", Mode::Everywhere, rules), ());
+ }
+}
+
+UNIT_CLASS_TEST(ProcessorTest, DisableSuggests)
+{
+ TestCity london1(m2::PointD(1, 1), "London", "en", 100 /* rank */);
+ TestCity london2(m2::PointD(-1, -1), "London", "en", 100 /* rank */);
+
+ auto worldId = BuildWorld([&](TestMwmBuilder & builder)
+ {
+ builder.Add(london1);
+ builder.Add(london2);
+ });
+
+ SetViewport(m2::RectD(m2::PointD(0.5, 0.5), m2::PointD(1.5, 1.5)));
+ {
+ SearchParams params;
+ params.m_query = "londo";
+ params.m_inputLocale = "en";
+ params.SetMode(Mode::World);
+ params.SetSuggestsEnabled(false);
+
+ TestSearchRequest request(m_engine, params, m_viewport);
+ request.Wait();
+ TRules rules = {ExactMatch(worldId, london1), ExactMatch(worldId, london2)};
+
+ TEST(MatchResults(rules, request.Results()), ());
+ }
+}
+
+UNIT_CLASS_TEST(ProcessorTest, TestRankingInfo)
+{
+ string const countryName = "Wonderland";
+
+ TestCity sanFrancisco(m2::PointD(1, 1), "San Francisco", "en", 100 /* rank */);
+ // Golden Gate Bridge-bridge is located in this test on the Golden
+ // Gate Bridge-street. Therefore, there are several valid parses of
+ // the query "Golden Gate Bridge", and search engine must return
+ // both features (street and bridge) as they were matched by full
+ // name.
+ TestStreet goldenGateStreet(
+ vector<m2::PointD>{m2::PointD(-0.5, -0.5), m2::PointD(0, 0), m2::PointD(0.5, 0.5)},
+ "Golden Gate Bridge", "en");
+
+ TestPOI goldenGateBridge(m2::PointD(0, 0), "Golden Gate Bridge", "en");
+
+ TestPOI waterfall(m2::PointD(0.5, 0.5), "", "en");
+ waterfall.SetTypes({{"waterway", "waterfall"}});
+
+ TestPOI lermontov(m2::PointD(1, 1), "Лермонтовъ", "en");
+ lermontov.SetTypes({{"amenity", "cafe"}});
+
+ // A city with two noname cafes.
+ TestCity lermontovo(m2::PointD(-1, -1), "Лермонтово", "en", 100 /* rank */);
+ TestPOI cafe1(m2::PointD(-1.01, -1.01), "", "en");
+ cafe1.SetTypes({{"amenity", "cafe"}});
+ TestPOI cafe2(m2::PointD(-0.99, -0.99), "", "en");
+ cafe2.SetTypes({{"amenity", "cafe"}});
+
+ auto worldId = BuildWorld([&](TestMwmBuilder & builder)
+ {
+ builder.Add(sanFrancisco);
+ builder.Add(lermontovo);
+ });
+ auto wonderlandId = BuildCountry(countryName, [&](TestMwmBuilder & builder)
+ {
+ builder.Add(cafe1);
+ builder.Add(cafe2);
+ builder.Add(goldenGateBridge);
+ builder.Add(goldenGateStreet);
+ builder.Add(lermontov);
+ builder.Add(waterfall);
+ });
+
+ SetViewport(m2::RectD(m2::PointD(-0.5, -0.5), m2::PointD(0.5, 0.5)));
+ {
+ auto request = MakeRequest("golden gate bridge ");
+
+ TRules rules = {ExactMatch(wonderlandId, goldenGateBridge),
+ ExactMatch(wonderlandId, goldenGateStreet)};
+
+ TEST(MatchResults(rules, request->Results()), ());
+ for (auto const & result : request->Results())
+ {
+ auto const & info = result.GetRankingInfo();
+ TEST_EQUAL(NAME_SCORE_FULL_MATCH, info.m_nameScore, (result));
+ TEST(!info.m_pureCats, (result));
+ TEST(!info.m_falseCats, (result));
+ }
+ }
+
+ // This test is quite important and must always pass.
+ {
+ auto request = MakeRequest("cafe лермонтов");
+ auto const & results = request->Results();
+
+ TRules rules{ExactMatch(wonderlandId, cafe1), ExactMatch(wonderlandId, cafe2),
+ ExactMatch(wonderlandId, lermontov)};
+ TEST(MatchResults(rules, results), ());
+
+ TEST_EQUAL(3, results.size(), ("Unexpected number of retrieved cafes."));
+ auto const & top = results.front();
+ TEST(MatchResults({ExactMatch(wonderlandId, lermontov)}, {top}), ());
+ }
+
+ {
+ TRules rules{ExactMatch(wonderlandId, waterfall)};
+ TEST(ResultsMatch("waterfall", rules), ());
+ }
+}
+
+UNIT_CLASS_TEST(ProcessorTest, TestPostcodes)
+{
+ string const countryName = "Russia";
+
+ TestCity dolgoprudny(m2::PointD(0, 0), "Долгопрудный", "ru", 100 /* rank */);
+ TestCity london(m2::PointD(10, 10), "London", "en", 100 /* rank */);
+
+ TestStreet street(
+ vector<m2::PointD>{m2::PointD(-0.5, 0.0), m2::PointD(0, 0), m2::PointD(0.5, 0.0)},
+ "Первомайская", "ru");
+ TestBuilding building28(m2::PointD(0.0, 0.00001), "", "28а", street, "ru");
+ building28.SetPostcode("141701");
+
+ TestBuilding building29(m2::PointD(0.0, -0.00001), "", "29", street, "ru");
+ building29.SetPostcode("141701");
+
+ TestBuilding building30(m2::PointD(0.00001, 0.00001), "", "30", street, "ru");
+ building30.SetPostcode("141702");
+
+ TestBuilding building1(m2::PointD(10, 10), "", "1", "en");
+ building1.SetPostcode("WC2H 7BX");
+
+ BuildWorld([&](TestMwmBuilder & builder)
+ {
+ builder.Add(dolgoprudny);
+ builder.Add(london);
+ });
+ auto countryId = BuildCountry(countryName, [&](TestMwmBuilder & builder)
+ {
+ builder.Add(street);
+ builder.Add(building28);
+ builder.Add(building29);
+ builder.Add(building30);
+
+ builder.Add(building1);
+ });
+
+ // Tests that postcode is added to the search index.
+ {
+ auto handle = m_engine.GetMwmHandleById(countryId);
+ TEST(handle.IsAlive(), ());
+ my::Cancellable cancellable;
+
+ QueryParams params;
+ params.m_tokens.emplace_back();
+ params.m_tokens.back().push_back(strings::MakeUniString("141702"));
+ auto * value = handle.GetValue<MwmValue>();
+ auto features = v2::RetrievePostcodeFeatures(countryId, *value, cancellable,
+ TokenSlice(params, 0, params.m_tokens.size()));
+ TEST_EQUAL(1, features->PopCount(), ());
+
+ uint64_t index = 0;
+ while (!features->GetBit(index))
+ ++index;
+
+ Index::FeaturesLoaderGuard loader(m_engine, countryId);
+ FeatureType ft;
+ loader.GetFeatureByIndex(index, ft);
+
+ auto rule = ExactMatch(countryId, building30);
+ TEST(rule->Matches(ft), ());
+ }
+
+ {
+ TRules rules{ExactMatch(countryId, building28)};
+ TEST(ResultsMatch("Долгопрудный первомайская 28а", "ru", rules), ());
+ }
+ {
+ TRules rules{ExactMatch(countryId, building28)};
+ TEST(ResultsMatch("Долгопрудный первомайская 28а, 141701", "ru", rules), ());
+ }
+ {
+ TRules rules{ExactMatch(countryId, building28), ExactMatch(countryId, building29)};
+ TEST(ResultsMatch("Долгопрудный первомайская 141701", "ru", rules), ());
+ }
+ {
+ TRules rules{ExactMatch(countryId, building28), ExactMatch(countryId, building29)};
+ TEST(ResultsMatch("Долгопрудный 141701", "ru", rules), ());
+ }
+ {
+ TRules rules{ExactMatch(countryId, building30)};
+ TEST(ResultsMatch("Долгопрудный 141702", "ru", rules), ());
+ }
+
+ {
+ string const kQueries[] = {"london WC2H 7BX", "london WC2H 7", "london WC2H ", "london WC"};
+ for (auto const & query : kQueries)
+ {
+ TRules rules{ExactMatch(countryId, building1)};
+ TEST(ResultsMatch(query, rules), (query));
+ }
+ }
+}
+
+UNIT_CLASS_TEST(ProcessorTest, TestCategories)
+{
+ string const countryName = "Wonderland";
+
+ TestCity sanFrancisco(m2::PointD(0, 0), "San Francisco", "en", 100 /* rank */);
+
+ TestPOI noname(m2::PointD(0, 0), "", "en");
+ noname.SetTypes({{"amenity", "atm"}});
+
+ TestPOI named(m2::PointD(0.0001, 0.0001), "ATM", "en");
+ named.SetTypes({{"amenity", "atm"}});
+
+ TestPOI busStop(m2::PointD(0.00005, 0.0005), "ATM Bus Stop", "en");
+ busStop.SetTypes({{"highway", "bus_stop"}});
+
+ TestPOI cafe(m2::PointD(0.0001, 0.0001), "Cafe", "en");
+ cafe.SetTypes({{"amenity", "cafe"}, {"internet_access", "wlan"}});
+
+ TestPOI toi(m2::PointD(0.0001, 0.0001), "", "en");
+ toi.SetTypes({{"amenity", "toilets"}});
+
+ BuildWorld([&](TestMwmBuilder & builder)
+ {
+ builder.Add(sanFrancisco);
+ });
+ auto wonderlandId = BuildCountry(countryName, [&](TestMwmBuilder & builder)
+ {
+ builder.Add(busStop);
+ builder.Add(cafe);
+ builder.Add(named);
+ builder.Add(noname);
+ builder.Add(toi);
+ });
+
+ SetViewport(m2::RectD(m2::PointD(-0.5, -0.5), m2::PointD(0.5, 0.5)));
+
+ {
+ TRules const rules = {ExactMatch(wonderlandId, noname), ExactMatch(wonderlandId, named),
+ ExactMatch(wonderlandId, busStop)};
+
+ auto request = MakeRequest("atm");
+ TEST(MatchResults(rules, request->Results()), ());
+ for (auto const & result : request->Results())
+ {
+ Index::FeaturesLoaderGuard loader(m_engine, wonderlandId);
+ FeatureType ft;
+ loader.GetFeatureByIndex(result.GetFeatureID().m_index, ft);
+
+ auto const & info = result.GetRankingInfo();
+
+ if (busStop.Matches(ft))
+ {
+ TEST(!info.m_pureCats, (result));
+ TEST(info.m_falseCats, (result));
+ }
+ else
+ {
+ TEST(info.m_pureCats, (result));
+ TEST(!info.m_falseCats, (result));
+ }
+ }
+ }
+
+ {
+ TRules const rules = {ExactMatch(wonderlandId, noname), ExactMatch(wonderlandId, named)};
+
+ auto request = MakeRequest("#atm");
+
+ TEST(MatchResults(rules, request->Results()), ());
+ for (auto const & result : request->Results())
+ {
+ auto const & info = result.GetRankingInfo();
+
+ // Token with a hashtag should not participate in name-score
+ // calculations.
+ TEST_EQUAL(NAME_SCORE_ZERO, info.m_nameScore, (result));
+ }
+ }
+
+ // Tests that inexistent hashtagged categories do not crash.
+ TEST(ResultsMatch("#void-", TRules{}), ());
+
+ TEST(ResultsMatch("wifi", {ExactMatch(wonderlandId, cafe)}), ());
+ TEST(ResultsMatch("toilet", {ExactMatch(wonderlandId, toi)}), ());
+}
+} // namespace
+} // namespace search