Repo created

This commit is contained in:
Fr4nz D13trich 2025-11-22 13:58:55 +01:00
parent 4af19165ec
commit 68073add76
12458 changed files with 12350765 additions and 2 deletions

View 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
)

View 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

View 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

View 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

View 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

File diff suppressed because it is too large Load diff

View 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

View file

@ -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

View 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

View 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

View 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