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,54 @@
project(indexer_tests)
set(SRC
bounds.hpp
brands_tests.cpp
categories_test.cpp
cell_coverer_test.cpp
cell_id_test.cpp
centers_table_test.cpp
checker_test.cpp
cities_boundaries_serdes_tests.cpp
classificator_tests.cpp
complex_serdes_tests.cpp
complex_serdes_utils_tests.cpp
custom_keyvalue_tests.cpp
data_source_test.cpp
drules_selector_parser_test.cpp
editable_map_object_test.cpp
feature_charge_sockets_test.cpp
feature_metadata_test.cpp
feature_names_test.cpp
feature_to_osm_tests.cpp
feature_types_test.cpp
features_offsets_table_test.cpp
features_vector_test.cpp
index_builder_test.cpp
interval_index_test.cpp
metadata_serdes_tests.cpp
mwm_set_test.cpp
postcodes_matcher_tests.cpp
rank_table_test.cpp
read_features_tests.cpp
road_shields_parser_tests.cpp
scale_index_reading_tests.cpp
search_string_utils_test.cpp
sort_and_merge_intervals_test.cpp
string_slice_tests.cpp
succinct_trie_test.cpp
test_mwm_set.hpp
test_type.cpp
tree_node_tests.cpp
trie_test.cpp
validate_and_format_contacts_test.cpp
visibility_test.cpp
wheelchair_tests.cpp
)
omim_add_test(${PROJECT_NAME} ${SRC})
target_link_libraries(${PROJECT_NAME}
generator_tests_support
platform_tests_support
indexer
)

View file

@ -0,0 +1,18 @@
#pragma once
#include "geometry/rect2d.hpp"
template <int MinX, int MinY, int MaxX, int MaxY>
struct Bounds
{
static double constexpr kMinX = MinX;
static double constexpr kMaxX = MaxX;
static double constexpr kMinY = MinY;
static double constexpr kMaxY = MaxY;
static double constexpr kRangeX = kMaxX - kMinX;
static double constexpr kRangeY = kMaxY - kMinY;
static m2::RectD FullRect() { return {MinX, MinY, MaxX, MaxY}; }
};
using OrthoBounds = Bounds<-180, -90, 180, 90>;

View file

@ -0,0 +1,89 @@
#include "testing/testing.hpp"
#include "indexer/brands_holder.hpp"
#include "coding/reader.hpp"
#include "coding/string_utf8_multilang.hpp"
#include <memory>
#include <set>
#include <string>
using namespace std;
using namespace indexer;
char const g_testBrandsTxt[] =
"brand.mcdonalds\n"
"en:McDonald's|Mc Donalds\n"
"ru:МакДональд'с|Мак Доналдс\n"
"uk:Макдональдз\n"
"\n"
"brand.subway\n"
"en:Subway\n"
"ru:Сабвэй|Сабвей";
UNIT_TEST(LoadDefaultBrands)
{
auto const & brands = GetDefaultBrands();
TEST(!brands.GetKeys().empty(), ());
}
UNIT_TEST(LoadBrands)
{
BrandsHolder const holder(make_unique<MemReader>(g_testBrandsTxt, sizeof(g_testBrandsTxt) - 1));
set<string> expectedKeys = {"mcdonalds", "subway"};
auto const keys = holder.GetKeys();
TEST_EQUAL(keys, expectedKeys, ());
using Names = set<BrandsHolder::Brand::Name>;
{
Names expectedNames;
expectedNames.emplace("McDonald's", StringUtf8Multilang::GetLangIndex("en"));
expectedNames.emplace("Mc Donalds", StringUtf8Multilang::GetLangIndex("en"));
expectedNames.emplace("МакДональд'с", StringUtf8Multilang::GetLangIndex("ru"));
expectedNames.emplace("Мак Доналдс", StringUtf8Multilang::GetLangIndex("ru"));
expectedNames.emplace("Макдональдз", StringUtf8Multilang::GetLangIndex("uk"));
Names names;
holder.ForEachNameByKey("mcdonalds", [&names](BrandsHolder::Brand::Name const & name) { names.insert(name); });
CHECK_EQUAL(names, expectedNames, ());
}
{
Names expectedNames;
expectedNames.emplace("Subway", StringUtf8Multilang::GetLangIndex("en"));
expectedNames.emplace("Сабвэй", StringUtf8Multilang::GetLangIndex("ru"));
expectedNames.emplace("Сабвей", StringUtf8Multilang::GetLangIndex("ru"));
Names names;
holder.ForEachNameByKey("subway", [&names](BrandsHolder::Brand::Name const & name) { names.insert(name); });
CHECK_EQUAL(names, expectedNames, ());
}
{
set<string> expectedNames = {"McDonald's", "Mc Donalds"};
set<string> names;
holder.ForEachNameByKeyAndLang("mcdonalds", "en", [&names](string const & name) { names.insert(name); });
CHECK_EQUAL(names, expectedNames, ());
}
{
set<string> expectedNames = {"МакДональд'с", "Мак Доналдс"};
set<string> names;
holder.ForEachNameByKeyAndLang("mcdonalds", "ru", [&names](string const & name) { names.insert(name); });
CHECK_EQUAL(names, expectedNames, ());
}
{
set<string> expectedNames = {"Макдональдз"};
set<string> names;
holder.ForEachNameByKeyAndLang("mcdonalds", "uk", [&names](string const & name) { names.insert(name); });
CHECK_EQUAL(names, expectedNames, ());
}
}

View file

@ -0,0 +1,328 @@
#include "testing/testing.hpp"
#include "indexer/categories_holder.hpp"
#include "indexer/categories_index.hpp"
#include "indexer/classificator.hpp"
#include "indexer/classificator_loader.hpp"
#include "coding/reader.hpp"
#include "coding/string_utf8_multilang.hpp"
#include "base/stl_helpers.hpp"
#include "base/string_utils.hpp"
#include <memory>
#include <vector>
using namespace indexer;
using namespace std;
char const g_testCategoriesTxt[] =
"amenity-bench\n"
"en:1bench|sit down|to sit\n"
"de:2bank|auf die strafbank schicken\n"
"zh-Hans:长凳\n"
"zh-Hant:長板凳\n"
"da:bænk\n"
"\n"
"place-village|place-hamlet\n"
"en:village\n"
"de:2dorf|4weiler";
struct Checker
{
explicit Checker(size_t & count) : m_count(count) {}
void operator()(CategoriesHolder::Category const & cat)
{
switch (m_count)
{
case 0:
{
TEST_EQUAL(cat.m_synonyms.size(), 8, ());
TEST_EQUAL(cat.m_synonyms[0].m_locale, CategoriesHolder::MapLocaleToInteger("en"), ());
TEST_EQUAL(cat.m_synonyms[0].m_name, "bench", ());
TEST_EQUAL(cat.m_synonyms[0].m_prefixLengthToSuggest, 1, ());
TEST_EQUAL(cat.m_synonyms[1].m_locale, CategoriesHolder::MapLocaleToInteger("en"), ());
TEST_EQUAL(cat.m_synonyms[1].m_name, "sit down", ());
TEST_EQUAL(cat.m_synonyms[1].m_prefixLengthToSuggest, 10, ());
TEST_EQUAL(cat.m_synonyms[2].m_locale, CategoriesHolder::MapLocaleToInteger("en"), ());
TEST_EQUAL(cat.m_synonyms[2].m_name, "to sit", ());
TEST_EQUAL(cat.m_synonyms[3].m_locale, CategoriesHolder::MapLocaleToInteger("de"), ());
TEST_EQUAL(cat.m_synonyms[3].m_name, "bank", ());
TEST_EQUAL(cat.m_synonyms[3].m_prefixLengthToSuggest, 2, ());
TEST_EQUAL(cat.m_synonyms[4].m_locale, CategoriesHolder::MapLocaleToInteger("de"), ());
TEST_EQUAL(cat.m_synonyms[4].m_name, "auf die strafbank schicken", ());
TEST_EQUAL(cat.m_synonyms[5].m_locale, CategoriesHolder::MapLocaleToInteger("zh_CN"), ());
TEST_EQUAL(cat.m_synonyms[5].m_locale, CategoriesHolder::MapLocaleToInteger("zh_rCN"), ());
TEST_EQUAL(cat.m_synonyms[5].m_locale, CategoriesHolder::MapLocaleToInteger("zh_HANS_CN"), ());
TEST_EQUAL(cat.m_synonyms[5].m_locale, CategoriesHolder::MapLocaleToInteger("zh-Hans"), ());
TEST_EQUAL(cat.m_synonyms[5].m_name, "长凳", ());
TEST_EQUAL(cat.m_synonyms[6].m_locale, CategoriesHolder::MapLocaleToInteger("zh_TW"), ());
TEST_EQUAL(cat.m_synonyms[6].m_locale, CategoriesHolder::MapLocaleToInteger("zh-MO"), ());
TEST_EQUAL(cat.m_synonyms[6].m_locale, CategoriesHolder::MapLocaleToInteger("zh-rTW"), ());
TEST_EQUAL(cat.m_synonyms[6].m_locale, CategoriesHolder::MapLocaleToInteger("zh_HANT_HK"), ());
TEST_EQUAL(cat.m_synonyms[6].m_locale, CategoriesHolder::MapLocaleToInteger("zh_HK"), ());
TEST_EQUAL(cat.m_synonyms[6].m_locale, CategoriesHolder::MapLocaleToInteger("zh-Hant"), ());
TEST_EQUAL(cat.m_synonyms[6].m_name, "長板凳", ());
TEST_EQUAL(cat.m_synonyms[7].m_locale, CategoriesHolder::MapLocaleToInteger("da"), ());
TEST_EQUAL(cat.m_synonyms[7].m_name, "bænk", ());
++m_count;
}
break;
case 1:
case 2:
{
TEST_EQUAL(cat.m_synonyms.size(), 3, ());
TEST_EQUAL(cat.m_synonyms[0].m_locale, CategoriesHolder::MapLocaleToInteger("en"), ());
TEST_EQUAL(cat.m_synonyms[0].m_name, "village", ());
TEST_EQUAL(cat.m_synonyms[1].m_locale, CategoriesHolder::MapLocaleToInteger("de"), ());
TEST_EQUAL(cat.m_synonyms[1].m_name, "dorf", ());
TEST_EQUAL(cat.m_synonyms[1].m_prefixLengthToSuggest, 2, ());
TEST_EQUAL(cat.m_synonyms[2].m_locale, CategoriesHolder::MapLocaleToInteger("de"), ());
TEST_EQUAL(cat.m_synonyms[2].m_name, "weiler", ());
TEST_EQUAL(cat.m_synonyms[2].m_prefixLengthToSuggest, 4, ());
++m_count;
}
break;
default: TEST(false, ("Too many categories"));
}
}
size_t & m_count;
};
UNIT_TEST(LoadCategories)
{
classificator::Load();
CategoriesHolder h(make_unique<MemReader>(g_testCategoriesTxt, sizeof(g_testCategoriesTxt) - 1));
size_t count = 0;
Checker f(count);
h.ForEachCategory(f);
TEST_EQUAL(count, 3, ());
}
UNIT_TEST(CategoriesHolder_Smoke)
{
auto const & mappings = CategoriesHolder::kLocaleMapping;
for (size_t i = 0; i < mappings.size(); ++i)
{
auto const & mapping = mappings[i];
TEST_EQUAL(static_cast<int8_t>(i + 1), mapping.m_code, ());
TEST_EQUAL(static_cast<int8_t>(i + 1), CategoriesHolder::MapLocaleToInteger(mapping.m_name), (mapping.m_name));
TEST_EQUAL(CategoriesHolder::MapIntegerToLocale(i + 1), mapping.m_name, ());
}
}
UNIT_TEST(CategoriesHolder_LoadDefault)
{
classificator::Load();
uint32_t counter = 0;
auto const count = [&counter](CategoriesHolder::Category const &) { ++counter; };
auto const & categoriesHolder = GetDefaultCategories();
categoriesHolder.ForEachCategory(count);
TEST_GREATER(counter, 0, ());
counter = 0;
auto const & cuisineCategoriesHolder = GetDefaultCuisineCategories();
cuisineCategoriesHolder.ForEachCategory(count);
TEST_GREATER(counter, 0, ());
}
UNIT_TEST(CategoriesHolder_ForEach)
{
char const kCategories[] =
"amenity-bar\n"
"en:abc|ddd-eee\n"
"\n"
"amenity-pub\n"
"en:ddd\n"
"\n"
"amenity-cafe\n"
"en:abc eee\n"
"\n"
"amenity-restaurant\n"
"en:ddd|eee\n"
"\n"
"";
classificator::Load();
CategoriesHolder holder(make_unique<MemReader>(kCategories, ARRAY_SIZE(kCategories) - 1));
{
uint32_t counter = 0;
holder.ForEachTypeByName(CategoriesHolder::kEnglishCode, strings::MakeUniString("abc"),
[&](uint32_t /* type */) { ++counter; });
TEST_EQUAL(counter, 2, ());
}
{
uint32_t counter = 0;
holder.ForEachTypeByName(CategoriesHolder::kEnglishCode, strings::MakeUniString("ddd"),
[&](uint32_t /* type */) { ++counter; });
TEST_EQUAL(counter, 3, ());
}
{
uint32_t counter = 0;
holder.ForEachTypeByName(CategoriesHolder::kEnglishCode, strings::MakeUniString("eee"),
[&](uint32_t /* type */) { ++counter; });
TEST_EQUAL(counter, 3, ());
}
}
UNIT_TEST(CategoriesIndex_Smoke)
{
classificator::Load();
CategoriesHolder holder(make_unique<MemReader>(g_testCategoriesTxt, sizeof(g_testCategoriesTxt) - 1));
CategoriesIndex index(holder);
uint32_t type1 = classif().GetTypeByPath({"amenity", "bench"});
uint32_t type2 = classif().GetTypeByPath({"place", "village"});
if (type1 > type2)
swap(type1, type2);
int8_t lang1 = CategoriesHolder::MapLocaleToInteger("en");
int8_t lang2 = CategoriesHolder::MapLocaleToInteger("de");
auto testTypes = [&](string const & query, vector<uint32_t> const & expected)
{
vector<uint32_t> result;
index.GetAssociatedTypes(query, result);
TEST_EQUAL(result, expected, (query));
};
index.AddCategoryByTypeAndLang(type1, lang1);
testTypes("bench", {type1});
testTypes("BENCH", {type1});
testTypes("down", {type1});
testTypes("benck", {});
testTypes("strafbank", {});
index.AddCategoryByTypeAndLang(type1, lang2);
testTypes("strafbank", {type1});
testTypes("ie strafbank sc", {type1});
testTypes("rafb", {type1});
index.AddCategoryByTypeAndLang(type2, lang1);
testTypes("i", {type1, type2});
CategoriesIndex fullIndex(holder);
fullIndex.AddCategoryByTypeAllLangs(type1);
fullIndex.AddCategoryByTypeAllLangs(type2);
vector<CategoriesHolder::Category> cats;
// The letter 'a' matches "strafbank" and "village".
// One language is not enough.
fullIndex.GetCategories("a", cats);
TEST_EQUAL(cats.size(), 2, ());
TEST_EQUAL(cats[0].m_synonyms.size(), 8, ());
TEST_EQUAL(cats[0].m_synonyms[4].m_locale, CategoriesHolder::MapLocaleToInteger("de"), ());
TEST_EQUAL(cats[0].m_synonyms[4].m_name, "auf die strafbank schicken", ());
TEST_EQUAL(cats[1].m_synonyms.size(), 3, ());
TEST_EQUAL(cats[1].m_synonyms[0].m_locale, CategoriesHolder::MapLocaleToInteger("en"), ());
TEST_EQUAL(cats[1].m_synonyms[0].m_name, "village", ());
}
UNIT_TEST(CategoriesIndex_MultipleTokens)
{
char const kCategories[] =
"shop-bakery\n"
"en:shop of buns\n"
"\n"
"shop-butcher\n"
"en:shop of meat";
classificator::Load();
CategoriesHolder holder(make_unique<MemReader>(kCategories, sizeof(kCategories) - 1));
CategoriesIndex index(holder);
index.AddAllCategoriesInAllLangs();
auto testTypes = [&](string const & query, vector<uint32_t> const & expected)
{
vector<uint32_t> result;
index.GetAssociatedTypes(query, result);
TEST_EQUAL(result, expected, (query));
};
uint32_t type1 = classif().GetTypeByPath({"shop", "bakery"});
uint32_t type2 = classif().GetTypeByPath({"shop", "butcher"});
if (type1 > type2)
swap(type1, type2);
testTypes("shop", {type1, type2});
testTypes("shop buns", {type1});
testTypes("shop meat", {type2});
}
UNIT_TEST(CategoriesIndex_Groups)
{
char const kCategories[] =
"@shop\n"
"en:shop\n"
"ru:магазин\n"
"\n"
"@meat\n"
"en:meat\n"
"\n"
"shop-bakery|@shop\n"
"en:buns\n"
"\n"
"shop-butcher|@shop|@meat\n"
"en:butcher\n"
"";
classificator::Load();
CategoriesHolder holder(make_unique<MemReader>(kCategories, sizeof(kCategories) - 1));
CategoriesIndex index(holder);
index.AddAllCategoriesInAllLangs();
auto testTypes = [&](string const & query, vector<uint32_t> const & expected)
{
vector<uint32_t> result;
index.GetAssociatedTypes(query, result);
TEST_EQUAL(result, expected, (query));
};
uint32_t type1 = classif().GetTypeByPath({"shop", "bakery"});
uint32_t type2 = classif().GetTypeByPath({"shop", "butcher"});
if (type1 > type2)
swap(type1, type2);
testTypes("buns", {type1});
testTypes("butcher", {type2});
testTypes("meat", {type2});
testTypes("shop", {type1, type2});
testTypes("магазин", {type1, type2});
testTypes("http", {});
}
#ifdef DEBUG
// A check that this data structure is not too heavy.
UNIT_TEST(CategoriesIndex_AllCategories)
{
classificator::Load();
CategoriesIndex index;
index.AddAllCategoriesInAllLangs();
// Consider deprecating this method if this bound rises as high as a million.
LOG(LINFO, ("Number of nodes in the CategoriesIndex trie:", index.GetNumTrieNodes()));
TEST_LESS(index.GetNumTrieNodes(), 900000, ());
}
// A check that this data structure is not too heavy.
UNIT_TEST(CategoriesIndex_AllCategoriesEnglishName)
{
classificator::Load();
CategoriesIndex index;
index.AddAllCategoriesInLang(CategoriesHolder::MapLocaleToInteger("en"));
TEST_LESS(index.GetNumTrieNodes(), 15000, ());
}
#endif

View file

@ -0,0 +1,66 @@
#include "testing/testing.hpp"
#include "geometry/covering_utils.hpp"
#include "indexer/cell_coverer.hpp"
#include "indexer/indexer_tests/bounds.hpp"
#include "coding/hex.hpp"
#include "base/logging.hpp"
#include <vector>
using namespace std;
// Unit test uses m2::CellId<30> for historical reasons, the actual production code uses RectId.
using CellId = m2::CellId<30>;
UNIT_TEST(CellIdToStringRecode)
{
char const kTest[] = "21032012203";
TEST_EQUAL(CellId::FromString(kTest).ToString(), kTest, ());
}
UNIT_TEST(GoldenCoverRect)
{
vector<CellId> cells;
CoverRect<OrthoBounds>({27.43, 53.83, 27.70, 53.96}, 4, RectId::DEPTH_LEVELS - 1, cells);
TEST_EQUAL(cells.size(), 4, ());
TEST_EQUAL(cells[0].ToString(), "32012211300", ());
TEST_EQUAL(cells[1].ToString(), "32012211301", ());
TEST_EQUAL(cells[2].ToString(), "32012211302", ());
TEST_EQUAL(cells[3].ToString(), "32012211303", ());
}
UNIT_TEST(ArtificialCoverRect)
{
typedef Bounds<0, 0, 16, 16> TestBounds;
vector<CellId> cells;
CoverRect<TestBounds>({5, 5, 11, 11}, 4, RectId::DEPTH_LEVELS - 1, cells);
TEST_EQUAL(cells.size(), 4, ());
TEST_EQUAL(cells[0].ToString(), "03", ());
TEST_EQUAL(cells[1].ToString(), "12", ());
TEST_EQUAL(cells[2].ToString(), "21", ());
TEST_EQUAL(cells[3].ToString(), "30", ());
}
UNIT_TEST(MaxDepthCoverSpiral)
{
using TestBounds = Bounds<0, 0, 8, 8>;
for (auto levelMax = 0; levelMax <= 2; ++levelMax)
{
auto cells = vector<m2::CellId<3>>{};
CoverSpiral<TestBounds, m2::CellId<3>>({2.1, 4.1, 2.1, 4.1}, levelMax, cells);
TEST_EQUAL(cells.size(), 1, ());
TEST_EQUAL(cells[0].Level(), levelMax, ());
}
}

View file

@ -0,0 +1,54 @@
#include "testing/testing.hpp"
#include "indexer/cell_id.hpp"
#include "indexer/indexer_tests/bounds.hpp"
#include "coding/hex.hpp"
#include <cmath>
#include <random>
#include <string>
#include <utility>
using namespace std;
typedef m2::CellId<30> CellIdT;
UNIT_TEST(ToCellId)
{
string s("2130000");
s.append(CellIdT::DEPTH_LEVELS - 1 - s.size(), '0');
TEST_EQUAL((CellIdConverter<Bounds<0, 0, 4, 4>, CellIdT>::ToCellId(1.5, 2.5).ToString()), s, ());
TEST_EQUAL(CellIdT::FromString(s), (CellIdConverter<Bounds<0, 0, 4, 4>, CellIdT>::ToCellId(1.5, 2.5)), ());
}
UNIT_TEST(CommonCell)
{
TEST_EQUAL((CellIdConverter<Bounds<0, 0, 4, 4>, CellIdT>::Cover2PointsWithCell(3.5, 2.5, 2.5, 3.5)),
CellIdT::FromString("3"), ());
TEST_EQUAL((CellIdConverter<Bounds<0, 0, 4, 4>, CellIdT>::Cover2PointsWithCell(2.25, 1.75, 2.75, 1.25)),
CellIdT::FromString("12"), ());
}
namespace
{
template <typename T1, typename T2>
bool PairsAlmostEqualULPs(pair<T1, T1> const & p1, pair<T2, T2> const & p2)
{
return fabs(p1.first - p2.first) + fabs(p1.second - p2.second) < 0.00001;
}
} // namespace
UNIT_TEST(CellId_RandomRecode)
{
mt19937 rng(0);
for (size_t i = 0; i < 1000; ++i)
{
uint32_t const x = rng() % 2000;
uint32_t const y = rng() % 1000;
m2::PointD const pt = CellIdConverter<Bounds<0, 0, 2000, 1000>, CellIdT>::FromCellId(
CellIdConverter<Bounds<0, 0, 2000, 1000>, CellIdT>::ToCellId(x, y));
TEST(fabs(pt.x - x) < 0.0002, (x, y, pt));
TEST(fabs(pt.y - y) < 0.0001, (x, y, pt));
}
}

View file

@ -0,0 +1,156 @@
#include "testing/testing.hpp"
#include "indexer/centers_table.hpp"
#include "indexer/classificator_loader.hpp"
#include "indexer/data_header.hpp"
#include "indexer/feature_algo.hpp"
#include "indexer/features_vector.hpp"
#include "platform/platform.hpp"
#include "coding/reader.hpp"
#include "coding/writer.hpp"
#include "geometry/mercator.hpp"
#include "geometry/point2d.hpp"
#include "base/file_name_utils.hpp"
#include <cstdint>
#include <string>
#include <utility>
#include <vector>
using namespace search;
using namespace std;
namespace
{
using TBuffer = vector<uint8_t>;
struct CentersTableTest
{
CentersTableTest() { classificator::Load(); }
};
UNIT_CLASS_TEST(CentersTableTest, Smoke)
{
string const kMap = base::JoinPath(GetPlatform().WritableDir(), "minsk-pass.mwm");
FeaturesVectorTest fv(kMap);
TBuffer buffer;
{
CentersTableBuilder builder;
feature::DataHeader header(kMap);
builder.SetGeometryParams(header.GetBounds());
fv.GetVector().ForEach([&](FeatureType & ft, uint32_t id) { builder.Put(id, feature::GetCenter(ft)); });
MemWriter<TBuffer> writer(buffer);
builder.Freeze(writer);
}
{
MemReader reader(buffer.data(), buffer.size());
auto table = CentersTable::LoadV1(reader);
TEST(table.get(), ());
fv.GetVector().ForEach([&](FeatureType & ft, uint32_t id)
{
m2::PointD actual;
TEST(table->Get(id, actual), ());
m2::PointD expected = feature::GetCenter(ft);
TEST_LESS_OR_EQUAL(mercator::DistanceOnEarth(actual, expected), 1.0, (id));
});
}
}
UNIT_CLASS_TEST(CentersTableTest, SmokeV0)
{
string const kMap = base::JoinPath(GetPlatform().WritableDir(), "minsk-pass.mwm");
FeaturesVectorTest fv(kMap);
feature::DataHeader header(kMap);
auto const codingParams = header.GetDefGeometryCodingParams();
TBuffer buffer;
{
CentersTableBuilder builder;
builder.SetGeometryCodingParamsV0ForTests(codingParams);
fv.GetVector().ForEach([&](FeatureType & ft, uint32_t id) { builder.PutV0ForTests(id, feature::GetCenter(ft)); });
MemWriter<TBuffer> writer(buffer);
builder.FreezeV0ForTests(writer);
}
{
MemReader reader(buffer.data(), buffer.size());
auto table = CentersTable::LoadV0(reader, codingParams);
TEST(table.get(), ());
fv.GetVector().ForEach([&](FeatureType & ft, uint32_t id)
{
m2::PointD actual;
TEST(table->Get(id, actual), ());
m2::PointD expected = feature::GetCenter(ft);
TEST_LESS_OR_EQUAL(mercator::DistanceOnEarth(actual, expected), 1.0, (id));
});
}
}
UNIT_CLASS_TEST(CentersTableTest, Subset)
{
vector<pair<uint32_t, m2::PointD>> const features = {
{1, m2::PointD(0.0, 0.0)}, {5, m2::PointD(1.0, 1.0)}, {10, m2::PointD(2.0, 2.0)}};
TBuffer buffer;
{
CentersTableBuilder builder;
builder.SetGeometryParams({{0.0, 0.0}, {2.0, 2.0}});
for (auto const & feature : features)
builder.Put(feature.first, feature.second);
MemWriter<TBuffer> writer(buffer);
builder.Freeze(writer);
}
{
MemReader reader(buffer.data(), buffer.size());
auto table = CentersTable::LoadV1(reader);
TEST(table.get(), ());
uint32_t i = 0;
size_t j = 0;
while (i < 100)
{
ASSERT(j == features.size() || features[j].first >= i, ("Invariant violation"));
m2::PointD actual;
if (j != features.size() && i == features[j].first)
{
TEST(table->Get(i, actual), ());
TEST_LESS_OR_EQUAL(mercator::DistanceOnEarth(actual, features[j].second), 1.0, ());
}
else
{
TEST(!table->Get(i, actual), ());
}
++i;
while (j != features.size() && features[j].first < i)
++j;
}
}
}
} // namespace

View file

@ -0,0 +1,148 @@
#include "testing/testing.hpp"
#include "search/utils.hpp"
#include "indexer/classificator.hpp"
#include "indexer/classificator_loader.hpp"
#include "indexer/ftypes_matcher.hpp"
#include <string>
#include <vector>
namespace checker_test
{
using namespace std;
namespace
{
size_t const roadArrColumnCount = 3;
vector<uint32_t> GetTypes(char const * arr[][roadArrColumnCount], size_t const recCount)
{
Classificator const & c = classif();
vector<uint32_t> types;
for (size_t i = 0; i < recCount; ++i)
types.push_back(c.GetTypeByPath(vector<string>(arr[i], arr[i] + roadArrColumnCount)));
return types;
}
vector<uint32_t> GetStreetTypes()
{
char const * arr[][roadArrColumnCount] = {{"highway", "trunk", "bridge"}, {"highway", "tertiary", "tunnel"}};
return GetTypes(arr, ARRAY_SIZE(arr));
}
vector<uint32_t> GetStreetAndNotStreetTypes()
{
char const * arr[][roadArrColumnCount] = {{"highway", "trunk", "bridge"}, {"highway", "primary_link", "tunnel"}};
return GetTypes(arr, ARRAY_SIZE(arr));
}
vector<uint32_t> GetLinkTypes()
{
char const * arr[][roadArrColumnCount] = {{"highway", "secondary_link", "bridge"},
{"highway", "motorway_link", "tunnel"}};
return GetTypes(arr, ARRAY_SIZE(arr));
}
uint32_t GetMotorwayJunctionType()
{
Classificator const & c = classif();
return c.GetTypeByPath({"highway", "motorway_junction"});
}
} // namespace
UNIT_TEST(IsBridgeOrTunnelChecker)
{
classificator::Load();
auto const & c = classif();
base::StringIL arrYes[] = {
{"highway", "trunk", "bridge"},
{"highway", "motorway_link", "tunnel"},
};
for (auto const & e : arrYes)
TEST(ftypes::IsBridgeOrTunnelChecker::Instance()(c.GetTypeByPath(e)), ());
base::StringIL arrNo[] = {
{"highway", "motorway_junction"},
{"highway", "service", "driveway"},
};
for (auto const & e : arrNo)
TEST(!ftypes::IsBridgeOrTunnelChecker::Instance()(c.GetTypeByPath(e)), ());
}
UNIT_TEST(IsWayChecker)
{
classificator::Load();
TEST(ftypes::IsWayChecker::Instance()(GetStreetTypes()), ());
TEST(ftypes::IsWayChecker::Instance()(GetStreetAndNotStreetTypes()), ());
// TODO (@y, @m, @vng): need to investigate - do we really need this
// TEST for absence of links, because IsWayChecker() is used for
// search only.
//
// TEST(!ftypes::IsWayChecker::Instance()(GetLinkTypes()), ());
}
UNIT_TEST(IsLinkChecker)
{
classificator::Load();
TEST(ftypes::IsLinkChecker::Instance()(GetLinkTypes()), ());
TEST(!ftypes::IsLinkChecker::Instance()(GetStreetTypes()), ());
}
UNIT_TEST(GetHighwayClassTest)
{
classificator::Load();
Classificator const & c = classif();
feature::TypesHolder types1;
types1.Add(c.GetTypeByPath({"route", "shuttle_train"}));
TEST_EQUAL(ftypes::GetHighwayClass(types1), ftypes::HighwayClass::Transported, ());
feature::TypesHolder types2;
types2.Add(c.GetTypeByPath({"highway", "motorway_link", "tunnel"}));
TEST_EQUAL(ftypes::GetHighwayClass(types2), ftypes::HighwayClass::Motorway, ());
feature::TypesHolder types3;
types3.Add(c.GetTypeByPath({"highway", "unclassified"}));
TEST_EQUAL(ftypes::GetHighwayClass(types3), ftypes::HighwayClass::LivingStreet, ());
feature::TypesHolder types4;
types4.Add(c.GetTypeByPath({"highway"}));
TEST_EQUAL(ftypes::GetHighwayClass(types4), ftypes::HighwayClass::Undefined, ());
}
UNIT_TEST(IsAttractionsChecker)
{
classificator::Load();
Classificator const & c = classif();
auto const & checker = ftypes::AttractionsChecker::Instance();
base::StringIL arrExceptions[] = {
{"tourism", "information"},
{"amenity", "ranger_station"},
};
std::vector<uint32_t> exceptions;
for (auto e : arrExceptions)
exceptions.push_back(c.GetTypeByPath(e));
for (uint32_t const t : search::GetCategoryTypes("sights", "en", GetDefaultCategories()))
if (!base::IsExist(exceptions, ftype::Trunc(t, 2)))
TEST(checker(t), (c.GetFullObjectName(t)));
}
UNIT_TEST(IsMotorwayJunctionChecker)
{
classificator::Load();
TEST(ftypes::IsMotorwayJunctionChecker::Instance()(GetMotorwayJunctionType()), ());
TEST(!ftypes::IsMotorwayJunctionChecker::Instance()(GetStreetTypes()), ());
}
} // namespace checker_test

