Repo created
This commit is contained in:
parent
4af19165ec
commit
68073add76
12458 changed files with 12350765 additions and 2 deletions
24
libs/search/search_integration_tests/CMakeLists.txt
Normal file
24
libs/search/search_integration_tests/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
project(search_integration_tests)
|
||||
|
||||
set(SRC
|
||||
downloader_search_test.cpp
|
||||
generate_tests.cpp
|
||||
postcode_points_tests.cpp
|
||||
pre_ranker_test.cpp
|
||||
processor_test.cpp
|
||||
ranker_test.cpp
|
||||
search_edited_features_test.cpp
|
||||
smoke_test.cpp
|
||||
tracer_tests.cpp
|
||||
utils_test.cpp
|
||||
)
|
||||
|
||||
omim_add_test(${PROJECT_NAME} ${SRC})
|
||||
|
||||
target_link_libraries(${PROJECT_NAME}
|
||||
generator_tests_support
|
||||
search_tests_support
|
||||
platform_tests_support
|
||||
generator
|
||||
search
|
||||
)
|
||||
258
libs/search/search_integration_tests/downloader_search_test.cpp
Normal file
258
libs/search/search_integration_tests/downloader_search_test.cpp
Normal file
|
|
@ -0,0 +1,258 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "generator/generator_tests_support/test_feature.hpp"
|
||||
|
||||
#include "search/downloader_search_callback.hpp"
|
||||
#include "search/mode.hpp"
|
||||
#include "search/result.hpp"
|
||||
#include "search/search_tests_support/helpers.hpp"
|
||||
#include "search/search_tests_support/test_results_matching.hpp"
|
||||
#include "search/search_tests_support/test_search_request.hpp"
|
||||
|
||||
#include "storage/downloader_queue_universal.hpp"
|
||||
#include "storage/downloader_search_params.hpp"
|
||||
#include "storage/map_files_downloader.hpp"
|
||||
#include "storage/queued_country.hpp"
|
||||
#include "storage/storage.hpp"
|
||||
#include "storage/storage_defines.hpp"
|
||||
|
||||
#include "platform/downloader_defines.hpp"
|
||||
|
||||
#include "geometry/rect2d.hpp"
|
||||
|
||||
#include "base/logging.hpp"
|
||||
#include "base/macros.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace generator::tests_support;
|
||||
using namespace search::tests_support;
|
||||
using namespace std;
|
||||
|
||||
class DataSource;
|
||||
|
||||
namespace search
|
||||
{
|
||||
namespace
|
||||
{
|
||||
string const kCountriesTxt = R"({
|
||||
"id": "Countries",
|
||||
"v": )" + strings::to_string(0 /* version */) +
|
||||
R"(,
|
||||
"g": [
|
||||
{
|
||||
"id": "Flatland",
|
||||
"g": [
|
||||
{
|
||||
"id": "Square One",
|
||||
"s": 123,
|
||||
"old": [
|
||||
"Flatland"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "Square Two",
|
||||
"s": 456,
|
||||
"old": [
|
||||
"Flatland"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "Wonderland",
|
||||
"g": [
|
||||
{
|
||||
"id": "Shortpondville",
|
||||
"s": 789,
|
||||
"old": [
|
||||
"Wonderland"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "Longpondville",
|
||||
"s": 100,
|
||||
"old": [
|
||||
"Wonderland"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]})";
|
||||
|
||||
class TestMapFilesDownloader : public storage::MapFilesDownloader
|
||||
{
|
||||
public:
|
||||
// MapFilesDownloader overrides:
|
||||
void Remove(storage::CountryId const &) override {}
|
||||
void Clear() override {}
|
||||
|
||||
storage::QueueInterface const & GetQueue() const override { return m_queue; }
|
||||
|
||||
private:
|
||||
void GetMetaConfig(MetaConfigCallback const &) override {}
|
||||
void Download(storage::QueuedCountry &&) override {}
|
||||
|
||||
storage::Queue m_queue;
|
||||
};
|
||||
|
||||
class TestDelegate : public DownloaderSearchCallback::Delegate
|
||||
{
|
||||
public:
|
||||
// DownloaderSearchCallback::Delegate overrides:
|
||||
void RunUITask(function<void()> fn) override { fn(); }
|
||||
};
|
||||
|
||||
class DownloaderSearchRequest
|
||||
: public TestSearchRequest
|
||||
, public TestDelegate
|
||||
{
|
||||
public:
|
||||
DownloaderSearchRequest(DataSource & dataSource, TestSearchEngine & engine, string const & query)
|
||||
: TestSearchRequest(engine, MakeSearchParams(query))
|
||||
, m_storage(kCountriesTxt, make_unique<TestMapFilesDownloader>())
|
||||
, m_downloaderCallback(static_cast<DownloaderSearchCallback::Delegate &>(*this), dataSource,
|
||||
m_engine.GetCountryInfoGetter(), m_storage, MakeDownloaderParams(query))
|
||||
{
|
||||
SetCustomOnResults(bind(&DownloaderSearchRequest::OnResultsDownloader, this, placeholders::_1));
|
||||
}
|
||||
|
||||
void OnResultsDownloader(search::Results const & results)
|
||||
{
|
||||
m_downloaderCallback(results);
|
||||
OnResults(results);
|
||||
}
|
||||
|
||||
vector<storage::DownloaderSearchResult> const & GetResults() const { return m_downloaderResults; }
|
||||
|
||||
private:
|
||||
search::SearchParams MakeSearchParams(string const & query)
|
||||
{
|
||||
search::SearchParams p;
|
||||
p.m_query = query;
|
||||
p.m_inputLocale = "en";
|
||||
p.m_viewport = m2::RectD(0, 0, 1, 1);
|
||||
p.m_mode = search::Mode::Downloader;
|
||||
p.m_suggestsEnabled = false;
|
||||
return p;
|
||||
}
|
||||
|
||||
storage::DownloaderSearchParams MakeDownloaderParams(string const & query)
|
||||
{
|
||||
storage::DownloaderSearchParams p;
|
||||
p.m_query = query;
|
||||
p.m_inputLocale = "en";
|
||||
p.m_onResults = [this](storage::DownloaderSearchResults const & r)
|
||||
{
|
||||
CHECK(!m_endMarker, ());
|
||||
|
||||
auto const & results = r.m_results;
|
||||
CHECK_GREATER_OR_EQUAL(results.size(), m_downloaderResults.size(), ());
|
||||
CHECK(equal(m_downloaderResults.begin(), m_downloaderResults.end(), results.begin()), ());
|
||||
|
||||
m_downloaderResults = r.m_results;
|
||||
if (r.m_endMarker)
|
||||
m_endMarker = true;
|
||||
};
|
||||
return p;
|
||||
}
|
||||
|
||||
vector<storage::DownloaderSearchResult> m_downloaderResults;
|
||||
bool m_endMarker = false;
|
||||
|
||||
storage::Storage m_storage;
|
||||
|
||||
DownloaderSearchCallback m_downloaderCallback;
|
||||
};
|
||||
|
||||
class DownloaderSearchTest : public SearchTest
|
||||
{
|
||||
public:
|
||||
void AddRegion(string const & countryName, string const & regionName, m2::PointD const & p1, m2::PointD const & p2)
|
||||
{
|
||||
TestPOI cornerPost1(p1, regionName + " corner post 1", "en");
|
||||
TestPOI cornerPost2(p2, regionName + " corner post 2", "en");
|
||||
TestCity capital((p1 + p2) * 0.5, regionName + " capital", "en", 0 /* rank */);
|
||||
TestCountry country(p1 * 0.3 + p2 * 0.7, countryName, "en");
|
||||
BuildCountry(regionName, [&](TestMwmBuilder & builder)
|
||||
{
|
||||
builder.Add(cornerPost1);
|
||||
builder.Add(cornerPost2);
|
||||
builder.Add(capital);
|
||||
if (!countryName.empty())
|
||||
{
|
||||
// Add the country feature to one region only.
|
||||
builder.Add(country);
|
||||
m_worldCountries.push_back(country);
|
||||
}
|
||||
});
|
||||
m_worldCities.push_back(capital);
|
||||
}
|
||||
|
||||
void BuildWorld()
|
||||
{
|
||||
SearchTest::BuildWorld([&](TestMwmBuilder & builder)
|
||||
{
|
||||
for (auto const & ft : m_worldCountries)
|
||||
builder.Add(ft);
|
||||
for (auto const & ft : m_worldCities)
|
||||
builder.Add(ft);
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
vector<TestCountry> m_worldCountries;
|
||||
vector<TestCity> m_worldCities;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void TestResults(vector<T> received, vector<T> expected)
|
||||
{
|
||||
sort(received.begin(), received.end());
|
||||
sort(expected.begin(), expected.end());
|
||||
TEST_EQUAL(expected, received, ());
|
||||
}
|
||||
|
||||
UNIT_CLASS_TEST(DownloaderSearchTest, Smoke)
|
||||
{
|
||||
AddRegion("Flatland", "Squareland One", m2::PointD(0.0, 0.0), m2::PointD(1.0, 1.0));
|
||||
AddRegion("", "Squareland Two", m2::PointD(1.0, 1.0), m2::PointD(3.0, 3.0));
|
||||
AddRegion("Wonderland", "Shortpondland", m2::PointD(-1.0, -1.0), m2::PointD(0.0, 0.0));
|
||||
AddRegion("", "Longpondland", m2::PointD(-3.0, -3.0), m2::PointD(-1.0, -1.0));
|
||||
BuildWorld();
|
||||
|
||||
{
|
||||
DownloaderSearchRequest request(m_dataSource, m_engine, "squareland one");
|
||||
request.Run();
|
||||
|
||||
TestResults(request.GetResults(), {storage::DownloaderSearchResult("Squareland One", "Squareland One capital")});
|
||||
}
|
||||
|
||||
{
|
||||
DownloaderSearchRequest request(m_dataSource, m_engine, "shortpondland");
|
||||
request.Run();
|
||||
|
||||
TestResults(request.GetResults(), {storage::DownloaderSearchResult("Shortpondland", "Shortpondland capital")});
|
||||
}
|
||||
|
||||
{
|
||||
DownloaderSearchRequest request(m_dataSource, m_engine, "flatland");
|
||||
request.Run();
|
||||
|
||||
TestResults(request.GetResults(), {storage::DownloaderSearchResult("Flatland", "Flatland")});
|
||||
}
|
||||
|
||||
{
|
||||
DownloaderSearchRequest request(m_dataSource, m_engine, "squareland");
|
||||
request.Run();
|
||||
|
||||
TestResults(request.GetResults(), {storage::DownloaderSearchResult("Squareland One", "Squareland One capital"),
|
||||
storage::DownloaderSearchResult("Squareland Two", "Squareland Two capital")});
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
} // namespace search
|
||||
91
libs/search/search_integration_tests/generate_tests.cpp
Normal file
91
libs/search/search_integration_tests/generate_tests.cpp
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "generator/generator_tests_support/test_mwm_builder.hpp"
|
||||
#include "generator/generator_tests_support/test_with_classificator.hpp"
|
||||
|
||||
#include "generator/feature_builder.hpp"
|
||||
#include "generator/osm2type.hpp"
|
||||
#include "generator/osm_element.hpp"
|
||||
|
||||
#include "indexer/classificator.hpp"
|
||||
#include "indexer/data_source.hpp"
|
||||
#include "indexer/feature.hpp"
|
||||
#include "indexer/feature_data.hpp"
|
||||
|
||||
#include "platform/local_country_file.hpp"
|
||||
|
||||
#include "base/stl_helpers.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
using namespace feature;
|
||||
using namespace generator::tests_support;
|
||||
using namespace std;
|
||||
|
||||
namespace
|
||||
{
|
||||
class GenerateTest : public TestWithClassificator
|
||||
{
|
||||
public:
|
||||
void MakeFeature(TestMwmBuilder & builder, vector<pair<string, string>> const & tags, m2::PointD const & pt)
|
||||
{
|
||||
OsmElement e;
|
||||
for (auto const & tag : tags)
|
||||
e.AddTag(tag.first, tag.second);
|
||||
|
||||
FeatureBuilderParams params;
|
||||
ftype::GetNameAndType(&e, params);
|
||||
params.AddName("en", "xxx");
|
||||
|
||||
FeatureBuilder fb;
|
||||
fb.SetParams(params);
|
||||
fb.SetCenter(pt);
|
||||
fb.GetMetadata().Set(Metadata::FMD_TEST_ID, strings::to_string(m_lastId));
|
||||
++m_lastId;
|
||||
|
||||
TEST(builder.Add(fb), (fb));
|
||||
}
|
||||
|
||||
private:
|
||||
uint64_t m_lastId = 0;
|
||||
};
|
||||
|
||||
UNIT_CLASS_TEST(GenerateTest, GenerateDeprecatedTypes)
|
||||
{
|
||||
auto file = platform::LocalCountryFile::MakeForTesting("testCountry");
|
||||
|
||||
{
|
||||
TestMwmBuilder builder(file, DataHeader::MapType::Country);
|
||||
|
||||
// Deprecated types.
|
||||
MakeFeature(builder, {{"leisure", "dog_park"}, {"sport", "tennis"}}, {0.0, 0.0});
|
||||
MakeFeature(builder, {{"leisure", "playground"}, {"sport", "tennis"}}, {1.0, 1.0});
|
||||
}
|
||||
|
||||
FrozenDataSource dataSource;
|
||||
TEST_EQUAL(dataSource.Register(file).second, MwmSet::RegResult::Success, ());
|
||||
|
||||
// New types.
|
||||
base::StringIL arr[] = {{"leisure", "dog_park"}, {"leisure", "playground"}, {"sport", "tennis"}};
|
||||
|
||||
Classificator const & cl = classif();
|
||||
set<uint32_t> types;
|
||||
for (auto const & s : arr)
|
||||
types.insert(cl.GetTypeByPath(s));
|
||||
|
||||
int count = 0;
|
||||
auto const fn = [&](FeatureType & ft)
|
||||
{
|
||||
++count;
|
||||
ft.ForEachType([&](uint32_t t) { TEST(types.count(t) > 0, (cl.GetReadableObjectName(t))); });
|
||||
};
|
||||
dataSource.ForEachInScale(fn, scales::GetUpperScale());
|
||||
|
||||
TEST_EQUAL(count, 2, ());
|
||||
|
||||
file.DeleteFromDisk(MapFileType::Map);
|
||||
}
|
||||
} // namespace
|
||||
253
libs/search/search_integration_tests/postcode_points_tests.cpp
Normal file
253
libs/search/search_integration_tests/postcode_points_tests.cpp
Normal file
|
|
@ -0,0 +1,253 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "search/postcode_points.hpp"
|
||||
#include "search/search_tests_support/helpers.hpp"
|
||||
|
||||
#include "generator/generator_tests_support/test_mwm_builder.hpp"
|
||||
|
||||
#include "storage/country_info_getter.hpp"
|
||||
|
||||
#include "indexer/search_string_utils.hpp"
|
||||
|
||||
#include "platform/platform.hpp"
|
||||
#include "platform/platform_tests_support/scoped_file.hpp"
|
||||
|
||||
#include "coding/point_coding.hpp"
|
||||
|
||||
#include "base/file_name_utils.hpp"
|
||||
|
||||
namespace postcode_points_tests
|
||||
{
|
||||
using namespace generator::tests_support;
|
||||
using namespace platform::tests_support;
|
||||
using namespace search::tests_support;
|
||||
using namespace search;
|
||||
using namespace std;
|
||||
|
||||
class PostcodePointsTest : public SearchTest
|
||||
{};
|
||||
|
||||
UNIT_CLASS_TEST(PostcodePointsTest, SmokeUK)
|
||||
{
|
||||
string const countryName = "United Kingdom";
|
||||
|
||||
Platform & platform = GetPlatform();
|
||||
auto const & writableDir = platform.WritableDir();
|
||||
string const testFile = "postcodes.csv";
|
||||
auto const postcodesRelativePath = base::JoinPath(writableDir, testFile);
|
||||
|
||||
ScopedFile const osmScopedFile(testFile,
|
||||
"header\n"
|
||||
"aa11 0bb, 1.0, 1.0\n"
|
||||
"aa11 1bb, 2.0, 2.0\n"
|
||||
"aa11 2bb, 3.0, 3.0\n");
|
||||
|
||||
auto infoGetter = std::make_shared<storage::CountryInfoGetterForTesting>();
|
||||
infoGetter->AddCountry(
|
||||
storage::CountryDef(countryName, m2::RectD(mercator::FromLatLon(0.99, 0.99), mercator::FromLatLon(3.01, 3.01))));
|
||||
|
||||
auto const id = BuildCountry(countryName, [&](TestMwmBuilder & builder)
|
||||
{ builder.SetPostcodesData(postcodesRelativePath, indexer::PostcodePointsDatasetType::UK, infoGetter); });
|
||||
|
||||
auto handle = m_dataSource.GetMwmHandleById(id);
|
||||
auto value = handle.GetValue();
|
||||
CHECK(value, ());
|
||||
TEST(value->m_cont.IsExist(POSTCODE_POINTS_FILE_TAG), ());
|
||||
|
||||
PostcodePoints p(*value);
|
||||
{
|
||||
vector<m2::PointD> points;
|
||||
p.Get(NormalizeAndSimplifyString("aa11 0bb"), points);
|
||||
TEST_EQUAL(points.size(), 1, ());
|
||||
TEST(AlmostEqualAbs(points[0], mercator::FromLatLon(1.0, 1.0), kMwmPointAccuracy), ());
|
||||
}
|
||||
{
|
||||
vector<m2::PointD> points;
|
||||
p.Get(NormalizeAndSimplifyString("aa11 1bb"), points);
|
||||
TEST_EQUAL(points.size(), 1, ());
|
||||
TEST(AlmostEqualAbs(points[0], mercator::FromLatLon(2.0, 2.0), kMwmPointAccuracy), ());
|
||||
}
|
||||
{
|
||||
vector<m2::PointD> points;
|
||||
p.Get(NormalizeAndSimplifyString("aa11 2bb"), points);
|
||||
TEST_EQUAL(points.size(), 1, ());
|
||||
TEST(AlmostEqualAbs(points[0], mercator::FromLatLon(3.0, 3.0), kMwmPointAccuracy), ());
|
||||
}
|
||||
{
|
||||
vector<m2::PointD> points;
|
||||
p.Get(NormalizeAndSimplifyString("aa11"), points);
|
||||
TEST_EQUAL(points.size(), 3, ());
|
||||
sort(points.begin(), points.end());
|
||||
TEST(AlmostEqualAbs(points[0], mercator::FromLatLon(1.0, 1.0), kMwmPointAccuracy), ());
|
||||
TEST(AlmostEqualAbs(points[1], mercator::FromLatLon(2.0, 2.0), kMwmPointAccuracy), ());
|
||||
TEST(AlmostEqualAbs(points[2], mercator::FromLatLon(3.0, 3.0), kMwmPointAccuracy), ());
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_CLASS_TEST(PostcodePointsTest, SmokeUS)
|
||||
{
|
||||
string const countryName = "United States of America";
|
||||
|
||||
Platform & platform = GetPlatform();
|
||||
auto const & writableDir = platform.WritableDir();
|
||||
string const testFile = "postcodes.csv";
|
||||
auto const postcodesRelativePath = base::JoinPath(writableDir, testFile);
|
||||
|
||||
ScopedFile const osmScopedFile(
|
||||
testFile,
|
||||
"header\n"
|
||||
R"("00601","18.18027","-66.75266","Adjuntas","PR","Puerto Rico","TRUE","","16834","100.9","72001","Adjuntas","{""72001"": 98.74, ""72141"": 1.26}","Adjuntas|Utuado","72001|72141","FALSE","FALSE","America/Puerto_Rico")");
|
||||
|
||||
auto infoGetter = std::make_shared<storage::CountryInfoGetterForTesting>();
|
||||
infoGetter->AddCountry(
|
||||
storage::CountryDef(countryName, m2::RectD(mercator::FromLatLon(0, -180), mercator::FromLatLon(90, 0))));
|
||||
|
||||
auto const id = BuildCountry(countryName, [&](TestMwmBuilder & builder)
|
||||
{ builder.SetPostcodesData(postcodesRelativePath, indexer::PostcodePointsDatasetType::UK, infoGetter); });
|
||||
|
||||
auto handle = m_dataSource.GetMwmHandleById(id);
|
||||
auto value = handle.GetValue();
|
||||
CHECK(value, ());
|
||||
TEST(value->m_cont.IsExist(POSTCODE_POINTS_FILE_TAG), ());
|
||||
|
||||
PostcodePoints p(*value);
|
||||
{
|
||||
vector<m2::PointD> points;
|
||||
p.Get(NormalizeAndSimplifyString("00601"), points);
|
||||
TEST_EQUAL(points.size(), 1, ());
|
||||
TEST(AlmostEqualAbs(points[0], mercator::FromLatLon(18.18027, -66.75266), kMwmPointAccuracy), ());
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_CLASS_TEST(PostcodePointsTest, SearchPostcode)
|
||||
{
|
||||
string const countryName = "Wonderland";
|
||||
|
||||
Platform & platform = GetPlatform();
|
||||
auto const & writableDir = platform.WritableDir();
|
||||
string const testFile = "postcodes.csv";
|
||||
auto const postcodesRelativePath = base::JoinPath(writableDir, testFile);
|
||||
|
||||
// Use the same latitude for easier center calculation.
|
||||
ScopedFile const osmScopedFile(testFile,
|
||||
"header\n"
|
||||
"BA6 7JP, 5.0, 4.0\n"
|
||||
"BA6 8JP, 5.0, 6.0\n");
|
||||
|
||||
auto infoGetter = std::make_shared<storage::CountryInfoGetterForTesting>();
|
||||
infoGetter->AddCountry(
|
||||
storage::CountryDef(countryName, m2::RectD(mercator::FromLatLon(3.0, 3.0), mercator::FromLatLon(7.0, 7.0))));
|
||||
|
||||
auto const id = BuildCountry(countryName, [&](TestMwmBuilder & builder)
|
||||
{ builder.SetPostcodesData(postcodesRelativePath, indexer::PostcodePointsDatasetType::UK, infoGetter); });
|
||||
|
||||
auto test = [&](string const & query, m2::PointD const & expected)
|
||||
{
|
||||
auto request = MakeRequest(query);
|
||||
auto const & results = request->Results();
|
||||
TEST_EQUAL(results.size(), 1, ());
|
||||
|
||||
auto const & result = results[0];
|
||||
TEST_EQUAL(result.GetResultType(), Result::Type::Postcode, ());
|
||||
TEST(result.HasPoint(), ());
|
||||
|
||||
auto const actual = result.GetFeatureCenter();
|
||||
TEST(AlmostEqualAbs(expected, actual, kMwmPointAccuracy), ());
|
||||
};
|
||||
|
||||
test("BA6 7JP", mercator::FromLatLon(5.0, 4.0));
|
||||
test("BA6 7JP ", mercator::FromLatLon(5.0, 4.0));
|
||||
test("BA6 8JP", mercator::FromLatLon(5.0, 6.0));
|
||||
test("BA6 8JP ", mercator::FromLatLon(5.0, 6.0));
|
||||
// Search should return center of all inward codes for outward query.
|
||||
test("BA6", mercator::FromLatLon(5.0, 5.0));
|
||||
test("BA6 ", mercator::FromLatLon(5.0, 5.0));
|
||||
}
|
||||
|
||||
UNIT_CLASS_TEST(PostcodePointsTest, SearchStreetWithPostcode)
|
||||
{
|
||||
string const countryName = "Wonderland";
|
||||
|
||||
Platform & platform = GetPlatform();
|
||||
auto const & writableDir = platform.WritableDir();
|
||||
string const testFile = "postcodes.csv";
|
||||
auto const postcodesRelativePath = base::JoinPath(writableDir, testFile);
|
||||
|
||||
ScopedFile const osmScopedFile(testFile,
|
||||
"header\n"
|
||||
"AA5 6KL, 4.0, 4.0\n"
|
||||
"BB7 8MN, 6.0, 6.0\n"
|
||||
"XX6 7KL, 4.0, 6.0\n"
|
||||
"YY8 9MN, 6.0, 4.0\n"
|
||||
// Some dummy postcodes to make postcode radius approximation not too big.
|
||||
"CC1 0AA, 5.0, 5.0\n"
|
||||
"CC1 0AB, 5.0, 5.0\n"
|
||||
"CC1 0AC, 5.0, 5.0\n"
|
||||
"CC1 0AD, 5.0, 5.0\n"
|
||||
"CC1 0AE, 5.0, 5.0\n"
|
||||
"CC1 0AF, 5.0, 5.0\n"
|
||||
"CC1 0AG, 5.0, 5.0\n"
|
||||
"CC1 0AH, 5.0, 5.0\n"
|
||||
"CC1 0AI, 5.0, 5.0\n"
|
||||
"CC1 0AJ, 5.0, 5.0\n"
|
||||
"CC1 0AK, 5.0, 5.0\n"
|
||||
"CC1 0AL, 5.0, 5.0\n"
|
||||
"CC1 0AM, 5.0, 5.0\n"
|
||||
"CC1 0AN, 5.0, 5.0\n"
|
||||
"CC1 0AO, 5.0, 5.0\n"
|
||||
"CC1 0AP, 5.0, 5.0\n"
|
||||
"CC1 0AQ, 5.0, 5.0\n"
|
||||
"CC1 0AR, 5.0, 5.0\n"
|
||||
"CC1 0AS, 5.0, 5.0\n"
|
||||
"CC1 0AT, 5.0, 5.0\n");
|
||||
|
||||
auto const rect = m2::RectD(mercator::FromLatLon(3.99, 3.99), mercator::FromLatLon(6.01, 6.01));
|
||||
auto infoGetter = std::make_shared<storage::CountryInfoGetterForTesting>();
|
||||
infoGetter->AddCountry(storage::CountryDef(countryName, rect));
|
||||
|
||||
TestStreet streetA(vector<m2::PointD>{mercator::FromLatLon(3.99, 3.99), mercator::FromLatLon(4.01, 4.01)},
|
||||
"Garden street", "en");
|
||||
TestPOI houseA(mercator::FromLatLon(4.0, 4.0), "", "en");
|
||||
houseA.SetHouseNumber("1");
|
||||
houseA.SetStreetName(streetA.GetName("en"));
|
||||
TestStreet streetB(vector<m2::PointD>{mercator::FromLatLon(5.99, 5.99), mercator::FromLatLon(6.01, 6.01)},
|
||||
"Garden street", "en");
|
||||
TestPOI houseB(mercator::FromLatLon(6.0, 6.0), "", "en");
|
||||
houseB.SetHouseNumber("1");
|
||||
houseB.SetStreetName(streetB.GetName("en"));
|
||||
TestStreet streetX(vector<m2::PointD>{mercator::FromLatLon(3.99, 5.99), mercator::FromLatLon(4.01, 6.01)},
|
||||
"Main street", "en");
|
||||
TestStreet streetY(vector<m2::PointD>{mercator::FromLatLon(5.99, 3.99), mercator::FromLatLon(6.01, 4.01)},
|
||||
"Main street", "en");
|
||||
|
||||
auto const id = BuildCountry(countryName, [&](TestMwmBuilder & builder)
|
||||
{
|
||||
builder.SetPostcodesData(postcodesRelativePath, indexer::PostcodePointsDatasetType::UK, infoGetter);
|
||||
|
||||
builder.Add(streetA);
|
||||
builder.Add(houseA);
|
||||
builder.Add(streetB);
|
||||
builder.Add(houseB);
|
||||
builder.Add(streetX);
|
||||
builder.Add(streetY);
|
||||
});
|
||||
|
||||
auto test = [&](string const & query, TestFeature const & bestResult)
|
||||
{
|
||||
auto request = MakeRequest(query);
|
||||
auto const & results = request->Results();
|
||||
|
||||
TEST_GREATER_OR_EQUAL(results.size(), 1, ("Unexpected number of results."));
|
||||
TEST(ResultsMatch({results[0]}, {ExactMatch(id, bestResult)}), ());
|
||||
TEST(results[0].GetRankingInfo().m_allTokensUsed, ());
|
||||
for (size_t i = 1; i < results.size(); ++i)
|
||||
TEST(!results[i].GetRankingInfo().m_allTokensUsed, ());
|
||||
};
|
||||
SetViewport(rect);
|
||||
test("Garden street 1 AA5 6KL ", houseA);
|
||||
test("Garden street 1 BB7 8MN ", houseB);
|
||||
test("Main street XX6 7KL ", streetX);
|
||||
test("Main street YY8 9MN ", streetY);
|
||||
}
|
||||
|
||||
} // namespace postcode_points_tests
|
||||
171
libs/search/search_integration_tests/pre_ranker_test.cpp
Normal file
171
libs/search/search_integration_tests/pre_ranker_test.cpp
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
#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"
|
||||
#include "search/pre_ranker.hpp"
|
||||
#include "search/ranker.hpp"
|
||||
#include "search/search_tests_support/helpers.hpp"
|
||||
#include "search/search_tests_support/test_search_engine.hpp"
|
||||
#include "search/suggest.hpp"
|
||||
|
||||
#include "indexer/categories_holder.hpp"
|
||||
#include "indexer/feature_algo.hpp"
|
||||
#include "indexer/features_vector.hpp"
|
||||
#include "indexer/mwm_set.hpp"
|
||||
#include "indexer/scales.hpp"
|
||||
|
||||
#include "generator/generator_tests_support/test_feature.hpp"
|
||||
#include "generator/generator_tests_support/test_mwm_builder.hpp"
|
||||
|
||||
#include "geometry/mercator.hpp"
|
||||
|
||||
#include "platform/country_defines.hpp"
|
||||
#include "platform/local_country_file.hpp"
|
||||
|
||||
#include "base/assert.hpp"
|
||||
#include "base/cancellable.hpp"
|
||||
#include "base/math.hpp"
|
||||
#include "base/stl_helpers.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
|
||||
namespace pre_ranker_test
|
||||
{
|
||||
using namespace generator::tests_support;
|
||||
using namespace search;
|
||||
using namespace std;
|
||||
|
||||
class TestRanker : public Ranker
|
||||
{
|
||||
public:
|
||||
TestRanker(DataSource & dataSource, storage::CountryInfoGetter & infoGetter,
|
||||
CitiesBoundariesTable const & boundariesTable, KeywordLangMatcher & keywordsScorer, Emitter & emitter,
|
||||
vector<Suggest> const & suggests, VillagesCache & villagesCache, base::Cancellable const & cancellable,
|
||||
size_t limit, vector<PreRankerResult> & results)
|
||||
: Ranker(dataSource, boundariesTable, infoGetter, keywordsScorer, emitter, GetDefaultCategories(), suggests,
|
||||
villagesCache, cancellable)
|
||||
, m_results(results)
|
||||
{
|
||||
Ranker::Params rankerParams;
|
||||
Geocoder::Params geocoderParams;
|
||||
rankerParams.m_limit = limit;
|
||||
Init(rankerParams, geocoderParams);
|
||||
}
|
||||
|
||||
inline bool Finished() const { return m_finished; }
|
||||
|
||||
// Ranker overrides:
|
||||
void AddPreRankerResults(vector<PreRankerResult> && preRankerResults) override
|
||||
{
|
||||
CHECK(!Finished(), ());
|
||||
std::move(preRankerResults.begin(), preRankerResults.end(), back_inserter(m_results));
|
||||
preRankerResults.clear();
|
||||
}
|
||||
|
||||
void UpdateResults(bool lastUpdate) override
|
||||
{
|
||||
CHECK(!Finished(), ());
|
||||
if (lastUpdate)
|
||||
m_finished = true;
|
||||
}
|
||||
|
||||
private:
|
||||
vector<PreRankerResult> & m_results;
|
||||
bool m_finished = false;
|
||||
};
|
||||
|
||||
class PreRankerTest : public search::tests_support::SearchTest
|
||||
{
|
||||
public:
|
||||
vector<Suggest> m_suggests;
|
||||
base::Cancellable m_cancellable;
|
||||
};
|
||||
|
||||
UNIT_CLASS_TEST(PreRankerTest, Smoke)
|
||||
{
|
||||
// Tests that PreRanker correctly computes distances to pivot when
|
||||
// number of results is larger than batch size, and that PreRanker
|
||||
// emits results nearest to the pivot.
|
||||
|
||||
m2::PointD const kPivot(0, 0);
|
||||
m2::RectD const kViewport(-5, -5, 5, 5);
|
||||
|
||||
vector<TestPOI> pois;
|
||||
for (int x = -5; x <= 5; ++x)
|
||||
{
|
||||
for (int y = -5; y <= 5; ++y)
|
||||
{
|
||||
pois.emplace_back(m2::PointD(x, y), "cafe", "en");
|
||||
pois.back().SetTypes({{"amenity", "cafe"}});
|
||||
}
|
||||
}
|
||||
|
||||
size_t const batchSize = pois.size() / 2;
|
||||
|
||||
auto mwmId = BuildCountry("Cafeland", [&](TestMwmBuilder & builder)
|
||||
{
|
||||
for (auto const & poi : pois)
|
||||
builder.Add(poi);
|
||||
});
|
||||
|
||||
vector<PreRankerResult> results;
|
||||
Emitter emitter;
|
||||
CitiesBoundariesTable boundariesTable(m_dataSource);
|
||||
VillagesCache villagesCache(m_cancellable);
|
||||
KeywordLangMatcher keywordsScorer(0 /* maxLanguageTiers */);
|
||||
|
||||
TestRanker ranker(m_dataSource, m_engine.GetCountryInfoGetter(), boundariesTable, keywordsScorer, emitter, m_suggests,
|
||||
villagesCache, m_cancellable, pois.size(), results);
|
||||
|
||||
PreRanker preRanker(m_dataSource, ranker);
|
||||
PreRanker::Params params;
|
||||
params.m_viewport = kViewport;
|
||||
params.m_accuratePivotCenter = kPivot;
|
||||
params.m_scale = scales::GetUpperScale();
|
||||
params.m_everywhereBatchSize = batchSize;
|
||||
params.m_limit = pois.size();
|
||||
params.m_viewportSearch = false;
|
||||
preRanker.Init(params);
|
||||
|
||||
vector<double> distances(pois.size());
|
||||
vector<bool> emit(pois.size());
|
||||
|
||||
FeaturesVectorTest fv(mwmId.GetInfo()->GetLocalFile().GetPath(MapFileType::Map));
|
||||
fv.GetVector().ForEach([&](FeatureType & ft, uint32_t index)
|
||||
{
|
||||
FeatureID id(mwmId, index);
|
||||
ResultTracer::Provenance provenance;
|
||||
preRanker.Emplace(id, PreRankingInfo(Model::TYPE_SUBPOI, TokenRange(0, 1)), provenance);
|
||||
|
||||
TEST_LESS(index, pois.size(), ());
|
||||
distances[index] = mercator::DistanceOnEarth(feature::GetCenter(ft), kPivot);
|
||||
emit[index] = true;
|
||||
});
|
||||
|
||||
preRanker.UpdateResults(true /* lastUpdate */);
|
||||
|
||||
TEST(all_of(emit.begin(), emit.end(), base::IdFunctor()), (emit));
|
||||
TEST(ranker.Finished(), ());
|
||||
|
||||
size_t const count = results.size();
|
||||
// Depends on std::shuffle, but lets keep 6% threshold.
|
||||
TEST(count > batchSize * 1.06 && count < batchSize * 1.94, (count));
|
||||
|
||||
vector<bool> checked(pois.size());
|
||||
for (size_t i = 0; i < count; ++i)
|
||||
{
|
||||
size_t const index = results[i].GetId().m_index;
|
||||
TEST_LESS(index, pois.size(), ());
|
||||
|
||||
TEST(!checked[index], (index));
|
||||
TEST(AlmostEqualAbs(distances[index], results[i].GetDistance(), 1.0 /* 1 meter epsilon */),
|
||||
(distances[index], results[i].GetDistance()));
|
||||
checked[index] = true;
|
||||
}
|
||||
}
|
||||
} // namespace pre_ranker_test
|
||||
3653
libs/search/search_integration_tests/processor_test.cpp
Normal file
3653
libs/search/search_integration_tests/processor_test.cpp
Normal file
File diff suppressed because it is too large
Load diff
115
libs/search/search_integration_tests/ranker_test.cpp
Normal file
115
libs/search/search_integration_tests/ranker_test.cpp
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "search/search_tests_support/helpers.hpp"
|
||||
#include "search/search_tests_support/test_results_matching.hpp"
|
||||
|
||||
#include "generator/generator_tests_support/test_feature.hpp"
|
||||
#include "generator/generator_tests_support/test_mwm_builder.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace ranker_test
|
||||
{
|
||||
using namespace generator::tests_support;
|
||||
using namespace search::tests_support;
|
||||
using namespace search;
|
||||
using namespace std;
|
||||
|
||||
class RankerTest : public SearchTest
|
||||
{};
|
||||
|
||||
UNIT_CLASS_TEST(RankerTest, ErrorsInStreets)
|
||||
{
|
||||
TestStreet mazurova(vector<m2::PointD>{m2::PointD(-0.001, -0.001), m2::PointD(0, 0), m2::PointD(0.001, 0.001)},
|
||||
"Мазурова", "ru");
|
||||
TestBuilding mazurova14(m2::PointD(-0.001, -0.001), "", "14", mazurova.GetName("ru"), "ru");
|
||||
|
||||
TestStreet masherova(vector<m2::PointD>{m2::PointD(-0.001, 0.001), m2::PointD(0, 0), m2::PointD(0.001, -0.001)},
|
||||
"Машерова", "ru");
|
||||
TestBuilding masherova14(m2::PointD(0.001, 0.001), "", "14", masherova.GetName("ru"), "ru");
|
||||
|
||||
auto id = BuildCountry("Belarus", [&](TestMwmBuilder & builder)
|
||||
{
|
||||
builder.Add(mazurova);
|
||||
builder.Add(mazurova14);
|
||||
|
||||
builder.Add(masherova);
|
||||
builder.Add(masherova14);
|
||||
});
|
||||
|
||||
SetViewport(m2::RectD(m2::PointD(0, 0), m2::PointD(0.001, 0.001)));
|
||||
{
|
||||
auto request = MakeRequest("Мазурова 14");
|
||||
auto const & results = request->Results();
|
||||
|
||||
Rules rules = {ExactMatch(id, mazurova14), ExactMatch(id, masherova14)};
|
||||
TEST(ResultsMatch(results, rules), ());
|
||||
|
||||
TEST_EQUAL(results.size(), 2, ());
|
||||
TEST(ResultsMatch({results[0]}, {rules[0]}), ());
|
||||
TEST(ResultsMatch({results[1]}, {rules[1]}), ());
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_CLASS_TEST(RankerTest, UniteSameResults)
|
||||
{
|
||||
TestCity city({1.5, 1.5}, "Buenos Aires", "es", 100);
|
||||
|
||||
m2::PointD org(1.0, 1.0);
|
||||
m2::PointD eps(1.0E-5, 1.0E-5);
|
||||
|
||||
TestPOI bus1(org, "Terminal 1", "de");
|
||||
bus1.SetTypes({{"highway", "bus_stop"}});
|
||||
TestPOI bus2(org + eps, "Terminal 1", "de");
|
||||
bus2.SetTypes({{"highway", "bus_stop"}});
|
||||
TestPOI bus3(org + eps + eps, "Terminal 1", "de");
|
||||
bus3.SetTypes({{"highway", "bus_stop"}});
|
||||
|
||||
TestCafe cafe1({0.5, 0.5}, "И точка", "ru");
|
||||
TestCafe cafe2({0.5, 0.5}, "И точка", "ru");
|
||||
|
||||
auto const worldID = BuildWorld([&](TestMwmBuilder & builder) { builder.Add(city); });
|
||||
|
||||
auto const countryID = BuildCountry("Wonderland", [&](TestMwmBuilder & builder)
|
||||
{
|
||||
builder.Add(city);
|
||||
builder.Add(bus1);
|
||||
builder.Add(bus2);
|
||||
builder.Add(bus3);
|
||||
builder.Add(cafe1);
|
||||
builder.Add(cafe2);
|
||||
});
|
||||
|
||||
SetViewport({0, 0, 2, 2});
|
||||
{
|
||||
TEST(ResultsMatch("buenos", {ExactMatch(worldID, city)}), ());
|
||||
// Expect bus1, because it is strictly in the center of viewport. But it can be any result from bus{1-3}.
|
||||
TEST(ResultsMatch("terminal", {ExactMatch(countryID, bus1)}), ());
|
||||
TEST_EQUAL(GetResultsNumber("точка", "ru"), 1, ());
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_CLASS_TEST(RankerTest, PreferCountry)
|
||||
{
|
||||
std::string const name = "Wonderland";
|
||||
TestCountry wonderland(m2::PointD(9.0, 9.0), name, "en"); // ~1400 km from (0, 0)
|
||||
TestPOI cafe(m2::PointD(0.0, 0.0), name, "en");
|
||||
cafe.SetTypes({{"amenity", "cafe"}});
|
||||
|
||||
auto const worldID = BuildWorld([&](TestMwmBuilder & builder) { builder.Add(wonderland); });
|
||||
|
||||
auto const countryID = BuildCountry(name, [&](TestMwmBuilder & builder) { builder.Add(cafe); });
|
||||
|
||||
SetViewport({0.0, 0.0, 1.0, 1.0});
|
||||
{
|
||||
// Country which exactly matches the query should be preferred even if cafe is much closer to viewport center.
|
||||
Rules const rules = {ExactMatch(worldID, wonderland), ExactMatch(countryID, cafe)};
|
||||
TEST(OrderedResultsMatch(name, rules), ());
|
||||
}
|
||||
{
|
||||
/// @todo Fuzzy match should rank nearest cafe first?
|
||||
Rules const rules = {ExactMatch(worldID, wonderland), ExactMatch(countryID, cafe)};
|
||||
TEST(OrderedResultsMatch("Wanderland", rules), ());
|
||||
}
|
||||
}
|
||||
} // namespace ranker_test
|
||||
|
|
@ -0,0 +1,201 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "search/search_tests_support/helpers.hpp"
|
||||
#include "search/search_tests_support/test_results_matching.hpp"
|
||||
|
||||
#include "generator/generator_tests_support/test_feature.hpp"
|
||||
|
||||
#include "indexer/editable_map_object.hpp"
|
||||
|
||||
#include "geometry/point2d.hpp"
|
||||
|
||||
#include "coding/string_utf8_multilang.hpp"
|
||||
|
||||
namespace search_edited_features_test
|
||||
{
|
||||
using namespace generator::tests_support;
|
||||
using namespace search::tests_support;
|
||||
using namespace search;
|
||||
using namespace std;
|
||||
|
||||
using SearchEditedFeaturesTest = SearchTest;
|
||||
|
||||
UNIT_CLASS_TEST(SearchEditedFeaturesTest, Smoke)
|
||||
{
|
||||
TestCity city(m2::PointD(0, 0), "Quahog", "default", 100 /* rank */);
|
||||
TestCafe 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 */);
|
||||
|
||||
{
|
||||
Rules const rules = {ExactMatch(id, cafe)};
|
||||
|
||||
TEST(ResultsMatch("Eat ", rules), ());
|
||||
TEST(ResultsMatch("cafe Bar", rules), ());
|
||||
TEST(ResultsMatch("Drunken", Rules{}), ());
|
||||
|
||||
EditFeature(cafeId, [](osm::EditableMapObject & emo)
|
||||
{ emo.SetName("The Drunken Clam", StringUtf8Multilang::kEnglishCode); });
|
||||
|
||||
TEST(ResultsMatch("Eat ", rules), ());
|
||||
TEST(ResultsMatch("cafe Bar", rules), ());
|
||||
TEST(ResultsMatch("Drunken", rules), ());
|
||||
}
|
||||
|
||||
{
|
||||
Rules const rules = {ExactMatch(id, cafe)};
|
||||
|
||||
TEST(ResultsMatch("Wifi", Rules{}), ());
|
||||
|
||||
EditFeature(cafeId, [](osm::EditableMapObject & emo) { emo.SetInternet(feature::Internet::Wlan); });
|
||||
|
||||
TEST(ResultsMatch("Wifi", rules), ());
|
||||
TEST(ResultsMatch("wifi bar quahog", rules), ());
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_CLASS_TEST(SearchEditedFeaturesTest, NonamePoi)
|
||||
{
|
||||
TestCafe nonameCafe(m2::PointD(0, 0), "", "default");
|
||||
|
||||
auto const id = BuildCountry("Wonderland", [&](TestMwmBuilder & builder) { builder.Add(nonameCafe); });
|
||||
|
||||
FeatureID cafeId(id, 0 /* index */);
|
||||
|
||||
{
|
||||
Rules const rules = {ExactMatch(id, nonameCafe)};
|
||||
|
||||
TEST(ResultsMatch("Eat ", rules), ());
|
||||
|
||||
EditFeature(cafeId, [](osm::EditableMapObject & emo) { emo.SetInternet(feature::Internet::Wlan); });
|
||||
|
||||
TEST(ResultsMatch("Eat ", rules), ());
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_CLASS_TEST(SearchEditedFeaturesTest, SearchInViewport)
|
||||
{
|
||||
TestCity city(m2::PointD(0, 0), "Canterlot", "default", 100 /* rank */);
|
||||
TestPOI bakery0(m2::PointD(0, 0), "French Bakery 0", "default");
|
||||
TestPOI cornerPost(m2::PointD(100, 100), "Corner Post", "default");
|
||||
auto & editor = osm::Editor::Instance();
|
||||
|
||||
BuildWorld([&](TestMwmBuilder & builder) { builder.Add(city); });
|
||||
|
||||
auto const countryId = BuildCountry("Equestria", [&](TestMwmBuilder & builder)
|
||||
{
|
||||
builder.Add(bakery0);
|
||||
builder.Add(cornerPost);
|
||||
});
|
||||
|
||||
auto const tmp1 = TestPOI::AddWithEditor(editor, countryId, "French Bakery1", {1.0, 1.0});
|
||||
TestPOI const & bakery1 = tmp1.first;
|
||||
FeatureID const & id1 = tmp1.second;
|
||||
auto const tmp2 = TestPOI::AddWithEditor(editor, countryId, "French Bakery2", {2.0, 2.0});
|
||||
TestPOI const & bakery2 = tmp2.first;
|
||||
FeatureID const & id2 = tmp2.second;
|
||||
auto const tmp3 = TestPOI::AddWithEditor(editor, countryId, "French Bakery3", {3.0, 3.0});
|
||||
TestPOI const & bakery3 = tmp3.first;
|
||||
FeatureID const & id3 = tmp3.second;
|
||||
UNUSED_VALUE(id2);
|
||||
|
||||
SetViewport({-1.0, -1.0, 4.0, 4.0});
|
||||
{
|
||||
Rules const rules = {ExactMatch(countryId, bakery0), ExactMatch(countryId, bakery1), ExactMatch(countryId, bakery2),
|
||||
ExactMatch(countryId, bakery3)};
|
||||
|
||||
TEST(ResultsMatch("french bakery", rules, "en", Mode::Viewport), ());
|
||||
}
|
||||
|
||||
SetViewport({-2.0, -2.0, -1.0, -1.0});
|
||||
{
|
||||
TEST(ResultsMatch("french bakery", {}, "en", Mode::Viewport), ());
|
||||
}
|
||||
|
||||
SetViewport({-1.0, -1.0, 1.5, 1.5});
|
||||
{
|
||||
Rules const rules = {ExactMatch(countryId, bakery0), ExactMatch(countryId, bakery1)};
|
||||
TEST(ResultsMatch("french bakery", rules, "en", Mode::Viewport), ());
|
||||
}
|
||||
|
||||
SetViewport({1.5, 1.5, 4.0, 4.0});
|
||||
{
|
||||
Rules const rules = {ExactMatch(countryId, bakery2), ExactMatch(countryId, bakery3)};
|
||||
TEST(ResultsMatch("french bakery", rules, "en", Mode::Viewport), ());
|
||||
}
|
||||
|
||||
editor.DeleteFeature(id1);
|
||||
editor.DeleteFeature(id3);
|
||||
|
||||
SetViewport({-1.0, -1.0, 4.0, 4.0});
|
||||
{
|
||||
Rules const rules = {ExactMatch(countryId, bakery0), ExactMatch(countryId, bakery2)};
|
||||
TEST(ResultsMatch("french bakery", rules, "en", Mode::Viewport), ());
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_CLASS_TEST(SearchEditedFeaturesTest, ViewportFilter)
|
||||
{
|
||||
TestCafe restaurant(m2::PointD(0.0, 0.0), "Pushkin", "default");
|
||||
// Need this POI for mwm bounding box.
|
||||
TestPOI dummy(m2::PointD(1.0, 1.0), "dummy", "default");
|
||||
auto & editor = osm::Editor::Instance();
|
||||
|
||||
auto const countryId = BuildCountry("Wounderland", [&](TestMwmBuilder & builder)
|
||||
{
|
||||
builder.Add(restaurant);
|
||||
builder.Add(dummy);
|
||||
});
|
||||
|
||||
auto const tmp = TestPOI::AddWithEditor(editor, countryId, "Pushkin cafe", {0.01, 0.01});
|
||||
TestPOI const & cafe = tmp.first;
|
||||
|
||||
SearchParams params;
|
||||
params.m_query = "pushkin";
|
||||
params.m_inputLocale = "en";
|
||||
params.m_viewport = {-1.0, -1.0, 1.0, 1.0};
|
||||
params.m_mode = Mode::Viewport;
|
||||
|
||||
// Test center for created feature loaded and filter for viewport works.
|
||||
{
|
||||
params.m_minDistanceOnMapBetweenResults = {0.02, 0.02};
|
||||
|
||||
// Min distance on map between results is 0.02, distance between results is 0.01.
|
||||
// The second result must be filtered out.
|
||||
Rules const rulesViewport = {ExactMatch(countryId, restaurant)};
|
||||
|
||||
TestSearchRequest request(m_engine, params);
|
||||
request.Run();
|
||||
TEST(ResultsMatch(request.Results(), rulesViewport), ());
|
||||
}
|
||||
|
||||
{
|
||||
params.m_minDistanceOnMapBetweenResults = {0.005, 0.005};
|
||||
|
||||
// Min distance on map between results is 0.005, distance between results is 0.01.
|
||||
// Filter should keep both results.
|
||||
Rules const rulesViewport = {ExactMatch(countryId, restaurant), ExactMatch(countryId, cafe)};
|
||||
|
||||
TestSearchRequest request(m_engine, params);
|
||||
request.Run();
|
||||
TEST(ResultsMatch(request.Results(), rulesViewport), ());
|
||||
}
|
||||
|
||||
SetViewport({-1.0, -1.0, 1.0, 1.0});
|
||||
{
|
||||
params.m_mode = Mode::Everywhere;
|
||||
params.m_minDistanceOnMapBetweenResults = {0.02, 0.02};
|
||||
|
||||
// No viewport filter for everywhere search mode.
|
||||
Rules const rulesEverywhere = {ExactMatch(countryId, restaurant), ExactMatch(countryId, cafe)};
|
||||
|
||||
TestSearchRequest request(m_engine, params);
|
||||
request.Run();
|
||||
TEST(ResultsMatch(request.Results(), rulesEverywhere), ());
|
||||
}
|
||||
}
|
||||
} // namespace search_edited_features_test
|
||||
401
libs/search/search_integration_tests/smoke_test.cpp
Normal file
401
libs/search/search_integration_tests/smoke_test.cpp
Normal file
|
|
@ -0,0 +1,401 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "search/search_tests_support/helpers.hpp"
|
||||
#include "search/search_tests_support/test_results_matching.hpp"
|
||||
#include "search/search_tests_support/test_search_request.hpp"
|
||||
|
||||
#include "generator/feature_builder.hpp"
|
||||
#include "generator/generator_tests_support/test_feature.hpp"
|
||||
#include "generator/generator_tests_support/test_mwm_builder.hpp"
|
||||
|
||||
#include "search/types_skipper.hpp"
|
||||
|
||||
#include "indexer/classificator.hpp"
|
||||
#include "indexer/feature_meta.hpp"
|
||||
#include "indexer/feature_visibility.hpp"
|
||||
|
||||
#include "geometry/point2d.hpp"
|
||||
#include "geometry/rect2d.hpp"
|
||||
|
||||
#include "base/string_utils.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace smoke_test
|
||||
{
|
||||
using namespace feature;
|
||||
using namespace generator::tests_support;
|
||||
using namespace search;
|
||||
using namespace search::tests_support;
|
||||
using namespace std;
|
||||
|
||||
class IncorrectCountry : public TestCountry
|
||||
{
|
||||
public:
|
||||
IncorrectCountry(m2::PointD const & center, string const & name, string const & lang)
|
||||
: TestCountry(center, name, lang)
|
||||
{}
|
||||
|
||||
// TestFeature overrides:
|
||||
void Serialize(FeatureBuilder & fb) const override
|
||||
{
|
||||
fb.GetMetadata().Set(Metadata::FMD_TEST_ID, strings::to_string(m_id));
|
||||
fb.SetCenter(m_center);
|
||||
|
||||
m_names.ForEach([&](int8_t langCode, string_view name)
|
||||
{
|
||||
if (!name.empty())
|
||||
fb.SetName(langCode, name);
|
||||
});
|
||||
|
||||
auto const & classificator = classif();
|
||||
fb.AddType(classificator.GetTypeByPath({"place", "country"}));
|
||||
}
|
||||
};
|
||||
|
||||
class SmokeTest : public SearchTest
|
||||
{};
|
||||
|
||||
class AlcoShop : public TestPOI
|
||||
{
|
||||
public:
|
||||
AlcoShop(m2::PointD const & center, string const & name, string const & lang) : TestPOI(center, name, lang)
|
||||
{
|
||||
SetTypes({{"shop", "alcohol"}});
|
||||
}
|
||||
};
|
||||
|
||||
class SubwayStation : public TestPOI
|
||||
{
|
||||
public:
|
||||
SubwayStation(m2::PointD const & center, string const & name, string const & lang) : TestPOI(center, name, lang)
|
||||
{
|
||||
SetTypes({{"railway", "station", "subway"}});
|
||||
}
|
||||
};
|
||||
|
||||
class SubwayStationMoscow : public TestPOI
|
||||
{
|
||||
public:
|
||||
SubwayStationMoscow(m2::PointD const & center, string const & name, string const & lang) : TestPOI(center, name, lang)
|
||||
{
|
||||
SetTypes({{"railway", "station", "subway", "moscow"}});
|
||||
}
|
||||
};
|
||||
|
||||
UNIT_CLASS_TEST(SmokeTest, Smoke)
|
||||
{
|
||||
char const kCountryName[] = "BuzzTown";
|
||||
|
||||
AlcoShop wineShop(m2::PointD(0, 0), "Wine shop", "en");
|
||||
AlcoShop tequilaShop(m2::PointD(1, 0), "Tequila shop", "en");
|
||||
AlcoShop brandyShop(m2::PointD(0, 1), "Brandy shop", "en");
|
||||
AlcoShop vodkaShop(m2::PointD(1, 1), "Russian vodka shop", "en");
|
||||
|
||||
auto id = BuildMwm(kCountryName, DataHeader::MapType::Country, [&](TestMwmBuilder & builder)
|
||||
{
|
||||
builder.Add(wineShop);
|
||||
builder.Add(tequilaShop);
|
||||
builder.Add(brandyShop);
|
||||
builder.Add(vodkaShop);
|
||||
});
|
||||
|
||||
TEST_EQUAL(4, CountFeatures(m2::RectD(m2::PointD(0, 0), m2::PointD(1, 1))), ());
|
||||
TEST_EQUAL(2, CountFeatures(m2::RectD(m2::PointD(-0.5, -0.5), m2::PointD(0.5, 1.5))), ());
|
||||
|
||||
SetViewport(m2::RectD(m2::PointD(0, 0), m2::PointD(100, 100)));
|
||||
{
|
||||
Rules rules = {ExactMatch(id, wineShop)};
|
||||
TEST(ResultsMatch("wine ", rules), ());
|
||||
}
|
||||
|
||||
Rules const allRule = {ExactMatch(id, wineShop), ExactMatch(id, tequilaShop), ExactMatch(id, brandyShop),
|
||||
ExactMatch(id, vodkaShop)};
|
||||
|
||||
TEST(ResultsMatch("shop ", allRule), ());
|
||||
TEST(ResultsMatch("alcohol ", allRule), ());
|
||||
TEST(CategoryMatch("алкоголь", allRule, "ru"), ());
|
||||
}
|
||||
|
||||
UNIT_CLASS_TEST(SmokeTest, DeepCategoryTest)
|
||||
{
|
||||
char const kCountryName[] = "Wonderland";
|
||||
|
||||
SubwayStation redStation(m2::PointD(0, 0), "red", "en");
|
||||
SubwayStationMoscow blueStation(m2::PointD(1, 1), "blue", "en");
|
||||
|
||||
auto id = BuildMwm(kCountryName, DataHeader::MapType::Country, [&](TestMwmBuilder & builder)
|
||||
{
|
||||
builder.Add(redStation);
|
||||
builder.Add(blueStation);
|
||||
});
|
||||
|
||||
SetViewport(m2::RectD(m2::PointD(0, 0), m2::PointD(1, 1)));
|
||||
{
|
||||
Rules rules = {ExactMatch(id, redStation), ExactMatch(id, blueStation)};
|
||||
TEST(ResultsMatch("Subway ", rules), ());
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_CLASS_TEST(SmokeTest, TypesSkipperTest)
|
||||
{
|
||||
TypesSkipper skipper;
|
||||
|
||||
auto const & cl = classif();
|
||||
|
||||
{
|
||||
base::StringIL const arr[] = {{"entrance"}};
|
||||
TypesHolder types;
|
||||
for (auto const & path : arr)
|
||||
types.Add(cl.GetTypeByPath(path));
|
||||
|
||||
TEST(!skipper.SkipAlways(types), ());
|
||||
TEST(!skipper.SkipSpecialNames(types, "ETH"), ());
|
||||
TEST(skipper.SkipSpecialNames(types, "2"), ());
|
||||
}
|
||||
|
||||
{
|
||||
base::StringIL const arr[] = {{"building"}};
|
||||
TypesHolder types;
|
||||
for (auto const & path : arr)
|
||||
types.Add(cl.GetTypeByPath(path));
|
||||
|
||||
TEST(!skipper.SkipAlways(types), ());
|
||||
TEST(!skipper.SkipSpecialNames(types, "3"), ());
|
||||
skipper.SkipEmptyNameTypes(types);
|
||||
TEST(types.Empty(), ());
|
||||
}
|
||||
|
||||
{
|
||||
base::StringIL const arr[] = {{"building"}, {"entrance"}};
|
||||
TypesHolder types;
|
||||
for (auto const & path : arr)
|
||||
types.Add(cl.GetTypeByPath(path));
|
||||
|
||||
TEST(!skipper.SkipAlways(types), ());
|
||||
TEST(!skipper.SkipSpecialNames(types, "4"), ());
|
||||
skipper.SkipEmptyNameTypes(types);
|
||||
TEST_EQUAL(types.Size(), 1, ());
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_CLASS_TEST(SmokeTest, CategoriesTest)
|
||||
{
|
||||
// Checks all types in categories.txt for their searchability,
|
||||
// which also depends on point drawability and presence of a name.
|
||||
|
||||
auto const & cl = classif();
|
||||
|
||||
/// @todo Should rewrite test
|
||||
base::StringIL const arrNotPoint[] = {
|
||||
// Area types without suitable point drawing rules.
|
||||
{"area:highway", "steps"},
|
||||
{"landuse", "basin"},
|
||||
{"natural", "glacier"},
|
||||
|
||||
// Linear types.
|
||||
{"waterway", "canal"},
|
||||
{"waterway", "river"},
|
||||
{"waterway", "stream"},
|
||||
{"highway", "footway"},
|
||||
{"highway", "cycleway"},
|
||||
{"highway", "living_street"},
|
||||
{"highway", "motorway"},
|
||||
{"highway", "motorway_link"},
|
||||
{"highway", "path"},
|
||||
{"highway", "pedestrian"},
|
||||
{"highway", "primary"},
|
||||
{"highway", "primary_link"},
|
||||
{"highway", "raceway"},
|
||||
{"highway", "residential"},
|
||||
{"highway", "road"},
|
||||
{"highway", "secondary"},
|
||||
{"highway", "secondary_link"},
|
||||
{"highway", "service"},
|
||||
{"highway", "steps"},
|
||||
{"highway", "tertiary"},
|
||||
{"highway", "tertiary_link"},
|
||||
{"highway", "track"},
|
||||
{"highway", "traffic_signals"},
|
||||
{"highway", "trunk"},
|
||||
{"highway", "trunk_link"},
|
||||
{"highway", "unclassified"},
|
||||
{"historic", "citywalls"},
|
||||
{"piste:type", "downhill"},
|
||||
{"piste:type", "nordic"},
|
||||
};
|
||||
set<uint32_t> notPointTypes;
|
||||
for (auto const & tags : arrNotPoint)
|
||||
notPointTypes.insert(cl.GetTypeByPath(tags));
|
||||
|
||||
// No point drawing rules for country scale range.
|
||||
base::StringIL const arrInvisible[] = {
|
||||
{"place", "continent"},
|
||||
{"place", "county"},
|
||||
{"place", "region"},
|
||||
};
|
||||
set<uint32_t> invisibleTypes;
|
||||
for (auto const & tags : arrInvisible)
|
||||
invisibleTypes.insert(cl.GetTypeByPath(tags));
|
||||
|
||||
// Not indexed types for Features with empty names.
|
||||
base::StringIL const arrNoEmptyNames[] = {
|
||||
{"area:highway"},
|
||||
{"building"},
|
||||
{"highway", "motorway_junction"},
|
||||
{"landuse"},
|
||||
{"man_made", "chimney"},
|
||||
{"man_made", "flagpole"},
|
||||
{"man_made", "mast"},
|
||||
{"man_made", "water_tower"},
|
||||
{"natural"},
|
||||
{"office"},
|
||||
{"place"},
|
||||
{"waterway"},
|
||||
|
||||
/// @todo Controversial here.
|
||||
/// Don't have point drawing rules (a label only), hence type will be removed for an empty name Feature.
|
||||
{"building", "train_station"},
|
||||
{"leisure", "track"},
|
||||
{"natural", "beach"},
|
||||
};
|
||||
set<uint32_t> noEmptyNames;
|
||||
for (auto const & tags : arrNoEmptyNames)
|
||||
noEmptyNames.insert(cl.GetTypeByPath(tags));
|
||||
|
||||
ftypes::TwoLevelPOIChecker isPoi;
|
||||
auto const isNoEmptyName = [&isPoi, &noEmptyNames](uint32_t t)
|
||||
{
|
||||
ftype::TruncValue(t, 2);
|
||||
if (noEmptyNames.count(t) > 0)
|
||||
return true;
|
||||
|
||||
if (isPoi(t))
|
||||
return false;
|
||||
|
||||
ftype::TruncValue(t, 1);
|
||||
return (noEmptyNames.count(t) > 0);
|
||||
};
|
||||
|
||||
auto const & holder = GetDefaultCategories();
|
||||
|
||||
uint32_t const cafeType = cl.GetTypeByPath({"amenity", "cafe"});
|
||||
|
||||
auto testCategory = [&](uint32_t type, CategoriesHolder::Category const &)
|
||||
{
|
||||
if (notPointTypes.count(type) > 0)
|
||||
return;
|
||||
|
||||
size_t resultIdx = 2;
|
||||
if (invisibleTypes.count(type) == 0)
|
||||
{
|
||||
if (isNoEmptyName(type))
|
||||
resultIdx = 1;
|
||||
else
|
||||
resultIdx = 0;
|
||||
}
|
||||
|
||||
string const countryName = "Wonderland";
|
||||
|
||||
TestPOI withName({1.0, 1.0}, "The Name", "en");
|
||||
if (IsCategoryNondrawableType(type))
|
||||
withName.SetTypes({type, cafeType});
|
||||
else
|
||||
withName.SetTypes({type});
|
||||
|
||||
TestPOI withoutName({2.0, 2.0}, "", "");
|
||||
if (IsCategoryNondrawableType(type))
|
||||
withoutName.SetTypes({type, cafeType});
|
||||
else
|
||||
withoutName.SetTypes({type});
|
||||
|
||||
auto id = BuildMwm(countryName, DataHeader::MapType::Country, [&](TestMwmBuilder & builder)
|
||||
{
|
||||
builder.AddSafe(withName);
|
||||
builder.AddSafe(withoutName);
|
||||
});
|
||||
|
||||
Rules const rules[] = {{ExactMatch(id, withName), ExactMatch(id, withoutName)}, {ExactMatch(id, withName)}, {}};
|
||||
auto const query = holder.GetReadableFeatureType(type, CategoriesHolder::kEnglishCode);
|
||||
|
||||
// If you have "Unsatisfied rules" error, consider:
|
||||
// - adding type to POIs here TwoLevelPOIChecker or
|
||||
// - review TypesSkipper or
|
||||
// - adding type to |arrNoEmptyNames| or |arrInvisible|
|
||||
TEST(CategoryMatch(query, rules[resultIdx]), (query, cl.GetReadableObjectName(type)));
|
||||
|
||||
DeregisterMap(countryName);
|
||||
};
|
||||
|
||||
holder.ForEachTypeAndCategory(testCategory);
|
||||
}
|
||||
|
||||
UNIT_CLASS_TEST(SmokeTest, NotPrefixFreeNames)
|
||||
{
|
||||
char const kCountryName[] = "ATown";
|
||||
|
||||
auto id = BuildMwm(kCountryName, DataHeader::MapType::Country, [&](TestMwmBuilder & builder)
|
||||
{
|
||||
builder.Add(TestPOI(m2::PointD(0, 0), "a", "en"));
|
||||
builder.Add(TestPOI(m2::PointD(0, 1), "aa", "en"));
|
||||
builder.Add(TestPOI(m2::PointD(1, 1), "aa", "en"));
|
||||
builder.Add(TestPOI(m2::PointD(1, 0), "aaa", "en"));
|
||||
builder.Add(TestPOI(m2::PointD(2, 0), "aaa", "en"));
|
||||
builder.Add(TestPOI(m2::PointD(2, 1), "aaa", "en"));
|
||||
});
|
||||
|
||||
TEST_EQUAL(6, CountFeatures(m2::RectD(m2::PointD(0, 0), m2::PointD(2, 2))), ());
|
||||
|
||||
m2::RectD const viewport(m2::PointD(0, 0), m2::PointD(100, 100));
|
||||
{
|
||||
TestSearchRequest request(m_engine, "a ", "en", Mode::Viewport, viewport);
|
||||
request.Run();
|
||||
TEST_EQUAL(1, request.Results().size(), ());
|
||||
}
|
||||
{
|
||||
TestSearchRequest request(m_engine, "aa ", "en", Mode::Viewport, viewport);
|
||||
request.Run();
|
||||
TEST_EQUAL(2, request.Results().size(), ());
|
||||
}
|
||||
{
|
||||
TestSearchRequest request(m_engine, "aaa ", "en", search::Mode::Viewport, viewport);
|
||||
request.Run();
|
||||
TEST_EQUAL(3, request.Results().size(), ());
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_CLASS_TEST(SmokeTest, NoDefaultNameTest)
|
||||
{
|
||||
char const kCountryName[] = "Wonderland";
|
||||
|
||||
IncorrectCountry wonderland(m2::PointD(0, 0), kCountryName, "en");
|
||||
auto worldId = BuildWorld([&](TestMwmBuilder & builder) { builder.Add(wonderland); });
|
||||
|
||||
SetViewport(m2::RectD(m2::PointD(-0.5, -0.5), m2::PointD(0.5, 0.5)));
|
||||
TEST(ResultsMatch("Wonderland", {ExactMatch(worldId, wonderland)}), ());
|
||||
}
|
||||
|
||||
UNIT_CLASS_TEST(SmokeTest, PoiWithAddress)
|
||||
{
|
||||
char const kCountryName[] = "Wonderland";
|
||||
TestStreet mainStreet({m2::PointD(0.0, 0.0), m2::PointD(1.0, 1.0), m2::PointD(2.0, 2.0)}, "Main Street", "en");
|
||||
TestCafe cafe(m2::PointD(1.0, 1.0), "Starbucks", "en");
|
||||
cafe.SetStreetName(mainStreet.GetName("en"));
|
||||
cafe.SetHouseNumber("27");
|
||||
|
||||
auto id = BuildMwm(kCountryName, DataHeader::MapType::Country, [&](TestMwmBuilder & builder)
|
||||
{
|
||||
builder.Add(mainStreet);
|
||||
builder.Add(cafe);
|
||||
});
|
||||
|
||||
SetViewport(m2::RectD(m2::PointD(0.0, 0.0), m2::PointD(2.0, 2.0)));
|
||||
{
|
||||
Rules rules = {ExactMatch(id, cafe)};
|
||||
TEST(ResultsMatch("Starbucks ", rules), ());
|
||||
TEST(ResultsMatch("Main street 27 ", rules), ());
|
||||
TEST(ResultsMatch("Main street 27 Starbucks ", rules), ());
|
||||
TEST(ResultsMatch("Starbucks Main street 27 ", rules), ());
|
||||
}
|
||||
}
|
||||
} // namespace smoke_test
|
||||
88
libs/search/search_integration_tests/tracer_tests.cpp
Normal file
88
libs/search/search_integration_tests/tracer_tests.cpp
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "search/geocoder_context.hpp"
|
||||
#include "search/search_tests_support/helpers.hpp"
|
||||
#include "search/search_tests_support/test_results_matching.hpp"
|
||||
#include "search/tracer.hpp"
|
||||
|
||||
#include "generator/generator_tests_support/test_feature.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
using namespace generator::tests_support;
|
||||
using namespace search::tests_support;
|
||||
using namespace search;
|
||||
using namespace std;
|
||||
|
||||
namespace
|
||||
{
|
||||
class TracerTest : public SearchTest
|
||||
{};
|
||||
|
||||
UNIT_CLASS_TEST(TracerTest, Smoke)
|
||||
{
|
||||
using TokenType = BaseContext::TokenType;
|
||||
|
||||
TestCity moscow(m2::PointD(0, 0), "Moscow", "en", 100 /* rank */);
|
||||
TestCafe regularCafe(m2::PointD(0, 0));
|
||||
TestCafe moscowCafe(m2::PointD(0, 0), "Moscow", "en");
|
||||
TestStreet tverskaya(vector<m2::PointD>{m2::PointD(0, 0), m2::PointD(0, 1)}, "Tverskaya street", "en");
|
||||
|
||||
BuildWorld([&](TestMwmBuilder & builder) { builder.Add(moscow); });
|
||||
|
||||
auto const id = BuildCountry("Wonderland", [&](TestMwmBuilder & builder)
|
||||
{
|
||||
builder.Add(regularCafe);
|
||||
builder.Add(moscowCafe);
|
||||
builder.Add(tverskaya);
|
||||
});
|
||||
|
||||
SearchParams params;
|
||||
params.m_inputLocale = "en";
|
||||
params.m_viewport = m2::RectD(-1, -1, 1, 1);
|
||||
params.m_mode = Mode::Everywhere;
|
||||
|
||||
{
|
||||
params.m_query = "moscow cafe";
|
||||
auto tracer = make_shared<Tracer>();
|
||||
params.m_tracer = tracer;
|
||||
|
||||
TestSearchRequest request(m_engine, params);
|
||||
request.Run();
|
||||
Rules rules = {ExactMatch(id, regularCafe), ExactMatch(id, moscowCafe)};
|
||||
TEST(ResultsMatch(request.Results(), rules), ());
|
||||
|
||||
auto const actual = tracer->GetUniqueParses();
|
||||
|
||||
vector<Tracer::Parse> const expected{
|
||||
Tracer::Parse{{{TokenType::TOKEN_TYPE_SUBPOI, TokenRange(0, 2)}}, false /* category */},
|
||||
Tracer::Parse{
|
||||
{{TokenType::TOKEN_TYPE_CITY, TokenRange(0, 1)}, {TokenType::TOKEN_TYPE_SUBPOI, TokenRange(1, 2)}},
|
||||
true /* category */}};
|
||||
|
||||
TEST_EQUAL(expected, actual, ());
|
||||
}
|
||||
|
||||
{
|
||||
params.m_query = "moscow tverskaya 1 or 2";
|
||||
auto tracer = make_shared<Tracer>();
|
||||
params.m_tracer = tracer;
|
||||
|
||||
TestSearchRequest request(m_engine, params);
|
||||
request.Run();
|
||||
TEST(ResultsMatch(request.Results(), {ExactMatch(id, tverskaya)}), ());
|
||||
|
||||
auto const actual = tracer->GetUniqueParses();
|
||||
// Unrecognized tokens are not included into the parses.
|
||||
vector<Tracer::Parse> const expected{
|
||||
Tracer::Parse{{{TokenType::TOKEN_TYPE_STREET, TokenRange(1, 2)}}, false /* category */},
|
||||
Tracer::Parse{
|
||||
{{TokenType::TOKEN_TYPE_CITY, TokenRange(0, 1)}, {TokenType::TOKEN_TYPE_STREET, TokenRange(1, 2)}},
|
||||
false /* category */},
|
||||
};
|
||||
|
||||
TEST_EQUAL(expected, actual, ());
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
118
libs/search/search_integration_tests/utils_test.cpp
Normal file
118
libs/search/search_integration_tests/utils_test.cpp
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "search/search_tests_support/helpers.hpp"
|
||||
|
||||
#include "generator/generator_tests_support/test_feature.hpp"
|
||||
#include "generator/generator_tests_support/test_mwm_builder.hpp"
|
||||
|
||||
#include "search/utils.hpp"
|
||||
|
||||
#include "indexer/categories_holder.hpp"
|
||||
#include "indexer/feature_decl.hpp"
|
||||
|
||||
#include "geometry/point2d.hpp"
|
||||
#include "geometry/rect2d.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace search_utils_test
|
||||
{
|
||||
using namespace generator::tests_support;
|
||||
using namespace search;
|
||||
using namespace std;
|
||||
|
||||
class SearchUtilsTest : public search::tests_support::SearchTest
|
||||
{
|
||||
public:
|
||||
DataSource const & GetDataSource() const { return m_dataSource; }
|
||||
};
|
||||
|
||||
UNIT_CLASS_TEST(SearchUtilsTest, Utils)
|
||||
{
|
||||
string const kCountryName = "FoodLand";
|
||||
auto file = platform::LocalCountryFile::MakeForTesting(kCountryName);
|
||||
|
||||
TestPOI cafe(m2::PointD(0.0, 0.0), "cafe", "en");
|
||||
cafe.SetTypes({{"amenity", "cafe"}});
|
||||
|
||||
TestPOI restaurant(m2::PointD(0.0, 0.0), "restaurant", "en");
|
||||
restaurant.SetTypes({{"amenity", "restaurant"}});
|
||||
|
||||
TestPOI bar(m2::PointD(0.0, 0.0), "bar", "en");
|
||||
bar.SetTypes({{"amenity", "bar"}});
|
||||
|
||||
auto id = BuildCountry(kCountryName, [&](TestMwmBuilder & builder)
|
||||
{
|
||||
builder.Add(cafe);
|
||||
builder.Add(restaurant);
|
||||
builder.Add(bar);
|
||||
});
|
||||
|
||||
auto const & categories = GetDefaultCategories();
|
||||
auto const typesPost = GetCategoryTypes("Oficina de correos", "es", categories);
|
||||
auto const typesCafe = GetCategoryTypes("Cafe", "en", categories);
|
||||
auto const typesRestaurant = GetCategoryTypes("Restaurant", "en", categories);
|
||||
auto const typesBar = GetCategoryTypes("Bar", "en", categories);
|
||||
auto const typesFood = GetCategoryTypes("Eat", "en", categories);
|
||||
|
||||
// GetCategoryTypes must return sorted vector of types.
|
||||
TEST(is_sorted(typesPost.begin(), typesPost.end()), ());
|
||||
TEST(is_sorted(typesCafe.begin(), typesCafe.end()), ());
|
||||
TEST(is_sorted(typesRestaurant.begin(), typesRestaurant.end()), ());
|
||||
TEST(is_sorted(typesBar.begin(), typesBar.end()), ());
|
||||
TEST(is_sorted(typesFood.begin(), typesFood.end()), ());
|
||||
|
||||
for (char const * s : {"post_office", "post_box", "parcel_locker"})
|
||||
TEST(binary_search(typesPost.begin(), typesPost.end(), classif().GetTypeByPath({"amenity", s})), (s));
|
||||
|
||||
// Now "Cafe" and "Restaurant" are synonyms in categories.
|
||||
TEST_EQUAL(typesCafe, typesRestaurant, ());
|
||||
TEST_NOT_EQUAL(typesCafe, typesBar, ());
|
||||
|
||||
for (auto const t : typesCafe)
|
||||
TEST(binary_search(typesFood.begin(), typesFood.end(), t), ());
|
||||
|
||||
for (auto const t : typesBar)
|
||||
TEST(binary_search(typesFood.begin(), typesFood.end(), t), ());
|
||||
|
||||
auto const & dataSource = GetDataSource();
|
||||
auto const rect = m2::RectD(m2::PointD(-0.5, -0.5), m2::PointD(0.5, 0.5));
|
||||
|
||||
auto const testTypes = [&](vector<uint32_t> const & types, size_t expectedCount)
|
||||
{
|
||||
vector<FeatureID> features;
|
||||
ForEachOfTypesInRect(dataSource, types, rect, [&features](FeatureID const & f) { features.push_back(f); });
|
||||
TEST_EQUAL(features.size(), expectedCount, ());
|
||||
};
|
||||
|
||||
// |cafe| and |restaurant|.
|
||||
testTypes(typesCafe, 2);
|
||||
|
||||
// |cafe| and |restaurant|.
|
||||
testTypes(typesRestaurant, 2);
|
||||
|
||||
// |bar|.
|
||||
testTypes(typesBar, 1);
|
||||
|
||||
// All.
|
||||
testTypes(typesFood, 3);
|
||||
}
|
||||
|
||||
UNIT_TEST(IsCategorialRequestFuzzy)
|
||||
{
|
||||
auto const isHotelRequest = [](string const & q) { return IsCategorialRequestFuzzy(q, "hotel"); };
|
||||
|
||||
TEST(isHotelRequest("hotel"), ());
|
||||
TEST(isHotelRequest("Hotel"), ());
|
||||
TEST(isHotelRequest("motel"), ());
|
||||
TEST(isHotelRequest("отель"), ());
|
||||
TEST(isHotelRequest("гостиница"), ());
|
||||
TEST(isHotelRequest("гостиница москва"), ());
|
||||
TEST(isHotelRequest("new york hotel"), ());
|
||||
TEST(!isHotelRequest("new york where to stay"), ());
|
||||
TEST(!isHotelRequest("where to stay"), ());
|
||||
TEST(!isHotelRequest("random request"), ());
|
||||
}
|
||||
} // namespace search_utils_test
|
||||
Loading…
Add table
Add a link
Reference in a new issue