Repo created
This commit is contained in:
parent
4af19165ec
commit
68073add76
12458 changed files with 12350765 additions and 2 deletions
27
libs/storage/storage_tests/CMakeLists.txt
Normal file
27
libs/storage/storage_tests/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
project(storage_tests)
|
||||
|
||||
set(SRC
|
||||
countries_tests.cpp
|
||||
country_info_getter_tests.cpp
|
||||
country_name_getter_tests.cpp
|
||||
downloader_tests.cpp
|
||||
fake_map_files_downloader.cpp
|
||||
fake_map_files_downloader.hpp
|
||||
helpers.cpp
|
||||
helpers.hpp
|
||||
simple_tree_test.cpp
|
||||
storage_tests.cpp
|
||||
task_runner.cpp
|
||||
task_runner.hpp
|
||||
test_map_files_downloader.cpp
|
||||
test_map_files_downloader.hpp
|
||||
)
|
||||
|
||||
omim_add_test(${PROJECT_NAME} ${SRC} REQUIRE_QT REQUIRE_SERVER)
|
||||
|
||||
target_link_libraries(${PROJECT_NAME}
|
||||
platform_tests_support
|
||||
generator_tests_support
|
||||
storage
|
||||
cppjansson
|
||||
)
|
||||
14
libs/storage/storage_tests/countries_tests.cpp
Normal file
14
libs/storage/storage_tests/countries_tests.cpp
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "platform/platform.hpp"
|
||||
|
||||
#include "coding/sha1.hpp"
|
||||
|
||||
#include "base/logging.hpp"
|
||||
|
||||
UNIT_TEST(CalculateWorldSHA)
|
||||
{
|
||||
auto const path = GetPlatform().ResourcesDir();
|
||||
for (char const * country : {WORLD_FILE_NAME, WORLD_COASTS_FILE_NAME})
|
||||
LOG(LINFO, (country, coding::SHA1::CalculateBase64(path + country + DATA_FILE_EXTENSION)));
|
||||
}
|
||||
409
libs/storage/storage_tests/country_info_getter_tests.cpp
Normal file
409
libs/storage/storage_tests/country_info_getter_tests.cpp
Normal file
|
|
@ -0,0 +1,409 @@
|
|||
#include "testing/benchmark.hpp"
|
||||
#include "testing/testing.hpp"
|
||||
|
||||
#include "storage/storage_tests/helpers.hpp"
|
||||
|
||||
#include "storage/country.hpp"
|
||||
#include "storage/country_decl.hpp"
|
||||
#include "storage/country_info_getter.hpp"
|
||||
#include "storage/storage.hpp"
|
||||
|
||||
#include "geometry/mercator.hpp"
|
||||
#include "geometry/point2d.hpp"
|
||||
#include "geometry/rect2d.hpp"
|
||||
|
||||
#include "platform/platform.hpp"
|
||||
|
||||
#include "base/assert.hpp"
|
||||
#include "base/logging.hpp"
|
||||
#include "base/stats.hpp"
|
||||
#include "base/timer.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <random>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace country_info_getter_tests
|
||||
{
|
||||
using namespace storage;
|
||||
using namespace std;
|
||||
|
||||
static double constexpr kRectCompareEpsilon = 1e-2;
|
||||
|
||||
bool IsEmptyName(map<string, CountryInfo> const & id2info, string const & id)
|
||||
{
|
||||
auto const it = id2info.find(id);
|
||||
TEST(it != id2info.end(), ());
|
||||
return it->second.m_name.empty();
|
||||
}
|
||||
|
||||
// A helper class to sample random points from mwms uniformly.
|
||||
class RandomPointGenerator
|
||||
{
|
||||
public:
|
||||
explicit RandomPointGenerator(mt19937 & randomEngine, vector<m2::RegionD> const & regions)
|
||||
: m_randomEngine(randomEngine)
|
||||
, m_regions(regions)
|
||||
{
|
||||
CHECK(!m_regions.empty(), ());
|
||||
vector<double> areas(m_regions.size());
|
||||
for (size_t i = 0; i < m_regions.size(); ++i)
|
||||
areas[i] = m_regions[i].CalculateArea();
|
||||
|
||||
m_distr = discrete_distribution<size_t>(areas.begin(), areas.end());
|
||||
}
|
||||
|
||||
m2::PointD operator()()
|
||||
{
|
||||
auto const i = m_distr(m_randomEngine);
|
||||
return m_regions[i].GetRandomPoint(m_randomEngine);
|
||||
}
|
||||
|
||||
private:
|
||||
mt19937 m_randomEngine;
|
||||
|
||||
vector<m2::RegionD> m_regions;
|
||||
discrete_distribution<size_t> m_distr;
|
||||
};
|
||||
|
||||
template <typename Cont>
|
||||
Cont Flatten(vector<Cont> const & cs)
|
||||
{
|
||||
Cont res;
|
||||
for (auto const & c : cs)
|
||||
res.insert(res.end(), c.begin(), c.end());
|
||||
return res;
|
||||
}
|
||||
|
||||
UNIT_TEST(CountryInfoGetter_GetByPoint_Smoke)
|
||||
{
|
||||
auto const getter = CreateCountryInfoGetter();
|
||||
|
||||
CountryInfo info;
|
||||
|
||||
// Minsk
|
||||
getter->GetRegionInfo(mercator::FromLatLon(53.9022651, 27.5618818), info);
|
||||
TEST_EQUAL(info.m_name, "Belarus, Minsk Region", ());
|
||||
|
||||
getter->GetRegionInfo(mercator::FromLatLon(-6.4146288, -38.0098101), info);
|
||||
TEST_EQUAL(info.m_name, "Brazil, Rio Grande do Norte", ());
|
||||
|
||||
getter->GetRegionInfo(mercator::FromLatLon(34.6509, 135.5018), info);
|
||||
TEST_EQUAL(info.m_name, "Japan, Kinki Region_Osaka_Osaka", ());
|
||||
}
|
||||
|
||||
UNIT_TEST(CountryInfoGetter_GetRegionsCountryIdByRect_Smoke)
|
||||
{
|
||||
auto const getter = CreateCountryInfoGetter();
|
||||
|
||||
m2::PointD const p = mercator::FromLatLon(52.537695, 32.203884);
|
||||
|
||||
// Single mwm.
|
||||
m2::PointD const halfSize = m2::PointD(0.1, 0.1);
|
||||
auto const countries = getter->GetRegionsCountryIdByRect(m2::RectD(p - halfSize, p + halfSize), false /* rough */);
|
||||
TEST_EQUAL(countries, vector<storage::CountryId>{"Russia_Bryansk Oblast"}, ());
|
||||
|
||||
// Several countries.
|
||||
m2::PointD const halfSize2 = m2::PointD(0.5, 0.5);
|
||||
auto const countries2 = getter->GetRegionsCountryIdByRect(m2::RectD(p - halfSize2, p + halfSize2), false /* rough */);
|
||||
auto const expected =
|
||||
vector<storage::CountryId>{"Belarus_Homiel Region", "Russia_Bryansk Oblast", "Ukraine_Chernihiv Oblast"};
|
||||
TEST_EQUAL(countries2, expected, ());
|
||||
|
||||
// No one found.
|
||||
auto const countries3 = getter->GetRegionsCountryIdByRect(m2::RectD(-halfSize, halfSize), false /* rough */);
|
||||
TEST_EQUAL(countries3, vector<storage::CountryId>{}, ());
|
||||
|
||||
// Inside mwm (rough).
|
||||
auto const countries4 = getter->GetRegionsCountryIdByRect(m2::RectD(p - halfSize, p + halfSize), true /* rough */);
|
||||
TEST_EQUAL(countries, vector<storage::CountryId>{"Russia_Bryansk Oblast"}, ());
|
||||
|
||||
// Several countries (rough).
|
||||
auto const countries5 = getter->GetRegionsCountryIdByRect(m2::RectD(p - halfSize2, p + halfSize2), true /* rough */);
|
||||
auto const expected2 = vector<storage::CountryId>{"Belarus_Homiel Region", "Belarus_Maglieu Region",
|
||||
"Russia_Bryansk Oblast", "Ukraine_Chernihiv Oblast", "US_Alaska"};
|
||||
TEST_EQUAL(countries5, expected2, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(CountryInfoGetter_ValidName_Smoke)
|
||||
{
|
||||
string buffer;
|
||||
ReaderPtr<Reader>(GetPlatform().GetReader(COUNTRIES_FILE)).ReadAsString(buffer);
|
||||
|
||||
map<string, CountryInfo> id2info;
|
||||
storage::LoadCountryFile2CountryInfo(buffer, id2info);
|
||||
|
||||
Storage storage;
|
||||
|
||||
TEST(!IsEmptyName(id2info, "Belgium_West Flanders"), ());
|
||||
TEST(!IsEmptyName(id2info, "France_Ile-de-France_Paris"), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(CountryInfoGetter_SomeRects)
|
||||
{
|
||||
auto const getter = CreateCountryInfoGetter();
|
||||
|
||||
m2::RectD rects[3];
|
||||
getter->CalcUSALimitRect(rects);
|
||||
|
||||
LOG(LINFO, ("USA Continental:", rects[0]));
|
||||
LOG(LINFO, ("Alaska:", rects[1]));
|
||||
LOG(LINFO, ("Hawaii:", rects[2]));
|
||||
|
||||
LOG(LINFO, ("Canada:", getter->CalcLimitRect("Canada_")));
|
||||
}
|
||||
|
||||
UNIT_TEST(CountryInfoGetter_HitsInRadius)
|
||||
{
|
||||
auto const getter = CreateCountryInfoGetter();
|
||||
CountriesVec results;
|
||||
getter->GetRegionsCountryId(mercator::FromLatLon(56.1702, 28.1505), results);
|
||||
TEST_EQUAL(results.size(), 3, ());
|
||||
TEST(find(results.begin(), results.end(), "Belarus_Vitebsk Region") != results.end(), ());
|
||||
TEST(find(results.begin(), results.end(), "Latvia") != results.end(), ());
|
||||
TEST(find(results.begin(), results.end(), "Russia_Pskov Oblast") != results.end(), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(CountryInfoGetter_HitsOnLongLine)
|
||||
{
|
||||
auto const getter = CreateCountryInfoGetter();
|
||||
CountriesVec results;
|
||||
getter->GetRegionsCountryId(mercator::FromLatLon(62.2507, -102.0753), results);
|
||||
TEST_EQUAL(results.size(), 2, ());
|
||||
TEST(find(results.begin(), results.end(), "Canada_Northwest Territories_East") != results.end(), ());
|
||||
TEST(find(results.begin(), results.end(), "Canada_Nunavut_South") != results.end(), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(CountryInfoGetter_HitsInTheMiddleOfNowhere)
|
||||
{
|
||||
auto const getter = CreateCountryInfoGetter();
|
||||
CountriesVec results;
|
||||
getter->GetRegionsCountryId(mercator::FromLatLon(62.2900, -103.9423), results);
|
||||
TEST_EQUAL(results.size(), 1, ());
|
||||
TEST(find(results.begin(), results.end(), "Canada_Northwest Territories_East") != results.end(), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(CountryInfoGetter_BorderRelations)
|
||||
{
|
||||
auto const getter = CreateCountryInfoGetter();
|
||||
|
||||
ms::LatLon labels[] = {
|
||||
{42.4318876, -8.6431592}, {42.6075172, -8.4714942}, {42.3436415, -7.8674242},
|
||||
{42.1968459, -7.6114105}, {43.0118437, -7.5565749}, {43.0462247, -7.4739921},
|
||||
{43.3709703, -8.3959425}, {43.0565609, -8.5296941}, {27.0006968, 49.6532161},
|
||||
};
|
||||
|
||||
for (auto const & ll : labels)
|
||||
{
|
||||
auto const region = getter->GetRegionCountryId(mercator::FromLatLon(ll));
|
||||
LOG(LINFO, (region));
|
||||
TEST(!region.empty(), (ll));
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST(CountryInfoGetter_GetLimitRectForLeafSingleMwm)
|
||||
{
|
||||
auto const getter = CreateCountryInfoGetter();
|
||||
Storage storage;
|
||||
|
||||
m2::RectD const boundingBox = getter->GetLimitRectForLeaf("Angola");
|
||||
m2::RectD const expectedBoundingBox = {9.205259 /* minX */, -18.34456 /* minY */, 24.08212 /* maxX */,
|
||||
-4.393187 /* maxY */};
|
||||
|
||||
TEST(AlmostEqualAbs(boundingBox, expectedBoundingBox, kRectCompareEpsilon), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(CountryInfoGetter_RegionRects)
|
||||
{
|
||||
auto reader = CountryInfoReader::CreateCountryInfoReader(GetPlatform());
|
||||
CHECK(reader != nullptr, ());
|
||||
|
||||
Storage storage;
|
||||
|
||||
auto const & countries = reader->GetCountries();
|
||||
|
||||
for (size_t i = 0; i < countries.size(); ++i)
|
||||
{
|
||||
vector<m2::RegionD> regions;
|
||||
reader->LoadRegionsFromDisk(i, regions);
|
||||
|
||||
m2::RectD rect;
|
||||
for (auto const & region : regions)
|
||||
region.ForEachPoint([&](m2::PointD const & point) { rect.Add(point); });
|
||||
|
||||
TEST(AlmostEqualAbs(rect, countries[i].m_rect, kRectCompareEpsilon), (rect, countries[i].m_rect));
|
||||
}
|
||||
}
|
||||
|
||||
// This is a test for consistency between data/countries.txt and data/packed_polygons.bin.
|
||||
UNIT_TEST(CountryInfoGetter_Countries_And_Polygons)
|
||||
{
|
||||
auto reader = CountryInfoReader::CreateCountryInfoReader(GetPlatform());
|
||||
CHECK(reader != nullptr, ());
|
||||
|
||||
Storage storage;
|
||||
|
||||
double const kRectSize = 10;
|
||||
|
||||
auto const & countries = reader->GetCountries();
|
||||
|
||||
// Set is used here because disputed territories may occur as leaves several times.
|
||||
set<CountryId> storageLeaves;
|
||||
storage.ForEachCountry([&](Country const & country) { storageLeaves.insert(country.Name()); });
|
||||
|
||||
TEST_EQUAL(countries.size(), storageLeaves.size(), ());
|
||||
|
||||
for (size_t defId = 0; defId < countries.size(); ++defId)
|
||||
{
|
||||
auto const & countryDef = countries[defId];
|
||||
TEST_GREATER(storageLeaves.count(countryDef.m_countryId), 0, (countryDef.m_countryId));
|
||||
|
||||
auto const & p = countryDef.m_rect.Center();
|
||||
auto const rect = mercator::RectByCenterXYAndSizeInMeters(p.x, p.y, kRectSize, kRectSize);
|
||||
auto vec = reader->GetRegionsCountryIdByRect(rect, false /* rough */);
|
||||
for (auto const & countryId : vec)
|
||||
{
|
||||
// This call fails a CHECK if |countryId| is not found.
|
||||
storage.GetCountryFile(countryId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_TEST(CountryInfoGetter_RegionsByRect)
|
||||
{
|
||||
auto reader = CountryInfoReader::CreateCountryInfoReader(GetPlatform());
|
||||
CHECK(reader != nullptr, ());
|
||||
|
||||
Storage storage;
|
||||
|
||||
auto const & countryDefs = reader->GetCountries();
|
||||
|
||||
base::Timer timer;
|
||||
|
||||
double const kRectSize = 10;
|
||||
|
||||
mt19937 rng(0);
|
||||
|
||||
vector<vector<m2::RegionD>> allRegions;
|
||||
allRegions.reserve(countryDefs.size());
|
||||
for (size_t i = 0; i < countryDefs.size(); ++i)
|
||||
{
|
||||
vector<m2::RegionD> regions;
|
||||
reader->LoadRegionsFromDisk(i, regions);
|
||||
allRegions.emplace_back(std::move(regions));
|
||||
}
|
||||
|
||||
size_t totalPoints = 0;
|
||||
for (auto const & regs : allRegions)
|
||||
for (auto const & reg : regs)
|
||||
totalPoints += reg.Size();
|
||||
LOG(LINFO, ("Total points:", totalPoints));
|
||||
|
||||
{
|
||||
size_t const kNumIterations = 1000;
|
||||
|
||||
double const t0 = timer.ElapsedSeconds();
|
||||
|
||||
// Antarctica's rect is too large and skews the random point generation.
|
||||
vector<vector<m2::RegionD>> regionsWithoutAnarctica;
|
||||
for (size_t i = 0; i < allRegions.size(); ++i)
|
||||
{
|
||||
if (countryDefs[i].m_countryId == "Antarctica")
|
||||
continue;
|
||||
|
||||
regionsWithoutAnarctica.emplace_back(allRegions[i]);
|
||||
}
|
||||
|
||||
RandomPointGenerator pointGen(rng, Flatten(regionsWithoutAnarctica));
|
||||
vector<m2::PointD> points;
|
||||
for (size_t i = 0; i < kNumIterations; i++)
|
||||
points.emplace_back(pointGen());
|
||||
|
||||
map<CountryId, int> hits;
|
||||
for (auto const & pt : points)
|
||||
{
|
||||
auto const rect = mercator::RectByCenterXYAndSizeInMeters(pt.x, pt.y, kRectSize, kRectSize);
|
||||
auto vec = reader->GetRegionsCountryIdByRect(rect, false /* rough */);
|
||||
for (auto const & countryId : vec)
|
||||
++hits[countryId];
|
||||
}
|
||||
double const t1 = timer.ElapsedSeconds();
|
||||
|
||||
LOG(LINFO, ("hits:", hits.size(), "/", countryDefs.size(), t1 - t0));
|
||||
}
|
||||
|
||||
{
|
||||
map<CountryId, vector<double>> timesByCountry;
|
||||
map<CountryId, double> avgTimeByCountry;
|
||||
size_t kNumPointsPerCountry = 1;
|
||||
CountryId longest;
|
||||
for (size_t countryDefId = 0; countryDefId < countryDefs.size(); ++countryDefId)
|
||||
{
|
||||
RandomPointGenerator pointGen(rng, allRegions[countryDefId]);
|
||||
auto const & countryId = countryDefs[countryDefId].m_countryId;
|
||||
|
||||
vector<double> & times = timesByCountry[countryId];
|
||||
times.resize(kNumPointsPerCountry);
|
||||
for (size_t i = 0; i < times.size(); ++i)
|
||||
{
|
||||
auto const pt = pointGen();
|
||||
auto const rect = mercator::RectByCenterXYAndSizeInMeters(pt.x, pt.y, kRectSize, kRectSize);
|
||||
double const t0 = timer.ElapsedSeconds();
|
||||
auto vec = reader->GetRegionsCountryIdByRect(rect, false /* rough */);
|
||||
double const t1 = timer.ElapsedSeconds();
|
||||
times[i] = t1 - t0;
|
||||
}
|
||||
|
||||
avgTimeByCountry[countryId] = base::AverageStats<double>(times).GetAverage();
|
||||
|
||||
if (longest.empty() || avgTimeByCountry[longest] < avgTimeByCountry[countryId])
|
||||
longest = countryId;
|
||||
}
|
||||
|
||||
LOG(LINFO, ("Slowest country for CountryInfoGetter (random point)", longest, avgTimeByCountry[longest]));
|
||||
}
|
||||
|
||||
{
|
||||
map<CountryId, vector<double>> timesByCountry;
|
||||
map<CountryId, double> avgTimeByCountry;
|
||||
size_t kNumSidesPerCountry = 1;
|
||||
CountryId longest;
|
||||
for (size_t countryDefId = 0; countryDefId < countryDefs.size(); ++countryDefId)
|
||||
{
|
||||
auto const & countryId = countryDefs[countryDefId].m_countryId;
|
||||
|
||||
vector<pair<m2::PointD, m2::PointD>> sides;
|
||||
for (auto const & region : allRegions[countryDefId])
|
||||
{
|
||||
auto const & points = region.Data();
|
||||
for (size_t i = 0; i < points.size(); ++i)
|
||||
sides.emplace_back(points[i], points[(i + 1) % points.size()]);
|
||||
}
|
||||
|
||||
CHECK(!sides.empty(), ());
|
||||
uniform_int_distribution<size_t> distr(0, sides.size() - 1);
|
||||
vector<double> & times = timesByCountry[countryId];
|
||||
times.resize(kNumSidesPerCountry);
|
||||
for (size_t i = 0; i < times.size(); ++i)
|
||||
{
|
||||
auto const & side = sides[distr(rng)];
|
||||
auto const pt = side.first.Mid(side.second);
|
||||
auto const rect = mercator::RectByCenterXYAndSizeInMeters(pt.x, pt.y, kRectSize, kRectSize);
|
||||
double const t0 = timer.ElapsedSeconds();
|
||||
auto vec = reader->GetRegionsCountryIdByRect(rect, false /* rough */);
|
||||
double const t1 = timer.ElapsedSeconds();
|
||||
times[i] = t1 - t0;
|
||||
}
|
||||
|
||||
avgTimeByCountry[countryId] = base::AverageStats<double>(times).GetAverage();
|
||||
|
||||
if (longest.empty() || avgTimeByCountry[longest] < avgTimeByCountry[countryId])
|
||||
longest = countryId;
|
||||
}
|
||||
LOG(LINFO, ("Slowest country for CountryInfoGetter (point on a random side)", longest, avgTimeByCountry[longest]));
|
||||
}
|
||||
}
|
||||
} // namespace country_info_getter_tests
|
||||
31
libs/storage/storage_tests/country_name_getter_tests.cpp
Normal file
31
libs/storage/storage_tests/country_name_getter_tests.cpp
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "storage/country_name_getter.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
UNIT_TEST(CountryNameGetterTest)
|
||||
{
|
||||
string const shortJson =
|
||||
"\
|
||||
{\
|
||||
\"Russia_Moscow\":\"Москва\",\
|
||||
\"Russia_Rostov-on-Don\":\"Ростов-на-Дону\"\
|
||||
}";
|
||||
|
||||
storage::CountryNameGetter getter;
|
||||
|
||||
TEST_EQUAL(string(), getter.GetLocale(), ());
|
||||
TEST_EQUAL(string("Russia_Moscow"), getter("Russia_Moscow"), ());
|
||||
TEST_EQUAL(string("Russia_Rostov-on-Don"), getter("Russia_Rostov-on-Don"), ());
|
||||
TEST_EQUAL(string("Russia_Murmansk"), getter("Russia_Murmansk"), ());
|
||||
|
||||
getter.SetLocaleForTesting(shortJson, "ru");
|
||||
|
||||
TEST_EQUAL(string("ru"), getter.GetLocale(), ());
|
||||
TEST_EQUAL(string("Москва"), getter("Russia_Moscow"), ());
|
||||
TEST_EQUAL(string("Ростов-на-Дону"), getter("Russia_Rostov-on-Don"), ());
|
||||
TEST_EQUAL(string("Russia_Murmansk"), getter("Russia_Murmansk"), ());
|
||||
}
|
||||
33
libs/storage/storage_tests/downloader_tests.cpp
Normal file
33
libs/storage/storage_tests/downloader_tests.cpp
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "storage/map_files_downloader_with_ping.hpp"
|
||||
|
||||
#include "base/logging.hpp"
|
||||
|
||||
#include "private.h"
|
||||
|
||||
namespace downloader_tests
|
||||
{
|
||||
|
||||
class DownloaderStub : public storage::MapFilesDownloaderWithPing
|
||||
{
|
||||
virtual void Download(storage::QueuedCountry && queuedCountry) {}
|
||||
};
|
||||
|
||||
UNIT_TEST(GetMetaConfig)
|
||||
{
|
||||
if (std::string(METASERVER_URL).empty())
|
||||
return;
|
||||
|
||||
base::ScopedLogLevelChanger logLevel(base::LDEBUG);
|
||||
Platform::ThreadRunner runner;
|
||||
|
||||
DownloaderStub().GetMetaConfig([](downloader::MetaConfig const & metaConfig)
|
||||
{
|
||||
TEST_GREATER(metaConfig.m_serversList.size(), 0, ());
|
||||
for (auto const & s : metaConfig.m_serversList)
|
||||
LOG(LINFO, (s));
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace downloader_tests
|
||||
132
libs/storage/storage_tests/fake_map_files_downloader.cpp
Normal file
132
libs/storage/storage_tests/fake_map_files_downloader.cpp
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
#include "storage/storage_tests/fake_map_files_downloader.hpp"
|
||||
|
||||
#include "storage/storage_tests/task_runner.hpp"
|
||||
|
||||
#include "base/assert.hpp"
|
||||
#include "base/scope_guard.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
|
||||
namespace storage
|
||||
{
|
||||
int64_t const FakeMapFilesDownloader::kBlockSize;
|
||||
|
||||
FakeMapFilesDownloader::FakeMapFilesDownloader(TaskRunner & taskRunner) : m_timestamp(0), m_taskRunner(taskRunner)
|
||||
{
|
||||
SetServersList({"http://test-url/"});
|
||||
}
|
||||
|
||||
FakeMapFilesDownloader::~FakeMapFilesDownloader()
|
||||
{
|
||||
CHECK_THREAD_CHECKER(m_checker, ());
|
||||
}
|
||||
|
||||
void FakeMapFilesDownloader::Download(QueuedCountry && queuedCountry)
|
||||
{
|
||||
CHECK_THREAD_CHECKER(m_checker, ());
|
||||
|
||||
m_queue.Append(std::move(queuedCountry));
|
||||
|
||||
if (m_queue.Count() == 1)
|
||||
Download();
|
||||
}
|
||||
|
||||
void FakeMapFilesDownloader::Remove(CountryId const & id)
|
||||
{
|
||||
CHECK_THREAD_CHECKER(m_checker, ());
|
||||
|
||||
if (m_queue.IsEmpty())
|
||||
return;
|
||||
|
||||
if (m_writer && m_queue.GetFirstId() == id)
|
||||
m_writer.reset();
|
||||
|
||||
m_queue.Remove(id);
|
||||
|
||||
++m_timestamp;
|
||||
}
|
||||
|
||||
void FakeMapFilesDownloader::Clear()
|
||||
{
|
||||
CHECK_THREAD_CHECKER(m_checker, ());
|
||||
|
||||
m_queue.Clear();
|
||||
m_writer.reset();
|
||||
++m_timestamp;
|
||||
}
|
||||
|
||||
QueueInterface const & FakeMapFilesDownloader::GetQueue() const
|
||||
{
|
||||
CHECK_THREAD_CHECKER(m_checker, ());
|
||||
|
||||
return m_queue;
|
||||
}
|
||||
|
||||
void FakeMapFilesDownloader::Download()
|
||||
{
|
||||
auto const & queuedCountry = m_queue.GetFirstCountry();
|
||||
if (!IsDownloadingAllowed())
|
||||
{
|
||||
OnFileDownloaded(queuedCountry, downloader::DownloadStatus::Failed);
|
||||
return;
|
||||
}
|
||||
|
||||
queuedCountry.OnStartDownloading();
|
||||
|
||||
++m_timestamp;
|
||||
m_progress = {};
|
||||
m_progress.m_bytesTotal = queuedCountry.GetDownloadSize();
|
||||
m_writer.reset(new FileWriter(queuedCountry.GetFileDownloadPath()));
|
||||
m_taskRunner.PostTask(std::bind(&FakeMapFilesDownloader::DownloadNextChunk, this, m_timestamp));
|
||||
}
|
||||
|
||||
void FakeMapFilesDownloader::DownloadNextChunk(uint64_t timestamp)
|
||||
{
|
||||
CHECK_THREAD_CHECKER(m_checker, ());
|
||||
|
||||
static std::string kZeroes(kBlockSize, '\0');
|
||||
|
||||
if (timestamp != m_timestamp)
|
||||
return;
|
||||
|
||||
ASSERT_LESS_OR_EQUAL(m_progress.m_bytesDownloaded, m_progress.m_bytesTotal, ());
|
||||
ASSERT(m_writer, ());
|
||||
|
||||
if (m_progress.m_bytesDownloaded == m_progress.m_bytesTotal)
|
||||
{
|
||||
OnFileDownloaded(m_queue.GetFirstCountry(), downloader::DownloadStatus::Completed);
|
||||
return;
|
||||
}
|
||||
|
||||
int64_t const bs = std::min(m_progress.m_bytesTotal - m_progress.m_bytesDownloaded, kBlockSize);
|
||||
|
||||
m_progress.m_bytesDownloaded += bs;
|
||||
m_writer->Write(kZeroes.data(), bs);
|
||||
m_writer->Flush();
|
||||
|
||||
m_taskRunner.PostTask([this, timestamp]()
|
||||
{
|
||||
CHECK_THREAD_CHECKER(m_checker, ());
|
||||
|
||||
if (timestamp != m_timestamp)
|
||||
return;
|
||||
|
||||
m_queue.GetFirstCountry().OnDownloadProgress(m_progress);
|
||||
});
|
||||
m_taskRunner.PostTask(std::bind(&FakeMapFilesDownloader::DownloadNextChunk, this, timestamp));
|
||||
}
|
||||
|
||||
void FakeMapFilesDownloader::OnFileDownloaded(QueuedCountry const & queuedCountry,
|
||||
downloader::DownloadStatus const & status)
|
||||
{
|
||||
auto const country = queuedCountry;
|
||||
m_queue.PopFront();
|
||||
|
||||
m_taskRunner.PostTask([country, status]() { country.OnDownloadFinished(status); });
|
||||
|
||||
if (!m_queue.IsEmpty())
|
||||
Download();
|
||||
}
|
||||
} // namespace storage
|
||||
60
libs/storage/storage_tests/fake_map_files_downloader.hpp
Normal file
60
libs/storage/storage_tests/fake_map_files_downloader.hpp
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
#pragma once
|
||||
|
||||
#include "storage/downloader_queue_universal.hpp"
|
||||
#include "storage/map_files_downloader.hpp"
|
||||
#include "storage/queued_country.hpp"
|
||||
|
||||
#include "platform/downloader_defines.hpp"
|
||||
|
||||
#include "coding/file_writer.hpp"
|
||||
|
||||
#include "base/thread_checker.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace storage
|
||||
{
|
||||
class TaskRunner;
|
||||
|
||||
// This class can be used in tests to mimic a real downloader. It
|
||||
// always returns a single URL for map files downloading and when
|
||||
// asked for a file, creates a file with zero-bytes content on a disk.
|
||||
// Because all callbacks must be invoked asynchronously, it needs a
|
||||
// single-thread message loop runner to run callbacks.
|
||||
//
|
||||
// *NOTE*, this class is not thread-safe.
|
||||
class FakeMapFilesDownloader : public MapFilesDownloader
|
||||
{
|
||||
public:
|
||||
static int64_t const kBlockSize = 1024 * 1024;
|
||||
|
||||
FakeMapFilesDownloader(TaskRunner & taskRunner);
|
||||
|
||||
~FakeMapFilesDownloader();
|
||||
|
||||
// MapFilesDownloader overrides:
|
||||
void Remove(CountryId const & id) override;
|
||||
void Clear() override;
|
||||
QueueInterface const & GetQueue() const override;
|
||||
|
||||
private:
|
||||
// MapFilesDownloader overrides:
|
||||
void Download(QueuedCountry && queuedCountry) override;
|
||||
|
||||
void Download();
|
||||
void DownloadNextChunk(uint64_t requestId);
|
||||
void OnFileDownloaded(QueuedCountry const & queuedCountry, downloader::DownloadStatus const & status);
|
||||
|
||||
downloader::Progress m_progress;
|
||||
|
||||
std::unique_ptr<FileWriter> m_writer;
|
||||
|
||||
uint64_t m_timestamp;
|
||||
|
||||
TaskRunner & m_taskRunner;
|
||||
ThreadChecker m_checker;
|
||||
Queue m_queue;
|
||||
};
|
||||
} // namespace storage
|
||||
17
libs/storage/storage_tests/helpers.cpp
Normal file
17
libs/storage/storage_tests/helpers.cpp
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "storage/storage_tests/helpers.hpp"
|
||||
|
||||
#include "storage/country_info_getter.hpp"
|
||||
|
||||
#include "platform/platform.hpp"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace storage
|
||||
{
|
||||
std::unique_ptr<storage::CountryInfoGetter> CreateCountryInfoGetter()
|
||||
{
|
||||
return CountryInfoReader::CreateCountryInfoGetter(GetPlatform());
|
||||
}
|
||||
} // namespace storage
|
||||
13
libs/storage/storage_tests/helpers.hpp
Normal file
13
libs/storage/storage_tests/helpers.hpp
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#pragma once
|
||||
|
||||
#include "geometry/mercator.hpp"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace storage
|
||||
{
|
||||
class CountryInfoGetter;
|
||||
|
||||
std::unique_ptr<CountryInfoGetter> CreateCountryInfoGetter();
|
||||
|
||||
} // namespace storage
|
||||
49
libs/storage/storage_tests/simple_tree_test.cpp
Normal file
49
libs/storage/storage_tests/simple_tree_test.cpp
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "storage/country_tree.hpp"
|
||||
|
||||
UNIT_TEST(CountryTree_Smoke)
|
||||
{
|
||||
using Tree = storage::CountryTree::Node;
|
||||
using Value = storage::Country;
|
||||
|
||||
Tree tree(Value("0"), nullptr);
|
||||
|
||||
tree.AddAtDepth(1, Value("4"));
|
||||
tree.AddAtDepth(1, Value("3"));
|
||||
tree.AddAtDepth(1, Value("5"));
|
||||
tree.AddAtDepth(1, Value("2"));
|
||||
tree.AddAtDepth(1, Value("1"));
|
||||
tree.AddAtDepth(2, Value("20"));
|
||||
tree.AddAtDepth(2, Value("10"));
|
||||
tree.AddAtDepth(2, Value("30"));
|
||||
|
||||
// children test
|
||||
TEST_EQUAL(tree.Child(0).Value().Name(), "4", ());
|
||||
TEST_EQUAL(tree.Child(1).Value().Name(), "3", ());
|
||||
TEST_EQUAL(tree.Child(2).Value().Name(), "5", ());
|
||||
TEST_EQUAL(tree.Child(3).Value().Name(), "2", ());
|
||||
TEST_EQUAL(tree.Child(4).Value().Name(), "1", ());
|
||||
TEST_EQUAL(tree.Child(4).Child(0).Value().Name(), "20", ());
|
||||
TEST_EQUAL(tree.Child(4).Child(1).Value().Name(), "10", ());
|
||||
TEST_EQUAL(tree.Child(4).Child(2).Value().Name(), "30", ());
|
||||
|
||||
// parent test
|
||||
TEST(!tree.HasParent(), ());
|
||||
TEST(!tree.Child(0).Parent().HasParent(), ());
|
||||
TEST_EQUAL(tree.Child(4).Child(0).Parent().Value().Name(), "1", ());
|
||||
TEST_EQUAL(tree.Child(4).Child(2).Parent().Value().Name(), "1", ());
|
||||
|
||||
size_t count = 0;
|
||||
auto countCallback = [&count](Tree const &) { ++count; };
|
||||
tree.ForEachChild(countCallback);
|
||||
TEST_EQUAL(count, 5, ());
|
||||
|
||||
count = 0;
|
||||
tree.ForEachDescendant(countCallback);
|
||||
TEST_EQUAL(count, 8, ());
|
||||
|
||||
count = 0;
|
||||
tree.Child(4).Child(0).ForEachAncestorExceptForTheRoot(countCallback);
|
||||
TEST_EQUAL(count, 1, ());
|
||||
}
|
||||
1488
libs/storage/storage_tests/storage_tests.cpp
Normal file
1488
libs/storage/storage_tests/storage_tests.cpp
Normal file
File diff suppressed because it is too large
Load diff
28
libs/storage/storage_tests/task_runner.cpp
Normal file
28
libs/storage/storage_tests/task_runner.cpp
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
#include "storage/storage_tests/task_runner.hpp"
|
||||
|
||||
#include "base/assert.hpp"
|
||||
|
||||
namespace storage
|
||||
{
|
||||
TaskRunner::~TaskRunner()
|
||||
{
|
||||
CHECK(m_checker.CalledOnOriginalThread(), ());
|
||||
}
|
||||
|
||||
void TaskRunner::Run()
|
||||
{
|
||||
CHECK(m_checker.CalledOnOriginalThread(), ());
|
||||
while (!m_tasks.empty())
|
||||
{
|
||||
TTask task = m_tasks.front();
|
||||
m_tasks.pop();
|
||||
task();
|
||||
}
|
||||
}
|
||||
|
||||
void TaskRunner::PostTask(TTask const & task)
|
||||
{
|
||||
CHECK(m_checker.CalledOnOriginalThread(), ());
|
||||
m_tasks.push(task);
|
||||
}
|
||||
} // namespace storage
|
||||
32
libs/storage/storage_tests/task_runner.hpp
Normal file
32
libs/storage/storage_tests/task_runner.hpp
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
#pragma once
|
||||
|
||||
#include "base/thread_checker.hpp"
|
||||
|
||||
#include <functional>
|
||||
#include <queue>
|
||||
|
||||
namespace storage
|
||||
{
|
||||
// This class can be used in tests to mimic asynchronious calls. For
|
||||
// example, when task A invokes task B and passes a callback C as an
|
||||
// argument to B, it's silly for B to call C directly if B is an
|
||||
// asynchronious task. So, the solution is to post C on the same
|
||||
// message loop where B is run.
|
||||
//
|
||||
// *NOTE*, this class is not thread-safe.
|
||||
class TaskRunner
|
||||
{
|
||||
public:
|
||||
using TTask = std::function<void()>;
|
||||
|
||||
~TaskRunner();
|
||||
|
||||
void Run();
|
||||
void PostTask(TTask const & task);
|
||||
|
||||
private:
|
||||
std::queue<TTask> m_tasks;
|
||||
|
||||
ThreadChecker m_checker;
|
||||
};
|
||||
} // namespace storage
|
||||
9
libs/storage/storage_tests/test_map_files_downloader.cpp
Normal file
9
libs/storage/storage_tests/test_map_files_downloader.cpp
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#include "storage/storage_tests/test_map_files_downloader.hpp"
|
||||
|
||||
namespace storage
|
||||
{
|
||||
TestMapFilesDownloader::TestMapFilesDownloader() : HttpMapFilesDownloader()
|
||||
{
|
||||
SetServersList({"http://localhost:34568/unit_tests/"});
|
||||
}
|
||||
} // namespace storage
|
||||
12
libs/storage/storage_tests/test_map_files_downloader.hpp
Normal file
12
libs/storage/storage_tests/test_map_files_downloader.hpp
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
#include "storage/http_map_files_downloader.hpp"
|
||||
|
||||
namespace storage
|
||||
{
|
||||
class TestMapFilesDownloader : public HttpMapFilesDownloader
|
||||
{
|
||||
public:
|
||||
TestMapFilesDownloader();
|
||||
};
|
||||
} // namespace storage
|
||||
Loading…
Add table
Add a link
Reference in a new issue