View file

@ -0,0 +1,195 @@
#include "testing/testing.hpp"
#include "indexer/cities_boundaries_serdes.hpp"
#include "indexer/city_boundary.hpp"
#include "platform/platform.hpp"
#include "coding/files_container.hpp"
#include "coding/reader.hpp"
#include "coding/writer.hpp"
#include "geometry/point2d.hpp"
#include "base/file_name_utils.hpp"
#include <vector>
namespace cities_boundaries_serdes_tests
{
using namespace indexer;
using namespace m2;
using namespace std;
using Boundary = vector<CityBoundary>;
using Boundaries = vector<Boundary>;
struct Result
{
Result(Boundaries const & boundaries, double eps) : m_boundaries(boundaries), m_eps(eps) {}
Boundaries m_boundaries;
double m_eps = 0.0;
};
void TestEqual(vector<PointD> const & lhs, vector<PointD> const & rhs, double eps)
{
TEST_EQUAL(lhs.size(), rhs.size(), (lhs, rhs));
for (size_t i = 0; i < lhs.size(); ++i)
TEST(AlmostEqualAbs(lhs[i], rhs[i], eps), (lhs, rhs));
}
void TestEqual(BoundingBox const & lhs, BoundingBox const & rhs, double eps)
{
TEST(AlmostEqualAbs(lhs.Min(), rhs.Min(), eps), (lhs, rhs));
TEST(AlmostEqualAbs(lhs.Max(), rhs.Max(), eps), (lhs, rhs));
}
void TestEqual(CalipersBox const & lhs, CalipersBox const & rhs, double eps)
{
// SerDes for CaliperBox works without normalization.
CalipersBox norm(rhs);
norm.Normalize();
TestEqual(lhs.Points(), norm.Points(), eps);
}
void TestEqual(DiamondBox const & lhs, DiamondBox const & rhs, double eps)
{
auto const lps = lhs.Points();
auto const rps = rhs.Points();
TEST_EQUAL(lps.size(), 4, (lhs));
TEST_EQUAL(rps.size(), 4, (rhs));
TestEqual(lps, rps, eps);
}
void TestEqual(CityBoundary const & lhs, CityBoundary const & rhs, double eps)
{
TestEqual(lhs.m_bbox, rhs.m_bbox, eps);
TestEqual(lhs.m_cbox, rhs.m_cbox, eps);
TestEqual(lhs.m_dbox, rhs.m_dbox, eps);
}
void TestEqual(Boundary const & lhs, Boundary const & rhs, double eps)
{
TEST_EQUAL(lhs.size(), rhs.size(), (lhs, rhs));
for (size_t i = 0; i < lhs.size(); ++i)
TestEqual(lhs[i], rhs[i], eps);
}
// Eps equal function to compare initial (expected) value (lhs) with encoded-decoded (rhs).
void TestEqual(Boundaries const & lhs, Boundaries const & rhs, double eps)
{
TEST_EQUAL(lhs.size(), rhs.size(), (lhs, rhs));
for (size_t i = 0; i < lhs.size(); ++i)
TestEqual(lhs[i], rhs[i], eps);
}
Result EncodeDecode(Boundaries const & boundaries)
{
vector<uint8_t> buffer;
{
MemWriter<decltype(buffer)> sink(buffer);
CitiesBoundariesSerDes::Serialize(sink, boundaries);
}
{
Boundaries boundaries;
double precision;
MemReader reader(buffer.data(), buffer.size());
NonOwningReaderSource source(reader);
CitiesBoundariesSerDes::Deserialize(source, boundaries, precision);
return Result(boundaries, precision);
}
}
void TestEncodeDecode(Boundaries const & expected)
{
auto const r = EncodeDecode(expected);
TestEqual(expected, r.m_boundaries, r.m_eps);
}
UNIT_TEST(CitiesBoundariesSerDes_Smoke)
{
{
Boundaries const expected;
TestEncodeDecode(expected);
}
{
Boundary boundary0;
boundary0.emplace_back(vector<PointD>{{PointD(0.1234, 5.6789)}});
boundary0.emplace_back(vector<PointD>{{PointD(3.1415, 2.1828), PointD(2.1828, 3.1415)}});
Boundary boundary1;
boundary1.emplace_back(vector<PointD>{{PointD(1.000, 1.000), PointD(1.002, 1.000), PointD(1.002, 1.003)}});
Boundaries const expected = {{boundary0, boundary1}};
TestEncodeDecode(expected);
}
}
UNIT_TEST(CitiesBoundaries_Moscow)
{
vector<PointD> const points = {
{37.04001, 67.55964}, {37.55650, 66.96428}, {38.02513, 67.37082}, {37.50865, 67.96618}};
PointD const target(37.44765, 67.65243);
vector<uint8_t> buffer;
{
CityBoundary boundary(points);
TEST(boundary.HasPoint(target), ());
MemWriter<decltype(buffer)> sink(buffer);
CitiesBoundariesSerDes::Serialize(sink, {{boundary}});
}
{
Boundaries boundaries;
double precision;
MemReader reader(buffer.data(), buffer.size());
NonOwningReaderSource source(reader);
CitiesBoundariesSerDes::Deserialize(source, boundaries, precision);
TEST_EQUAL(boundaries.size(), 1, ());
TEST_EQUAL(boundaries[0].size(), 1, ());
TEST(boundaries[0][0].HasPoint(target, precision), ());
}
}
UNIT_TEST(CitiesBoundaries_Compression)
{
FilesContainerR cont(base::JoinPath(GetPlatform().WritableDir(), WORLD_FILE_NAME) + DATA_FILE_EXTENSION);
vector<vector<CityBoundary>> all1;
double precision;
ReaderSource source1(cont.GetReader(CITIES_BOUNDARIES_FILE_TAG));
LOG(LINFO, ("Size before:", source1.Size()));
CitiesBoundariesSerDes::Deserialize(source1, all1, precision);
vector<uint8_t> buffer;
MemWriter writer(buffer);
CitiesBoundariesSerDes::Serialize(writer, all1);
LOG(LINFO, ("Size after:", buffer.size()));
// Equal test.
vector<vector<CityBoundary>> all2;
MemReader reader(buffer.data(), buffer.size());
ReaderSource source2(reader);
CitiesBoundariesSerDes::Deserialize(source2, all2, precision);
TEST_EQUAL(all1.size(), all2.size(), ());
for (size_t i = 0; i < all1.size(); ++i)
{
TEST_EQUAL(all1[i].size(), all2[i].size(), ());
for (size_t j = 0; j < all1[i].size(); ++j)
if (!(all1[i][j] == all2[i][j]))
LOG(LINFO, (i, all1[i][j], all2[i][j]));
}
}
} // namespace cities_boundaries_serdes_tests

View file

@ -0,0 +1,104 @@
#include "testing/testing.hpp"
#include "indexer/classificator.hpp"
#include "generator/generator_tests_support/test_with_classificator.hpp"
#include <algorithm>
#include <cstdint>
#include <string>
#include <vector>
using namespace generator::tests_support;
using namespace std;
UNIT_CLASS_TEST(TestWithClassificator, Classificator_GetType)
{
Classificator const & c = classif();
uint32_t const type1 = c.GetTypeByPath({"natural", "coastline"});
TEST_NOT_EQUAL(0, type1, ());
TEST(c.IsTypeValid(type1), ());
TEST_EQUAL(type1, c.GetTypeByReadableObjectName("natural-coastline"), ());
uint32_t const type2 = c.GetTypeByPath({"amenity", "parking", "private"});
TEST_NOT_EQUAL(0, type2, ());
TEST(c.IsTypeValid(type2), ());
TEST_EQUAL(type2, c.GetTypeByReadableObjectName("amenity-parking-private"), ());
TEST_EQUAL(0, c.GetTypeByPathSafe({"nonexisting", "type"}), ());
TEST_EQUAL(0, c.GetTypeByReadableObjectName("nonexisting-type"), ());
TEST(!c.IsTypeValid(0), ());
}
UNIT_CLASS_TEST(TestWithClassificator, Classificator_CoastlineType)
{
Classificator const & c = classif();
uint32_t const type = c.GetTypeByPath({"natural", "coastline"});
TEST(c.IsTypeValid(type), ());
TEST_EQUAL(type, c.GetCoastType(), ());
}
UNIT_CLASS_TEST(TestWithClassificator, Classificator_GetIndex)
{
Classificator const & c = classif();
uint32_t const type = c.GetTypeByPath({"railway", "station", "subway"});
uint32_t const index = c.GetIndexForType(type);
TEST(c.IsTypeValid(type), ());
TEST_EQUAL(type, c.GetTypeForIndex(index), ());
}
UNIT_CLASS_TEST(TestWithClassificator, Classificator_Subtree)
{
Classificator const & c = classif();
uint32_t const cityType = c.GetTypeByPath({"place", "city"});
vector<vector<string>> const expectedPaths = {
{"place", "city"},
{"place", "city", "capital"},
{"place", "city", "capital", "2"},
{"place", "city", "capital", "3"},
{"place", "city", "capital", "4"},
{"place", "city", "capital", "5"},
{"place", "city", "capital", "6"},
{"place", "city", "capital", "7"},
{"place", "city", "capital", "8"},
{"place", "city", "capital", "9"},
{"place", "city", "capital", "10"},
{"place", "city", "capital", "11"},
};
vector<uint32_t> expectedTypes;
for (auto const & path : expectedPaths)
expectedTypes.push_back(classif().GetTypeByPath(path));
sort(expectedTypes.begin(), expectedTypes.end());
vector<uint32_t> subtreeTypes;
c.ForEachInSubtree([&subtreeTypes](uint32_t type) { subtreeTypes.push_back(type); }, cityType);
sort(subtreeTypes.begin(), subtreeTypes.end());
TEST_EQUAL(expectedTypes, subtreeTypes, ());
}
UNIT_CLASS_TEST(TestWithClassificator, Classificator_StableIndex)
{
// mapcss-mapping.csv:
//
// amenity|parking|underground|fee;[amenity=parking][location=underground][fee?],[amenity=parking][parking=underground][fee?];x;name;int_name;356;amenity|parking|underground
// amenity|parking|underground;[amenity=parking][location=underground],[amenity=parking][parking=underground];;name;int_name;357;
//
// The main definition of amenity|parking|underground goes second but we must use it for index. Test both indexes.
// belong to amenity|parking|underground type and GetIndexForType returns second one.
Classificator const & c = classif();
uint32_t const type = c.GetTypeByPath({"amenity", "parking", "underground"});
TEST(c.IsTypeValid(type), ());
uint32_t const index = c.GetIndexForType(type);
TEST_EQUAL(index, 357 - 1, ());
TEST_NOT_EQUAL(type, c.GetTypeForIndex(356 - 1), ()); // Restored underground-fee
TEST_EQUAL(type, c.GetTypeForIndex(357 - 1), ());
}

View file

@ -0,0 +1,71 @@
#include "testing/testing.hpp"
#include "indexer/complex/serdes.hpp"
#include "indexer/complex/tree_node.hpp"
#include "coding/reader.hpp"
#include "coding/writer.hpp"
#include <cstdint>
#include <vector>
namespace complex_serdes_tests
{
using ByteVector = std::vector<uint8_t>;
using ::complex::ComplexSerdes;
decltype(auto) GetForest()
{
auto tree1 = tree_node::MakeTreeNode<ComplexSerdes::Ids>({1, 2, 3});
auto node11 = tree_node::MakeTreeNode<ComplexSerdes::Ids>({11, 12, 13});
tree_node::Link(tree_node::MakeTreeNode<ComplexSerdes::Ids>({111}), node11);
tree_node::Link(tree_node::MakeTreeNode<ComplexSerdes::Ids>({112, 113}), node11);
tree_node::Link(tree_node::MakeTreeNode<ComplexSerdes::Ids>({114}), node11);
tree_node::Link(node11, tree1);
tree_node::Link(tree_node::MakeTreeNode<ComplexSerdes::Ids>({6, 7}), tree1);
auto tree2 = tree_node::MakeTreeNode<ComplexSerdes::Ids>({9});
tree_node::Link(tree_node::MakeTreeNode<ComplexSerdes::Ids>({21, 22, 23}), tree2);
tree_node::Link(tree_node::MakeTreeNode<ComplexSerdes::Ids>({24, 25}), tree2);
tree_node::Forest<ComplexSerdes::Ids> forest;
forest.Append(tree1);
forest.Append(tree2);
return forest;
}
UNIT_TEST(Complex_SerdesV0)
{
auto const expectedForest = GetForest();
ByteVector buffer;
{
MemWriter<decltype(buffer)> writer(buffer);
WriterSink<decltype(writer)> sink(writer);
ComplexSerdes::Serialize(sink, ComplexSerdes::Version::V0, expectedForest);
}
{
MemReader reader(buffer.data(), buffer.size());
ReaderSource<decltype(reader)> src(reader);
tree_node::Forest<ComplexSerdes::Ids> forest;
ComplexSerdes::Deserialize(src, ComplexSerdes::Version::V0, forest);
TEST_EQUAL(forest, expectedForest, ());
}
}
UNIT_TEST(Complex_Serdes)
{
auto const expectedForest = GetForest();
ByteVector buffer;
{
MemWriter<decltype(buffer)> writer(buffer);
WriterSink<decltype(writer)> sink(writer);
ComplexSerdes::Serialize(sink, expectedForest);
}
{
MemReader reader(buffer.data(), buffer.size());
tree_node::Forest<ComplexSerdes::Ids> forest;
ComplexSerdes::Deserialize(reader, forest);
TEST_EQUAL(forest, expectedForest, ());
}
}
} // namespace complex_serdes_tests

View file

@ -0,0 +1,60 @@
#include "testing/testing.hpp"
#include "indexer/complex/serdes_utils.hpp"
#include "coding/reader.hpp"
#include "coding/writer.hpp"
#include <algorithm>
#include <cstdint>
#include <list>
#include <set>
#include <vector>
namespace
{
using ByteVector = std::vector<uint8_t>;
template <typename Cont>
void CollectionPrimitiveTest(Cont const & cont)
{
ByteVector buffer;
MemWriter<decltype(buffer)> writer(buffer);
WriterSink<decltype(writer)> sink(writer);
coding_utils::WriteCollectionPrimitive(sink, cont);
MemReader reader(buffer.data(), buffer.size());
ReaderSource<decltype(reader)> src(reader);
Cont res;
coding_utils::ReadCollectionPrimitive(src, std::inserter(res, std::end(res)));
TEST_EQUAL(cont, res, ());
}
UNIT_TEST(Utils_CollectionPrimitive)
{
{
std::list<uint8_t> const cont{1, 2, 3, 4};
CollectionPrimitiveTest(cont);
}
{
std::list<int8_t> const cont{-1, -2, -3, -4};
CollectionPrimitiveTest(cont);
}
{
std::vector<uint32_t> const cont{1, 2, 3, 4};
CollectionPrimitiveTest(cont);
}
{
std::vector<int32_t> const cont{-1, -2, -3, -4};
CollectionPrimitiveTest(cont);
}
{
std::set<uint64_t> const cont{1, 2, 3, 4};
CollectionPrimitiveTest(cont);
}
{
std::set<int64_t> const cont{-1, -2, -3, -4};
CollectionPrimitiveTest(cont);
}
}
} // namespace

View file

@ -0,0 +1,21 @@
#include "testing/testing.hpp"
#include "indexer/custom_keyvalue.hpp"
UNIT_TEST(CustomKeyValue_Smoke)
{
indexer::CustomKeyValue empty("");
TEST(!empty.Get(0), ());
TEST_EQUAL(empty.ToString(), "", ());
indexer::CustomKeyValue kv;
kv.Add(1, 777);
kv.Add(255, 0xFFFFFFFF);
kv.Add(0, 0);
indexer::CustomKeyValue actual(kv.ToString());
TEST(!actual.Get(5), ());
TEST_EQUAL(actual.GetSure(1), 777, ());
TEST_EQUAL(actual.GetSure(255), 0xFFFFFFFF, ());
TEST_EQUAL(actual.GetSure(0), 0, ());
}

View file

@ -0,0 +1,157 @@
#include "testing/testing.hpp"
#include "indexer/data_header.hpp"
#include "indexer/data_source.hpp"
#include "indexer/feature_source.hpp"
#include "indexer/mwm_set.hpp"
#include "coding/internal/file_data.hpp"
#include "platform/country_file.hpp"
#include "platform/local_country_file.hpp"
#include "platform/platform.hpp"
#include "base/file_name_utils.hpp"
#include "base/logging.hpp"
#include "base/macros.hpp"
#include "base/scope_guard.hpp"
#include "base/stl_helpers.hpp"
#include <algorithm>
#include <string>
namespace data_source_test
{
using platform::CountryFile;
using platform::LocalCountryFile;
class DataSourceTest : public MwmSet::Observer
{
public:
DataSourceTest() { TEST(m_dataSource.AddObserver(*this), ()); }
~DataSourceTest() override { TEST(m_dataSource.RemoveObserver(*this), ()); }
void ExpectRegistered(platform::LocalCountryFile const & localFile)
{
AddEvent(m_expected, MwmSet::Event::TYPE_REGISTERED, localFile);
}
void ExpectDeregistered(platform::LocalCountryFile const & localFile)
{
AddEvent(m_expected, MwmSet::Event::TYPE_DEREGISTERED, localFile);
}
// Checks expectations and clears them.
bool CheckExpectations()
{
bool ok = true;
if (m_actual != m_expected)
{
LOG(LINFO, ("Check failed. Expected:", m_expected, "actual:", m_actual));
ok = false;
}
m_actual.clear();
m_expected.clear();
return ok;
}
// MwmSet::Observer overrides:
void OnMapRegistered(platform::LocalCountryFile const & localFile) override
{
AddEvent(m_actual, MwmSet::Event::TYPE_REGISTERED, localFile);
}
void OnMapDeregistered(platform::LocalCountryFile const & localFile) override
{
AddEvent(m_actual, MwmSet::Event::TYPE_DEREGISTERED, localFile);
}
protected:
template <typename... TArgs>
void AddEvent(std::vector<MwmSet::Event> & events, TArgs... args)
{
events.emplace_back(std::forward<TArgs>(args)...);
}
FrozenDataSource m_dataSource;
std::vector<MwmSet::Event> m_expected;
std::vector<MwmSet::Event> m_actual;
};
UNIT_CLASS_TEST(DataSourceTest, Parse)
{
UNUSED_VALUE(m_dataSource.RegisterMap(platform::LocalCountryFile::MakeForTesting("minsk-pass")));
// Make sure that index is actually parsed.
m_dataSource.ForEachInScale([](FeatureType &) { return; }, 15);
}
UNIT_CLASS_TEST(DataSourceTest, StatusNotifications)
{
std::string const mapsDir = GetPlatform().WritableDir();
CountryFile const country("minsk-pass");
// These two classes point to the same file, but will be considered
// by DataSource as distinct files because versions are artificially set
// to different numbers.
LocalCountryFile const file1(mapsDir, country, 1 /* version */);
LocalCountryFile const file2(mapsDir, country, 2 /* version */);
MwmSet::MwmId id1;
// Checks that observers are triggered after map registration.
{
auto result = m_dataSource.RegisterMap(file1);
TEST_EQUAL(MwmSet::RegResult::Success, result.second, ());
id1 = result.first;
TEST(id1.IsAlive(), ());
ExpectRegistered(file1);
TEST(CheckExpectations(), ());
}
// Checks that map can't registered twice.
{
auto result = m_dataSource.RegisterMap(file1);
TEST_EQUAL(MwmSet::RegResult::VersionAlreadyExists, result.second, ());
TEST(result.first.IsAlive(), ());
TEST_EQUAL(id1, result.first, ());
TEST(CheckExpectations(), ());
}
// Checks that observers are notified when map is updated.
MwmSet::MwmId id2;
{
auto result = m_dataSource.RegisterMap(file2);
TEST_EQUAL(MwmSet::RegResult::Success, result.second, ());
id2 = result.first;
TEST(id2.IsAlive(), ());
TEST_NOT_EQUAL(id1, id2, ());
ExpectDeregistered(file1);
ExpectRegistered(file2);
TEST(CheckExpectations(), ());
}
// Tries to deregister a map in presence of an active handle. Map
// should be marked "to be removed" but can't be deregistered. After
// leaving the inner block the map should be deregistered.
{
{
MwmSet::MwmHandle const handle = m_dataSource.GetMwmHandleByCountryFile(country);
TEST(handle.IsAlive(), ());
TEST(!m_dataSource.DeregisterMap(country), ());
TEST(CheckExpectations(), ());
}
ExpectDeregistered(file2);
TEST(CheckExpectations(), ());
}
}
} // namespace data_source_test

View file

@ -0,0 +1,168 @@
#include "testing/testing.hpp"
#include "indexer/drules_selector.hpp"
#include "indexer/drules_selector_parser.hpp"
#include <string>
#include <vector>
namespace drules_selector_parser_test
{
using namespace drule;
using namespace std;
UNIT_TEST(TestDruleSelectorIsSet)
{
SelectorExpression e;
TEST(ParseSelector("name", e), ());
TEST_EQUAL("name", e.m_tag, ());
TEST_EQUAL("", e.m_value, ());
TEST_EQUAL(SelectorOperatorIsSet, e.m_operator, ());
}
UNIT_TEST(TestDruleSelectorIsSet2)
{
SelectorExpression e;
TEST(ParseSelector("bbox_area", e), ());
TEST_EQUAL("bbox_area", e.m_tag, ());
TEST_EQUAL("", e.m_value, ());
TEST_EQUAL(SelectorOperatorIsSet, e.m_operator, ());
}
UNIT_TEST(TestDruleSelectorIsNotSet)
{
SelectorExpression e;
TEST(ParseSelector("!name", e), ());
TEST_EQUAL("name", e.m_tag, ());
TEST_EQUAL("", e.m_value, ());
TEST_EQUAL(SelectorOperatorIsNotSet, e.m_operator, ());
}
UNIT_TEST(TestDruleSelectorIsNotSet2)
{
SelectorExpression e;
TEST(ParseSelector("!bbox_area", e), ());
TEST_EQUAL("bbox_area", e.m_tag, ());
TEST_EQUAL("", e.m_value, ());
TEST_EQUAL(SelectorOperatorIsNotSet, e.m_operator, ());
}
UNIT_TEST(TestDruleSelectorEqual)
{
SelectorExpression e;
TEST(ParseSelector("population=1000", e), ());
TEST_EQUAL("population", e.m_tag, ());
TEST_EQUAL("1000", e.m_value, ());
TEST_EQUAL(SelectorOperatorEqual, e.m_operator, ());
}
UNIT_TEST(TestDruleSelectorNotEqual)
{
SelectorExpression e;
TEST(ParseSelector("population!=1000", e), ());
TEST_EQUAL("population", e.m_tag, ());
TEST_EQUAL("1000", e.m_value, ());
TEST_EQUAL(SelectorOperatorNotEqual, e.m_operator, ());
}
UNIT_TEST(TestDruleSelectorLess)
{
SelectorExpression e;
TEST(ParseSelector("population<1000", e), ());
TEST_EQUAL("population", e.m_tag, ());
TEST_EQUAL("1000", e.m_value, ());
TEST_EQUAL(SelectorOperatorLess, e.m_operator, ());
}
UNIT_TEST(TestDruleSelectorLess2)
{
SelectorExpression e;
TEST(ParseSelector("bbox_area<1000", e), ());
TEST_EQUAL("bbox_area", e.m_tag, ());
TEST_EQUAL("1000", e.m_value, ());
TEST_EQUAL(SelectorOperatorLess, e.m_operator, ());
}
UNIT_TEST(TestDruleSelectorGreater)
{
SelectorExpression e;
TEST(ParseSelector("population>1000", e), ());
TEST_EQUAL("population", e.m_tag, ());
TEST_EQUAL("1000", e.m_value, ());
TEST_EQUAL(SelectorOperatorGreater, e.m_operator, ());
}
UNIT_TEST(TestDruleSelectorGreater2)
{
SelectorExpression e;
TEST(ParseSelector("bbox_area>1000", e), ());
TEST_EQUAL("bbox_area", e.m_tag, ());
TEST_EQUAL("1000", e.m_value, ());
TEST_EQUAL(SelectorOperatorGreater, e.m_operator, ());
}
UNIT_TEST(TestDruleSelectorLessOrEqual)
{
SelectorExpression e;
TEST(ParseSelector("population<=1000", e), ());
TEST_EQUAL("population", e.m_tag, ());
TEST_EQUAL("1000", e.m_value, ());
TEST_EQUAL(SelectorOperatorLessOrEqual, e.m_operator, ());
}
UNIT_TEST(TestDruleSelectorGreaterOrEqual)
{
SelectorExpression e;
TEST(ParseSelector("population>=1000", e), ());
TEST_EQUAL("population", e.m_tag, ());
TEST_EQUAL("1000", e.m_value, ());
TEST_EQUAL(SelectorOperatorGreaterOrEqual, e.m_operator, ());
}
UNIT_TEST(TestDruleSelectorInvalid)
{
char const * const badFormats[] = {
"", "=badformat", "!=badformat", ">badformat", "<badformat", ">=badformat", "<=badformat",
"bad$name", "!bad$name", "bad$name=1000",
};
for (auto e : badFormats)
{
SelectorExpression expr;
TEST_EQUAL(false, ParseSelector(e, expr), ("string is", e));
}
}
UNIT_TEST(PopulationSelector_Smoke)
{
TEST(ParseSelector("population<1000"), ());
TEST(ParseSelector(vector<string>({"population>1000"})), ());
TEST(ParseSelector(vector<string>({"population>=1000", "population<=1000000"})), ());
}
UNIT_TEST(NameSelector_Smoke)
{
TEST(ParseSelector("name"), ());
TEST(ParseSelector("!name"), ());
}
UNIT_TEST(InvalidSelector_Smoke)
{
TEST(!ParseSelector(""), ());
TEST(!ParseSelector(vector<string>({""})), ());
TEST(!ParseSelector(vector<string>({"population>=1000", "population<=1000000", ""})), ());
}
} // namespace drules_selector_parser_test

View file

@ -0,0 +1,554 @@
#include "testing/testing.hpp"
#include "indexer/classificator.hpp"
#include "indexer/classificator_loader.hpp"
#include "indexer/editable_map_object.hpp"
#include "indexer/feature.hpp"
#include "indexer/feature_utils.hpp"
#include "indexer/validate_and_format_contacts.hpp"
#include <string>
#include <vector>
namespace editable_map_object_test
{
using namespace std;
using osm::EditableMapObject;
int8_t GetLangCode(char const * ch)
{
return StringUtf8Multilang::GetLangIndex(ch);
}
struct ExpectedName
{
string m_lang;
string m_value;
};
string DebugPrint(ExpectedName const & expectedName)
{
return expectedName.m_lang + ", " + expectedName.m_value;
}
void CheckExpectations(StringUtf8Multilang const & s, vector<ExpectedName> const & expectations)
{
size_t counter = 0;
s.ForEach([&expectations, &counter](int8_t const code, string_view name)
{
auto const it = find_if(expectations.begin(), expectations.end(),
[&code](ExpectedName const & item) { return GetLangCode(item.m_lang.c_str()) == code; });
if (it == expectations.end())
TEST(false, ("Unexpected language code: ", code, ". Expectations: ", expectations));
TEST_EQUAL(name, it->m_value, ());
++counter;
});
TEST_EQUAL(counter, expectations.size(),
("Unexpected count of names, expected ", expectations.size(), ", but turned out ", counter,
". Expectations: ", expectations));
}
UNIT_TEST(EditableMapObject_SetWebsite)
{
pair<char const *, char const *> arr[] = {
{"https://some.thing.org", "https://some.thing.org"},
{"http://some.thing.org", "http://some.thing.org"},
{"some.thing.org", "http://some.thing.org"},
{"", ""},
};
EditableMapObject emo;
for (auto const & e : arr)
{
emo.SetMetadata(feature::Metadata::FMD_WEBSITE, e.first);
TEST_EQUAL(emo.GetMetadata(feature::Metadata::FMD_WEBSITE), e.second, ());
}
}
UNIT_TEST(EditableMapObject_ValidateBuildingLevels)
{
TEST(EditableMapObject::ValidateBuildingLevels(""), ());
TEST(EditableMapObject::ValidateBuildingLevels("7"), ());
TEST(EditableMapObject::ValidateBuildingLevels("17"), ());
TEST(EditableMapObject::ValidateBuildingLevels("25"), ());
TEST(!EditableMapObject::ValidateBuildingLevels("0"), ());
TEST(!EditableMapObject::ValidateBuildingLevels("005"), ());
TEST(!EditableMapObject::ValidateBuildingLevels(std::to_string(EditableMapObject::kMaximumLevelsEditableByUsers + 1)),
());
TEST(!EditableMapObject::ValidateBuildingLevels("22a"), ());
TEST(!EditableMapObject::ValidateBuildingLevels("a22"), ());
TEST(!EditableMapObject::ValidateBuildingLevels("2a22"), ());
TEST(!EditableMapObject::ValidateBuildingLevels("ab"), ());
TEST(!EditableMapObject::ValidateBuildingLevels("2345534564564453645534545345534564564453645"), ());
}
UNIT_TEST(EditableMapObject_ValidateHouseNumber)
{
TEST(EditableMapObject::ValidateHouseNumber(""), ());
TEST(EditableMapObject::ValidateHouseNumber("qwer7ty"), ());
TEST(EditableMapObject::ValidateHouseNumber("12345678"), ());
// House number must contain at least one number.
TEST(!EditableMapObject::ValidateHouseNumber("qwerty"), ());
// House number is too long.
TEST(!EditableMapObject::ValidateHouseNumber("1234567890123456"), ());
}
UNIT_TEST(EditableMapObject_ValidateFlats)
{
TEST(EditableMapObject::ValidateFlats(""), ());
TEST(EditableMapObject::ValidateFlats("123"), ());
TEST(EditableMapObject::ValidateFlats("123a"), ());
TEST(EditableMapObject::ValidateFlats("a"), ());
TEST(EditableMapObject::ValidateFlats("123-456;a-e"), ());
TEST(EditableMapObject::ValidateFlats("123-456"), ());
TEST(EditableMapObject::ValidateFlats("123-456; 43-45"), ());
TEST(!EditableMapObject::ValidateFlats("123-456, 43-45"), ());
TEST(!EditableMapObject::ValidateFlats("234-234 124"), ());
TEST(!EditableMapObject::ValidateFlats("123-345-567"), ());
TEST(!EditableMapObject::ValidateFlats("234-234;234("), ());
TEST(!EditableMapObject::ValidateFlats("-;"), ());
}
// See search_tests/postcodes_matcher_test.cpp
// UNIT_TEST(EditableMapObject_ValidatePostCode)
// {
// }
UNIT_TEST(EditableMapObject_ValidatePhoneList)
{
TEST(EditableMapObject::ValidatePhoneList(""), ());
TEST(EditableMapObject::ValidatePhoneList("+7 000 000 00 00"), ());
TEST(EditableMapObject::ValidatePhoneList("+7 (000) 000 00 00"), ());
TEST(EditableMapObject::ValidatePhoneList("+7 0000000000"), ());
TEST(EditableMapObject::ValidatePhoneList("+7 0000 000 000"), ());
TEST(EditableMapObject::ValidatePhoneList("8 0000-000-000"), ());
TEST(EditableMapObject::ValidatePhoneList("000 00 00"), ());
TEST(EditableMapObject::ValidatePhoneList("000 000 00"), ());
TEST(EditableMapObject::ValidatePhoneList("+00 0000 000 000"), ());
TEST(EditableMapObject::ValidatePhoneList("+7 000 000 00 00; +7 000 000 00 00"), ());
TEST(EditableMapObject::ValidatePhoneList("+7 (000) 000 00 00, +7 (000) 000 00 00"), ());
TEST(EditableMapObject::ValidatePhoneList("+7 0000000000;+7 0000000000"), ());
TEST(EditableMapObject::ValidatePhoneList("+7 0000 000 000,+7 0000 000 000"), ());
TEST(EditableMapObject::ValidatePhoneList("8 0000-000-000; 8 0000-000-000"), ());
TEST(EditableMapObject::ValidatePhoneList("+7 00 00;7 (0)00 0, 800-00-0; 000000000000000,12345"), ());
TEST(!EditableMapObject::ValidatePhoneList("+00 0000 000 0000 000"), ());
TEST(!EditableMapObject::ValidatePhoneList("00 00"), ());
TEST(!EditableMapObject::ValidatePhoneList("acb"), ());
TEST(!EditableMapObject::ValidatePhoneList("000 000 00b"), ());
TEST(!EditableMapObject::ValidatePhoneList(";"), ());
TEST(!EditableMapObject::ValidatePhoneList(","), ());
TEST(!EditableMapObject::ValidatePhoneList(";;;;;;"), ());
// Now it is possible to specify the following incorrect phone numbers.
// TODO: replace current implementation of ValidatePhoneList by a correct one.
TEST(EditableMapObject::ValidatePhoneList("7+ 10 10"), ());
TEST(EditableMapObject::ValidatePhoneList("+7 )10( 10"), ());
TEST(EditableMapObject::ValidatePhoneList("+7 )10 10"), ());
TEST(EditableMapObject::ValidatePhoneList("+7 10 (---) 10"), ());
}
UNIT_TEST(EditableMapObject_ValidateWebsite)
{
TEST(osm::ValidateWebsite(""), ());
TEST(osm::ValidateWebsite("qwe.rty"), ());
TEST(osm::ValidateWebsite("http://websit.e"), ());
TEST(osm::ValidateWebsite("https://websit.e"), ());
TEST(!osm::ValidateWebsite("qwerty"), ());
TEST(!osm::ValidateWebsite(".qwerty"), ());
TEST(!osm::ValidateWebsite("qwerty."), ());
TEST(!osm::ValidateWebsite(".qwerty."), ());
TEST(!osm::ValidateWebsite("w..com"), ());
TEST(!osm::ValidateWebsite("http://.websit.e"), ());
TEST(!osm::ValidateWebsite("https://.websit.e"), ());
TEST(!osm::ValidateWebsite("http://"), ());
TEST(!osm::ValidateWebsite("https://"), ());
}
UNIT_TEST(EditableMapObject_ValidateEmail)
{
TEST(EditableMapObject::ValidateEmail(""), ());
TEST(EditableMapObject::ValidateEmail("e@ma.il"), ());
TEST(EditableMapObject::ValidateEmail("e@ma.i.l"), ());
TEST(EditableMapObject::ValidateEmail("e-m.ail@dot.com.gov"), ());
TEST(EditableMapObject::ValidateEmail("#$%&'*+-/=?^`_{}|~.@dot.qw.com.gov"), ());
TEST(!EditableMapObject::ValidateEmail("e.ma.il"), ());
TEST(!EditableMapObject::ValidateEmail("e@ma@il"), ());
TEST(!EditableMapObject::ValidateEmail("e@ma@i.l"), ());
TEST(!EditableMapObject::ValidateEmail("e@mail"), ());
TEST(!EditableMapObject::ValidateEmail("@email.a"), ());
TEST(!EditableMapObject::ValidateEmail("emai.l@"), ());
TEST(!EditableMapObject::ValidateEmail("emai@l."), ());
TEST(!EditableMapObject::ValidateEmail("e mai@l.com"), ());
TEST(!EditableMapObject::ValidateEmail("emai@.l"), ());
TEST(!EditableMapObject::ValidateEmail("emai@_l.ab"), ());
TEST(!EditableMapObject::ValidateEmail("emai@l_.ab"), ());
TEST(!EditableMapObject::ValidateEmail("email@e#$%&'*+-/=?^`_{}|~.com"), ());
}
UNIT_TEST(EditableMapObject_ValidateName)
{
vector<string> correctNames = {"abc", "абв", "ᆺᆯㅕ", "꫞ꪺꫀꪸ", "a b?c", "a!b.c", "a(b)c",
"a,b.c", "a$bc", "a%bc", "a#bc", "a№bc", "c&a", "a[bc"};
vector<string> incorrectNames = {"a^bc",
"a~bc",
"a§bc",
"a>bc",
"a<bc",
"a{bc",
"*",
"a*bc",
"a=bc",
"a_bc",
"a±bc",
"a\nbc",
"a\tbc",
"a\rbc",
"a\vbc",
"a\fbc",
"a|bc",
"N√",
"Hello World!\U0001F600",
"Exit →",
"∫0dx = C",
"\U0001210A",
"⚠︎",
"⚠️"};
for (auto const & name : correctNames)
TEST(EditableMapObject::ValidateName(name), ());
for (auto const & name : incorrectNames)
TEST(!EditableMapObject::ValidateName(name), ());
}
UNIT_TEST(EditableMapObject_CanUseAsDefaultName)
{
EditableMapObject emo;
vector<int8_t> const nativeMwmLanguages{GetLangCode("de"), GetLangCode("fr")};
TEST(EditableMapObject::CanUseAsDefaultName(GetLangCode("de"), nativeMwmLanguages),
("Check possibility to use Mwm language code"));
TEST(EditableMapObject::CanUseAsDefaultName(GetLangCode("fr"), nativeMwmLanguages),
("Check possibility to use Mwm language code"));
TEST(!EditableMapObject::CanUseAsDefaultName(GetLangCode("int_name"), nativeMwmLanguages),
("Check possibility to use international language code"));
TEST(!EditableMapObject::CanUseAsDefaultName(100, nativeMwmLanguages), ("Incorrect language code is not supported"));
TEST(!EditableMapObject::CanUseAsDefaultName(GetLangCode("en"), {GetLangCode("abcd")}),
("Incorrect Mwm language name is not supported"));
TEST(!EditableMapObject::CanUseAsDefaultName(GetLangCode("en"), nativeMwmLanguages),
("Can not to use language which not Mwm language or international"));
TEST(!EditableMapObject::CanUseAsDefaultName(GetLangCode("ru"), nativeMwmLanguages),
("Check possibility to use user`s language code"));
// Trying to use language codes in reverse priority.
StringUtf8Multilang names;
names.AddString(GetLangCode("fr"), "second mwm language");
emo.SetName(names);
TEST(EditableMapObject::CanUseAsDefaultName(GetLangCode("fr"), nativeMwmLanguages), ("It is possible to fix typo"));
names.AddString(GetLangCode("de"), "first mwm language");
emo.SetName(names);
TEST(EditableMapObject::CanUseAsDefaultName(GetLangCode("de"), nativeMwmLanguages), ("It is possible to fix typo"));
TEST(EditableMapObject::CanUseAsDefaultName(GetLangCode("fr"), nativeMwmLanguages), ("It is possible to fix typo"));
}
UNIT_TEST(EditableMapObject_GetNamesDataSource)
{
EditableMapObject emo;
StringUtf8Multilang names;
names.AddString(GetLangCode("default"), "Default name");
names.AddString(GetLangCode("en"), "Eng name");
names.AddString(GetLangCode("int_name"), "Int name");
names.AddString(GetLangCode("de"), "De name");
names.AddString(GetLangCode("ru"), "Ru name");
names.AddString(GetLangCode("sv"), "Sv name");
names.AddString(GetLangCode("be"), "By name");
names.AddString(GetLangCode("ko"), "Ko name");
names.AddString(GetLangCode("it"), "It name");
emo.SetName(names);
vector<int8_t> nativeMwmLanguages = {GetLangCode("de"), GetLangCode("fr")};
auto const namesDataSource =
EditableMapObject::GetNamesDataSource(emo.GetNameMultilang(), nativeMwmLanguages, GetLangCode("ko"));
TEST_EQUAL(namesDataSource.names.size(), 9, ("All names including the default should be pushed into data source"));
TEST_EQUAL(namesDataSource.mandatoryNamesCount, 1, ("Mandatory names count should always be 1"));
TEST_EQUAL(namesDataSource.names[0].m_code, GetLangCode("default"), ("Default is always first in the list"));
{
vector<int8_t> nativeMwmLanguages = {GetLangCode("de"), GetLangCode("fr")};
auto const namesDataSource =
EditableMapObject::GetNamesDataSource(emo.GetNameMultilang(), nativeMwmLanguages, GetLangCode("fr"));
TEST_EQUAL(namesDataSource.names.size(), 9, ("All names including the default should be pushed into data source"));
TEST_EQUAL(namesDataSource.mandatoryNamesCount, 1, ("Mandatory names count should always be 1"));
}
{
vector<int8_t> nativeMwmLanguages = {GetLangCode("fr"), GetLangCode("en")};
auto const namesDataSource =
EditableMapObject::GetNamesDataSource(emo.GetNameMultilang(), nativeMwmLanguages, GetLangCode("fr"));
TEST_EQUAL(namesDataSource.names.size(), 9, ("All names including the default should be pushed into data source"));
TEST_EQUAL(namesDataSource.mandatoryNamesCount, 1, ("Mandatory names count should always be 1"));
}
{
vector<int8_t> nativeMwmLanguages = {GetLangCode("en"), GetLangCode("en")};
auto const namesDataSource =
EditableMapObject::GetNamesDataSource(emo.GetNameMultilang(), nativeMwmLanguages, GetLangCode("en"));
TEST_EQUAL(namesDataSource.names.size(), 9, ("All names including the default should be pushed into data source"));
TEST_EQUAL(namesDataSource.mandatoryNamesCount, 1, ("Mandatory names count should always be 1"));
}
}
namespace
{
void SetTypes(EditableMapObject & emo, std::initializer_list<base::StringIL> types)
{
auto const & cl = classif();
feature::TypesHolder holder;
for (auto const & t : types)
holder.Add(cl.GetTypeByPath(t));
emo.SetTypes(holder);
}
} // namespace
UNIT_TEST(EditableMapObject_SetInternet)
{
classificator::Load();
EditableMapObject emo;
auto const wifiType = classif().GetTypeByPath({"internet_access", "wlan"});
emo.SetType(wifiType);
auto types = emo.GetTypes();
TEST(types.Has(wifiType), ());
auto const setInternetAndCheck = [wifiType](EditableMapObject & emo, feature::Internet internet, bool hasWifi)
{
emo.SetInternet(internet);
TEST_EQUAL(emo.GetInternet(), internet, ());
auto const & types = emo.GetTypes();
TEST_EQUAL(types.Has(wifiType), hasWifi, ());
};
setInternetAndCheck(emo, feature::Internet::No, false);
setInternetAndCheck(emo, feature::Internet::Yes, false);
setInternetAndCheck(emo, feature::Internet::Wired, false);
setInternetAndCheck(emo, feature::Internet::Wlan, true);
setInternetAndCheck(emo, feature::Internet::Unknown, false);
setInternetAndCheck(emo, feature::Internet::Terminal, false);
EditableMapObject bunkerEmo;
SetTypes(bunkerEmo, {{"military", "bunker"}});
types = bunkerEmo.GetTypes();
TEST(!types.Has(wifiType), ());
setInternetAndCheck(bunkerEmo, feature::Internet::Wlan, true);
setInternetAndCheck(bunkerEmo, feature::Internet::No, false);
setInternetAndCheck(bunkerEmo, feature::Internet::Wlan, true);
setInternetAndCheck(bunkerEmo, feature::Internet::Yes, false);
setInternetAndCheck(bunkerEmo, feature::Internet::Wlan, true);
setInternetAndCheck(bunkerEmo, feature::Internet::Wired, false);
setInternetAndCheck(bunkerEmo, feature::Internet::Wlan, true);
setInternetAndCheck(bunkerEmo, feature::Internet::Unknown, false);
setInternetAndCheck(bunkerEmo, feature::Internet::Wlan, true);
setInternetAndCheck(bunkerEmo, feature::Internet::Terminal, false);
setInternetAndCheck(bunkerEmo, feature::Internet::Wlan, true);
setInternetAndCheck(bunkerEmo, feature::Internet::Wlan, true);
}
UNIT_TEST(EditableMapObject_RemoveBlankNames)
{
auto const getCountOfNames = [](StringUtf8Multilang const & names)
{
size_t counter = 0;
names.ForEach([&counter](int8_t, string_view) { ++counter; });
return counter;
};
StringUtf8Multilang name;
name.AddString(GetLangCode("default"), "Default name");
name.AddString(GetLangCode("ru"), "Ru name");
name.AddString(GetLangCode("en"), "En name");
name.AddString(GetLangCode("de"), "De name");
EditableMapObject emo;
emo.SetName(name);
emo.RemoveBlankNames();
TEST_EQUAL(getCountOfNames(emo.GetNameMultilang()), 4, ());
name.Clear();
name.AddString(GetLangCode("default"), "");
name.AddString(GetLangCode("ru"), "Ru name");
name.AddString(GetLangCode("en"), "En name");
name.AddString(GetLangCode("de"), "");
emo.SetName(name);
emo.RemoveBlankNames();
TEST_EQUAL(getCountOfNames(emo.GetNameMultilang()), 2, ());
name.Clear();
name.AddString(GetLangCode("default"), "Default name");
name.AddString(GetLangCode("ru"), "");
name.AddString(GetLangCode("en"), "");
name.AddString(GetLangCode("de"), "");
emo.SetName(name);
emo.RemoveBlankNames();
TEST_EQUAL(getCountOfNames(emo.GetNameMultilang()), 1, ());
name.Clear();
name.AddString(GetLangCode("default"), "");
name.AddString(GetLangCode("ru"), "");
name.AddString(GetLangCode("en"), "");
name.AddString(GetLangCode("de"), "De name");
emo.SetName(name);
emo.RemoveBlankNames();
TEST_EQUAL(getCountOfNames(emo.GetNameMultilang()), 1, ());
}
UNIT_TEST(EditableMapObject_FromFeatureType)
{
classificator::Load();
EditableMapObject emo;
SetTypes(emo, {{"amenity", "cafe"}});
emo.SetHouseNumber("1");
StringUtf8Multilang names;
names.AddString(GetLangCode("default"), "Default name");
names.AddString(GetLangCode("ru"), "Ru name");
emo.SetName(names);
emo.SetMetadata(feature::Metadata::FMD_WEBSITE, "https://some.thing.org");
emo.SetInternet(feature::Internet::Wlan);
emo.SetPointType();
emo.SetMercator(m2::PointD(1.0, 1.0));
auto ft = FeatureType::CreateFromMapObject(emo);
EditableMapObject emo2;
emo2.SetFromFeatureType(*ft);
TEST(emo.GetTypes().Equals(emo2.GetTypes()), ());
TEST_EQUAL(emo.GetNameMultilang(), emo2.GetNameMultilang(), ());
TEST_EQUAL(emo.GetHouseNumber(), emo2.GetHouseNumber(), ());
TEST_EQUAL(emo.GetMercator(), emo2.GetMercator(), ());
TEST_EQUAL(emo.GetMetadata(feature::Metadata::FMD_WEBSITE), emo2.GetMetadata(feature::Metadata::FMD_WEBSITE), ());
TEST_EQUAL(emo.GetInternet(), emo2.GetInternet(), ());
TEST(emo.IsPointType(), ());
TEST(emo2.IsPointType(), ());
}
UNIT_TEST(EditableMapObject_GetLocalizedAllTypes)
{
classificator::Load();
{
EditableMapObject emo;
SetTypes(emo, {{"amenity", "fuel"}, {"shop"}, {"building"}, {"toilets", "yes"}});
TEST_EQUAL(emo.GetLocalizedAllTypes(true), "amenity-fuel • shop", ());
TEST_EQUAL(emo.GetLocalizedAllTypes(false), "shop", ());
}
{
EditableMapObject emo;
SetTypes(emo, {{"amenity", "shelter"}, {"amenity", "bench"}, {"highway", "bus_stop"}});
TEST_EQUAL(emo.GetLocalizedAllTypes(true), "highway-bus_stop • amenity-shelter • amenity-bench", ());
TEST_EQUAL(emo.GetLocalizedAllTypes(false), "amenity-shelter • amenity-bench", ());
}
{
EditableMapObject emo;
SetTypes(emo, {{"leisure", "pitch"}, {"sport", "soccer"}});
TEST_EQUAL(emo.GetLocalizedAllTypes(true), "sport-soccer • leisure-pitch", ());
TEST_EQUAL(emo.GetLocalizedAllTypes(false), "leisure-pitch", ());
}
{
EditableMapObject emo;
SetTypes(emo, {{"craft", "key_cutter"}});
TEST_EQUAL(emo.GetLocalizedAllTypes(true), "craft-key_cutter", ());
TEST_EQUAL(emo.GetLocalizedAllTypes(false), "", ());
}
{
EditableMapObject emo;
SetTypes(emo, {{"amenity", "parking_entrance"}, {"barrier", "gate"}});
TEST_EQUAL(emo.GetLocalizedAllTypes(true), "barrier-gate • amenity-parking_entrance", ());
TEST_EQUAL(emo.GetLocalizedAllTypes(false), "amenity-parking_entrance", ());
}
{
EditableMapObject emo;
SetTypes(emo, {{"barrier", "gate"}});
TEST_EQUAL(emo.GetLocalizedAllTypes(true), "barrier-gate", ());
TEST_EQUAL(emo.GetLocalizedAllTypes(false), "", ());
}
{
EditableMapObject emo;
SetTypes(emo, {{"entrance", "main"}});
TEST_EQUAL(emo.GetLocalizedAllTypes(true), "entrance-main", ());
TEST_EQUAL(emo.GetLocalizedAllTypes(false), "", ());
}
{
EditableMapObject emo;
SetTypes(emo, {{"entrance", "main"}, {"barrier", "gate"}});
TEST_EQUAL(emo.GetLocalizedAllTypes(true), "barrier-gate", ());
TEST_EQUAL(emo.GetLocalizedAllTypes(false), "", ());
}
{
EditableMapObject emo;
SetTypes(emo, {{"amenity"}});
TEST_EQUAL(emo.GetLocalizedAllTypes(true), "amenity", ());
TEST_EQUAL(emo.GetLocalizedAllTypes(false), "", ());
}
{
EditableMapObject emo;
SetTypes(emo, {{"shop"}});
TEST_EQUAL(emo.GetLocalizedAllTypes(true), "shop", ());
TEST_EQUAL(emo.GetLocalizedAllTypes(false), "", ());
}
{
EditableMapObject emo;
SetTypes(emo, {{"tourism", "artwork"}, {"amenity"}});
TEST_EQUAL(emo.GetLocalizedAllTypes(true), "tourism-artwork", ());
TEST_EQUAL(emo.GetLocalizedAllTypes(false), "", ());
}
}
} // namespace editable_map_object_test

View file

@ -0,0 +1,254 @@
#include "indexer/feature_charge_sockets.hpp"
#include "testing/testing.hpp"
namespace feature_charge_sockets_test
{
ChargeSocketsHelper FromKVs(OSMKeyValues const & kvs)
{
ChargeSocketsHelper helper;
for (auto const & kv : kvs)
helper.AggregateChargeSocketKey(kv.first, kv.second);
return helper;
}
UNIT_TEST(ChargeSockets_Processing)
{
///////////////////////////////////////////////////////////
// Internal model consistency
// valid socket lists
TEST_EQUAL(ChargeSocketsHelper("type2||").GetSockets().size(), 1, ());
TEST_EQUAL(ChargeSocketsHelper("type2|1|50;type2|2|43").GetSockets().size(), 2, ());
TEST_EQUAL(ChargeSocketsHelper("type2|1|50;type2|2|43;type1||").GetSockets().size(), 3, ());
TEST_EQUAL(ChargeSocketsHelper("type2||;type2_cable||;type2_combo||;type1||;nacs||;chademo||").GetSockets().size(), 6,
());
TEST_EQUAL(ChargeSocketsHelper("unknown|2|150").GetSockets().size(), 1, ());
TEST_EQUAL(ChargeSocketsHelper("||").GetSockets().size(), 1, ());
// invalid/partially valid socket lists
TEST_EQUAL(ChargeSocketsHelper("type2|").GetSockets().size(), 0, ());
TEST_EQUAL(ChargeSocketsHelper("type2|;|;|||;|45||").GetSockets().size(), 0, ());
TEST_EQUAL(ChargeSocketsHelper("type2|;type2_cable|1|50").GetSockets().size(), 1, ());
TEST(ChargeSocketsHelper("type2||").ToString() != "", ("ChargeSocketsHelper::ToString returned an empty string!"));
TEST_EQUAL(ChargeSocketsHelper("||").ToString(), "unknown||", ());
TEST_EQUAL(ChargeSocketsHelper("this_type_does_not_exist||").ToString(), "unknown||", ());
TEST_EQUAL(ChargeSocketsHelper("type2||").ToString(), "type2||", ());
TEST_EQUAL(ChargeSocketsHelper("type2|0|0").ToString(), "type2||", ());
TEST_EQUAL(ChargeSocketsHelper("type2||50").ToString(), "type2||50", ());
TEST_EQUAL(ChargeSocketsHelper("type2||7.4").ToString(), "type2||7.4", ());
TEST_EQUAL(ChargeSocketsHelper("type2|0|50").ToString(), "type2||50", ());
TEST_EQUAL(ChargeSocketsHelper("type2|1|50").ToString(), "type2|1|50", ());
TEST_EQUAL(ChargeSocketsHelper("unknown||").ToString(), "unknown||", ());
TEST_EQUAL(ChargeSocketsHelper("unknown||150").ToString(), "unknown||150", ());
TEST_EQUAL(ChargeSocketsHelper("type2|;type2_cable|1|50").ToString(), "type2_cable|1|50", ());
// sorting
TEST_EQUAL(ChargeSocketsHelper("type2||;type2_cable|1|50").ToString(), "type2_cable|1|50;type2||", ());
TEST_EQUAL(ChargeSocketsHelper("type2||;type2_cable||;||;type2_combo||").ToString(),
"type2_combo||;type2_cable||;type2||;unknown||", ());
// multiple sockets of same type, but different power
TEST_EQUAL(ChargeSocketsHelper("type2|1|50;type2|2|43").ToString(), "type2|1|50;type2|2|43", ());
// TEST_EQUAL(ChargeSocketsHelper("type2|1|43;type2|2|50").ToString(), "type2|1|50;type2|2|43", ());
///////////////////////////////////////////////////////////
// OSM key parsing
OSMKeyValues kvs;
kvs = {{"socket:type2", "2"}};
TEST_EQUAL(FromKVs(kvs).ToString(), "type2|2|", ());
kvs = {{"socket:type2", "yes"}};
TEST_EQUAL(FromKVs(kvs).ToString(), "type2||", ());
kvs = {{"socket:type2", "malformed"}};
TEST_EQUAL(FromKVs(kvs).ToString(), "", ());
kvs = {{"socket:type2:output", "22"}};
TEST_EQUAL(FromKVs(kvs).ToString(), "type2||22", ());
kvs = {{"socket:type2:malformed", "22"}};
TEST_EQUAL(FromKVs(kvs).ToString(), "", ());
kvs = {{"socket:type2", "malformed"}, {"socket:type2:output", "22 kW"}};
TEST_EQUAL(FromKVs(kvs).ToString(), "type2||22", ());
kvs = {{"socket:type2", "2"}, {"socket:type2:output", "22 kW"}};
TEST_EQUAL(FromKVs(kvs).ToString(), "type2|2|22", ());
kvs = {{"socket:type2", "2"}, {"socket:type2:output", "22kW"}};
TEST_EQUAL(FromKVs(kvs).ToString(), "type2|2|22", ());
kvs = {{"socket:type2", "2"}, {"socket:type2:output", "22KW"}};
TEST_EQUAL(FromKVs(kvs).ToString(), "type2|2|22", ());
kvs = {{"socket:type2", "2"}, {"socket:type2:output", "22"}};
TEST_EQUAL(FromKVs(kvs).ToString(), "type2|2|22", ());
kvs = {{"socket:chademo", "2"}, {"socket:chademo:output", "50"},
{"socket:type2_combo", "10"}, {"socket:type2_combo:output", "200"},
{"socket:type2_cable", "2"}, {"socket:type2_cable:output", "50"}};
TEST_EQUAL(FromKVs(kvs).ToString(), "type2_combo|10|200;chademo|2|50;type2_cable|2|50", ());
// unit conversion
kvs = {{"socket:type2:output", "7400W"}};
TEST_EQUAL(FromKVs(kvs).ToString(), "type2||7.4", ());
kvs = {{"socket:type2_combo:output", "150 kw"}};
TEST_EQUAL(FromKVs(kvs).ToString(), "type2_combo||150", ());
kvs = {{"socket:type2_combo:output", "150 KW"}};
TEST_EQUAL(FromKVs(kvs).ToString(), "type2_combo||150", ());
kvs = {{"socket:type2_combo:output", " 150kw"}};
TEST_EQUAL(FromKVs(kvs).ToString(), "type2_combo||150", ());
kvs = {{"socket:type2_combo:output", "150kva"}};
TEST_EQUAL(FromKVs(kvs).ToString(), "type2_combo||150", ());
kvs = {{"socket:type2_combo:output", "0.150MW"}};
TEST_EQUAL(FromKVs(kvs).ToString(), "type2_combo||150", ());
kvs = {{"socket:type2_combo:output", ".150MW"}};
TEST_EQUAL(FromKVs(kvs).ToString(), "type2_combo||150", ());
// invalid
kvs = {{"socket:type2", "-1"}};
TEST_EQUAL(FromKVs(kvs).GetSockets().size(), 0, ());
kvs = {{"socket:type2", "-2"}};
TEST_EQUAL(FromKVs(kvs).GetSockets().size(), 0, ());
kvs = {{"socket:type2", "-2"}, {"socket:type2:output", "-50"}};
TEST_EQUAL(FromKVs(kvs).GetSockets().size(), 0, ());
// count ignored (because invalid), but power valid
kvs = {{"socket:type2", "-2"}, {"socket:type2:output", "50"}};
TEST_EQUAL(FromKVs(kvs).ToString(), "type2||50", ());
// normalization
kvs = {{"socket:tesla_supercharger", "2"}, {"socket:tesla_supercharger:output", "150"}};
TEST_EQUAL(FromKVs(kvs).ToString(), "nacs|2|150", ());
kvs = {{"socket:ccs", "2"}, {"socket:ccs:output", "150"}};
TEST_EQUAL(FromKVs(kvs).ToString(), "type2_combo|2|150", ());
// multiple socket of same type
kvs = {{"socket:type2", "2;3"}, {"socket:type2:output", "50;43"}};
TEST_EQUAL(FromKVs(kvs).ToString(), "type2|2|50;type2|3|43", ());
kvs = {{"socket:type2:output", "50;43"}, {"socket:type2", "2;3"}};
TEST_EQUAL(FromKVs(kvs).ToString(), "type2|2|50;type2|3|43", ());
kvs = {{"socket:type2", "2;3"}, {"socket:type2:output", "43;50"}};
TEST_EQUAL(FromKVs(kvs).ToString(), "type2|3|50;type2|2|43", ());
kvs = {{"socket:type2", "2;3;5"}, {"socket:type2:output", "43;50;7.4"}};
TEST_EQUAL(FromKVs(kvs).ToString(), "type2|3|50;type2|2|43;type2|5|7.4", ());
kvs = {{"socket:type2", "2;3"}, {"socket:type2:output", "50 kW; 43 kw"}};
TEST_EQUAL(FromKVs(kvs).ToString(), "type2|2|50;type2|3|43", ());
// unbalanced multiple sockets
kvs = {{"socket:type2", "2"}, {"socket:type2:output", "50 kW; 43 kw"}};
TEST_EQUAL(FromKVs(kvs).ToString(), "type2|2|50;type2||43", ());
kvs = {{"socket:type2", "2;"}, {"socket:type2:output", "50 kW; 43 kw"}};
TEST_EQUAL(FromKVs(kvs).ToString(), "type2|2|50;type2||43", ());
kvs = {{"socket:type2", "2;3"}, {"socket:type2:output", "50 kW"}};
TEST_EQUAL(FromKVs(kvs).ToString(), "type2|2|50;type2|3|", ());
///////////////////////////////////////////////////////////
// OSM key generation
kvs = {{"socket:type2", "2"}};
TEST_EQUAL(ChargeSocketsHelper("type2|2|").GetOSMKeyValues(), kvs, ());
TEST_EQUAL(ChargeSocketsHelper("type2|2|0").GetOSMKeyValues(), kvs, ());
kvs = {{"socket:type2", "yes"}};
TEST_EQUAL(ChargeSocketsHelper("type2||").GetOSMKeyValues(), kvs, ());
TEST_EQUAL(ChargeSocketsHelper("type2|0|").GetOSMKeyValues(), kvs, ());
kvs = {{"socket:type2", "yes"}, {"socket:type2:output", "150"}};
TEST_EQUAL(ChargeSocketsHelper("type2||150").GetOSMKeyValues(), kvs, ());
// the order should always be the same, as the sockets are sorted
kvs = {{"socket:type2_combo", "10"}, {"socket:type2_combo:output", "200"}, {"socket:chademo", "2"},
{"socket:chademo:output", "50"}, {"socket:type2_cable", "2"}, {"socket:type2_cable:output", "50"}};
TEST_EQUAL(ChargeSocketsHelper("type2_combo|10|200;chademo|2|50;type2_cable|2|50").GetOSMKeyValues(), kvs, ());
TEST_EQUAL(ChargeSocketsHelper("chademo|2|50;type2_cable|2|50;type2_combo|10|200").GetOSMKeyValues(), kvs, ());
// multiple socket of same type
// (should always be ordered from higher power to lower)
kvs = {{"socket:type2", "2;3"}, {"socket:type2:output", "50;43"}};
TEST_EQUAL(ChargeSocketsHelper("type2|2|50;type2|3|43").GetOSMKeyValues(), kvs, ());
kvs = {{"socket:type2", "3;2"}, {"socket:type2:output", "50;43"}};
TEST_EQUAL(ChargeSocketsHelper("type2|2|43;type2|3|50").GetOSMKeyValues(), kvs, ());
kvs = {{"socket:type2", "2;3;5"}, {"socket:type2:output", "50;43;7.4"}};
TEST_EQUAL(ChargeSocketsHelper("type2|3|43;type2|5|7.4;type2|2|50").GetOSMKeyValues(), kvs, ());
kvs = {{"socket:type2_combo", "10;2"},
{"socket:type2_combo:output", "250;100"},
{"socket:type2", "2;3;5"},
{"socket:type2:output", "50;43;7.4"}};
TEST_EQUAL(
ChargeSocketsHelper("type2|3|43;type2|5|7.4;type2_combo|10|250;type2|2|50;type2_combo|2|100").GetOSMKeyValues(),
kvs, ());
///////////////////////////////////////////////////////////
// OSM attribute diff
OSMKeyValues kvs_old, kvs_new;
KeyValueDiffSet diff;
kvs_old = {{"socket:type2", "2"}};
kvs_new = {{"socket:type2", "2"}};
diff = {};
TEST_EQUAL(FromKVs(kvs_new).Diff(FromKVs(kvs_old).GetSockets()), diff, ());
kvs_old = {{"socket:type2", "3"}};
kvs_new = {{"socket:type2", "2"}};
diff = {{"socket:type2", "3", "2"}};
TEST_EQUAL(FromKVs(kvs_new).Diff(FromKVs(kvs_old).GetSockets()), diff, ());
kvs_old = {{"socket:type2", "2"}};
kvs_new = {{"socket:type2", "3"}};
diff = {{"socket:type2", "2", "3"}};
TEST_EQUAL(FromKVs(kvs_new).Diff(FromKVs(kvs_old).GetSockets()), diff, ());
kvs_old = {};
kvs_new = {{"socket:type2", "2"}};
diff = {{"socket:type2", "", "2"}};
TEST_EQUAL(FromKVs(kvs_new).Diff(FromKVs(kvs_old).GetSockets()), diff, ());
kvs_old = {{"socket:type2", "2"}};
kvs_new = {};
diff = {{"socket:type2", "2", ""}};
TEST_EQUAL(FromKVs(kvs_new).Diff(FromKVs(kvs_old).GetSockets()), diff, ());
kvs_old = {{"socket:type2_combo", "10;2"},
{"socket:type2_combo:output", "250;100"},
{"socket:type1", "5"},
{"socket:type2", "2;3;5"},
{"socket:type2:output", "50;43;7.4"}};
kvs_new = {{"socket:type2_combo", "10;2"},
{"socket:type2_combo:output", "250;100"},
{"socket:chademo", "2"},
{"socket:type2", "2;3"},
{"socket:type2:output", "50;43"}};
diff = {{"socket:type1", "5", ""},
{"socket:type2", "2;3;5", "2;3"},
{"socket:type2:output", "50;43;7.4", "50;43"},
{"socket:chademo", "", "2"}};
TEST_EQUAL(FromKVs(kvs_new).Diff(FromKVs(kvs_old).GetSockets()), diff, ());
}
} // namespace feature_charge_sockets_test

View file

@ -0,0 +1,131 @@
#include "testing/testing.hpp"
#include "indexer/feature_meta.hpp"
#include "coding/reader.hpp"
#include "coding/writer.hpp"
#include <map>
#include <string>
#include <vector>
namespace feature_metadata_test
{
using namespace std;
using feature::Metadata;
using EType = Metadata::EType;
map<EType, string> const kKeyValues = {{EType::FMD_ELE, "12345"},
{EType::FMD_EMAIL, "cool@email.at"},
// This string is longer than 255 bytes.
{EType::FMD_WEBSITE,
"http://rskxmkjwnikfnjqhyvkpjgaghhyhukjyenduiuanxgbmndtlpfphdgaizfcpzuiuspcp"
"umeojwvekvjprlutwjmxudyzrlwwsepewevsuqelobqcfdzsoqozkesghojribepbaitivmaqep"
"hheckitonddqhbapdybhetvnwvlchjafepdjaeoaapysdvculxuwjbgdddryodiihvnpvmkgqvs"
"mawbdsrbmnndcozmrgeoahbkhcevxkmtdqnxpxlsju.org"}};
UNIT_TEST(Feature_Metadata_GetSet)
{
Metadata m;
EType const type = EType::FMD_ELE;
// Absent types should return empty values.
TEST_EQUAL(m.Get(type), "", ());
m.Set(type, "12345");
TEST_EQUAL(m.Get(type), "12345", ());
TEST_EQUAL(m.Size(), 1, ());
// Same types should replace old metadata values.
m.Set(type, "9876543210");
TEST_EQUAL(m.Get(type), "9876543210", ());
// Empty values should drop fields.
m.Set(type, "");
TEST_EQUAL(m.Get(type), "", ());
TEST_EQUAL(m.Size(), 0, ());
TEST(m.Empty(), ());
}
UNIT_TEST(Feature_Metadata_PresentTypes)
{
Metadata m;
for (auto const & value : kKeyValues)
m.Set(value.first, value.second);
TEST_EQUAL(m.Size(), kKeyValues.size(), ());
m.ForEach([&](Metadata::EType type, std::string const &)
{ TEST_EQUAL(m.Get(type), kKeyValues.find(type)->second, ()); });
}
UNIT_TEST(Feature_Metadata_MwmTmpSerialization)
{
Metadata original;
for (auto const & value : kKeyValues)
original.Set(value.first, value.second);
TEST_EQUAL(original.Size(), kKeyValues.size(), ());
{
Metadata serialized;
vector<char> buffer;
MemWriter<decltype(buffer)> writer(buffer);
original.SerializeForMwmTmp(writer);
MemReader reader(buffer.data(), buffer.size());
ReaderSource<MemReader> src(reader);
serialized.DeserializeFromMwmTmp(src);
for (auto const & value : kKeyValues)
TEST_EQUAL(serialized.Get(value.first), value.second, ());
TEST_EQUAL(serialized.Get(EType::FMD_OPERATOR), "", ());
TEST_EQUAL(serialized.Size(), kKeyValues.size(), ());
}
}
UNIT_TEST(Feature_Metadata_GetWikipedia)
{
Metadata m;
EType const wikiType = EType::FMD_WIKIPEDIA;
m.Set(wikiType, "en:Article");
TEST_EQUAL(m.Get(wikiType), "en:Article", ());
#ifdef OMIM_OS_MOBILE
TEST_EQUAL(m.GetWikiURL(), "https://en.m.wikipedia.org/wiki/Article", ());
#else
TEST_EQUAL(m.GetWikiURL(), "https://en.wikipedia.org/wiki/Article", ());
#endif
}
UNIT_TEST(Feature_Metadata_RegionData_Languages)
{
{
feature::RegionData rd;
vector<string> const langs = {"ru", "en", "et"};
rd.SetLanguages(langs);
TEST(rd.HasLanguage(StringUtf8Multilang::GetLangIndex("ru")), ());
TEST(rd.HasLanguage(StringUtf8Multilang::GetLangIndex("en")), ());
TEST(rd.HasLanguage(StringUtf8Multilang::GetLangIndex("et")), ());
TEST(!rd.HasLanguage(StringUtf8Multilang::GetLangIndex("es")), ());
TEST(!rd.IsSingleLanguage(StringUtf8Multilang::GetLangIndex("ru")), ());
}
{
feature::RegionData rd;
vector<string> const langs = {"et"};
rd.SetLanguages(langs);
TEST(rd.HasLanguage(StringUtf8Multilang::GetLangIndex("et")), ());
TEST(rd.IsSingleLanguage(StringUtf8Multilang::GetLangIndex("et")), ());
TEST(!rd.HasLanguage(StringUtf8Multilang::GetLangIndex("en")), ());
TEST(!rd.IsSingleLanguage(StringUtf8Multilang::GetLangIndex("en")), ());
}
}
UNIT_TEST(Feature_Metadata_Print)
{
StringUtf8Multilang s;
s.AddString("en", "English");
s.AddString("be", "Беларуская");
Metadata m;
m.Set(EType::FMD_DESCRIPTION, s.GetBuffer());
TEST_EQUAL(DebugPrint(m), "Metadata [description=" + DebugPrint(s) + "]", ());
}
} // namespace feature_metadata_test

View file

@ -0,0 +1,563 @@
#include "testing/testing.hpp"
#include "indexer/feature_meta.hpp"
#include "indexer/feature_utils.hpp"
#include "coding/string_utf8_multilang.hpp"
#include <string>
namespace feature_names_test
{
using namespace std;
using StrUtf8 = StringUtf8Multilang;
void GetPreferredNames(feature::RegionData const & regionData, StrUtf8 const & src, int8_t deviceLang,
bool allowTranslit, std::string & primary, std::string & secondary)
{
feature::NameParamsIn in{src, regionData, deviceLang, allowTranslit};
feature::NameParamsOut out;
feature::GetPreferredNames(in, out);
primary = out.GetPrimary();
secondary = out.secondary;
}
UNIT_TEST(GetPrefferedNames)
{
feature::RegionData regionData;
regionData.SetLanguages({"de", "ko"});
int8_t deviceLang = StrUtf8::GetLangIndex("ru");
string primary, secondary;
bool const allowTranslit = false;
{
StrUtf8 src;
src.AddString("fr", "fr name");
GetPreferredNames(regionData, src, deviceLang, allowTranslit, primary, secondary);
TEST_EQUAL(primary, "", ());
TEST_EQUAL(secondary, "", ());
}
{
StrUtf8 src;
src.AddString("default", "default name");
GetPreferredNames(regionData, src, deviceLang, allowTranslit, primary, secondary);
TEST_EQUAL(primary, "default name", ());
TEST_EQUAL(secondary, "", ());
}
{
StrUtf8 src;
src.AddString("default", "default name");
src.AddString("en", "en name");
GetPreferredNames(regionData, src, deviceLang, allowTranslit, primary, secondary);
TEST_EQUAL(primary, "en name", ());
TEST_EQUAL(secondary, "default name", ());
}
{
StrUtf8 src;
src.AddString("default", "default name");
src.AddString("en", "en name");
src.AddString("ru", "ru name");
GetPreferredNames(regionData, src, deviceLang, allowTranslit, primary, secondary);
TEST_EQUAL(primary, "ru name", ());
TEST_EQUAL(secondary, "default name", ());
}
{
StrUtf8 src;
src.AddString("default", "same name");
src.AddString("en", "en name");
src.AddString("ru", "same name");
src.AddString("int_name", "int name");
GetPreferredNames(regionData, src, deviceLang, allowTranslit, primary, secondary);
TEST_EQUAL(primary, "same name", ());
TEST_EQUAL(secondary, "", ());
}
{
StrUtf8 src;
src.AddString("default", "default name");
src.AddString("en", "en name");
src.AddString("ru", "ru name");
src.AddString("int_name", "int name");
src.AddString("de", "de name");
GetPreferredNames(regionData, src, deviceLang, allowTranslit, primary, secondary);
TEST_EQUAL(primary, "ru name", ());
TEST_EQUAL(secondary, "default name", ());
}
{
StrUtf8 src;
src.AddString("default", "default name");
src.AddString("en", "en name");
src.AddString("ru", "ru name");
src.AddString("int_name", "int name");
src.AddString("de", "de name");
src.AddString("ko", "ko name");
GetPreferredNames(regionData, src, deviceLang, allowTranslit, primary, secondary);
TEST_EQUAL(primary, "ru name", ());
TEST_EQUAL(secondary, "default name", ());
}
{
StrUtf8 src;
src.AddString("default", "default name");
src.AddString("en", "en name");
src.AddString("int_name", "int name");
src.AddString("de", "de name");
src.AddString("ko", "ko name");
GetPreferredNames(regionData, src, deviceLang, allowTranslit, primary, secondary);
TEST_EQUAL(primary, "int name", ());
TEST_EQUAL(secondary, "default name", ());
}
{
StrUtf8 src;
src.AddString("en", "en name");
src.AddString("int_name", "int name");
src.AddString("de", "de name");
src.AddString("ko", "ko name");
GetPreferredNames(regionData, src, deviceLang, allowTranslit, primary, secondary);
TEST_EQUAL(primary, "int name", ());
TEST_EQUAL(secondary, "", ());
}
{
StrUtf8 src;
src.AddString("en", "en name");
src.AddString("de", "de name");
src.AddString("ko", "ko name");
GetPreferredNames(regionData, src, deviceLang, allowTranslit, primary, secondary);
TEST_EQUAL(primary, "en name", ());
TEST_EQUAL(secondary, "de name", ());
}
{
StrUtf8 src;
src.AddString("en", "en name");
src.AddString("ko", "ko name");
GetPreferredNames(regionData, src, deviceLang, allowTranslit, primary, secondary);
TEST_EQUAL(primary, "en name", ());
TEST_EQUAL(secondary, "ko name", ());
}
{
StrUtf8 src;
src.AddString("en", "en name");
GetPreferredNames(regionData, src, deviceLang, allowTranslit, primary, secondary);
TEST_EQUAL(primary, "en name", ());
TEST_EQUAL(secondary, "", ());
}
{
int8_t deviceLang = StrUtf8::GetLangIndex("be");
StrUtf8 src;
src.AddString("int_name", "int name");
src.AddString("en", "en name");
src.AddString("ru", "ru name");
GetPreferredNames(regionData, src, deviceLang, allowTranslit, primary, secondary);
TEST_EQUAL(primary, "ru name", ());
TEST_EQUAL(secondary, "int name", ());
}
{
feature::RegionData regionData;
regionData.SetLanguages({"ru"});
int8_t deviceLang = StrUtf8::GetLangIndex("be");
StrUtf8 src;
src.AddString("int_name", "int name");
src.AddString("en", "en name");
src.AddString("ru", "ru name");
GetPreferredNames(regionData, src, deviceLang, allowTranslit, primary, secondary);
TEST_EQUAL(primary, "ru name", ());
TEST_EQUAL(secondary, "", ());
}
{
feature::RegionData regionData;
regionData.SetLanguages({"ru"});
int8_t deviceLang = StrUtf8::GetLangIndex("be");
StrUtf8 src;
src.AddString("default", "default name");
src.AddString("int_name", "int name");
src.AddString("en", "en name");
src.AddString("ru", "ru name");
GetPreferredNames(regionData, src, deviceLang, allowTranslit, primary, secondary);
TEST_EQUAL(primary, "default name", ());
TEST_EQUAL(secondary, "", ());
}
{
feature::RegionData regionData;
regionData.SetLanguages({"ru"});
int8_t deviceLang = StrUtf8::GetLangIndex("ru");
StrUtf8 src;
src.AddString("default", "default name");
src.AddString("int_name", "int name");
src.AddString("en", "en name");
src.AddString("be", "be name");
GetPreferredNames(regionData, src, deviceLang, allowTranslit, primary, secondary);
TEST_EQUAL(primary, "default name", ());
TEST_EQUAL(secondary, "", ());
}
}
UNIT_TEST(GetPrefferedNamesLocal)
{
string primary, secondary;
bool const allowTranslit = true;
{
feature::RegionData regionData;
regionData.SetLanguages({"kk", "ru"});
int8_t deviceLang = StrUtf8::GetLangIndex("ru");
StrUtf8 src;
src.AddString("default", "default name");
src.AddString("en", "en name");
GetPreferredNames(regionData, src, deviceLang, allowTranslit, primary, secondary);
TEST_EQUAL(primary, "default name", ());
TEST_EQUAL(secondary, "", ());
}
{
feature::RegionData regionData;
regionData.SetLanguages({"kk", "be"});
int8_t deviceLang = StrUtf8::GetLangIndex("be");
StrUtf8 src;
src.AddString("int_name", "int name");
src.AddString("en", "en name");
src.AddString("ru", "ru name");
GetPreferredNames(regionData, src, deviceLang, allowTranslit, primary, secondary);
TEST_EQUAL(primary, "ru name", ());
TEST_EQUAL(secondary, "", ());
}
{
feature::RegionData regionData;
regionData.SetLanguages({"kk", "ru"});
int8_t deviceLang = StrUtf8::GetLangIndex("ru");
StrUtf8 src;
src.AddString("int_name", "int name");
src.AddString("en", "en name");
src.AddString("be", "be name");
GetPreferredNames(regionData, src, deviceLang, allowTranslit, primary, secondary);
TEST_EQUAL(primary, "int name", ());
TEST_EQUAL(secondary, "", ());
}
}
void GetReadableName(feature::RegionData const & regionData, StrUtf8 const & src, int8_t deviceLang, bool allowTranslit,
std::string & name)
{
feature::NameParamsIn in{src, regionData, deviceLang, allowTranslit};
feature::NameParamsOut out;
feature::GetPreferredNames(in, out);
name = out.GetPrimary();
}
UNIT_TEST(GetReadableName)
{
feature::RegionData regionData;
regionData.SetLanguages({"de", "ko"});
int8_t deviceLang = StrUtf8::GetLangIndex("ru");
bool const allowTranslit = false;
string name;
{
StrUtf8 src;
src.AddString("fr", "fr name");
GetReadableName(regionData, src, deviceLang, allowTranslit, name);
TEST_EQUAL(name, "", ());
}
{
StrUtf8 src;
src.AddString("ko", "ko name");
GetReadableName(regionData, src, deviceLang, allowTranslit, name);
TEST_EQUAL(name, "ko name", ());
}
{
StrUtf8 src;
src.AddString("ko", "ko name");
src.AddString("de", "de name");
GetReadableName(regionData, src, deviceLang, allowTranslit, name);
TEST_EQUAL(name, "de name", ());
}
{
StrUtf8 src;
src.AddString("ko", "ko name");
src.AddString("de", "de name");
src.AddString("default", "default name");
GetReadableName(regionData, src, deviceLang, allowTranslit, name);
TEST_EQUAL(name, "default name", ());
}
{
StrUtf8 src;
src.AddString("ko", "ko name");
src.AddString("de", "de name");
src.AddString("default", "default name");
src.AddString("en", "en name");
GetReadableName(regionData, src, deviceLang, allowTranslit, name);
TEST_EQUAL(name, "en name", ());
}
{
StrUtf8 src;
src.AddString("ko", "ko name");
src.AddString("de", "de name");
src.AddString("default", "default name");
src.AddString("en", "en name");
src.AddString("int_name", "int name");
GetReadableName(regionData, src, deviceLang, allowTranslit, name);
TEST_EQUAL(name, "int name", ());
}
{
StrUtf8 src;
src.AddString("ko", "ko name");
src.AddString("de", "de name");
src.AddString("default", "default name");
src.AddString("en", "en name");
src.AddString("int_name", "int name");
src.AddString("ru", "ru name");
GetReadableName(regionData, src, deviceLang, allowTranslit, name);
TEST_EQUAL(name, "ru name", ());
}
deviceLang = StrUtf8::GetLangIndex("de");
{
StrUtf8 src;
src.AddString("ko", "ko name");
src.AddString("de", "de name");
src.AddString("default", "default name");
src.AddString("en", "en name");
src.AddString("int_name", "int name");
GetReadableName(regionData, src, deviceLang, allowTranslit, name);
TEST_EQUAL(name, "de name", ());
}
{
StrUtf8 src;
src.AddString("ko", "ko name");
src.AddString("default", "default name");
src.AddString("en", "en name");
src.AddString("int_name", "int name");
GetReadableName(regionData, src, deviceLang, allowTranslit, name);
TEST_EQUAL(name, "default name", ());
}
{
StrUtf8 src;
src.AddString("ko", "ko name");
src.AddString("en", "en name");
src.AddString("int_name", "int name");
GetReadableName(regionData, src, deviceLang, allowTranslit, name);
TEST_EQUAL(name, "int name", ());
}
{
StrUtf8 src;
src.AddString("ko", "ko name");
src.AddString("en", "en name");
GetReadableName(regionData, src, deviceLang, allowTranslit, name);
TEST_EQUAL(name, "en name", ());
}
{
StrUtf8 src;
src.AddString("ko", "ko name");
GetReadableName(regionData, src, deviceLang, allowTranslit, name);
TEST_EQUAL(name, "ko name", ());
}
{
int8_t deviceLang = StrUtf8::GetLangIndex("be");
StrUtf8 src;
src.AddString("int_name", "int name");
src.AddString("en", "en name");
src.AddString("ru", "ru name");
GetReadableName(regionData, src, deviceLang, allowTranslit, name);
TEST_EQUAL(name, "ru name", ());
}
{
feature::RegionData regionData;
regionData.SetLanguages({"ru"});
int8_t deviceLang = StrUtf8::GetLangIndex("be");
StrUtf8 src;
src.AddString("default", "default name");
src.AddString("int_name", "int name");
src.AddString("en", "en name");
src.AddString("ru", "ru name");
GetReadableName(regionData, src, deviceLang, allowTranslit, name);
TEST_EQUAL(name, "default name", ());
}
{
feature::RegionData regionData;
regionData.SetLanguages({"ru"});
int8_t deviceLang = StrUtf8::GetLangIndex("ru");
StrUtf8 src;
src.AddString("default", "default name");
src.AddString("int_name", "int name");
src.AddString("en", "en name");
src.AddString("be", "be name");
GetReadableName(regionData, src, deviceLang, allowTranslit, name);
TEST_EQUAL(name, "default name", ());
}
{
feature::RegionData regionData;
regionData.SetLanguages({"ru"});
int8_t deviceLang = StrUtf8::GetLangIndex("ru");
StrUtf8 src;
src.AddString("en", "en name");
src.AddString("be", "be name");
GetReadableName(regionData, src, deviceLang, allowTranslit, name);
TEST_EQUAL(name, "en name", ());
}
}
/*
UNIT_TEST(GetNameForSearchOnBooking)
{
{
StrUtf8 src;
feature::RegionData regionData;
string result;
auto lang = feature::GetNameForSearchOnBooking(regionData, src, result);
TEST_EQUAL(lang, StrUtf8::kUnsupportedLanguageCode, ());
TEST(result.empty(), ());
}
{
StrUtf8 src;
src.AddString("default", "default name");
feature::RegionData regionData;
string result;
auto lang = feature::GetNameForSearchOnBooking(regionData, src, result);
TEST_EQUAL(lang, StrUtf8::kDefaultCode, ());
TEST_EQUAL(result, "default name", ());
}
{
StrUtf8 src;
src.AddString("default", "default name");
src.AddString("ko", "ko name");
src.AddString("en", "en name");
feature::RegionData regionData;
regionData.SetLanguages({"ko", "en"});
string result;
auto lang = feature::GetNameForSearchOnBooking(regionData, src, result);
TEST_EQUAL(lang, StrUtf8::kDefaultCode, ());
TEST_EQUAL(result, "default name", ());
}
{
StrUtf8 src;
src.AddString("en", "en name");
src.AddString("ko", "ko name");
feature::RegionData regionData;
regionData.SetLanguages({"ko"});
string result;
auto lang = feature::GetNameForSearchOnBooking(regionData, src, result);
TEST_EQUAL(lang, StrUtf8::GetLangIndex("ko"), ());
TEST_EQUAL(result, "ko name", ());
}
{
StrUtf8 src;
src.AddString("en", "en name");
src.AddString("ko", "ko name");
src.AddString("de", "de name");
feature::RegionData regionData;
regionData.SetLanguages({"de", "ko"});
string result;
auto lang = feature::GetNameForSearchOnBooking(regionData, src, result);
TEST_EQUAL(lang, StrUtf8::GetLangIndex("de"), ());
TEST_EQUAL(result, "de name", ());
}
{
StrUtf8 src;
src.AddString("en", "en name");
src.AddString("ko", "ko name");
feature::RegionData regionData;
regionData.SetLanguages({"de", "fr"});
string result;
auto lang = feature::GetNameForSearchOnBooking(regionData, src, result);
TEST_EQUAL(lang, StrUtf8::GetLangIndex("en"), ());
TEST_EQUAL(result, "en name", ());
}
}
*/
} // namespace feature_names_test

View file

@ -0,0 +1,110 @@
#include "testing/testing.hpp"
#include "generator/generator_tests_support/test_with_custom_mwms.hpp"
#include "indexer/feature_decl.hpp"
#include "indexer/feature_to_osm.hpp"
#include "coding/file_writer.hpp"
#include "coding/reader.hpp"
#include "coding/writer.hpp"
#include "base/geo_object_id.hpp"
#include "base/macros.hpp"
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <string>
#include <utility>
#include <vector>
#include "defines.hpp"
namespace feature_to_osm_tests
{
using namespace indexer;
using namespace generator::tests_support;
using Entries = std::vector<std::pair<uint32_t, base::GeoObjectId>>;
template <typename Cont>
Entries GetEntries(Cont const & cont)
{
Entries res;
cont.ForEachEntry([&res](uint32_t const fid, base::GeoObjectId const & gid)
{ res.emplace_back(std::make_pair(fid, gid)); });
std::sort(res.begin(), res.end());
return res;
}
class FeatureIdToGeoObjectIdTest : public TestWithCustomMwms
{
public:
DataSource const & GetDataSource() const { return m_dataSource; }
};
UNIT_CLASS_TEST(FeatureIdToGeoObjectIdTest, Smoke)
{
Entries const kEntries = {
{0, base::MakeOsmNode(123)},
{1, base::MakeOsmWay(456)},
{2, base::MakeOsmRelation(789)},
};
FeatureIdToGeoObjectIdBimapMem origM;
for (auto const & e : kEntries)
origM.Add(e.first, e.second);
// TestMwmBuilder will create the section but we will rewrite it right away.
auto testWorldId = BuildWorld([&](TestMwmBuilder & builder) {});
auto const testWorldPath = testWorldId.GetInfo()->GetLocalFile().GetPath(MapFileType::Map);
std::vector<uint8_t> buf;
{
MemWriter<decltype(buf)> writer(buf);
FeatureIdToGeoObjectIdSerDes::Serialize(writer, origM);
}
{
FilesContainerW writer(testWorldPath, FileWriter::OP_WRITE_EXISTING);
writer.Write(buf, FEATURE_TO_OSM_FILE_TAG);
}
FeatureIdToGeoObjectIdBimapMem deserMem;
{
MemReader reader(buf.data(), buf.size());
FeatureIdToGeoObjectIdSerDes::Deserialize(reader, deserMem);
}
indexer::FeatureIdToGeoObjectIdOneWay deserOneWay(GetDataSource());
TEST(deserOneWay.Load(), ());
indexer::FeatureIdToGeoObjectIdTwoWay deserTwoWay(GetDataSource());
TEST(deserTwoWay.Load(), ());
Entries actualEntriesMem = GetEntries(deserMem);
Entries actualEntriesOneWay = GetEntries(deserOneWay);
Entries actualEntriesTwoWay = GetEntries(deserTwoWay);
TEST_EQUAL(kEntries, actualEntriesMem, ());
TEST_EQUAL(kEntries, actualEntriesOneWay, ());
TEST_EQUAL(kEntries, actualEntriesTwoWay, ());
for (auto const & entry : kEntries)
{
base::GeoObjectId gid;
TEST(deserOneWay.GetGeoObjectId(FeatureID(testWorldId, entry.first), gid), ());
TEST_EQUAL(entry.second, gid, ());
TEST(deserTwoWay.GetGeoObjectId(FeatureID(testWorldId, entry.first), gid), ());
TEST_EQUAL(entry.second, gid, ());
}
for (auto const & entry : kEntries)
{
FeatureID fid;
TEST(deserTwoWay.GetFeatureID(entry.second, fid), ());
TEST_EQUAL(entry.first, fid.m_index, ());
}
}
} // namespace feature_to_osm_tests

View file

@ -0,0 +1,140 @@
#include "testing/testing.hpp"
#include "indexer/classificator.hpp"
#include "indexer/classificator_loader.hpp"
#include "indexer/feature_data.hpp"
namespace feature_types_test
{
feature::TypesHolder MakeTypesHolder(std::initializer_list<base::StringIL> const & arr, bool sortBySpec = true,
feature::GeomType geomType = feature::GeomType::Point)
{
auto const & cl = classif();
feature::TypesHolder types(geomType);
for (auto const & t : arr)
types.Add(cl.GetTypeByPath(t));
if (sortBySpec)
types.SortBySpec();
else
types.SortByUseless();
return types;
}
UNIT_TEST(Feature_UselessTypes)
{
/// @todo Take out TestWithClassificator into some common test support lib.
classificator::Load();
auto const & cl = classif();
{
feature::TypesHolder types = MakeTypesHolder(
{
{"wheelchair", "yes"},
{"building", "train_station"},
},
false /* sortBySpec */);
TEST_EQUAL(types.front(), cl.GetTypeByPath({"building", "train_station"}), ());
}
{
feature::TypesHolder types = MakeTypesHolder(
{
{"hwtag", "lit"},
{"hwtag", "oneway"},
},
false /* sortBySpec */);
TEST_EQUAL(types.front(), cl.GetTypeByPath({"hwtag", "oneway"}), ());
}
}
UNIT_TEST(Feature_TypesPriority)
{
/// @todo Take out TestWithClassificator into some common test support lib.
classificator::Load();
auto const & cl = classif();
{
feature::TypesHolder types = MakeTypesHolder({
{"wheelchair", "yes"},
{"building", "train_station"},
});
TEST_EQUAL(types.front(), cl.GetTypeByPath({"building", "train_station"}), ());
}
/// @todo post_office should be bigger than copyshop.
// {
// feature::TypesHolder types = MakeTypesHolder({
// {"shop", "copyshop"},
// {"amenity", "post_office"},
// });
// TEST_EQUAL(types.front(), cl.GetTypeByPath({"amenity", "post_office"}), ());
// }
{
feature::TypesHolder types = MakeTypesHolder({
{"internet_access", "wlan"},
{"amenity", "compressed_air"},
{"amenity", "fuel"},
});
TEST_EQUAL(types.front(), cl.GetTypeByPath({"amenity", "fuel"}), ());
}
{
feature::TypesHolder types = MakeTypesHolder({
{"leisure", "pitch"},
{"sport", "soccer"},
});
TEST_EQUAL(types.front(), cl.GetTypeByPath({"sport", "soccer"}), ());
}
{
feature::TypesHolder types = MakeTypesHolder({
{"amenity", "shelter"},
{"highway", "bus_stop"},
});
TEST_EQUAL(types.front(), cl.GetTypeByPath({"highway", "bus_stop"}), ());
}
{
feature::TypesHolder types = MakeTypesHolder({
{"amenity", "toilets"},
{"amenity", "community_centre"},
});
TEST_EQUAL(types.front(), cl.GetTypeByPath({"amenity", "community_centre"}), ());
}
{
feature::TypesHolder types = MakeTypesHolder({
{"highway", "elevator"},
{"emergency", "defibrillator"},
{"railway", "subway_entrance"},
});
TEST_EQUAL(types.front(), cl.GetTypeByPath({"railway", "subway_entrance"}), ());
}
{
feature::TypesHolder types = MakeTypesHolder(
{
{"hwtag", "lit"},
{"hwtag", "oneway"},
{"highway", "cycleway"},
},
true /* sortBySpec */, feature::GeomType::Line);
TEST_EQUAL(types.front(), cl.GetTypeByPath({"highway", "cycleway"}), ());
}
}
} // namespace feature_types_test

View file

@ -0,0 +1,94 @@
#include "testing/testing.hpp"
#include "indexer/data_header.hpp"
#include "indexer/features_offsets_table.hpp"
#include "indexer/features_vector.hpp"
#include "platform/local_country_file_utils.hpp"
#include "platform/platform.hpp"
#include "coding/files_container.hpp"
#include "base/scope_guard.hpp"
#include "defines.hpp"
#include <functional>
#include <memory>
#include <string>
using namespace platform;
using namespace std;
namespace feature
{
UNIT_TEST(FeaturesOffsetsTable_Empty)
{
FeaturesOffsetsTable::Builder builder;
unique_ptr<FeaturesOffsetsTable> table(FeaturesOffsetsTable::Build(builder));
TEST(table.get(), ());
TEST_EQUAL(static_cast<uint64_t>(0), table->size(), ());
}
UNIT_TEST(FeaturesOffsetsTable_Basic)
{
FeaturesOffsetsTable::Builder builder;
builder.PushOffset(1);
builder.PushOffset(4);
builder.PushOffset(17);
builder.PushOffset(128);
builder.PushOffset(129);
builder.PushOffset(510);
builder.PushOffset(513);
builder.PushOffset(1024);
unique_ptr<FeaturesOffsetsTable> table(FeaturesOffsetsTable::Build(builder));
TEST(table.get(), ());
TEST_EQUAL(static_cast<uint64_t>(8), table->size(), ());
TEST_EQUAL(static_cast<uint64_t>(1), table->GetFeatureOffset(0), ());
TEST_EQUAL(static_cast<uint64_t>(4), table->GetFeatureOffset(1), ());
TEST_EQUAL(static_cast<uint64_t>(17), table->GetFeatureOffset(2), ());
TEST_EQUAL(static_cast<uint64_t>(128), table->GetFeatureOffset(3), ());
TEST_EQUAL(static_cast<uint64_t>(129), table->GetFeatureOffset(4), ());
TEST_EQUAL(static_cast<uint64_t>(510), table->GetFeatureOffset(5), ());
TEST_EQUAL(static_cast<uint64_t>(513), table->GetFeatureOffset(6), ());
TEST_EQUAL(static_cast<uint64_t>(1024), table->GetFeatureOffset(7), ());
TEST_EQUAL(static_cast<size_t>(0), table->GetFeatureIndexbyOffset(1), ());
TEST_EQUAL(static_cast<size_t>(1), table->GetFeatureIndexbyOffset(4), ());
TEST_EQUAL(static_cast<size_t>(2), table->GetFeatureIndexbyOffset(17), ());
TEST_EQUAL(static_cast<size_t>(3), table->GetFeatureIndexbyOffset(128), ());
TEST_EQUAL(static_cast<size_t>(4), table->GetFeatureIndexbyOffset(129), ());
TEST_EQUAL(static_cast<size_t>(5), table->GetFeatureIndexbyOffset(510), ());
TEST_EQUAL(static_cast<size_t>(6), table->GetFeatureIndexbyOffset(513), ());
TEST_EQUAL(static_cast<size_t>(7), table->GetFeatureIndexbyOffset(1024), ());
}
UNIT_TEST(FeaturesOffsetsTable_ReadWrite)
{
string const testFileName = "test_file";
Platform & pl = GetPlatform();
FilesContainerR baseContainer(pl.GetReader("minsk-pass" DATA_FILE_EXTENSION));
size_t constexpr minFeaturesCount = 5000;
LocalCountryFile localFile = LocalCountryFile::MakeForTesting(testFileName);
CountryIndexes::PreparePlaceOnDisk(localFile);
string const indexFile = CountryIndexes::GetPath(localFile, CountryIndexes::Index::Offsets);
SCOPE_GUARD(deleteTestFileIndexGuard, bind(&FileWriter::DeleteFileX, cref(indexFile)));
FeaturesOffsetsTable::Build(baseContainer, indexFile);
unique_ptr<FeaturesOffsetsTable> table(FeaturesOffsetsTable::Load(baseContainer, FEATURE_OFFSETS_FILE_TAG));
TEST(table.get() && table->size() > minFeaturesCount, ());
unique_ptr<FeaturesOffsetsTable> loadedTable(FeaturesOffsetsTable::Load(indexFile));
TEST(loadedTable.get() && loadedTable->size() > minFeaturesCount, ());
TEST_EQUAL(table->size(), loadedTable->size(), ());
for (uint64_t i = 0; i < table->size(); ++i)
TEST_EQUAL(table->GetFeatureOffset(i), loadedTable->GetFeatureOffset(i), ());
}
} // namespace feature

View file

@ -0,0 +1,63 @@
#include "testing/testing.hpp"
#include "indexer/data_source.hpp"
#include "indexer/features_vector.hpp"
#include "indexer/mwm_set.hpp"
#include "platform/local_country_file.hpp"
#include <map>
#include <string>
#include <vector>
namespace features_vector_test
{
using namespace platform;
using namespace std;
// Postcodes with frequences.
// One can easily get this list of frequences with postcodes:
//
// cat data/minsk-pass.osm.bz2 | bunzip2 | grep 'addr:postcode' |
// sed "s/.*v='\(.*\)'.*/\1/g" |
// sort | uniq -c | awk '{ printf("{%s, %s},\n", $2, $1) }'
//
// Note, (220006, 145) (220007, 271) are broken and not included in minsk-pass.mwm,
// corresponding postcode frequencies are decremented.
vector<pair<int, int>> kCodeFreq = {{220000, 2}, {220001, 3}, {220004, 10}, {220006, 144}, {220007, 270},
{220010, 4}, {220011, 1}, {220014, 3}, {220030, 247}, {220033, 7},
{220036, 204}, {220039, 15}, {220048, 1}, {220050, 4}, {220069, 5},
{220073, 1}, {220089, 1}, {220121, 1}, {721816, 1}};
UNIT_TEST(FeaturesVectorTest_ParseMetadata)
{
string const kCountryName = "minsk-pass";
map<string, int> expected;
for (auto const & p : kCodeFreq)
expected[strings::to_string(p.first)] = p.second;
LocalCountryFile localFile = LocalCountryFile::MakeForTesting(kCountryName);
FrozenDataSource dataSource;
auto result = dataSource.RegisterMap(localFile);
TEST_EQUAL(result.second, MwmSet::RegResult::Success, ());
auto const & id = result.first;
MwmSet::MwmHandle handle = dataSource.GetMwmHandleById(id);
TEST(handle.IsAlive(), ());
auto const * value = handle.GetValue();
FeaturesVector fv(value->m_cont, value->GetHeader(), value->m_ftTable.get(), value->m_relTable.get(),
value->m_metaDeserializer.get());
map<string, int> actual;
fv.ForEach([&](FeatureType & ft, uint32_t index)
{
string const postcode(ft.GetMetadata(feature::Metadata::FMD_POSTCODE));
if (!postcode.empty())
++actual[postcode];
});
TEST_EQUAL(expected, actual, ());
}
} // namespace features_vector_test

View file

@ -0,0 +1,66 @@
#include "testing/testing.hpp"
#include "indexer/classificator_loader.hpp"
#include "indexer/data_source.hpp"
#include "indexer/features_vector.hpp"
#include "indexer/index_builder.hpp"
#include "indexer/scales.hpp"
#include "defines.hpp"
#include "platform/platform.hpp"
#include "coding/files_container.hpp"
#include "base/macros.hpp"
#include "base/stl_helpers.hpp"
#include <string>
#include <vector>
using namespace std;
UNIT_TEST(BuildIndexTest)
{
Platform & p = GetPlatform();
classificator::Load();
FilesContainerR originalContainer(p.GetReader("minsk-pass" DATA_FILE_EXTENSION));
// Build index.
vector<char> serialIndex;
{
FeaturesVectorTest features(originalContainer);
MemWriter<vector<char>> serialWriter(serialIndex);
indexer::BuildIndex(features.GetHeader(), features.GetVector(), serialWriter, "build_index_test");
}
// Create a new mwm file.
string const fileName = "build_index_test" DATA_FILE_EXTENSION;
string const filePath = p.WritablePathForFile(fileName);
FileWriter::DeleteFileX(filePath);
// Copy original mwm file and replace index in it.
{
FilesContainerW containerWriter(filePath);
vector<string> tags;
originalContainer.ForEachTag(base::MakeBackInsertFunctor(tags));
for (size_t i = 0; i < tags.size(); ++i)
if (tags[i] != INDEX_FILE_TAG)
containerWriter.Write(originalContainer.GetReader(tags[i]), tags[i]);
containerWriter.Write(serialIndex, INDEX_FILE_TAG);
}
{
// Check that index actually works.
FrozenDataSource dataSource;
UNUSED_VALUE(dataSource.Register(platform::LocalCountryFile::MakeForTesting("build_index_test")));
// Make sure that index is actually parsed.
dataSource.ForEachInScale([](FeatureType &) { return; }, 15);
}
// Clean after the test.
FileWriter::DeleteFileX(filePath);
}

View file

@ -0,0 +1,298 @@
#include "testing/testing.hpp"
#include "indexer/interval_index.hpp"
#include "indexer/interval_index_builder.hpp"
#include "coding/reader.hpp"
#include "coding/writer.hpp"
#include "base/macros.hpp"
#include "base/stl_helpers.hpp"
#include <utility>
#include <vector>
using namespace std;
namespace
{
struct CellIdFeaturePairForTest
{
using ValueType = uint32_t;
CellIdFeaturePairForTest(uint64_t cell, uint32_t value) : m_cell(cell), m_value(value) {}
uint64_t GetCell() const { return m_cell; }
uint32_t GetValue() const { return m_value; }
uint64_t m_cell;
uint32_t m_value;
};
auto IndexValueInserter(vector<uint32_t> & values)
{
return [inserter = base::MakeBackInsertFunctor(values)](uint64_t, auto value) { inserter(value); };
}
} // namespace
UNIT_TEST(IntervalIndex_LevelCount)
{
TEST_EQUAL(IntervalIndexBuilder(10, 1, 3).GetLevelCount(), 1, ());
TEST_EQUAL(IntervalIndexBuilder(11, 1, 3).GetLevelCount(), 1, ());
TEST_EQUAL(IntervalIndexBuilder(12, 1, 3).GetLevelCount(), 2, ());
TEST_EQUAL(IntervalIndexBuilder(19, 2, 3).GetLevelCount(), 1, ());
TEST_EQUAL(IntervalIndexBuilder(19, 1, 3).GetLevelCount(), 4, ());
TEST_EQUAL(IntervalIndexBuilder(20, 1, 3).GetLevelCount(), 4, ());
}
UNIT_TEST(IntervalIndex_SerializedNodeBitmap)
{
uint32_t const offset = 350; // == 0x15E
uint32_t childSizes[8] = {0, 0, 0, 10, 0, 0, 1000, 0};
char const expSerial[] =
"\xBD\x05" // (350 << 1) + 1 == 701 == 0x2BD - offset encoded as varuint.
"\x48" // (1 << 3) | (1 << 6) == 72 == 0x48 - bitmap.
"\x0A" // 10 - childSizes[3] encoded as varuint.
"\xE8\x07" // 1000 = 0x3E8 - childSizes[6] encoded as varuint.
"";
vector<uint8_t> serializedNode;
MemWriter<vector<uint8_t>> writer(serializedNode);
IntervalIndexBuilder(11, 1, 3).WriteNode(writer, offset, childSizes);
TEST_EQUAL(serializedNode, vector<uint8_t>(expSerial, expSerial + ARRAY_SIZE(expSerial) - 1), ());
}
UNIT_TEST(IntervalIndex_SerializedNodeList)
{
uint32_t const offset = 350; // == 0x15E
uint32_t childSizes[16] = {0, 0, 0, 0, 0, 0, 1000, 0, 0, 0, 0, 0, 0, 0, 0, 0};
char const expSerial[] =
"\xBC\x05" // (350 << 1) + 0 == 700 == 0x2BC - offset encoded as varuint.
"\x06"
"\xE8\x07" // 6, 1000
"";
vector<uint8_t> serializedNode;
MemWriter<vector<uint8_t>> writer(serializedNode);
IntervalIndexBuilder(11, 1, 4).WriteNode(writer, offset, childSizes);
TEST_EQUAL(serializedNode, vector<uint8_t>(expSerial, expSerial + ARRAY_SIZE(expSerial) - 1), ());
}
UNIT_TEST(IntervalIndex_SerializedLeaves)
{
vector<CellIdFeaturePairForTest> data;
data.push_back(CellIdFeaturePairForTest(0x1537U, 0));
data.push_back(CellIdFeaturePairForTest(0x1538U, 1));
data.push_back(CellIdFeaturePairForTest(0x1637U, 2));
vector<uint8_t> serialLeaves;
MemWriter<vector<uint8_t>> writer(serialLeaves);
vector<uint32_t> sizes;
IntervalIndexBuilder(16, 1, 4).BuildLeaves(writer, data.begin(), data.end(), sizes);
char const expSerial[] =
"\x37\x00"
"\x38\x02"
"\x37\x04"; // 0x1537 0x1538 0x1637
uint32_t const expSizes[] = {4, 2};
TEST_EQUAL(serialLeaves, vector<uint8_t>(expSerial, expSerial + ARRAY_SIZE(expSerial) - 1), ());
TEST_EQUAL(sizes, vector<uint32_t>(expSizes, expSizes + ARRAY_SIZE(expSizes)), ());
}
UNIT_TEST(IntervalIndex_SerializedNodes)
{
vector<CellIdFeaturePairForTest> data;
data.push_back(CellIdFeaturePairForTest(0x1537U, 0));
data.push_back(CellIdFeaturePairForTest(0x1538U, 1));
data.push_back(CellIdFeaturePairForTest(0x1637U, 2));
uint32_t const leavesSizes[] = {4, 2};
vector<uint8_t> serialNodes;
MemWriter<vector<uint8_t>> writer(serialNodes);
vector<uint32_t> sizes;
IntervalIndexBuilder(16, 1, 4).BuildLevel(writer, data.begin(), data.end(), 1, leavesSizes,
leavesSizes + ARRAY_SIZE(leavesSizes), sizes);
char const expSerial[] = "\x01\x60\x00\x04\x02";
uint32_t const expSizes[] = {ARRAY_SIZE(expSerial) - 1};
TEST_EQUAL(serialNodes, vector<uint8_t>(expSerial, expSerial + ARRAY_SIZE(expSerial) - 1), ());
TEST_EQUAL(sizes, vector<uint32_t>(expSizes, expSizes + ARRAY_SIZE(expSizes)), ());
}
UNIT_TEST(IntervalIndex_Serialized)
{
vector<CellIdFeaturePairForTest> data;
data.push_back(CellIdFeaturePairForTest(0x1537U, 0));
data.push_back(CellIdFeaturePairForTest(0x1538U, 1));
data.push_back(CellIdFeaturePairForTest(0x1637U, 2));
vector<uint8_t> serialIndex;
MemWriter<vector<uint8_t>> writer(serialIndex);
IntervalIndexBuilder(16, 1, 4).BuildIndex(writer, data.begin(), data.end());
char const expSerial[] =
"\x01\x02\x04\x01" // Header
"\x14\x00\x00\x00" // Leaves level offset
"\x1A\x00\x00\x00" // Level 1 offset
"\x1F\x00\x00\x00" // Root level offset
"\x22\x00\x00\x00" // Root level offset
"\x37\x00"
"\x38\x02"
"\x37\x04" // 0x1537 0x1538 0x1637
"\x01\x60\x00\x04\x02" // 0x15, 0x16 node
"\x00\x01\x05" // Root
"";
TEST_EQUAL(serialIndex, vector<uint8_t>(expSerial, expSerial + ARRAY_SIZE(expSerial) - 1), ());
MemReader reader(&serialIndex[0], serialIndex.size());
IntervalIndex<MemReader, uint32_t> index(reader);
uint32_t expected[] = {0, 1, 2};
vector<uint32_t> values;
TEST_EQUAL(index.KeyEnd(), 0x10000, ());
index.ForEach(IndexValueInserter(values), 0, 0x10000);
TEST_EQUAL(values, vector<uint32_t>(expected, expected + ARRAY_SIZE(expected)), ());
}
UNIT_TEST(IntervalIndex_Simple)
{
vector<CellIdFeaturePairForTest> data;
data.push_back(CellIdFeaturePairForTest(0xA0B1C2D100ULL, 0));
data.push_back(CellIdFeaturePairForTest(0xA0B1C2D200ULL, 1));
data.push_back(CellIdFeaturePairForTest(0xA0B2C2D100ULL, 2));
vector<char> serialIndex;
MemWriter<vector<char>> writer(serialIndex);
BuildIntervalIndex(data.begin(), data.end(), writer, 40);
MemReader reader(&serialIndex[0], serialIndex.size());
IntervalIndex<MemReader, uint32_t> index(reader);
TEST_EQUAL(index.KeyEnd(), 0x10000000000ULL, ());
{
uint32_t expected[] = {0, 1, 2};
vector<uint32_t> values;
index.ForEach(IndexValueInserter(values), 0ULL, index.KeyEnd());
TEST_EQUAL(values, vector<uint32_t>(expected, expected + ARRAY_SIZE(expected)), ());
}
{
uint32_t expected[] = {0, 1};
vector<uint32_t> values;
index.ForEach(IndexValueInserter(values), 0xA0B1C2D100ULL, 0xA0B1C2D201ULL);
TEST_EQUAL(values, vector<uint32_t>(expected, expected + ARRAY_SIZE(expected)), ());
}
{
uint32_t expected[] = {0, 1};
vector<uint32_t> values;
index.ForEach(IndexValueInserter(values), 0x0ULL, 0xA0B1C30000ULL);
TEST_EQUAL(values, vector<uint32_t>(expected, expected + ARRAY_SIZE(expected)), ());
}
{
uint32_t expected[] = {0};
vector<uint32_t> values;
index.ForEach(IndexValueInserter(values), 0xA0B1C2D100ULL, 0xA0B1C2D101ULL);
TEST_EQUAL(values, vector<uint32_t>(expected, expected + ARRAY_SIZE(expected)), ());
}
{
uint32_t expected[] = {0};
vector<uint32_t> values;
index.ForEach(IndexValueInserter(values), 0xA0B1C2D100ULL, 0xA0B1C2D200ULL);
TEST_EQUAL(values, vector<uint32_t>(expected, expected + ARRAY_SIZE(expected)), ());
}
{
vector<uint32_t> values;
index.ForEach(IndexValueInserter(values), 0xA0B1C2D100ULL, 0xA0B1C2D100ULL);
TEST_EQUAL(values, vector<uint32_t>(), ());
}
{
vector<uint32_t> values;
index.ForEach(IndexValueInserter(values), 0xA0B1000000ULL, 0xA0B1B20000ULL);
TEST_EQUAL(values, vector<uint32_t>(), ());
}
}
UNIT_TEST(IntervalIndex_Empty)
{
vector<CellIdFeaturePairForTest> data;
vector<char> serialIndex;
MemWriter<vector<char>> writer(serialIndex);
BuildIntervalIndex(data.begin(), data.end(), writer, 40);
MemReader reader(&serialIndex[0], serialIndex.size());
IntervalIndex<MemReader, uint32_t> index(reader);
{
vector<uint32_t> values;
index.ForEach(IndexValueInserter(values), 0ULL, 0xFFFFFFFFFFULL);
TEST_EQUAL(values, vector<uint32_t>(), ());
}
}
UNIT_TEST(IntervalIndex_Simple2)
{
vector<CellIdFeaturePairForTest> data;
data.push_back(CellIdFeaturePairForTest(0xA0B1C2D200ULL, 0));
data.push_back(CellIdFeaturePairForTest(0xA0B1C2D200ULL, 1));
data.push_back(CellIdFeaturePairForTest(0xA0B1C2D200ULL, 3));
data.push_back(CellIdFeaturePairForTest(0xA0B2C2D200ULL, 2));
vector<char> serialIndex;
MemWriter<vector<char>> writer(serialIndex);
BuildIntervalIndex(data.begin(), data.end(), writer, 40);
MemReader reader(&serialIndex[0], serialIndex.size());
IntervalIndex<MemReader, uint32_t> index(reader);
{
uint32_t expected[] = {0, 1, 2, 3};
vector<uint32_t> values;
index.ForEach(IndexValueInserter(values), 0, 0xFFFFFFFFFFULL);
sort(values.begin(), values.end());
TEST_EQUAL(values, vector<uint32_t>(expected, expected + ARRAY_SIZE(expected)), ());
}
}
UNIT_TEST(IntervalIndex_Simple3)
{
vector<CellIdFeaturePairForTest> data;
data.push_back(CellIdFeaturePairForTest(0x0100ULL, 0));
data.push_back(CellIdFeaturePairForTest(0x0200ULL, 1));
vector<char> serialIndex;
MemWriter<vector<char>> writer(serialIndex);
BuildIntervalIndex(data.begin(), data.end(), writer, 40);
MemReader reader(&serialIndex[0], serialIndex.size());
IntervalIndex<MemReader, uint32_t> index(reader);
{
uint32_t expected[] = {0, 1};
vector<uint32_t> values;
index.ForEach(IndexValueInserter(values), 0, 0xFFFFULL);
sort(values.begin(), values.end());
TEST_EQUAL(values, vector<uint32_t>(expected, expected + ARRAY_SIZE(expected)), ());
}
}
UNIT_TEST(IntervalIndex_Simple4)
{
vector<CellIdFeaturePairForTest> data;
data.push_back(CellIdFeaturePairForTest(0x01030400ULL, 0));
data.push_back(CellIdFeaturePairForTest(0x02030400ULL, 1));
vector<char> serialIndex;
MemWriter<vector<char>> writer(serialIndex);
BuildIntervalIndex(data.begin(), data.end(), writer, 40);
MemReader reader(&serialIndex[0], serialIndex.size());
IntervalIndex<MemReader, uint32_t> index(reader);
{
uint32_t expected[] = {0, 1};
vector<uint32_t> values;
index.ForEach(IndexValueInserter(values), 0, 0xFFFFFFFFULL);
sort(values.begin(), values.end());
TEST_EQUAL(values, vector<uint32_t>(expected, expected + ARRAY_SIZE(expected)), ());
}
}
UNIT_TEST(IntervalIndex_Simple5)
{
vector<CellIdFeaturePairForTest> data;
data.push_back(CellIdFeaturePairForTest(0xA0B1C2D200ULL, 0));
data.push_back(CellIdFeaturePairForTest(0xA0B1C2D200ULL, 1));
data.push_back(CellIdFeaturePairForTest(0xA0B1C2D200ULL, 3));
data.push_back(CellIdFeaturePairForTest(0xA0B2C2D200ULL, 2));
vector<char> serialIndex;
MemWriter<vector<char>> writer(serialIndex);
BuildIntervalIndex(data.begin(), data.end(), writer, 40);
MemReader reader(&serialIndex[0], serialIndex.size());
IntervalIndex<MemReader, uint32_t> index(reader);
{
uint32_t expected[] = {0, 1, 2, 3};
vector<uint32_t> values;
index.ForEach(IndexValueInserter(values), 0, 0xFFFFFFFFFFULL);
sort(values.begin(), values.end());
TEST_EQUAL(values, vector<uint32_t>(expected, expected + ARRAY_SIZE(expected)), ());
}
}

View file

@ -0,0 +1,81 @@
#include "testing/testing.hpp"
#include "indexer/feature_meta.hpp"
#include "indexer/metadata_serdes.hpp"
#include "coding/reader.hpp"
#include "coding/writer.hpp"
#include "base/string_utils.hpp"
#include <cstdint>
#include <map>
#include <string>
#include <vector>
using namespace feature;
using namespace indexer;
using namespace std;
namespace
{
using Buffer = vector<uint8_t>;
UNIT_TEST(MetadataSerDesTest_Smoke)
{
Buffer buffer;
auto const genMeta = [](uint32_t i)
{
feature::Metadata meta;
meta.Set(Metadata::FMD_TEST_ID, strings::to_string(i));
return meta;
};
uint32_t constexpr kMetaNumber = 1000;
map<uint32_t, Metadata> values;
for (uint32_t i = 0; i < kMetaNumber; ++i)
values.emplace(i, genMeta(i));
{
MetadataBuilder builder;
for (auto const & kv : values)
builder.Put(kv.first, kv.second);
MemWriter<Buffer> writer(buffer);
builder.Freeze(writer);
}
{
MemReader reader(buffer.data(), buffer.size());
auto deserializer = MetadataDeserializer::Load(reader);
TEST(deserializer.get(), ());
for (uint32_t i = 0; i < kMetaNumber; ++i)
{
Metadata meta;
TEST(deserializer->Get(i, meta), ());
TEST(meta.Equals(values[i]), (meta, i));
}
}
{
MemReader reader(buffer.data(), buffer.size());
auto deserializer = MetadataDeserializer::Load(reader);
TEST(deserializer.get(), ());
for (uint32_t i = 0; i < kMetaNumber; ++i)
{
MetadataDeserializer::MetaIds ids;
TEST(deserializer->GetIds(i, ids), ());
auto const & meta = values[i];
TEST_EQUAL(meta.Size(), 1, (meta));
TEST_EQUAL(ids.size(), 1, (ids));
TEST(meta.Has(Metadata::FMD_TEST_ID), (meta));
TEST_EQUAL(ids[0].first, Metadata::FMD_TEST_ID, (ids));
TEST_EQUAL(meta.Get(Metadata::FMD_TEST_ID), deserializer->GetMetaById(ids[0].second), (i, meta, ids));
}
}
}
} // namespace

View file

@ -0,0 +1,171 @@
#include "testing/testing.hpp"
#include "platform/platform_tests_support/scoped_mwm.hpp"
#include "indexer/indexer_tests/test_mwm_set.hpp"
#include "indexer/mwm_set.hpp"
#include "base/macros.hpp"
#include <initializer_list>
#include <unordered_map>
namespace mwm_set_test
{
using namespace platform::tests_support;
using namespace std;
using platform::CountryFile;
using platform::LocalCountryFile;
using tests::TestMwmSet;
using MwmsInfo = unordered_map<string, shared_ptr<MwmInfo>>;
void GetMwmsInfo(MwmSet const & mwmSet, MwmsInfo & mwmsInfo)
{
vector<shared_ptr<MwmInfo>> mwmsInfoList;
mwmSet.GetMwmsInfo(mwmsInfoList);
mwmsInfo.clear();
for (shared_ptr<MwmInfo> const & info : mwmsInfoList)
mwmsInfo[info->GetCountryName()] = info;
}
void TestFilesPresence(MwmsInfo const & mwmsInfo, initializer_list<string> const & expectedNames)
{
TEST_EQUAL(expectedNames.size(), mwmsInfo.size(), ());
for (string const & countryFileName : expectedNames)
TEST_EQUAL(1, mwmsInfo.count(countryFileName), (countryFileName));
}
UNIT_TEST(MwmSetSmokeTest)
{
TestMwmSet mwmSet;
MwmsInfo mwmsInfo;
ScopedMwm mwm0("0.mwm");
ScopedMwm mwm1("1.mwm");
ScopedMwm mwm2("2.mwm");
ScopedMwm mwm3("3.mwm");
ScopedMwm mwm4("4.mwm");
ScopedMwm mwm5("5.mwm");
UNUSED_VALUE(mwmSet.Register(LocalCountryFile::MakeForTesting("0")));
UNUSED_VALUE(mwmSet.Register(LocalCountryFile::MakeForTesting("1")));
UNUSED_VALUE(mwmSet.Register(LocalCountryFile::MakeForTesting("2")));
mwmSet.Deregister(CountryFile("1"));
GetMwmsInfo(mwmSet, mwmsInfo);
TestFilesPresence(mwmsInfo, {"0", "2"});
TEST(mwmsInfo["0"]->IsUpToDate(), ());
TEST_EQUAL(mwmsInfo["0"]->m_maxScale, 0, ());
TEST(mwmsInfo["2"]->IsUpToDate(), ());
{
MwmSet::MwmHandle const handle0 = mwmSet.GetMwmHandleByCountryFile(CountryFile("0"));
MwmSet::MwmHandle const handle1 = mwmSet.GetMwmHandleByCountryFile(CountryFile("1"));
TEST(handle0.IsAlive(), ());
TEST(!handle1.IsAlive(), ());
}
UNUSED_VALUE(mwmSet.Register(LocalCountryFile::MakeForTesting("3")));
GetMwmsInfo(mwmSet, mwmsInfo);
TestFilesPresence(mwmsInfo, {"0", "2", "3"});
TEST(mwmsInfo["0"]->IsUpToDate(), ());
TEST_EQUAL(mwmsInfo["0"]->m_maxScale, 0, ());
TEST(mwmsInfo["2"]->IsUpToDate(), ());
TEST_EQUAL(mwmsInfo["2"]->m_maxScale, 2, ());
TEST(mwmsInfo["3"]->IsUpToDate(), ());
TEST_EQUAL(mwmsInfo["3"]->m_maxScale, 3, ());
{
MwmSet::MwmHandle const handle1 = mwmSet.GetMwmHandleByCountryFile(CountryFile("1"));
TEST(!handle1.IsAlive(), ());
mwmSet.Deregister(CountryFile("3"));
UNUSED_VALUE(mwmSet.Register(LocalCountryFile::MakeForTesting("4")));
}
GetMwmsInfo(mwmSet, mwmsInfo);
TestFilesPresence(mwmsInfo, {"0", "2", "4"});
TEST(mwmsInfo["0"]->IsUpToDate(), ());
TEST_EQUAL(mwmsInfo["0"]->m_maxScale, 0, ());
TEST(mwmsInfo["2"]->IsUpToDate(), ());
TEST_EQUAL(mwmsInfo["2"]->m_maxScale, 2, ());
TEST(mwmsInfo["4"]->IsUpToDate(), ());
TEST_EQUAL(mwmsInfo["4"]->m_maxScale, 4, ());
UNUSED_VALUE(mwmSet.Register(LocalCountryFile::MakeForTesting("5")));
GetMwmsInfo(mwmSet, mwmsInfo);
TestFilesPresence(mwmsInfo, {"0", "2", "4", "5"});
TEST_EQUAL(mwmsInfo.size(), 4, ());
TEST(mwmsInfo["0"]->IsUpToDate(), ());
TEST_EQUAL(mwmsInfo["0"]->m_maxScale, 0, ());
TEST(mwmsInfo["2"]->IsUpToDate(), ());
TEST_EQUAL(mwmsInfo["2"]->m_maxScale, 2, ());
TEST(mwmsInfo["4"]->IsUpToDate(), ());
TEST_EQUAL(mwmsInfo["4"]->m_maxScale, 4, ());
TEST(mwmsInfo["5"]->IsUpToDate(), ());
TEST_EQUAL(mwmsInfo["5"]->m_maxScale, 5, ());
}
UNIT_TEST(MwmSetIdTest)
{
ScopedMwm mwm3("3.mwm");
TestMwmSet mwmSet;
TEST_EQUAL(MwmSet::RegResult::Success, mwmSet.Register(LocalCountryFile::MakeForTesting("3")).second, ());
MwmSet::MwmId const id0 = mwmSet.GetMwmHandleByCountryFile(CountryFile("3")).GetId();
MwmSet::MwmId const id1 = mwmSet.GetMwmHandleByCountryFile(CountryFile("3")).GetId();
TEST(id0.IsAlive(), ());
TEST(id1.IsAlive(), ());
TEST_EQUAL(id0.GetInfo().get(), id1.GetInfo().get(), ());
TEST_EQUAL(MwmInfo::STATUS_REGISTERED, id0.GetInfo()->GetStatus(), ());
TEST(mwmSet.Deregister(CountryFile("3")), ());
// Test that both id's are sour now.
TEST(!id0.IsAlive(), ());
TEST(!id1.IsAlive(), ());
TEST_EQUAL(id0.GetInfo().get(), id1.GetInfo().get(), ());
TEST_EQUAL(MwmInfo::STATUS_DEREGISTERED, id0.GetInfo()->GetStatus(), ());
}
UNIT_TEST(MwmSetLockAndIdTest)
{
ScopedMwm mwm4("4.mwm");
TestMwmSet mwmSet;
MwmSet::MwmId id;
{
auto p = mwmSet.Register(LocalCountryFile::MakeForTesting("4"));
MwmSet::MwmHandle handle = mwmSet.GetMwmHandleById(p.first);
TEST(handle.IsAlive(), ());
TEST_EQUAL(MwmSet::RegResult::Success, p.second, ("Can't register test mwm 4"));
TEST_EQUAL(MwmInfo::STATUS_REGISTERED, handle.GetInfo()->GetStatus(), ());
TEST(!mwmSet.Deregister(CountryFile("4")), ()); // It's not possible to remove mwm 4 right now.
TEST(handle.IsAlive(), ());
TEST_EQUAL(MwmInfo::STATUS_MARKED_TO_DEREGISTER, handle.GetInfo()->GetStatus(), ());
id = handle.GetId();
TEST(id.IsAlive(), ());
}
TEST(!id.IsAlive(), ()); // Mwm is not alive, so id is sour now.
TEST(id.GetInfo().get(), ()); // But it's still possible to get an MwmInfo.
TEST_EQUAL(MwmInfo::STATUS_DEREGISTERED, id.GetInfo()->GetStatus(), ());
TEST_EQUAL(4, id.GetInfo()->m_maxScale, ());
// It is not possible to lock mwm 4 because it is already deleted,
// and it is not possible to get to it's info from mwmSet.
MwmSet::MwmHandle handle = mwmSet.GetMwmHandleByCountryFile(CountryFile("4"));
TEST(!handle.IsAlive(), ());
TEST(!handle.GetId().IsAlive(), ());
TEST(!handle.GetId().GetInfo().get(), ());
}
} // namespace mwm_set_test

View file

@ -0,0 +1,41 @@
#include "testing/testing.hpp"
#include "indexer/postcodes_matcher.hpp"
namespace postcodes_matcher_test
{
using namespace search;
UNIT_TEST(PostcodesMatcher_Smoke)
{
/// @todo We are not _complete_ here, because G4 is also a postcode prefix (Glasgow, Scotland)
/// like BN1 or BN3 (Brighton).
TEST(!LooksLikePostcode("G4", false /* handleAsPrefix */), ());
TEST(LooksLikePostcode("G4", true /* handleAsPrefix */), ());
TEST(LooksLikePostcode("BN1", false /* handleAsPrefix */), ());
TEST(LooksLikePostcode("BN3 ", false /* handleAsPrefix */), ());
TEST(LooksLikePostcode("BN1", true /* handleAsPrefix */), ());
TEST(LooksLikePostcode("BN3 ", true /* handleAsPrefix */), ());
TEST(LooksLikePostcode("141701", false /* handleAsPrefix */), ());
TEST(LooksLikePostcode("141", true /* handleAsPrefix */), ());
TEST(LooksLikePostcode("BA6 8JP", true /* handleAsPrefix */), ());
TEST(LooksLikePostcode("BA6-8JP", true /* handleAsPrefix */), ());
TEST(LooksLikePostcode("BA22 9HR", true /* handleAsPrefix */), ());
TEST(LooksLikePostcode("BA22", true /* handleAsPrefix */), ());
TEST(LooksLikePostcode("DE56 4FW", true /* handleAsPrefix */), ());
TEST(LooksLikePostcode("NY 1000", true /* handleAsPrefix */), ());
TEST(LooksLikePostcode("AZ 85203", true /* handleAsPrefix */), ());
TEST(LooksLikePostcode("AZ", true /* handleAsPrefix */), ());
TEST(LooksLikePostcode("803 0271", true /* handleAsPrefix */), ());
TEST(LooksLikePostcode("803-0271", true /* handleAsPrefix */), ());
TEST(LooksLikePostcode("〒803-0271", true /* handleAsPrefix */), ());
TEST(!LooksLikePostcode("1 мая", true /* handleAsPrefix */), ());
TEST(!LooksLikePostcode("1 мая улица", true /* handleAsPrefix */), ());
TEST(!LooksLikePostcode("москва", true /* handleAsPrefix */), ());
TEST(!LooksLikePostcode("39 с 79", true /* handleAsPrefix */), ());
}
} // namespace postcodes_matcher_test

View file

@ -0,0 +1,107 @@
#include "testing/testing.hpp"
#include "indexer/classificator_loader.hpp"
#include "indexer/data_source.hpp"
#include "indexer/mwm_set.hpp"
#include "indexer/rank_table.hpp"
#include "platform/country_defines.hpp"
#include "platform/local_country_file.hpp"
#include "platform/platform.hpp"
#include "coding/file_writer.hpp"
#include "coding/files_container.hpp"
#include "coding/internal/file_data.hpp"
#include "coding/writer.hpp"
#include "base/file_name_utils.hpp"
#include "base/scope_guard.hpp"
#include "defines.hpp"
#include <cstdint>
#include <memory>
#include <string>
#include <vector>
using namespace std;
namespace
{
void TestTable(vector<uint8_t> const & ranks, search::RankTable const & table)
{
TEST_EQUAL(ranks.size(), table.Size(), ());
TEST_EQUAL(table.GetVersion(), search::RankTable::V0, ());
for (size_t i = 0; i < ranks.size(); ++i)
TEST_EQUAL(ranks[i], table.Get(i), ());
}
void TestTable(vector<uint8_t> const & ranks, string const & path)
{
// Tries to load table via file read.
{
FilesContainerR rcont(path);
auto table = search::RankTable::Load(rcont, SEARCH_RANKS_FILE_TAG);
TEST(table, ());
TestTable(ranks, *table);
}
// Tries to load table via file mapping.
{
FilesMappingContainer mcont(path);
auto table = search::RankTable::Load(mcont, SEARCH_RANKS_FILE_TAG);
TEST(table, ());
TestTable(ranks, *table);
}
}
} // namespace
UNIT_TEST(RankTableBuilder_Smoke)
{
char const kTestCont[] = "test.tmp";
size_t const kNumRanks = 256;
FileWriter::DeleteFileX(kTestCont);
SCOPE_GUARD(cleanup, bind(&FileWriter::DeleteFileX, kTestCont));
vector<uint8_t> ranks;
for (size_t i = 0; i < kNumRanks; ++i)
ranks.push_back(i);
{
FilesContainerW wcont(kTestCont);
search::RankTableBuilder::Create(ranks, wcont, SEARCH_RANKS_FILE_TAG);
}
TestTable(ranks, kTestCont);
}
UNIT_TEST(RankTableBuilder_EndToEnd)
{
classificator::Load();
string const originalMapPath = base::JoinPath(GetPlatform().WritableDir(), "minsk-pass.mwm");
string const mapPath = base::JoinPath(GetPlatform().WritableDir(), "minsk-pass-copy.mwm");
base::CopyFileX(originalMapPath, mapPath);
SCOPE_GUARD(cleanup, bind(&FileWriter::DeleteFileX, mapPath));
auto const localFile = platform::LocalCountryFile::MakeForTesting("minsk-pass-copy");
TEST(localFile.OnDisk(MapFileType::Map), ());
vector<uint8_t> ranks;
{
FilesContainerR rcont(mapPath);
search::SearchRankTableBuilder::CalcSearchRanks(rcont, ranks);
}
{
FilesContainerW wcont(mapPath, FileWriter::OP_WRITE_EXISTING);
search::RankTableBuilder::Create(ranks, wcont, SEARCH_RANKS_FILE_TAG);
}
FrozenDataSource dataSource;
auto regResult = dataSource.RegisterMap(localFile);
TEST_EQUAL(regResult.second, MwmSet::RegResult::Success, ());
TestTable(ranks, mapPath);
}

View file

@ -0,0 +1,37 @@
#include "testing/testing.hpp"
#include "indexer/classificator_loader.hpp"
#include "indexer/data_source.hpp"
#include "platform/local_country_file.hpp"
#include <cstdint>
#include <memory>
#include <vector>
using namespace std;
UNIT_TEST(ReadFeatures_Smoke)
{
classificator::Load();
FrozenDataSource dataSource;
dataSource.RegisterMap(platform::LocalCountryFile::MakeForTesting("minsk-pass"));
vector<shared_ptr<MwmInfo>> infos;
dataSource.GetMwmsInfo(infos);
CHECK_EQUAL(infos.size(), 1, ());
auto handle = dataSource.GetMwmHandleById(MwmSet::MwmId(infos[0]));
FeaturesLoaderGuard const guard(dataSource, handle.GetId());
LOG(LINFO, (guard.GetNumFeatures()));
for (uint32_t i = 0; i + 1 < guard.GetNumFeatures(); ++i)
{
auto ft1 = guard.GetFeatureByIndex(i);
auto ft2 = guard.GetFeatureByIndex(i + 1);
ft2->ForEachType([](auto const /* t */) {});
ft1->ForEachType([](auto const /* t */) {});
}
}

View file

@ -0,0 +1,58 @@
#include "testing/testing.hpp"
#include "indexer/road_shields_parser.hpp"
UNIT_TEST(RoadShields_Smoke)
{
using namespace ftypes;
auto shields = GetRoadShields("France", "D 116A");
TEST_EQUAL(shields.size(), 1, ());
TEST_EQUAL(shields[0].m_type, RoadShieldType::Generic_Orange, ());
shields = GetRoadShields("Belarus", "M1"); // latin letter M
TEST_EQUAL(shields.size(), 1, ());
TEST_EQUAL(shields[0].m_type, RoadShieldType::Generic_Red, ());
shields = GetRoadShields("Belarus", "Е2"); // cyrillic letter Е
TEST_EQUAL(shields.size(), 1, ());
TEST_EQUAL(shields[0].m_type, RoadShieldType::Generic_Green, ());
shields = GetRoadShields("Ukraine", "Р50"); // cyrillic letter Р
TEST_EQUAL(shields.size(), 1, ());
TEST_EQUAL(shields[0].m_type, RoadShieldType::Generic_Blue, ());
shields = GetRoadShields("Malaysia", "AH7");
TEST_EQUAL(shields.size(), 1, ());
TEST_EQUAL(shields[0].m_type, RoadShieldType::Generic_Blue, ());
shields = GetRoadShields("Germany", "A 3;A 7");
TEST_EQUAL(shields.size(), 2, ());
TEST_EQUAL(shields[0].m_type, RoadShieldType::Generic_Blue, ());
TEST_EQUAL(shields[1].m_type, RoadShieldType::Generic_Blue, ());
shields = GetRoadShields("Germany", "blue/A 31;national/B 2R");
TEST_EQUAL(shields.size(), 2, ());
TEST_EQUAL(shields[0].m_type, RoadShieldType::Generic_Blue, ());
TEST_EQUAL(shields[1].m_type, RoadShieldType::Generic_Orange, ());
shields = GetRoadShields("Germany", "TMC 33388 (St 2047)");
TEST_EQUAL(shields.size(), 0, ());
shields = GetRoadShields("US", "US:IN");
TEST_EQUAL(shields.size(), 1, ());
TEST_EQUAL(shields[0].m_type, RoadShieldType::Default, ());
shields = GetRoadShields("US", "SR 38;US:IN");
TEST_EQUAL(shields.size(), 2, ());
TEST_EQUAL(shields[0].m_type, RoadShieldType::Generic_White, ());
TEST_EQUAL(shields[1].m_type, RoadShieldType::Default, ());
shields = GetRoadShields("Switzerland", "e-road/E 67");
TEST_EQUAL(shields.size(), 1, ());
TEST_EQUAL(shields[0].m_type, RoadShieldType::Generic_Green, ());
shields = GetRoadShields("Estonia", "ee:national/27;ee:local/7841171");
TEST_EQUAL(shields.size(), 1, ());
TEST_EQUAL(shields[0].m_type, RoadShieldType::Generic_Orange, ());
}

View file

@ -0,0 +1,120 @@
#include "testing/testing.hpp"
#include "generator/generator_tests_support/test_feature.hpp"
#include "generator/generator_tests_support/test_mwm_builder.hpp"
#include "generator/generator_tests_support/test_with_custom_mwms.hpp"
#include "indexer/cell_id.hpp"
#include "indexer/data_header.hpp"
#include "indexer/data_source.hpp"
#include "indexer/feature.hpp"
#include "indexer/feature_covering.hpp"
#include "indexer/feature_visibility.hpp"
#include "indexer/mwm_set.hpp"
#include "indexer/scale_index.hpp"
#include "platform/country_defines.hpp"
#include "platform/local_country_file.hpp"
#include "coding/files_container.hpp"
#include "coding/mmap_reader.hpp"
#include "coding/reader.hpp"
#include "geometry/rect2d.hpp"
#include "defines.hpp"
#include <algorithm>
#include <string>
#include <vector>
namespace scale_index_reading_tests
{
using namespace generator::tests_support;
using namespace indexer;
using namespace std;
using Names = vector<string>;
class ScaleIndexReadingTest : public TestWithCustomMwms
{
public:
template <typename ScaleIndex>
Names CollectNames(MwmSet::MwmId const & id, ScaleIndex const & index, int scaleForIntervals, int scaleForZoomLevels,
m2::RectD const & rect)
{
covering::CoveringGetter covering(rect, covering::ViewportWithLowLevels);
vector<uint32_t> indices;
for (auto const & interval : covering.Get<RectId::DEPTH_LEVELS>(scaleForIntervals))
{
index.ForEachInIntervalAndScale(interval.first, interval.second, scaleForZoomLevels,
[&](uint64_t /* key */, uint32_t value) { indices.push_back(value); });
}
FeaturesLoaderGuard loader(m_dataSource, id);
Names names;
for (auto const & index : indices)
{
auto ft = loader.GetFeatureByIndex(index);
TEST(ft, (index));
string_view const name = ft->GetName(StringUtf8Multilang::kEnglishCode);
TEST(!name.empty(), (index));
names.push_back(std::string(name));
}
sort(names.begin(), names.end());
return names;
}
};
UNIT_CLASS_TEST(ScaleIndexReadingTest, Mmap)
{
TestPOI a(m2::PointD{0, 0}, "A", "en");
TestPOI b(m2::PointD{1, 0}, "B", "en");
TestPOI c(m2::PointD{1, 1}, "C", "en");
TestPOI d(m2::PointD{0, 1}, "D", "en");
auto id = BuildCountry("Wonderland", [&](TestMwmBuilder & builder)
{
builder.Add(a);
builder.Add(b);
builder.Add(c);
builder.Add(d);
});
TEST(id.IsAlive(), ());
auto const path = id.GetInfo()->GetLocalFile().GetPath(MapFileType::Map);
FilesContainerR cont(path);
feature::DataHeader header(cont);
auto const offsetSize = cont.GetAbsoluteOffsetAndSize(INDEX_FILE_TAG);
MmapReader reader(path);
ReaderPtr<Reader> subReader(reader.CreateSubReader(offsetSize.first, offsetSize.second));
ScaleIndex<ReaderPtr<Reader>> index(subReader);
auto collectNames = [&](m2::RectD const & rect)
{ return CollectNames(id, index, header.GetLastScale(), header.GetLastScale(), rect); };
TEST_EQUAL(collectNames(m2::RectD{-0.5, -0.5, 0.5, 0.5}), Names({"A"}), ());
TEST_EQUAL(collectNames(m2::RectD{0.5, -0.5, 1.5, 1.5}), Names({"B", "C"}), ());
TEST_EQUAL(collectNames(m2::RectD{-0.5, -0.5, 1.5, 1.5}), Names({"A", "B", "C", "D"}), ());
auto collectNamesForExactScale = [&](m2::RectD const & rect, int scale)
{ return CollectNames(id, index, header.GetLastScale(), scale, rect); };
auto const drawableScale = feature::GetMinDrawableScaleClassifOnly(a.GetTypes());
CHECK_LESS(drawableScale, header.GetLastScale(), ("Change the test to ensure scales less than last scale work."));
TEST_EQUAL(collectNamesForExactScale(m2::RectD{-0.5, -0.5, 0.5, 0.5}, drawableScale), Names({"A"}), ());
TEST_EQUAL(collectNamesForExactScale(m2::RectD{0.5, -0.5, 1.5, 1.5}, drawableScale), Names({"B", "C"}), ());
TEST_EQUAL(collectNamesForExactScale(m2::RectD{-0.5, -0.5, 1.5, 1.5}, drawableScale), Names({"A", "B", "C", "D"}),
());
}
} // namespace scale_index_reading_tests

View file

@ -0,0 +1,351 @@
#include "testing/testing.hpp"
#include "indexer/search_string_utils.hpp"
#include "base/string_utils.hpp"
#include <string>
#include <vector>
namespace search_string_utils_test
{
using namespace search;
using namespace std;
using namespace strings;
class Utf8StreetTokensFilter
{
public:
explicit Utf8StreetTokensFilter(vector<pair<string, size_t>> & cont, bool withMisprints = false)
: m_cont(cont)
, m_filter([&](UniString const & token, size_t tag) { m_cont.emplace_back(ToUtf8(token), tag); }, withMisprints)
{}
void Put(string const & token, bool isPrefix, size_t tag) { m_filter.Put(MakeUniString(token), isPrefix, tag); }
private:
vector<pair<string, size_t>> & m_cont;
StreetTokensFilter m_filter;
};
bool TestStreetSynonym(char const * s)
{
return IsStreetSynonym(MakeUniString(s));
}
bool TestStreetPrefixMatch(char const * s)
{
return IsStreetSynonymPrefix(MakeUniString(s));
}
bool TestStreetSynonymWithMisprints(char const * s)
{
return IsStreetSynonymWithMisprints(MakeUniString(s));
}
bool TestStreetPrefixMatchWithMisprints(char const * s)
{
return IsStreetSynonymPrefixWithMisprints(MakeUniString(s));
}
string NormalizeAndSimplifyStringUtf8(string const & s)
{
return strings::ToUtf8(NormalizeAndSimplifyString(s));
}
UNIT_TEST(FeatureTypeToString)
{
TEST_EQUAL("!type:123", ToUtf8(FeatureTypeToString(123)), ());
}
UNIT_TEST(NormalizeAndSimplifyString_WithOurTambourines)
{
// This test is dependent from strings::NormalizeAndSimplifyString implementation.
// TODO: Fix it when logic with и-й will change.
/*
string const arr[] = {"ÜbërÅłłęšß", "uberallesss", // Basic test case.
"Iiİı", "iiii", // Famous turkish "I" letter bug.
"ЙЁйёШКИЙй", "йейешкийй", // Better handling of Russian й letter.
"ØøÆæŒœ", "ooaeaeoeoe",
"バス", "ハス",
"âàáạăốợồôểềệếỉđưựứửýĂÂĐÊÔƠƯ",
"aaaaaooooeeeeiduuuuyaadeoou", // Vietnamese
"ăâț", "aat" // Romanian
};
*/
string const arr[] = {
"ÜbërÅłłęšß",
"uberallesss", // Basic test case.
"Iiİı",
"iiii", // Famous turkish "I" letter bug.
"ЙЁйёШКИЙй",
"иеиешкиии", // Better handling of Russian й letter.
"ØøÆæŒœ",
"ooaeaeoeoe", // Dansk
"バス",
"ハス",
"âàáạăốợồôểềệếỉđưựứửýĂÂĐÊÔƠƯ",
"aaaaaooooeeeeiduuuuyaadeoou", // Vietnamese
"ăâț",
"aat", // Romanian
"Триу́мф-Пала́с",
"триумф-палас", // Russian accent
" a b c d ",
" a b c d ", // Multiple spaces
};
for (size_t i = 0; i < ARRAY_SIZE(arr); i += 2)
TEST_EQUAL(arr[i + 1], NormalizeAndSimplifyStringUtf8(arr[i]), ());
}
UNIT_TEST(NormalizeAndSimplifyString_Contains)
{
constexpr char const * kTestStr = "ØøÆæŒœ Ўвага!";
TEST(ContainsNormalized(kTestStr, ""), ());
TEST(!ContainsNormalized("", "z"), ());
TEST(ContainsNormalized(kTestStr, "ooae"), ());
TEST(ContainsNormalized(kTestStr, " у"), ());
TEST(ContainsNormalized(kTestStr, "Ў"), ());
TEST(ContainsNormalized(kTestStr, "ўв"), ());
TEST(!ContainsNormalized(kTestStr, "ага! "), ());
TEST(!ContainsNormalized(kTestStr, "z"), ());
}
UNIT_TEST(Street_Synonym)
{
TEST(TestStreetSynonym("street"), ());
TEST(TestStreetSynonym("улица"), ());
TEST(TestStreetSynonym("strasse"), ());
TEST(TestStreetSynonymWithMisprints("strasse"), ());
TEST(!TestStreetSynonym("strase"), ());
TEST(TestStreetSynonymWithMisprints("strase"), ());
// TEST(TestStreetSynonym("boulevard"), ());
// TEST(TestStreetSynonymWithMisprints("boulevard"), ());
// TEST(!TestStreetSynonym("boulevrd"), ());
// TEST(TestStreetSynonymWithMisprints("boulevrd"), ());
TEST(TestStreetSynonym("avenue"), ());
TEST(TestStreetSynonymWithMisprints("avenue"), ());
TEST(!TestStreetSynonym("aveneu"), ());
TEST(TestStreetSynonymWithMisprints("aveneu"), ());
TEST(!TestStreetSynonymWithMisprints("abcdefg"), ());
TEST(TestStreetSynonym("g."), ());
TEST(TestStreetSynonymWithMisprints("g."), ());
TEST(!TestStreetSynonymWithMisprints("ву"), ());
TEST(TestStreetSynonymWithMisprints("вул"), ());
TEST(!TestStreetSynonymWithMisprints("gat"), ());
TEST(!TestStreetSynonymWithMisprints("sok"), ());
TEST(!TestStreetSynonymWithMisprints("ca"), ());
// soka -> sokak
TEST(TestStreetSynonymWithMisprints("soka"), ());
TEST(!TestStreetSynonym("soka"), ());
}
UNIT_TEST(Street_PrefixMatch)
{
TEST(TestStreetPrefixMatch("у"), ());
TEST(TestStreetPrefixMatch("ул"), ());
TEST(TestStreetPrefixMatch("ули"), ());
TEST(TestStreetPrefixMatch("gat"), ());
TEST(TestStreetPrefixMatch("sok"), ());
TEST(TestStreetPrefixMatch("ca"), ());
TEST(TestStreetPrefixMatch("ву"), ());
// TEST(TestStreetPrefixMatch("п"), ());
// TEST(TestStreetPrefixMatch("пр"), ());
// TEST(TestStreetPrefixMatch("про"), ());
// TEST(TestStreetPrefixMatch("прое"), ());
// TEST(TestStreetPrefixMatch("проез"), ());
// TEST(TestStreetPrefixMatch("проезд"), ());
// TEST(!TestStreetPrefixMatch("проездд"), ());
TEST(TestStreetPrefixMatchWithMisprints("ул"), ());
TEST(!TestStreetPrefixMatch("уле"), ());
TEST(!TestStreetPrefixMatchWithMisprints("уле"), ());
TEST(!TestStreetPrefixMatch("улец"), ());
TEST(TestStreetPrefixMatchWithMisprints("улец"), ());
TEST(!TestStreetPrefixMatch("улеца"), ());
TEST(TestStreetPrefixMatchWithMisprints("улеца"), ());
TEST(TestStreetPrefixMatchWithMisprints("roadx"), ());
TEST(!TestStreetPrefixMatchWithMisprints("roadxx"), ());
TEST(!TestStreetPrefixMatchWithMisprints("groad"), ()); // road, but no
TEST(TestStreetPrefixMatchWithMisprints("karre"), ()); // carrer
TEST(!TestStreetPrefixMatchWithMisprints("karrerx"), ());
}
UNIT_TEST(Street_TokensFilter)
{
using List = vector<pair<string, size_t>>;
{
List expected = {};
List actual;
Utf8StreetTokensFilter filter(actual);
filter.Put("ули", true /* isPrefix */, 0 /* tag */);
TEST_EQUAL(expected, actual, ());
}
{
List expected = {};
List actual;
Utf8StreetTokensFilter filter(actual);
filter.Put("улица", false /* isPrefix */, 0 /* tag */);
TEST_EQUAL(expected, actual, ());
}
{
List expected = {{"генерала", 1}, {"антонова", 2}};
List actual;
Utf8StreetTokensFilter filter(actual);
filter.Put("ул", false /* isPrefix */, 0 /* tag */);
filter.Put("генерала", false /* isPrefix */, 1 /* tag */);
filter.Put("антонова", false /* isPrefix */, 2 /* tag */);
TEST_EQUAL(expected, actual, ());
}
{
List expected = {{"набережная", 50}};
List actual;
Utf8StreetTokensFilter filter(actual);
filter.Put("улица", false /* isPrefix */, 100 /* tag */);
filter.Put("набережная", true /* isPrefix */, 50 /* tag */);
TEST_EQUAL(expected, actual, ());
}
{
List expected = {{"набережная", 1}};
List actual;
Utf8StreetTokensFilter filter(actual);
filter.Put("улица", false /* isPrefix */, 0 /* tag */);
filter.Put("набережная", true /* isPrefix */, 1 /* tag */);
filter.Put("проспект", false /* isPrefix */, 2 /* tag */);
TEST_EQUAL(expected, actual, ());
}
{
List expectedWithMP = {{"ленинский", 0}};
List expectedWithoutMP = {{"ленинский", 0}, {"пропект", 1}};
List actualWithMisprints;
List actualWithoutMisprints;
Utf8StreetTokensFilter filterWithMisprints(actualWithMisprints, true /* withMisprints */);
Utf8StreetTokensFilter filterWithoutMisprints(actualWithoutMisprints, false /* withMisprints */);
filterWithMisprints.Put("ленинский", false /* isPrefix */, 0 /* tag */);
filterWithoutMisprints.Put("ленинский", false /* isPrefix */, 0 /* tag */);
filterWithMisprints.Put("пропект", false /* isPrefix */, 1 /* tag */);
filterWithoutMisprints.Put("пропект", false /* isPrefix */, 1 /* tag */);
TEST_EQUAL(expectedWithMP, actualWithMisprints, ());
TEST_EQUAL(expectedWithoutMP, actualWithoutMisprints, ());
}
{
List expected = {{"набрежная", 1}};
List actualWithMisprints;
List actualWithoutMisprints;
Utf8StreetTokensFilter filterWithMisprints(actualWithMisprints, true /* withMisprints */);
Utf8StreetTokensFilter filterWithoutMisprints(actualWithoutMisprints, false /* withMisprints */);
filterWithMisprints.Put("улица", false /* isPrefix */, 0 /* tag */);
filterWithoutMisprints.Put("улица", false /* isPrefix */, 0 /* tag */);
filterWithMisprints.Put("набрежная", false /* isPrefix */, 1 /* tag */);
filterWithoutMisprints.Put("набрежная", false /* isPrefix */, 1 /* tag */);
TEST_EQUAL(expected, actualWithMisprints, ());
TEST_EQUAL(expected, actualWithoutMisprints, ());
}
}
UNIT_TEST(NormalizeAndSimplifyString_Numero)
{
TEST_EQUAL(NormalizeAndSimplifyStringUtf8("Зона №51"), "зона #51", ());
TEST_EQUAL(NormalizeAndSimplifyStringUtf8("Area № 51"), "area # 51", ());
TEST_EQUAL(NormalizeAndSimplifyStringUtf8("Area #One"), "area #one", ());
}
UNIT_TEST(NormalizeAndSimplifyString_Apostrophe)
{
TEST_EQUAL(NormalizeAndSimplifyStringUtf8("Pops"), "pop's", ());
}
UNIT_TEST(Steet_GetStreetNameAsKey)
{
auto const Check = [](std::string_view src, std::string_view expected)
{ TEST_EQUAL(GetStreetNameAsKey(src, true /* ignoreStreetSynonyms */), strings::MakeUniString(expected), ()); };
{
std::string_view const ethalon = "680northwest";
Check("N 680 W", ethalon);
Check("North 680 West", ethalon);
Check("680 NW", ethalon);
}
Check("North 20th Rd", "20thnorth");
Check("Lane st", "lane st"); /// @todo Probably, doesn't matter here?
Check("West North", "westnorth"); /// @todo Should order?
Check("NW", "northwest");
}
UNIT_TEST(Steet_GetNormalizedStreetName)
{
auto const Check = [](std::string_view s1, std::string_view s2)
{ TEST_EQUAL(GetNormalizedStreetName(s1), GetNormalizedStreetName(s2), ()); };
Check("Lane G", "G Ln");
Check("South Grapetree Road", "S Grape Tree Rd");
Check("Peter's Farm Road", "Peters Farm Rd");
Check("Farrelly - Soto Avenue", "Farrelly-Soto Ave");
Check("2nd Loop South", "2nd Lp S");
Check("Circle Street", "Circle St");
Check("Rue de St. Anne", "Rue de St Anne");
Check("St. Lucia Drive", "St Lucia Dr");
Check("County Road 87", "Co Rd 87");
Check("Mountain Vista", "Mtn Vis");
Check("Scott's Trace", "Scotts Trce");
Check("Inverness Cliffs Drive", "Inverness Clfs Dr");
Check("Pine Crest Loop", "Pine Crst Lp");
Check("8th Street North East", "N Eighth E St");
Check("Black Creek Crossing", "Black Creek Xing");
Check("Magruders Bluff", "Magruders Blf");
Check("5th Avenue", "Fifth ave");
Check("Northeast 26th Avenue", "NE 26th Ave");
/// @todo Fancy examples:
// https://www.openstreetmap.org/way/1188750428
// Check("East Ridge Road", "E Rdg");
// Check("7th Street", "Sevens St");
// https://www.openstreetmap.org/way/8605899
// Check("Beaver Crest Drive", "Beaver Crst");
// https://www.openstreetmap.org/way/8607254
// Check("St Annes Drive", "Saint Annes Dr");
// https://www.openstreetmap.org/way/7703018
// Check("AL 60", "Al Highway 60");
// https://www.openstreetmap.org/way/7705380
// Seems like it means "Centerville Street" or "County Road 25"
// Check("Centreville Street", "Centerville St Co Rd 25");
// https://www.openstreetmap.org/way/23629713
// Check("Northeast Martin Luther King Junior Boulevard", "NE M L King Blvd");
}
} // namespace search_string_utils_test

View file

@ -0,0 +1,63 @@
#include "indexer/feature_covering.hpp"
#include "testing/testing.hpp"
#include <vector>
using namespace std;
UNIT_TEST(SortAndMergeIntervals_1Interval)
{
vector<pair<int64_t, int64_t>> v;
v.push_back(make_pair(1ULL, 2ULL));
TEST_EQUAL(covering::SortAndMergeIntervals(v), v, ());
}
UNIT_TEST(SortAndMergeIntervals_2NotSortedNotOverlappin)
{
vector<pair<int64_t, int64_t>> v;
v.push_back(make_pair(3ULL, 4ULL));
v.push_back(make_pair(1ULL, 2ULL));
vector<pair<int64_t, int64_t>> e;
e.push_back(make_pair(1ULL, 2ULL));
e.push_back(make_pair(3ULL, 4ULL));
TEST_EQUAL(covering::SortAndMergeIntervals(v), e, ());
}
UNIT_TEST(SortAndMergeIntervals_BorderMerge)
{
vector<pair<int64_t, int64_t>> v;
v.push_back(make_pair(1ULL, 2ULL));
v.push_back(make_pair(2ULL, 3ULL));
vector<pair<int64_t, int64_t>> e;
e.push_back(make_pair(1ULL, 3ULL));
TEST_EQUAL(covering::SortAndMergeIntervals(v), e, ());
}
UNIT_TEST(SortAndMergeIntervals_Overlap)
{
vector<pair<int64_t, int64_t>> v;
v.push_back(make_pair(1ULL, 3ULL));
v.push_back(make_pair(2ULL, 4ULL));
vector<pair<int64_t, int64_t>> e;
e.push_back(make_pair(1ULL, 4ULL));
TEST_EQUAL(covering::SortAndMergeIntervals(v), e, ());
}
UNIT_TEST(SortAndMergeIntervals_Contain)
{
vector<pair<int64_t, int64_t>> v;
v.push_back(make_pair(2ULL, 3ULL));
v.push_back(make_pair(1ULL, 4ULL));
vector<pair<int64_t, int64_t>> e;
e.push_back(make_pair(1ULL, 4ULL));
TEST_EQUAL(covering::SortAndMergeIntervals(v), e, ());
}
UNIT_TEST(SortAndMergeIntervals_ContainAndTouchBorder)
{
vector<pair<int64_t, int64_t>> v;
v.push_back(make_pair(1ULL, 3ULL));
v.push_back(make_pair(1ULL, 4ULL));
vector<pair<int64_t, int64_t>> e;
e.push_back(make_pair(1ULL, 4ULL));
TEST_EQUAL(covering::SortAndMergeIntervals(v), e, ());
}

View file

@ -0,0 +1,78 @@
#include "../../testing/testing.hpp"
#include "indexer/string_slice.hpp"
#include "base/string_utils.hpp"
#include <iterator>
#include <vector>
using namespace search;
using namespace std;
using namespace strings;
namespace
{
UniString ToString(vector<UniString> const & v)
{
StringSlice slice(v);
UniString r;
copy(JoinIterator::Begin(slice), JoinIterator::End(slice), back_inserter(r));
return r;
}
UNIT_TEST(JoinIterator_Smoke)
{
{
vector<UniString> v;
StringSlice slice1(v);
auto begin1 = JoinIterator::Begin(slice1);
auto end1 = JoinIterator::End(slice1);
StringSlice slice2(v);
auto begin2 = JoinIterator::Begin(slice2);
auto end2 = JoinIterator::End(slice2);
TEST(begin1 == end1, ());
TEST(begin2 == end2, ());
TEST(begin1 != begin2, ());
TEST(end1 != end2, ());
TEST(begin1 != end2, ());
TEST(begin2 != end1, ());
}
{
vector<UniString> const v;
TEST_EQUAL(MakeUniString(""), ToString(v), ());
}
{
vector<UniString> const v = {MakeUniString("")};
TEST_EQUAL(MakeUniString(""), ToString(v), ());
}
{
vector<UniString> const v = {MakeUniString(""), MakeUniString("")};
TEST_EQUAL(MakeUniString(" "), ToString(v), ());
}
{
vector<UniString> const v = {MakeUniString(""), MakeUniString("b"), MakeUniString("")};
TEST_EQUAL(MakeUniString(" b "), ToString(v), ());
}
{
vector<UniString> const v = {MakeUniString("Hello")};
TEST_EQUAL(MakeUniString("Hello"), ToString(v), ());
}
{
vector<UniString> const v = {MakeUniString("Hello"), MakeUniString("World!")};
TEST_EQUAL(MakeUniString("Hello World!"), ToString(v), ());
}
}
} // namespace

View file

@ -0,0 +1,270 @@
#include "testing/testing.hpp"
#include "coding/reader.hpp"
#include "coding/writer.hpp"
#include "indexer/succinct_trie_builder.hpp"
#include "indexer/succinct_trie_reader.hpp"
#include "indexer/trie.hpp"
#include "indexer/trie_builder.hpp"
#include "indexer/trie_reader.hpp"
#include "base/string_utils.hpp"
#include <string>
#include <utility>
#include <vector>
using namespace std;
namespace
{
struct StringsFileEntryMock
{
StringsFileEntryMock() = default;
StringsFileEntryMock(string const & key, uint8_t value) : m_key(key.begin(), key.end()), m_value(value) {}
trie::TrieChar const * GetKeyData() { return m_key.data(); }
size_t GetKeySize() const { return m_key.size(); }
uint8_t GetValue() const { return m_value; }
void * value_data() const { return nullptr; }
size_t value_size() const { return 0; }
void Swap(StringsFileEntryMock & o)
{
swap(m_key, o.m_key);
swap(m_value, o.m_value);
}
bool operator==(StringsFileEntryMock const & o) const { return m_key == o.m_key && m_value == o.m_value; }
bool operator<(StringsFileEntryMock const & o) const
{
if (m_key != o.m_key)
return m_key < o.m_key;
return m_value < o.m_value;
}
vector<trie::TrieChar> m_key;
uint8_t m_value;
};
template <typename TWriter>
struct EmptyValueList
{
size_t size() const { return 0; }
void Dump(TWriter &) const {}
void Append(int) {}
};
struct EmptyValueReader
{
using ValueType = unsigned char;
EmptyValueReader() = default;
template <typename SourceT>
void operator()(SourceT &, ValueType & value) const
{
value = 0;
}
};
struct SimpleValueReader
{
public:
SimpleValueReader() = default;
using ValueType = uint8_t;
template <typename TReader>
void operator()(TReader & reader, ValueType & v) const
{
v = ReadPrimitiveFromSource<uint8_t>(reader);
}
template <class TWriter>
void Save(TWriter & writer, ValueType const & v) const
{
WriteToSink(writer, v);
}
};
template <typename TWriter>
struct SimpleValueList
{
size_t size() const { return m_valueList.size(); }
void Dump(TWriter & writer) const
{
for (uint8_t x : m_valueList)
WriteToSink(writer, x);
}
void Append(uint8_t x) { m_valueList.push_back(x); }
vector<uint8_t> m_valueList;
};
using TSimpleIterator = trie::SuccinctTrieIterator<MemReader, SimpleValueReader>;
void ReadAllValues(TSimpleIterator & root, vector<uint8_t> & values)
{
for (size_t i = 0; i < root.NumValues(); ++i)
values.push_back(root.GetValue(i));
}
void CollectInSubtree(TSimpleIterator & root, vector<uint8_t> & collectedValues)
{
ReadAllValues(root, collectedValues);
if (auto l = root.GoToEdge(0))
CollectInSubtree(*l, collectedValues);
if (auto r = root.GoToEdge(1))
CollectInSubtree(*r, collectedValues);
}
template <typename TWriter>
void BuildFromSimpleValueList(TWriter & writer, vector<StringsFileEntryMock> & data)
{
trie::BuildSuccinctTrie<TWriter, vector<StringsFileEntryMock>::iterator, SimpleValueList<TWriter>>(
writer, data.begin(), data.end());
}
} // namespace
namespace trie
{
// todo(@pimenov): It may be worth it to write a test
// for the trie's topology but the test may be flaky because
// it has to depend on the particular Huffman encoding of the key strings.
// This is remedied by separation of the string-encoding and trie-building
// parts, but they are not separated now, hence there is no such test.
UNIT_TEST(SuccinctTrie_Serialization_Smoke1)
{
vector<uint8_t> buf;
using TWriter = MemWriter<vector<uint8_t>>;
TWriter memWriter(buf);
vector<StringsFileEntryMock> data = {StringsFileEntryMock("abacaba", 1)};
trie::BuildSuccinctTrie<TWriter, vector<StringsFileEntryMock>::iterator, EmptyValueList<TWriter>>(
memWriter, data.begin(), data.end());
MemReader memReader(buf.data(), buf.size());
auto trieRoot = trie::ReadSuccinctTrie(memReader, EmptyValueReader());
TEST(trieRoot, ());
}
UNIT_TEST(SuccinctTrie_Serialization_Smoke2)
{
vector<uint8_t> buf;
using TWriter = MemWriter<vector<uint8_t>>;
TWriter memWriter(buf);
vector<StringsFileEntryMock> data = {StringsFileEntryMock("abacaba", 1)};
BuildFromSimpleValueList(memWriter, data);
MemReader memReader(buf.data(), buf.size());
auto trieRoot = trie::ReadSuccinctTrie(memReader, SimpleValueReader());
TEST(trieRoot, ());
}
UNIT_TEST(SuccinctTrie_Iterator)
{
vector<uint8_t> buf;
using TWriter = MemWriter<vector<uint8_t>>;
TWriter memWriter(buf);
vector<StringsFileEntryMock> data = {StringsFileEntryMock("a", 1), StringsFileEntryMock("b", 2),
StringsFileEntryMock("ab", 3), StringsFileEntryMock("ba", 4),
StringsFileEntryMock("abc", 5)};
sort(data.begin(), data.end());
BuildFromSimpleValueList(memWriter, data);
MemReader memReader(buf.data(), buf.size());
auto trieRoot = trie::ReadSuccinctTrie(memReader, SimpleValueReader());
TEST(trieRoot, ());
vector<uint8_t> collectedValues;
CollectInSubtree(*trieRoot, collectedValues);
sort(collectedValues.begin(), collectedValues.end());
TEST_EQUAL(collectedValues.size(), 5, ());
for (size_t i = 0; i < collectedValues.size(); ++i)
TEST_EQUAL(collectedValues[i], i + 1, ());
}
UNIT_TEST(SuccinctTrie_MoveToString)
{
vector<uint8_t> buf;
using TWriter = MemWriter<vector<uint8_t>>;
TWriter memWriter(buf);
vector<StringsFileEntryMock> data = {StringsFileEntryMock("abcde", 1), StringsFileEntryMock("aaaaa", 2),
StringsFileEntryMock("aaa", 3), StringsFileEntryMock("aaa", 4)};
sort(data.begin(), data.end());
BuildFromSimpleValueList(memWriter, data);
MemReader memReader(buf.data(), buf.size());
auto trieRoot = trie::ReadSuccinctTrie(memReader, SimpleValueReader());
{
auto it = trieRoot->GoToString(strings::MakeUniString("a"));
TEST(it != nullptr, ());
vector<uint8_t> expectedValues;
vector<uint8_t> receivedValues;
ReadAllValues(*it.get(), receivedValues);
TEST_EQUAL(expectedValues, receivedValues, ());
}
{
auto it = trieRoot->GoToString(strings::MakeUniString("abcde"));
TEST(it != nullptr, ());
vector<uint8_t> expectedValues{1};
vector<uint8_t> receivedValues;
ReadAllValues(*it.get(), receivedValues);
TEST_EQUAL(expectedValues, receivedValues, ());
}
{
auto it = trieRoot->GoToString(strings::MakeUniString("aaaaa"));
TEST(it != nullptr, ());
vector<uint8_t> expectedValues{2};
vector<uint8_t> receivedValues;
ReadAllValues(*it.get(), receivedValues);
TEST_EQUAL(expectedValues, receivedValues, ());
}
{
auto it = trieRoot->GoToString(strings::MakeUniString("aaa"));
TEST(it != nullptr, ());
vector<uint8_t> expectedValues{3, 4};
vector<uint8_t> receivedValues;
ReadAllValues(*it.get(), receivedValues);
TEST_EQUAL(expectedValues, receivedValues, ());
}
{
auto it = trieRoot->GoToString(strings::MakeUniString("b"));
TEST(it == nullptr, ());
}
{
auto it = trieRoot->GoToString(strings::MakeUniString("bbbbb"));
TEST(it == nullptr, ());
}
}
} // namespace trie

View file

@ -0,0 +1,41 @@
#pragma once
#include "indexer/mwm_set.hpp"
#include "platform/country_file.hpp"
#include "platform/local_country_file.hpp"
#include "platform/mwm_version.hpp"
#include "geometry/rect2d.hpp"
#include <memory>
using platform::CountryFile;
using platform::LocalCountryFile;
namespace tests
{
class TestMwmSet : public MwmSet
{
protected:
/// @name MwmSet overrides
//@{
std::unique_ptr<MwmInfo> CreateInfo(platform::LocalCountryFile const & localFile) const override
{
int const n = localFile.GetCountryName()[0] - '0';
auto info = std::make_unique<MwmInfo>();
info->m_maxScale = n;
info->m_bordersRect = m2::RectD(0, 0, 1, 1);
info->m_version.SetFormat(version::Format::lastFormat);
return info;
}
std::unique_ptr<MwmValue> CreateValue(MwmInfo & info) const override
{
return std::make_unique<MwmValue>(info.GetLocalFile());
}
//@}
};
} // namespace tests

View file

@ -0,0 +1,46 @@
#include "testing/testing.hpp"
#include "indexer/classificator.hpp"
namespace
{
void check_values_array(uint8_t values[], uint8_t count)
{
uint32_t type = ftype::GetEmptyValue();
for (uint8_t i = 0; i < count; ++i)
ftype::PushValue(type, values[i]);
for (uint8_t i = 0; i < count; ++i)
TEST_EQUAL(ftype::GetValue(type, i), values[i], ());
while (count > 0)
{
TEST_EQUAL(ftype::GetLevel(type), count, ());
ftype::PopValue(type);
--count;
}
TEST_EQUAL(ftype::GetLevel(type), 0, ());
TEST_EQUAL(type, ftype::GetEmptyValue(), (type));
}
} // namespace
UNIT_TEST(SetGetTypes)
{
uint8_t v1[] = {6, 30, 0, 1};
check_values_array(v1, 4);
check_values_array(v1, 3);
uint8_t v2[] = {0, 0, 0, 0};
check_values_array(v2, 4);
check_values_array(v2, 3);
uint8_t v3[] = {1, 1, 1, 1};
check_values_array(v3, 4);
check_values_array(v3, 3);
uint8_t v4[] = {63, 63, 63, 63};
check_values_array(v4, 4);
check_values_array(v4, 3);
}

View file

@ -0,0 +1,196 @@
#include "testing/testing.hpp"
#include "indexer/complex/tree_node.hpp"
#include "base/control_flow.hpp"
#include <iterator>
#include <list>
#include <string>
#include <vector>
namespace
{
decltype(auto) MakeTree()
{
auto tree1 = tree_node::MakeTreeNode(1);
auto node11 = tree_node::MakeTreeNode(21);
tree_node::Link(tree_node::MakeTreeNode(31), node11);
tree_node::Link(tree_node::MakeTreeNode(32), node11);
tree_node::Link(tree_node::MakeTreeNode(33), node11);
tree_node::Link(node11, tree1);
tree_node::Link(tree_node::MakeTreeNode(34), tree1);
auto tree2 = tree_node::MakeTreeNode(22);
tree_node::Link(tree_node::MakeTreeNode(35), tree2);
tree_node::Link(tree_node::MakeTreeNode(36), tree2);
tree_node::Link(tree2, tree1);
return tree1;
}
UNIT_TEST(TreeNode_PreOrderVisit)
{
auto const tree = MakeTree();
std::vector<int> res;
tree_node::PreOrderVisit(tree, [&](auto const & node) { res.emplace_back(node->GetData()); });
std::vector<int> const expected = {1, 21, 31, 32, 33, 34, 22, 35, 36};
TEST_EQUAL(res, expected, ());
auto countVisitedNode = 0;
tree_node::PreOrderVisit(tree, [&](auto const & node)
{
++countVisitedNode;
return node->GetData() == 32 ? base::ControlFlow::Break : base::ControlFlow::Continue;
});
TEST_EQUAL(countVisitedNode, 4, ());
}
UNIT_TEST(TreeNode_Size)
{
auto const tree = MakeTree();
auto const size = tree_node::Size(tree);
TEST_EQUAL(size, 9, ());
}
UNIT_TEST(TreeNode_FindIf)
{
auto const tree = MakeTree();
auto node = tree_node::FindIf(tree, [](auto const & d) { return d == 1; });
TEST(node, ());
node = tree_node::FindIf(tree, [](auto const & d) { return d == 22; });
TEST(node, ());
node = tree_node::FindIf(tree, [](auto const & d) { return d == 36; });
TEST(node, ());
node = tree_node::FindIf(tree, [](auto const & d) { return d == 100; });
TEST(!node, ());
}
UNIT_TEST(TreeNode_GetDepth)
{
auto const tree = MakeTree();
auto depth = tree_node::GetDepth(tree_node::FindIf(tree, [](auto const & d) { return d == 1; }));
TEST_EQUAL(depth, 1, ());
depth = tree_node::GetDepth(tree_node::FindIf(tree, [](auto const & d) { return d == 22; }));
TEST_EQUAL(depth, 2, ());
depth = tree_node::GetDepth(tree_node::FindIf(tree, [](auto const & d) { return d == 36; }));
TEST_EQUAL(depth, 3, ());
}
UNIT_TEST(TreeNode_GetRoot)
{
auto const tree = MakeTree();
auto const node22 = tree_node::FindIf(tree, [](auto const & d) { return d == 22; });
auto const root = tree_node::GetRoot(node22);
TEST(tree, ());
TEST_EQUAL(tree->GetData(), root->GetData(), ());
}
UNIT_TEST(TreeNode_GetPath)
{
auto const tree = MakeTree();
auto const node33 = tree_node::FindIf(tree, [](auto const & d) { return d == 33; });
auto const path = tree_node::GetPathToRoot(node33);
tree_node::types::Ptrs<int> expected = {tree_node::FindIf(tree, [](auto const & d) { return d == 33; }),
tree_node::FindIf(tree, [](auto const & d) { return d == 21; }),
tree_node::FindIf(tree, [](auto const & d) { return d == 1; })};
TEST_EQUAL(path, expected, ());
}
UNIT_TEST(TreeNode_IsEqual)
{
auto tree1 = tree_node::MakeTreeNode(1);
auto node11 = tree_node::MakeTreeNode(21);
tree_node::Link(tree_node::MakeTreeNode(31), node11);
tree_node::Link(tree_node::MakeTreeNode(32), node11);
tree_node::Link(tree_node::MakeTreeNode(33), node11);
tree_node::Link(node11, tree1);
TEST(tree_node::IsEqual(tree1, tree1), ());
TEST(!tree_node::IsEqual(tree1, node11), ());
}
UNIT_TEST(TreeNode_TransformToTree)
{
auto const tree = MakeTree();
auto const newTree = tree_node::TransformToTree(tree, [](auto const & data) { return std::to_string(data); });
auto expected = tree_node::MakeTreeNode<std::string>("1");
auto node11 = tree_node::MakeTreeNode<std::string>("21");
tree_node::Link(tree_node::MakeTreeNode<std::string>("31"), node11);
tree_node::Link(tree_node::MakeTreeNode<std::string>("32"), node11);
tree_node::Link(tree_node::MakeTreeNode<std::string>("33"), node11);
tree_node::Link(node11, expected);
tree_node::Link(tree_node::MakeTreeNode<std::string>("34"), expected);
auto tree2 = tree_node::MakeTreeNode<std::string>("22");
tree_node::Link(tree_node::MakeTreeNode<std::string>("35"), tree2);
tree_node::Link(tree_node::MakeTreeNode<std::string>("36"), tree2);
tree_node::Link(tree2, expected);
TEST(tree_node::IsEqual(newTree, expected), ());
}
UNIT_TEST(TreeNode_CountIf)
{
auto const tree = MakeTree();
auto const count = tree_node::CountIf(tree, [](auto const & data) { return data >= 30; });
TEST_EQUAL(count, 6, ());
}
UNIT_TEST(TreeNode_DebugPrint)
{
auto const tree = MakeTree();
LOG(LINFO, (tree_node::DebugPrint(tree)));
}
UNIT_TEST(TreeNode_Forest)
{
tree_node::Forest<int> forest;
std::set<tree_node::types::Ptr<int>> s = {MakeTree(), tree_node::MakeTreeNode(10)};
for (auto const & tree : s)
forest.Append(tree);
TEST_EQUAL(forest.Size(), 2, ());
forest.ForEachTree([&](auto const & tree)
{
auto const count = s.erase(tree);
TEST_EQUAL(count, 1, ());
});
TEST(s.empty(), ());
auto const copy = forest;
TEST_EQUAL(copy, forest, ());
tree_node::Forest<int> empty;
TEST_NOT_EQUAL(empty, forest, ());
}
UNIT_TEST(TreeNode_ForestFindIf)
{
tree_node::Forest<int> forest;
forest.Append(MakeTree());
forest.Append(tree_node::MakeTreeNode(100));
auto const node33 = tree_node::FindIf(forest, [](auto const & d) { return d == 33; });
TEST(node33, ());
TEST_EQUAL(node33->GetData(), 33, ());
auto const node100 = tree_node::FindIf(forest, [](auto const & d) { return d == 100; });
TEST(node100, ());
TEST_EQUAL(node100->GetData(), 100, ());
}
UNIT_TEST(TreeNode_ForestDebugPrint)
{
tree_node::Forest<int> forest;
forest.Append(MakeTree());
forest.Append(tree_node::MakeTreeNode(100));
forest.Append(tree_node::MakeTreeNode(200));
LOG(LINFO, (tree_node::DebugPrint(forest)));
}
} // namespace

View file

@ -0,0 +1,285 @@
#include "testing/testing.hpp"
#include "indexer/trie.hpp"
#include "indexer/trie_builder.hpp"
#include "indexer/trie_reader.hpp"
#include "coding/byte_stream.hpp"
#include "coding/reader.hpp"
#include "coding/write_to_sink.hpp"
#include "base/logging.hpp"
#include <algorithm>
#include <cstring>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>
#include <boost/utility/binary.hpp>
namespace trie_test
{
using namespace std;
struct ChildNodeInfo
{
ChildNodeInfo(bool isLeaf, uint32_t size, char const * edge) : m_isLeaf(isLeaf), m_size(size)
{
while (*edge)
m_edge.push_back(*edge++);
}
uint32_t Size() const { return m_size; }
bool IsLeaf() const { return m_isLeaf; }
trie::TrieChar const * GetEdge() const { return &m_edge[0]; }
size_t GetEdgeSize() const { return m_edge.size(); }
bool m_isLeaf;
uint32_t m_size;
vector<trie::TrieChar> m_edge;
};
// The SingleValueSerializer and ValueList classes are similar to
// those in indexer/search_index_values.hpp.
template <typename Primitive>
class SingleValueSerializer
{
public:
#if !defined(OMIM_OS_LINUX)
static_assert(std::is_trivially_copyable<Primitive>::value, "");
#endif
template <typename Sink>
void Serialize(Sink & sink, Primitive const & v) const
{
WriteToSink(sink, v);
}
};
template <typename Primitive>
class ValueList
{
public:
using Value = Primitive;
using Serializer = SingleValueSerializer<Value>;
#if !defined(OMIM_OS_LINUX)
static_assert(std::is_trivially_copyable<Primitive>::value, "");
#endif
void Init(vector<Value> const & values) { m_values = values; }
size_t Size() const { return m_values.size(); }
bool IsEmpty() const { return m_values.empty(); }
template <typename Sink>
void Serialize(Sink & sink, Serializer const & /* serializer */) const
{
for (auto const & value : m_values)
WriteToSink(sink, value);
}
template <typename Source>
void Deserialize(Source & src, uint32_t valueCount, Serializer const & /* serializer */)
{
m_values.resize(valueCount);
for (size_t i = 0; i < valueCount; ++i)
m_values[i] = ReadPrimitiveFromSource<Value>(src);
}
template <typename Source>
void Deserialize(Source & source, Serializer const & /* serializer */)
{
m_values.clear();
while (source.Size() > 0)
m_values.emplace_back(ReadPrimitiveFromSource<Value>(source));
}
template <typename ToDo>
void ForEach(ToDo && toDo) const
{
for (auto const & value : m_values)
toDo(value);
}
private:
vector<Value> m_values;
};
#define ZENC bits::ZigZagEncode
#define MKSC(x) static_cast<signed char>(x)
#define MKUC(x) static_cast<uint8_t>(x)
UNIT_TEST(TrieBuilder_WriteNode_Smoke)
{
vector<uint8_t> buf;
PushBackByteSink<vector<uint8_t>> sink(buf);
ChildNodeInfo children[] = {
ChildNodeInfo(true, 1, "1A"), ChildNodeInfo(false, 2, "B"), ChildNodeInfo(false, 3, "zz"),
ChildNodeInfo(true, 4, "abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij"),
ChildNodeInfo(true, 5, "a")};
ValueList<char> valueList;
valueList.Init({'1', '2', '3'});
trie::WriteNode(sink, SingleValueSerializer<char>(), 0, valueList, &children[0], &children[0] + ARRAY_SIZE(children));
uint8_t const expected[] = {
BOOST_BINARY(11000101), // Header: [0b11] [0b000101]
3, // Number of values
'1',
'2',
'3', // Values
BOOST_BINARY(10000001), // Child 1: header: [+leaf] [-supershort] [2 symbols]
MKUC(ZENC(MKSC('1'))),
MKUC(ZENC(MKSC('A') - MKSC('1'))), // Child 1: edge
1, // Child 1: size
MKUC(64 | ZENC(MKSC('B') - MKSC('1'))), // Child 2: header: [-leaf] [+supershort]
2, // Child 2: size
BOOST_BINARY(00000001), // Child 3: header: [-leaf] [-supershort] [2 symbols]
MKUC(ZENC(MKSC('z') - MKSC('B'))),
0, // Child 3: edge
3, // Child 3: size
BOOST_BINARY(10111111), // Child 4: header: [+leaf] [-supershort] [>= 63 symbols]
69, // Child 4: edgeSize - 1
MKUC(ZENC(MKSC('a') - MKSC('z'))),
2,
2,
2,
2,
2,
2,
2,
2,
2, // Child 4: edge
MKUC(ZENC(MKSC('a') - MKSC('j'))),
2,
2,
2,
2,
2,
2,
2,
2,
2, // Child 4: edge
MKUC(ZENC(MKSC('a') - MKSC('j'))),
2,
2,
2,
2,
2,
2,
2,
2,
2, // Child 4: edge
MKUC(ZENC(MKSC('a') - MKSC('j'))),
2,
2,
2,
2,
2,
2,
2,
2,
2, // Child 4: edge
MKUC(ZENC(MKSC('a') - MKSC('j'))),
2,
2,
2,
2,
2,
2,
2,
2,
2, // Child 4: edge
MKUC(ZENC(MKSC('a') - MKSC('j'))),
2,
2,
2,
2,
2,
2,
2,
2,
2, // Child 4: edge
MKUC(ZENC(MKSC('a') - MKSC('j'))),
2,
2,
2,
2,
2,
2,
2,
2,
2, // Child 4: edge
4, // Child 4: size
MKUC(BOOST_BINARY(11000000) | ZENC(0)), // Child 5: header: [+leaf] [+supershort]
};
TEST_EQUAL(buf, vector<uint8_t>(&expected[0], &expected[0] + ARRAY_SIZE(expected)), ());
}
UNIT_TEST(TrieBuilder_Build)
{
uint32_t const kBase = 3;
int const kMaxLen = 3;
vector<string> possibleStrings(1, string{});
for (int len = 1; len <= kMaxLen; ++len)
{
for (uint32_t i = 0, p = math::PowUint(kBase, len); i < p; ++i)
{
string s(len, 'A');
uint32_t t = i;
for (int l = len - 1; l >= 0; --l, t /= kBase)
s[l] += (t % kBase);
possibleStrings.push_back(s);
}
}
sort(possibleStrings.begin(), possibleStrings.end());
// LOG(LINFO, (possibleStrings));
int const count = static_cast<int>(possibleStrings.size());
for (int i0 = -1; i0 < count; ++i0)
{
for (int i1 = i0; i1 < count; ++i1)
{
for (int i2 = i1; i2 < count; ++i2)
{
using Key = buffer_vector<trie::TrieChar, 8>;
using Value = uint32_t;
using KeyValuePair = pair<Key, Value>;
vector<KeyValuePair> v;
auto makeKey = [](string const & s) { return Key(s.begin(), s.end()); };
if (i0 >= 0)
v.emplace_back(makeKey(possibleStrings[i0]), i0);
if (i1 >= 0)
v.emplace_back(makeKey(possibleStrings[i1]), i1 + 10);
if (i2 >= 0)
v.emplace_back(makeKey(possibleStrings[i2]), i2 + 100);
vector<string> vs;
for (size_t i = 0; i < v.size(); ++i)
vs.push_back(string(v[i].first.begin(), v[i].first.end()));
vector<uint8_t> buf;
PushBackByteSink<vector<uint8_t>> sink(buf);
SingleValueSerializer<uint32_t> serializer;
trie::Build<PushBackByteSink<vector<uint8_t>>, Key, ValueList<uint32_t>, SingleValueSerializer<uint32_t>>(
sink, serializer, v);
reverse(buf.begin(), buf.end());
MemReader memReader = MemReader(&buf[0], buf.size());
auto const root = trie::ReadTrie<MemReader, ValueList<uint32_t>>(memReader, serializer);
vector<KeyValuePair> res;
auto addKeyValuePair = [&res](Key const & k, Value const & v) { res.emplace_back(k, v); };
trie::ForEachRef(*root, addKeyValuePair, Key{});
sort(res.begin(), res.end());
TEST_EQUAL(v, res, ());
}
}
}
}
} // namespace trie_test

View file

@ -0,0 +1,367 @@
#include "testing/testing.hpp"
#include "indexer/validate_and_format_contacts.hpp"
#include <string>
UNIT_TEST(EditableMapObject_ValidateAndFormat_facebook)
{
TEST_EQUAL(osm::ValidateAndFormat_facebook(""), "", ());
TEST_EQUAL(osm::ValidateAndFormat_facebook("facebook.com/OpenStreetMap"), "OpenStreetMap", ());
TEST_EQUAL(osm::ValidateAndFormat_facebook("www.facebook.com/OpenStreetMap"), "OpenStreetMap", ());
TEST_EQUAL(osm::ValidateAndFormat_facebook("www.facebook.fr/OpenStreetMap"), "OpenStreetMap", ());
TEST_EQUAL(osm::ValidateAndFormat_facebook("http://facebook.com/OpenStreetMap"), "OpenStreetMap", ());
TEST_EQUAL(osm::ValidateAndFormat_facebook("https://facebook.com/OpenStreetMap"), "OpenStreetMap", ());
TEST_EQUAL(osm::ValidateAndFormat_facebook("http://www.facebook.com/OpenStreetMap"), "OpenStreetMap", ());
TEST_EQUAL(osm::ValidateAndFormat_facebook("https://www.facebook.com/OpenStreetMap"), "OpenStreetMap", ());
TEST_EQUAL(osm::ValidateAndFormat_facebook("https://de-de.facebook.de/Open_Street_Map"), "Open_Street_Map", ());
TEST_EQUAL(osm::ValidateAndFormat_facebook("https://en-us.facebook.com/OpenStreetMap"), "OpenStreetMap", ());
TEST_EQUAL(osm::ValidateAndFormat_facebook("https://de-de.facebook.com/profile.php?id=100085707580841"),
"100085707580841", ());
TEST_EQUAL(osm::ValidateAndFormat_facebook("http://facebook.com/profile.php?share=app&id=100086487430889#m"),
"100086487430889", ());
TEST_EQUAL(osm::ValidateAndFormat_facebook("some.good.page"), "some.good.page", ());
TEST_EQUAL(osm::ValidateAndFormat_facebook("@tree-house-interiors"), "tree-house-interiors", ());
TEST_EQUAL(osm::ValidateAndFormat_facebook("instagram.com/openstreetmapus"), "", ());
TEST_EQUAL(osm::ValidateAndFormat_facebook("https://instagram.com/openstreetmapus"), "", ());
TEST_EQUAL(osm::ValidateAndFormat_facebook("osm"), "", ());
TEST_EQUAL(osm::ValidateAndFormat_facebook("@spaces are not welcome here"), "", ());
TEST_EQUAL(osm::ValidateAndFormat_facebook("spaces are not welcome here"), "", ());
}
UNIT_TEST(EditableMapObject_ValidateAndFormat_instagram)
{
TEST_EQUAL(osm::ValidateAndFormat_instagram(""), "", ());
TEST_EQUAL(osm::ValidateAndFormat_instagram("instagram.com/openstreetmapus"), "openstreetmapus", ());
TEST_EQUAL(osm::ValidateAndFormat_instagram("www.instagram.com/openstreetmapus"), "openstreetmapus", ());
TEST_EQUAL(osm::ValidateAndFormat_instagram("http://instagram.com/openstreetmapus"), "openstreetmapus", ());
TEST_EQUAL(osm::ValidateAndFormat_instagram("https://instagram.com/openstreetmapus"), "openstreetmapus", ());
TEST_EQUAL(osm::ValidateAndFormat_instagram("http://www.instagram.com/openstreetmapus"), "openstreetmapus", ());
TEST_EQUAL(osm::ValidateAndFormat_instagram("https://www.instagram.com/openstreetmapus"), "openstreetmapus", ());
TEST_EQUAL(osm::ValidateAndFormat_instagram("https://en-us.instagram.com/openstreetmapus"), "openstreetmapus", ());
TEST_EQUAL(osm::ValidateAndFormat_instagram("@open_street_map_us"), "open_street_map_us", ());
TEST_EQUAL(
osm::ValidateAndFormat_instagram("https://www.instagram.com/explore/locations/358536820/trivium-sport-en-dance/"),
"explore/locations/358536820/trivium-sport-en-dance", ());
TEST_EQUAL(osm::ValidateAndFormat_instagram("https://www.instagram.com/p/BvkgKZNDbqN/?ghid=UwPchX7B"),
"p/BvkgKZNDbqN", ());
TEST_EQUAL(osm::ValidateAndFormat_instagram("facebook.com/osm_us"), "", ());
TEST_EQUAL(osm::ValidateAndFormat_instagram(".dots_not_allowed."), "", ());
TEST_EQUAL(osm::ValidateAndFormat_instagram("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"), "", ());
}
UNIT_TEST(EditableMapObject_ValidateAndFormat_twitter)
{
TEST_EQUAL(osm::ValidateAndFormat_twitter("twitter.com/osm_tech"), "osm_tech", ());
TEST_EQUAL(osm::ValidateAndFormat_twitter("www.twitter.com/osm_tech"), "osm_tech", ());
TEST_EQUAL(osm::ValidateAndFormat_twitter("http://twitter.com/osm_tech"), "osm_tech", ());
TEST_EQUAL(osm::ValidateAndFormat_twitter("https://twitter.com/osm_tech"), "osm_tech", ());
TEST_EQUAL(osm::ValidateAndFormat_twitter("http://www.twitter.com/osm_tech"), "osm_tech", ());
TEST_EQUAL(osm::ValidateAndFormat_twitter("https://www.twitter.com/osm_tech"), "osm_tech", ());
TEST_EQUAL(osm::ValidateAndFormat_twitter("@_osm_tech_"), "_osm_tech_", ());
TEST_EQUAL(osm::ValidateAndFormat_twitter("instagram.com/osm_tech"), "", ());
TEST_EQUAL(osm::ValidateAndFormat_twitter("dots.not.allowed"), "", ());
TEST_EQUAL(osm::ValidateAndFormat_twitter("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"), "", ());
}
UNIT_TEST(EditableMapObject_ValidateAndFormat_vk)
{
TEST_EQUAL(osm::ValidateAndFormat_vk("vk.com/id404"), "id404", ());
TEST_EQUAL(osm::ValidateAndFormat_vk("vkontakte.ru/id4321"), "id4321", ());
TEST_EQUAL(osm::ValidateAndFormat_vk("www.vkontakte.ru/id43210"), "id43210", ());
TEST_EQUAL(osm::ValidateAndFormat_vk("www.vk.com/id404"), "id404", ());
TEST_EQUAL(osm::ValidateAndFormat_vk("http://vk.com/ozon"), "ozon", ());
TEST_EQUAL(osm::ValidateAndFormat_vk("https://vk.com/sklad169"), "sklad169", ());
TEST_EQUAL(osm::ValidateAndFormat_vk("https://vkontakte.ru/id4321"), "id4321", ());
TEST_EQUAL(osm::ValidateAndFormat_vk("https://www.vkontakte.ru/id4321"), "id4321", ());
TEST_EQUAL(osm::ValidateAndFormat_vk("http://www.vk.com/ugona.net.expert"), "ugona.net.expert", ());
TEST_EQUAL(osm::ValidateAndFormat_vk("https://www.vk.com/7cvetov18"), "7cvetov18", ());
TEST_EQUAL(osm::ValidateAndFormat_vk("https://www.vk.com/7cvetov18/"), "7cvetov18", ());
TEST_EQUAL(osm::ValidateAndFormat_vk("@22ab.cdef"), "22ab.cdef", ());
TEST_EQUAL(osm::ValidateAndFormat_vk("instagram.com/hello_world"), "", ());
}
UNIT_TEST(EditableMapObject_ValidateAndFormat_contactLine)
{
TEST_EQUAL(osm::ValidateAndFormat_contactLine("http://line.me/ti/p/mzog4fnz24"), "mzog4fnz24", ());
TEST_EQUAL(osm::ValidateAndFormat_contactLine("https://line.me/ti/p/xnv0g02rws"), "xnv0g02rws", ());
TEST_EQUAL(osm::ValidateAndFormat_contactLine("https://line.me/ti/p/@dgxs9r6wad"), "dgxs9r6wad", ());
TEST_EQUAL(osm::ValidateAndFormat_contactLine("https://line.me/ti/p/%40vne5uwke17"), "vne5uwke17", ());
TEST_EQUAL(osm::ValidateAndFormat_contactLine("http://line.me/R/ti/p/bfsg1a8x9u"), "bfsg1a8x9u", ());
TEST_EQUAL(osm::ValidateAndFormat_contactLine("line.me/R/ti/p/bfsg1a8x9u"), "bfsg1a8x9u", ());
TEST_EQUAL(osm::ValidateAndFormat_contactLine("https://line.me/R/ti/p/gdltt7s380"), "gdltt7s380", ());
TEST_EQUAL(osm::ValidateAndFormat_contactLine("https://line.me/R/ti/p/@sdb2pb3lsg"), "sdb2pb3lsg", ());
TEST_EQUAL(osm::ValidateAndFormat_contactLine("https://line.me/R/ti/p/%40b30h5mdj11"), "b30h5mdj11", ());
TEST_EQUAL(osm::ValidateAndFormat_contactLine("http://line.me/R/home/public/main?id=hmczqsbav5"), "hmczqsbav5", ());
TEST_EQUAL(osm::ValidateAndFormat_contactLine("https://line.me/R/home/public/main?id=wa1gvx91jb"), "wa1gvx91jb", ());
TEST_EQUAL(osm::ValidateAndFormat_contactLine("http://line.me/R/home/public/profile?id=5qll5dyqqu"), "5qll5dyqqu",
());
TEST_EQUAL(osm::ValidateAndFormat_contactLine("https://line.me/R/home/public/profile?id=r90ck7n1rq"), "r90ck7n1rq",
());
TEST_EQUAL(osm::ValidateAndFormat_contactLine("https://line.me/R/home/public/profile?id=r90ck7n1rq"), "r90ck7n1rq",
());
TEST_EQUAL(osm::ValidateAndFormat_contactLine("https://page.line.me/fom5198h"), "fom5198h", ());
TEST_EQUAL(osm::ValidateAndFormat_contactLine("https://page.line.me/qn58n8g?web=mobile"), "qn58n8g", ());
TEST_EQUAL(osm::ValidateAndFormat_contactLine("https://page.line.me/?accountId=673watcr"), "673watcr", ());
TEST_EQUAL(osm::ValidateAndFormat_contactLine("page.line.me/?accountId=673watcr"), "673watcr", ());
TEST_EQUAL(osm::ValidateAndFormat_contactLine("https://liff.line.me/1645278921-kWRPP32q/?accountId=673watcr"),
"liff.line.me/1645278921-kWRPP32q/?accountId=673watcr", ());
TEST_EQUAL(osm::ValidateAndFormat_contactLine("https://abc.line.me/en/some/page?id=xaladqv"),
"abc.line.me/en/some/page?id=xaladqv", ());
TEST_EQUAL(osm::ValidateAndFormat_contactLine("@abcd"), "abcd", ());
TEST_EQUAL(osm::ValidateAndFormat_contactLine("@-hyphen-test-"), "-hyphen-test-", ());
TEST_EQUAL(osm::ValidateAndFormat_contactLine("https://line.com/ti/p/invalid-domain"), "", ());
}
UNIT_TEST(EditableMapObject_ValidateAndFormat_fediverse)
{
TEST_EQUAL(osm::ValidateAndFormat_fediverse("https://floss.social/@comaps"), "comaps@floss.social", ());
TEST_EQUAL(osm::ValidateAndFormat_fediverse("https://floss.social/users/comaps"), "comaps@floss.social", ());
TEST_EQUAL(osm::ValidateAndFormat_fediverse("http://floss.social/users/comaps"), "comaps@floss.social", ());
TEST_EQUAL(osm::ValidateAndFormat_fediverse("floss.social/users/comaps"), "comaps@floss.social", ());
TEST_EQUAL(osm::ValidateAndFormat_fediverse("comaps@floss.social"), "comaps@floss.social", ());
TEST_EQUAL(osm::ValidateAndFormat_fediverse("@comaps@floss.social"), "comaps@floss.social", ());
TEST_EQUAL(osm::ValidateAndFormat_fediverse("@comaps@floss.social.uk"), "comaps@floss.social.uk", ());
TEST_EQUAL(osm::ValidateAndFormat_fediverse("pub.mastodon.org.uk/@comaps"), "comaps@pub.mastodon.org.uk", ());
TEST_EQUAL(osm::ValidateAndFormat_fediverse("pub.mastodon.org.uk/users/@comaps"), "comaps@pub.mastodon.org.uk", ());
TEST_EQUAL(osm::ValidateAndFormat_fediverse("comaps@fosstodon@mastodon.org"), "", ());
TEST_EQUAL(osm::ValidateAndFormat_fediverse("co$maps@mastodon.social"), "", ());
TEST_EQUAL(osm::ValidateAndFormat_fediverse("pub.mastodon.org.uk/comaps"), "", ());
TEST_EQUAL(osm::ValidateAndFormat_fediverse("pub.mastodon.org.uk/users/"), "", ());
}
UNIT_TEST(EditableMapObject_ValidateAndFormat_bluesky)
{
TEST_EQUAL(osm::ValidateAndFormat_bluesky("comaps.bsky.social"), "comaps.bsky.social", ());
TEST_EQUAL(osm::ValidateAndFormat_bluesky("@comaps.bsky.social"), "comaps.bsky.social", ());
TEST_EQUAL(osm::ValidateAndFormat_bluesky("https://bsky.app/profile/comaps.bsky.social"), "comaps.bsky.social", ());
TEST_EQUAL(osm::ValidateAndFormat_bluesky("https://bsky.app/profile/@comaps.bsky.social"), "comaps.bsky.social", ());
TEST_EQUAL(osm::ValidateAndFormat_bluesky("http://bsky.app/profile/comaps.bsky.social"), "comaps.bsky.social", ());
TEST_EQUAL(osm::ValidateAndFormat_bluesky("bsky.app/profile/comaps.bsky.social"), "comaps.bsky.social", ());
TEST_EQUAL(osm::ValidateAndFormat_bluesky("https://bsky.app/profile/comaps.bsky.social"), "comaps.bsky.social", ());
TEST_EQUAL(osm::ValidateAndFormat_bluesky("https://bsky.app/profile/comap$.bsky.social"), "", ());
TEST_EQUAL(osm::ValidateAndFormat_bluesky("https://bsky.app/profile/comaps.bsky.social$"), "", ());
TEST_EQUAL(osm::ValidateAndFormat_bluesky("https://bsky.app/pineapple/comaps.bsky.social"), "", ());
}
UNIT_TEST(EditableMapObject_ValidateFacebookPage)
{
TEST(osm::ValidateFacebookPage(""), ());
TEST(osm::ValidateFacebookPage("facebook.com/OpenStreetMap"), ());
TEST(osm::ValidateFacebookPage("www.facebook.com/OpenStreetMap"), ());
TEST(osm::ValidateFacebookPage("www.facebook.fr/OpenStreetMap"), ());
TEST(osm::ValidateFacebookPage("http://facebook.com/OpenStreetMap"), ());
TEST(osm::ValidateFacebookPage("https://facebook.com/OpenStreetMap"), ());
TEST(osm::ValidateFacebookPage("http://www.facebook.com/OpenStreetMap"), ());
TEST(osm::ValidateFacebookPage("https://www.facebook.com/OpenStreetMap"), ());
TEST(osm::ValidateFacebookPage("https://de-de.facebook.de/OpenStreetMap"), ());
TEST(osm::ValidateFacebookPage("https://en-us.facebook.com/OpenStreetMap"), ());
TEST(osm::ValidateFacebookPage("https://www.facebook.com/profile.php?id=100085707580841"), ());
TEST(osm::ValidateFacebookPage("OpenStreetMap"), ());
TEST(osm::ValidateFacebookPage("some.good.page"), ());
TEST(osm::ValidateFacebookPage("Quaama-Volunteer-Bushfire-Brigade-526790054021506"), ());
TEST(osm::ValidateFacebookPage("Páter-Bonifác-Restaurant-Budapest-111001693867133"), ());
TEST(osm::ValidateFacebookPage("MÊGÅ--CÄFË-3141592653589793"), ());
TEST(osm::ValidateFacebookPage("ресторан"), ()); // Cyrillic
TEST(osm::ValidateFacebookPage("საქართველო"), ()); // Georgian
TEST(osm::ValidateFacebookPage("日本語"), ()); // Japanese
TEST(osm::ValidateFacebookPage("@tree-house-interiors"), ());
TEST(osm::ValidateFacebookPage("allow_underscore-1234567890"), ());
TEST(osm::ValidateFacebookPage("alexander.net"), ());
TEST(!osm::ValidateFacebookPage("instagram.com/openstreetmapus"), ());
TEST(!osm::ValidateFacebookPage("https://instagram.com/openstreetmapus"), ());
TEST(!osm::ValidateFacebookPage("osm"), ());
TEST(!osm::ValidateFacebookPage("@spaces are not welcome here"), ());
TEST(!osm::ValidateFacebookPage("spaces are not welcome here"), ());
constexpr char kForbiddenFBSymbols[] = " !@^*()~[]{}#$%&;,:+\"'/\\";
for (size_t i = 0; i < std::size(kForbiddenFBSymbols) - 1; i++)
{
auto test_str = std::string("special-symbol-") + kForbiddenFBSymbols[i] + "-forbidden";
TEST(!osm::ValidateFacebookPage(test_str), (test_str));
}
// Symbols "£€¥" are not allowed, but to check such cases it requires unicode magic. Not supported currently.
// TODO: find all restricted *Unicode* symbols from https://www.facebook.com/pages/create page
// and them to the test
// TEST(!osm::ValidateFacebookPage(u8"you-shall-not-pass-£€¥"), ());
}
UNIT_TEST(EditableMapObject_ValidateInstagramPage)
{
TEST(osm::ValidateInstagramPage(""), ());
TEST(osm::ValidateInstagramPage("instagram.com/openstreetmapus"), ());
TEST(osm::ValidateInstagramPage("www.instagram.com/openstreetmapus"), ());
TEST(osm::ValidateInstagramPage("http://instagram.com/openstreetmapus"), ());
TEST(osm::ValidateInstagramPage("https://instagram.com/openstreetmapus"), ());
TEST(osm::ValidateInstagramPage("http://www.instagram.com/openstreetmapus"), ());
TEST(osm::ValidateInstagramPage("https://www.instagram.com/openstreetmapus"), ());
TEST(osm::ValidateInstagramPage("https://en-us.instagram.com/openstreetmapus"), ());
TEST(osm::ValidateInstagramPage("openstreetmapus"), ());
TEST(osm::ValidateInstagramPage("open.street.map.us"), ());
TEST(osm::ValidateInstagramPage("open_street_map_us"), ());
TEST(osm::ValidateInstagramPage("@open_street_map_us"), ());
TEST(osm::ValidateInstagramPage("_osm_"), ());
TEST(!osm::ValidateInstagramPage("facebook.com/osm_us"), ());
TEST(!osm::ValidateInstagramPage("https://facebook.com/osm_us"), ());
TEST(!osm::ValidateInstagramPage(".osm"), ());
TEST(!osm::ValidateInstagramPage("osm."), ());
TEST(!osm::ValidateInstagramPage(".dots_not_allowed."), ());
TEST(!osm::ValidateInstagramPage("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"), ());
}
UNIT_TEST(EditableMapObject_ValidateTwitterPage)
{
TEST(osm::ValidateTwitterPage(""), ());
TEST(osm::ValidateTwitterPage("twitter.com/osm_tech"), ());
TEST(osm::ValidateTwitterPage("www.twitter.com/osm_tech"), ());
TEST(osm::ValidateTwitterPage("http://twitter.com/osm_tech"), ());
TEST(osm::ValidateTwitterPage("https://twitter.com/osm_tech"), ());
TEST(osm::ValidateTwitterPage("http://www.twitter.com/osm_tech"), ());
TEST(osm::ValidateTwitterPage("https://www.twitter.com/osm_tech"), ());
TEST(osm::ValidateTwitterPage("osm_tech"), ());
TEST(osm::ValidateTwitterPage("_osm_tech_"), ());
TEST(osm::ValidateTwitterPage("@_osm_tech_"), ());
TEST(osm::ValidateTwitterPage("1"), ());
TEST(!osm::ValidateTwitterPage("instagram.com/osm_tech"), ());
TEST(!osm::ValidateTwitterPage("https://instagram.com/osm_tech"), ());
TEST(!osm::ValidateTwitterPage("dots.not.allowed"), ());
TEST(!osm::ValidateTwitterPage("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"), ());
}
UNIT_TEST(EditableMapObject_ValidateVkPage)
{
TEST(osm::ValidateVkPage(""), ());
TEST(osm::ValidateVkPage("vk.com/id404"), ());
TEST(osm::ValidateVkPage("vkontakte.ru/id404"), ());
TEST(osm::ValidateVkPage("www.vk.com/id404"), ());
TEST(osm::ValidateVkPage("http://vk.com/id404"), ());
TEST(osm::ValidateVkPage("https://vk.com/id404"), ());
TEST(osm::ValidateVkPage("https://vkontakte.ru/id404"), ());
TEST(osm::ValidateVkPage("http://www.vk.com/id404"), ());
TEST(osm::ValidateVkPage("https://www.vk.com/id404"), ());
TEST(osm::ValidateVkPage("id432160160"), ());
TEST(osm::ValidateVkPage("hello_world"), ());
TEST(osm::ValidateVkPage("osm63rus"), ());
TEST(osm::ValidateVkPage("22ab.cdef"), ());
TEST(osm::ValidateVkPage("@hello_world"), ());
TEST(osm::ValidateVkPage("@osm63rus"), ());
TEST(osm::ValidateVkPage("@22ab.cdef"), ());
TEST(!osm::ValidateVkPage("333too_many_numbers"), ());
TEST(!osm::ValidateVkPage("vk"), ());
TEST(!osm::ValidateVkPage("@five"), ());
TEST(!osm::ValidateVkPage("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"), ());
TEST(!osm::ValidateVkPage("_invalid_underscores_"), ());
TEST(!osm::ValidateVkPage("invalid-dashes"), ());
// TEST(!osm::ValidateVkPage("to.ma.ny.do.ts"), ()); //TODO: it's hard to test such cases. Skip for now
// TEST(!osm::ValidateVkPage("dots.__.dots"), ()); //TODO: it's hard to test such cases. Skip for now
TEST(!osm::ValidateVkPage("instagram.com/hello_world"), ());
TEST(!osm::ValidateVkPage("https://instagram.com/hello_world"), ());
}
UNIT_TEST(EditableMapObject_ValidateLinePage)
{
TEST(osm::ValidateLinePage(""), ());
TEST(osm::ValidateLinePage("http://line.me/ti/p/mzog4fnz24"), ());
TEST(osm::ValidateLinePage("https://line.me/ti/p/xnv0g02rws"), ());
TEST(osm::ValidateLinePage("https://line.me/ti/p/@dgxs9r6wad"), ());
TEST(osm::ValidateLinePage("https://line.me/ti/p/%40vne5uwke17"), ());
TEST(osm::ValidateLinePage("http://line.me/R/ti/p/bfsg1a8x9u"), ());
TEST(osm::ValidateLinePage("https://line.me/R/ti/p/gdltt7s380"), ());
TEST(osm::ValidateLinePage("https://line.me/R/ti/p/@sdb2pb3lsg"), ());
TEST(osm::ValidateLinePage("https://line.me/R/ti/p/%40b30h5mdj11"), ());
TEST(osm::ValidateLinePage("http://line.me/R/home/public/main?id=hmczqsbav5"), ());
TEST(osm::ValidateLinePage("https://line.me/R/home/public/main?id=wa1gvx91jb"), ());
TEST(osm::ValidateLinePage("http://line.me/R/home/public/profile?id=5qll5dyqqu"), ());
TEST(osm::ValidateLinePage("https://line.me/R/home/public/profile?id=r90ck7n1rq"), ());
TEST(osm::ValidateLinePage("https://line.me/R/home/public/profile?id=r90ck7n1rq"), ());
TEST(osm::ValidateLinePage("https://page.line.me/fom5198h"), ());
TEST(osm::ValidateLinePage("https://page.line.me/qn58n8g?web=mobile"), ());
TEST(osm::ValidateLinePage("https://abc.line.me/en/some/page?id=xaladqv"), ());
TEST(osm::ValidateLinePage("@abcd"), ());
TEST(osm::ValidateLinePage("0000"), ());
TEST(osm::ValidateLinePage(".dots.are.allowed."), ());
TEST(osm::ValidateLinePage("@.dots.are.allowed."), ());
TEST(osm::ValidateLinePage("-hyphen-test-"), ());
TEST(osm::ValidateLinePage("@-hyphen-test-"), ());
TEST(osm::ValidateLinePage("under_score"), ());
TEST(osm::ValidateLinePage("@under_score"), ());
TEST(!osm::ValidateLinePage("no"), ());
TEST(!osm::ValidateLinePage("yes"), ());
TEST(!osm::ValidateLinePage("No-upper-case"), ());
TEST(!osm::ValidateLinePage("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), ());
TEST(!osm::ValidateLinePage("https://line.com/ti/p/invalid-domain"), ());
}
UNIT_TEST(EditableMapObject_ValidateFediversePage)
{
TEST(osm::ValidateFediversePage("https://floss.social/@comaps"), ());
TEST(osm::ValidateFediversePage("https://floss.social/users/comaps"), ());
TEST(osm::ValidateFediversePage("http://floss.social/users/comaps"), ());
TEST(osm::ValidateFediversePage("floss.social/users/comaps"), ());
TEST(osm::ValidateFediversePage("comaps@floss.social"), ());
TEST(osm::ValidateFediversePage("@comaps@floss.social"), ());
TEST(osm::ValidateFediversePage("@comaps@floss.social.uk"), ());
TEST(osm::ValidateFediversePage("pub.mastodon.org.uk/@comaps"), ());
TEST(osm::ValidateFediversePage("pub.mastodon.org.uk/users/@comaps"), ());
TEST(!osm::ValidateFediversePage("comaps@floss@mastodon.org"), ());
TEST(!osm::ValidateFediversePage("orga$nicmaps@mastodon.social"), ());
TEST(!osm::ValidateFediversePage("pub.mastodon.org.uk/comaps"), ());
TEST(!osm::ValidateFediversePage("pub.mastodon.org.uk/users/"), ());
}
UNIT_TEST(EditableMapObject_ValidateBlueskyPage)
{
TEST(osm::ValidateBlueskyPage("comaps.bsky.social"), ());
TEST(osm::ValidateBlueskyPage("@comaps.bsky.social"), ());
TEST(osm::ValidateBlueskyPage("https://bsky.app/profile/comaps.bsky.social"), ());
TEST(osm::ValidateBlueskyPage("https://bsky.app/profile/@comaps.bsky.social"), ());
TEST(osm::ValidateBlueskyPage("http://bsky.app/profile/comaps.bsky.social"), ());
TEST(osm::ValidateBlueskyPage("bsky.app/profile/comaps.bsky.social"), ());
TEST(osm::ValidateBlueskyPage("https://bsky.app/profile/comaps.bsky.social"), ());
TEST(!osm::ValidateBlueskyPage("https://bsky.app/profile/comap$.bsky.social"), ());
TEST(!osm::ValidateBlueskyPage("https://bsky.app/profile/comaps.bsky.social$"), ());
TEST(!osm::ValidateBlueskyPage("https://bsky.app/pineapple/comaps.bsky.social"), ());
}
UNIT_TEST(EditableMapObject_socialContactToURL)
{
TEST_EQUAL(osm::socialContactToURL(osm::MapObject::MetadataID::FMD_CONTACT_INSTAGRAM, "some_page_name"),
"https://instagram.com/some_page_name", ());
TEST_EQUAL(osm::socialContactToURL(osm::MapObject::MetadataID::FMD_CONTACT_INSTAGRAM, "p/BvkgKZNDbqN"),
"https://instagram.com/p/BvkgKZNDbqN", ());
TEST_EQUAL(osm::socialContactToURL(osm::MapObject::MetadataID::FMD_CONTACT_FACEBOOK, "100086487430889"),
"https://facebook.com/100086487430889", ());
TEST_EQUAL(osm::socialContactToURL(osm::MapObject::MetadataID::FMD_CONTACT_FACEBOOK, "nova.poshta.official"),
"https://facebook.com/nova.poshta.official", ());
TEST_EQUAL(osm::socialContactToURL(osm::MapObject::MetadataID::FMD_CONTACT_FACEBOOK, "pg/ESQ-336537783591903/about"),
"https://facebook.com/pg/ESQ-336537783591903/about", ());
TEST_EQUAL(osm::socialContactToURL(osm::MapObject::MetadataID::FMD_CONTACT_TWITTER, "carmelopizza"),
"https://twitter.com/carmelopizza", ());
TEST_EQUAL(osm::socialContactToURL(osm::MapObject::MetadataID::FMD_CONTACT_TWITTER,
"demhamburguesa/status/688001869269078016"),
"https://twitter.com/demhamburguesa/status/688001869269078016", ());
TEST_EQUAL(osm::socialContactToURL(osm::MapObject::MetadataID::FMD_CONTACT_VK, "beerhousebar"),
"https://vk.com/beerhousebar", ());
TEST_EQUAL(osm::socialContactToURL(osm::MapObject::MetadataID::FMD_CONTACT_VK, "wall-41524_29351"),
"https://vk.com/wall-41524_29351", ());
TEST_EQUAL(osm::socialContactToURL(osm::MapObject::MetadataID::FMD_CONTACT_LINE, "a26235875"),
"https://line.me/R/ti/p/@a26235875", ());
TEST_EQUAL(osm::socialContactToURL(osm::MapObject::MetadataID::FMD_CONTACT_LINE,
"liff.line.me/1645278921-kWRPP32q/?accountId=673watcr"),
"https://liff.line.me/1645278921-kWRPP32q/?accountId=673watcr", ());
}

View file

@ -0,0 +1,91 @@
#include "testing/testing.hpp"
#include "indexer/classificator.hpp"
#include "indexer/classificator_loader.hpp"
#include "indexer/feature_data.hpp"
#include "indexer/feature_visibility.hpp"
#include "indexer/scales.hpp"
#include "base/logging.hpp"
#include <cstdint>
#include <set>
#include <string>
#include <utility>
#include <vector>
using namespace std;
namespace
{
class DoGetMaxLowMinHighZoom
{
Classificator const & m_classif;
pair<int, int> m_res;
string m_low;
set<uint32_t> m_skip;
bool IsSkip(uint32_t t) const
{
ftype::TruncValue(t, 2);
return m_skip.count(t) > 0;
}
public:
explicit DoGetMaxLowMinHighZoom(Classificator const & c) : m_classif(classif()), m_res(-1, 1000)
{
char const * arr[][2] = {
{"highway", "bus_stop"},
{"highway", "speed_camera"},
{"highway", "world_level"},
{"highway", "world_towns_level"},
};
for (size_t i = 0; i < ARRAY_SIZE(arr); ++i)
m_skip.insert(c.GetTypeByPath(vector<string>(arr[i], arr[i] + 2)));
}
void operator()(ClassifObject const * p, uint32_t type)
{
if (IsSkip(type))
return;
pair<int, int> const r = feature::GetDrawableScaleRange(type);
if (r.first == -1 || r.second == -1)
{
LOG(LINFO, (r, m_classif.GetFullObjectName(type)));
return;
}
if (m_res.first < r.first)
{
m_res.first = r.first;
m_low = p->GetName();
}
if (m_res.second > r.second)
m_res.second = r.second;
}
void Print()
{
TEST_EQUAL(m_res.second, scales::GetUpperStyleScale(), (m_res));
LOG(LINFO, ("Max low highway zoom:", m_res, "for type:", m_low));
}
};
} // namespace
UNIT_TEST(VisibleScales_Highway)
{
Classificator const & c = classif();
char const * arr[] = {"highway"};
uint32_t const type = c.GetTypeByPath(vector<string>(arr, arr + 1));
ClassifObject const * pObj = c.GetObject(type);
DoGetMaxLowMinHighZoom doGet(c);
pObj->ForEachObjectInTree(doGet, type);
doGet.Print();
}

View file

@ -0,0 +1,37 @@
#include "testing/testing.hpp"
#include "indexer/classificator.hpp"
#include "indexer/classificator_loader.hpp"
#include "indexer/ftraits.hpp"
UNIT_TEST(Wheelchair_GetType)
{
classificator::Load();
Classificator const & c = classif();
using ftraits::Wheelchair;
using ftraits::WheelchairAvailability;
feature::TypesHolder holder;
{
holder.Assign(c.GetTypeByPath({"wheelchair", "no"}));
TEST_EQUAL(*Wheelchair::GetValue(holder), WheelchairAvailability::No, ());
}
{
holder.Assign(c.GetTypeByPath({"wheelchair", "yes"}));
TEST_EQUAL(*Wheelchair::GetValue(holder), WheelchairAvailability::Yes, ());
}
{
holder.Assign(c.GetTypeByPath({"wheelchair", "limited"}));
TEST_EQUAL(*Wheelchair::GetValue(holder), WheelchairAvailability::Limited, ());
}
{
holder.Assign(c.GetTypeByPath({"amenity", "dentist"}));
TEST(!Wheelchair::GetValue(holder), ());
}
{
holder.Assign(c.GetTypeByPath({"amenity", "dentist"}));
holder.Add(c.GetTypeByPath({"wheelchair", "yes"}));
TEST_EQUAL(*Wheelchair::GetValue(holder), WheelchairAvailability::Yes, ());
}
}