Repo created
This commit is contained in:
parent
4af19165ec
commit
68073add76
12458 changed files with 12350765 additions and 2 deletions
28
libs/platform/platform_tests/CMakeLists.txt
Normal file
28
libs/platform/platform_tests/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
project(platform_tests)
|
||||
|
||||
set(SRC
|
||||
country_file_tests.cpp
|
||||
distance_tests.cpp
|
||||
duration_tests.cpp
|
||||
downloader_tests/downloader_test.cpp
|
||||
downloader_utils_tests.cpp
|
||||
get_text_by_id_tests.cpp
|
||||
glaze_test.cpp
|
||||
jansson_test.cpp
|
||||
language_test.cpp
|
||||
local_country_file_tests.cpp
|
||||
location_test.cpp
|
||||
measurement_tests.cpp
|
||||
platform_test.cpp
|
||||
meta_config_tests.cpp
|
||||
utm_mgrs_utils_tests.cpp
|
||||
)
|
||||
|
||||
omim_add_test(${PROJECT_NAME} ${SRC} REQUIRE_QT REQUIRE_SERVER)
|
||||
|
||||
target_link_libraries(${PROJECT_NAME}
|
||||
platform_tests_support
|
||||
platform
|
||||
cppjansson
|
||||
glaze::glaze
|
||||
)
|
||||
33
libs/platform/platform_tests/country_file_tests.cpp
Normal file
33
libs/platform/platform_tests/country_file_tests.cpp
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "defines.hpp"
|
||||
|
||||
#include "platform/country_file.hpp"
|
||||
#include "platform/mwm_version.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace platform
|
||||
{
|
||||
UNIT_TEST(CountryFile_Smoke)
|
||||
{
|
||||
{
|
||||
CountryFile cf("One");
|
||||
TEST_EQUAL("One", cf.GetName(), ());
|
||||
auto const mapFileName = cf.GetFileName(MapFileType::Map);
|
||||
|
||||
TEST_EQUAL("One" DATA_FILE_EXTENSION, mapFileName, ());
|
||||
TEST_EQUAL(0, cf.GetRemoteSize(), ());
|
||||
}
|
||||
|
||||
{
|
||||
CountryFile cf("Three", 666, "xxxSHAxxx");
|
||||
TEST_EQUAL("Three", cf.GetName(), ());
|
||||
auto const mapFileName = cf.GetFileName(MapFileType::Map);
|
||||
|
||||
TEST_EQUAL("Three" DATA_FILE_EXTENSION, mapFileName, ());
|
||||
TEST_EQUAL(666, cf.GetRemoteSize(), ());
|
||||
TEST_EQUAL("xxxSHAxxx", cf.GetSha1(), ());
|
||||
}
|
||||
}
|
||||
} // namespace platform
|
||||
365
libs/platform/platform_tests/distance_tests.cpp
Normal file
365
libs/platform/platform_tests/distance_tests.cpp
Normal file
|
|
@ -0,0 +1,365 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "platform/distance.hpp"
|
||||
#include "platform/measurement_utils.hpp"
|
||||
#include "platform/settings.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace platform
|
||||
{
|
||||
std::string MakeDistanceStr(std::string value, Distance::Units unit)
|
||||
{
|
||||
static Locale const loc = GetCurrentLocale();
|
||||
|
||||
constexpr char kHardCodedGroupingSeparator = ',';
|
||||
if (auto found = value.find(kHardCodedGroupingSeparator); found != std::string::npos)
|
||||
value.replace(found, 1, loc.m_groupingSeparator);
|
||||
|
||||
constexpr char kHardCodedDecimalSeparator = '.';
|
||||
if (auto found = value.find(kHardCodedDecimalSeparator); found != std::string::npos)
|
||||
value.replace(found, 1, loc.m_decimalSeparator);
|
||||
|
||||
return value.append(kNarrowNonBreakingSpace).append(DebugPrint(unit));
|
||||
}
|
||||
|
||||
struct ScopedSettings
|
||||
{
|
||||
/// Saves/restores previous units and sets new units for a scope.
|
||||
explicit ScopedSettings(measurement_utils::Units newUnits) : m_oldUnits(measurement_utils::Units::Metric)
|
||||
{
|
||||
m_wasSet = settings::Get(settings::kMeasurementUnits, m_oldUnits);
|
||||
settings::Set(settings::kMeasurementUnits, newUnits);
|
||||
}
|
||||
|
||||
~ScopedSettings()
|
||||
{
|
||||
if (m_wasSet)
|
||||
settings::Set(settings::kMeasurementUnits, m_oldUnits);
|
||||
else
|
||||
settings::Delete(settings::kMeasurementUnits);
|
||||
}
|
||||
|
||||
bool m_wasSet;
|
||||
measurement_utils::Units m_oldUnits;
|
||||
};
|
||||
|
||||
UNIT_TEST(Distance_InititalDistance)
|
||||
{
|
||||
Distance const d;
|
||||
TEST(!d.IsValid(), ());
|
||||
TEST_ALMOST_EQUAL_ULPS(d.GetDistance(), -1.0, ());
|
||||
TEST_EQUAL(d.GetDistanceString(), "", ());
|
||||
TEST_EQUAL(d.ToString(), "", ());
|
||||
}
|
||||
|
||||
UNIT_TEST(Distance_CreateFormatted)
|
||||
{
|
||||
using enum Distance::Units;
|
||||
{
|
||||
ScopedSettings const guard(measurement_utils::Units::Metric);
|
||||
|
||||
Distance const d = Distance::CreateFormatted(100);
|
||||
TEST_EQUAL(d.GetUnits(), Meters, ());
|
||||
TEST_ALMOST_EQUAL_ULPS(d.GetDistance(), 100.0, ());
|
||||
TEST_EQUAL(d.GetDistanceString(), "100", ());
|
||||
TEST_EQUAL(d.ToString(), MakeDistanceStr("100", Meters), ());
|
||||
}
|
||||
{
|
||||
ScopedSettings const guard(measurement_utils::Units::Imperial);
|
||||
|
||||
Distance const d = Distance::CreateFormatted(100);
|
||||
TEST_EQUAL(d.GetUnits(), Feet, ());
|
||||
TEST_ALMOST_EQUAL_ULPS(d.GetDistance(), 330.0, ());
|
||||
TEST_EQUAL(d.GetDistanceString(), "330", ());
|
||||
TEST_EQUAL(d.ToString(), MakeDistanceStr("330", Feet), ());
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST(Distance_CreateAltitudeFormatted)
|
||||
{
|
||||
using enum Distance::Units;
|
||||
{
|
||||
ScopedSettings const guard(measurement_utils::Units::Metric);
|
||||
|
||||
TEST_EQUAL(Distance::FormatAltitude(5), MakeDistanceStr("5", Meters), ());
|
||||
TEST_EQUAL(Distance::FormatAltitude(-8849), MakeDistanceStr("-8849", Meters), ());
|
||||
TEST_EQUAL(Distance::FormatAltitude(12345), MakeDistanceStr("12,345", Meters), ());
|
||||
}
|
||||
{
|
||||
ScopedSettings const guard(measurement_utils::Units::Imperial);
|
||||
|
||||
TEST_EQUAL(Distance::FormatAltitude(10000), MakeDistanceStr("32,808", Feet), ());
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST(Distance_IsLowUnits)
|
||||
{
|
||||
using enum Distance::Units;
|
||||
TEST_EQUAL(Distance(0.0, Meters).IsLowUnits(), true, ());
|
||||
TEST_EQUAL(Distance(0.0, Feet).IsLowUnits(), true, ());
|
||||
TEST_EQUAL(Distance(0.0, Kilometers).IsLowUnits(), false, ());
|
||||
TEST_EQUAL(Distance(0.0, Miles).IsLowUnits(), false, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(Distance_IsHighUnits)
|
||||
{
|
||||
using enum Distance::Units;
|
||||
TEST_EQUAL(Distance(0.0, Meters).IsHighUnits(), false, ());
|
||||
TEST_EQUAL(Distance(0.0, Feet).IsHighUnits(), false, ());
|
||||
TEST_EQUAL(Distance(0.0, Kilometers).IsHighUnits(), true, ());
|
||||
TEST_EQUAL(Distance(0.0, Miles).IsHighUnits(), true, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(Distance_To)
|
||||
{
|
||||
struct TestData
|
||||
{
|
||||
double initialDistance;
|
||||
Distance::Units initialUnits;
|
||||
Distance::Units to;
|
||||
double newDistance;
|
||||
Distance::Units newUnits;
|
||||
};
|
||||
|
||||
using enum Distance::Units;
|
||||
// clang-format off
|
||||
TestData constexpr testData[] = {
|
||||
{0.1, Meters, Feet, 0, Feet},
|
||||
{0.3, Meters, Feet, 1, Feet},
|
||||
{0.3048, Meters, Feet, 1, Feet},
|
||||
{0.4573, Meters, Feet, 2, Feet},
|
||||
{0.9, Meters, Feet, 3, Feet},
|
||||
{3, Meters, Feet, 10, Feet},
|
||||
{30.17, Meters, Feet, 99, Feet},
|
||||
{30.33, Meters, Feet, 100, Feet},
|
||||
{30.49, Meters, Feet, 100, Feet},
|
||||
{33.5, Meters, Feet, 110, Feet},
|
||||
{302, Meters, Feet, 990, Feet},
|
||||
{304.7, Meters, Feet, 0.2, Miles},
|
||||
{304.8, Meters, Feet, 0.2, Miles},
|
||||
{402.3, Meters, Feet, 0.2, Miles},
|
||||
{402.4, Meters, Feet, 0.3, Miles},
|
||||
{482.8, Meters, Feet, 0.3, Miles},
|
||||
{1609.3, Meters, Feet, 1.0, Miles},
|
||||
{1610, Meters, Feet, 1.0, Miles},
|
||||
{1770, Meters, Feet, 1.1, Miles},
|
||||
{15933, Meters, Feet, 9.9, Miles},
|
||||
{16093, Meters, Feet, 10, Miles},
|
||||
{16093.5, Meters, Feet, 10, Miles},
|
||||
{16898.464, Meters, Feet, 11, Miles},
|
||||
{16898.113, Meters, Kilometers, 17, Kilometers},
|
||||
{302, Meters, Miles, 990, Feet},
|
||||
{994, Meters, Kilometers, 990, Meters},
|
||||
{995, Meters, Kilometers, 1.0, Kilometers},
|
||||
{0.1, Kilometers, Meters, 100, Meters},
|
||||
{0.3, Kilometers, Kilometers, 300, Meters},
|
||||
{12, Kilometers, Feet, 7.5, Miles},
|
||||
{0.1, Kilometers, Feet, 330, Feet},
|
||||
{110, Feet, Meters, 34, Meters},
|
||||
{1100, Feet, Kilometers, 340, Meters},
|
||||
{1100, Feet, Meters, 340, Meters},
|
||||
{1100, Feet, Miles, 0.2, Miles},
|
||||
{0.2, Miles, Meters, 320, Meters},
|
||||
{11, Miles, Meters, 18, Kilometers},
|
||||
{11, Miles, Kilometers, 18, Kilometers},
|
||||
{0.1, Miles, Feet, 530, Feet},
|
||||
};
|
||||
|
||||
// clang-format on
|
||||
for (TestData const & data : testData)
|
||||
{
|
||||
Distance const formatted = Distance(data.initialDistance, data.initialUnits).To(data.to).GetFormattedDistance();
|
||||
TEST_ALMOST_EQUAL_ULPS(formatted.GetDistance(), data.newDistance, (data.initialDistance));
|
||||
TEST_EQUAL(formatted.GetUnits(), data.newUnits, ());
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST(Distance_ToPlatformUnitsFormatted)
|
||||
{
|
||||
using enum Distance::Units;
|
||||
{
|
||||
ScopedSettings const guard(measurement_utils::Units::Metric);
|
||||
|
||||
Distance d{11, Feet};
|
||||
Distance newDistance = d.ToPlatformUnitsFormatted();
|
||||
|
||||
TEST_EQUAL(newDistance.GetUnits(), Meters, (d.ToString()));
|
||||
TEST_ALMOST_EQUAL_ULPS(newDistance.GetDistance(), 3.0, (d.ToString()));
|
||||
TEST_EQUAL(newDistance.GetDistanceString(), "3", (d.ToString()));
|
||||
TEST_EQUAL(newDistance.ToString(), MakeDistanceStr("3", Meters), (d.ToString()));
|
||||
|
||||
d = Distance{11, Kilometers};
|
||||
newDistance = d.ToPlatformUnitsFormatted();
|
||||
|
||||
TEST_EQUAL(newDistance.GetUnits(), Kilometers, (d.ToString()));
|
||||
TEST_ALMOST_EQUAL_ULPS(newDistance.GetDistance(), 11.0, (d.ToString()));
|
||||
TEST_EQUAL(newDistance.GetDistanceString(), "11", (d.ToString()));
|
||||
TEST_EQUAL(newDistance.ToString(), MakeDistanceStr("11", Kilometers), (d.ToString()));
|
||||
}
|
||||
|
||||
{
|
||||
ScopedSettings const guard(measurement_utils::Units::Imperial);
|
||||
|
||||
Distance d{11, Feet};
|
||||
Distance newDistance = d.ToPlatformUnitsFormatted();
|
||||
|
||||
TEST_EQUAL(newDistance.GetUnits(), Feet, (d.ToString()));
|
||||
TEST_ALMOST_EQUAL_ULPS(newDistance.GetDistance(), 11.0, (d.ToString()));
|
||||
TEST_EQUAL(newDistance.GetDistanceString(), "11", (d.ToString()));
|
||||
TEST_EQUAL(newDistance.ToString(), MakeDistanceStr("11", Feet), (d.ToString()));
|
||||
|
||||
d = Distance{11, Kilometers};
|
||||
newDistance = d.ToPlatformUnitsFormatted();
|
||||
|
||||
TEST_EQUAL(newDistance.GetUnits(), Miles, (d.ToString()));
|
||||
TEST_ALMOST_EQUAL_ULPS(newDistance.GetDistance(), 6.8, (d.ToString()));
|
||||
TEST_EQUAL(newDistance.GetDistanceString(), "6.8", (d.ToString()));
|
||||
TEST_EQUAL(newDistance.ToString(), MakeDistanceStr("6.8", Miles), (d.ToString()));
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST(Distance_GetUnits)
|
||||
{
|
||||
using enum Distance::Units;
|
||||
TEST_EQUAL(Distance(1234).GetUnits(), Meters, ());
|
||||
TEST_EQUAL(Distance(1234, Kilometers).GetUnits(), Kilometers, ());
|
||||
TEST_EQUAL(Distance(1234, Feet).GetUnits(), Feet, ());
|
||||
TEST_EQUAL(Distance(1234, Miles).GetUnits(), Miles, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(Distance_GetUnitsString)
|
||||
{
|
||||
using enum Distance::Units;
|
||||
TEST_EQUAL(Distance(1234).GetUnitsString(), "m", ());
|
||||
TEST_EQUAL(Distance(1234, Meters).GetUnitsString(), "m", ());
|
||||
TEST_EQUAL(Distance(1234, Kilometers).GetUnitsString(), "km", ());
|
||||
TEST_EQUAL(Distance(1234, Feet).GetUnitsString(), "ft", ());
|
||||
TEST_EQUAL(Distance(1234, Miles).GetUnitsString(), "mi", ());
|
||||
}
|
||||
|
||||
UNIT_TEST(Distance_FormattedDistance)
|
||||
{
|
||||
struct TestData
|
||||
{
|
||||
Distance distance;
|
||||
double formattedDistance;
|
||||
Distance::Units formattedUnits;
|
||||
std::string formattedDistanceStringInUsLocale;
|
||||
};
|
||||
|
||||
using enum Distance::Units;
|
||||
// clang-format off
|
||||
TestData const testData[] = {
|
||||
// From Meters to Meters
|
||||
{Distance(0, Meters), 0, Meters, "0"},
|
||||
{Distance(0.3, Meters), 0, Meters, "0"},
|
||||
{Distance(0.9, Meters), 1, Meters, "1"},
|
||||
{Distance(1, Meters), 1, Meters, "1"},
|
||||
{Distance(1.234, Meters), 1, Meters, "1"},
|
||||
{Distance(9.99, Meters), 10, Meters, "10"},
|
||||
{Distance(10.01, Meters), 10, Meters, "10"},
|
||||
{Distance(10.4, Meters), 10, Meters, "10"},
|
||||
{Distance(10.5, Meters), 11, Meters, "11"},
|
||||
{Distance(10.51, Meters), 11, Meters, "11"},
|
||||
{Distance(64.2, Meters), 64, Meters, "64"},
|
||||
{Distance(99, Meters), 99, Meters, "99"},
|
||||
{Distance(100, Meters), 100, Meters, "100"},
|
||||
{Distance(101, Meters), 100, Meters, "100"},
|
||||
{Distance(109, Meters), 110, Meters, "110"},
|
||||
{Distance(991, Meters), 990, Meters, "990"},
|
||||
|
||||
// From Kilometers to Kilometers
|
||||
{Distance(0, Kilometers), 0, Meters, "0"},
|
||||
{Distance(0.3, Kilometers), 300, Meters, "300"},
|
||||
{Distance(1.234, Kilometers), 1.2, Kilometers, "1.2"},
|
||||
{Distance(10, Kilometers), 10, Kilometers, "10"},
|
||||
{Distance(11, Kilometers), 11, Kilometers, "11"},
|
||||
{Distance(54, Kilometers), 54, Kilometers, "54"},
|
||||
{Distance(99.99, Kilometers), 100, Kilometers, "100"},
|
||||
{Distance(100.01, Kilometers), 100, Kilometers, "100"},
|
||||
{Distance(115, Kilometers), 115, Kilometers, "115"},
|
||||
{Distance(999, Kilometers), 999, Kilometers, "999"},
|
||||
{Distance(1000, Kilometers), 1000, Kilometers, "1000"},
|
||||
{Distance(1049.99, Kilometers), 1050, Kilometers, "1050"},
|
||||
{Distance(1050, Kilometers), 1050, Kilometers, "1050"},
|
||||
{Distance(1050.01, Kilometers), 1050, Kilometers, "1050"},
|
||||
{Distance(1234, Kilometers), 1234, Kilometers, "1234"},
|
||||
{Distance(12345, Kilometers), 12345, Kilometers, "12,345"},
|
||||
|
||||
// From Feet to Feet
|
||||
{Distance(0, Feet), 0, Feet, "0"},
|
||||
{Distance(1, Feet), 1, Feet, "1"},
|
||||
{Distance(9.99, Feet), 10, Feet, "10"},
|
||||
{Distance(10.01, Feet), 10, Feet, "10"},
|
||||
{Distance(95, Feet), 95, Feet, "95"},
|
||||
{Distance(125, Feet), 130, Feet, "130"},
|
||||
{Distance(991, Feet), 990, Feet, "990"},
|
||||
|
||||
// From Miles to Miles
|
||||
{Distance(0, Miles), 0, Feet, "0"},
|
||||
{Distance(0.1, Miles), 530, Feet, "530"},
|
||||
{Distance(1, Miles), 1.0, Miles, "1.0"},
|
||||
{Distance(1.234, Miles), 1.2, Miles, "1.2"},
|
||||
{Distance(9.99, Miles), 10, Miles, "10"},
|
||||
{Distance(10.01, Miles), 10, Miles, "10"},
|
||||
{Distance(11, Miles), 11, Miles, "11"},
|
||||
{Distance(54, Miles), 54, Miles, "54"},
|
||||
{Distance(145, Miles), 145, Miles, "145"},
|
||||
{Distance(999, Miles), 999, Miles, "999"},
|
||||
{Distance(1149.99, Miles), 1150, Miles, "1150"},
|
||||
{Distance(1150, Miles), 1150, Miles, "1150"},
|
||||
{Distance(1150.01, Miles), 1150, Miles, "1150"},
|
||||
{Distance(12345.0, Miles), 12345, Miles, "12,345"},
|
||||
|
||||
// From Meters to Kilometers
|
||||
{Distance(999, Meters), 1.0, Kilometers, "1.0"},
|
||||
{Distance(1000, Meters), 1.0, Kilometers, "1.0"},
|
||||
{Distance(1001, Meters), 1.0, Kilometers, "1.0"},
|
||||
{Distance(1100, Meters), 1.1, Kilometers, "1.1"},
|
||||
{Distance(1140, Meters), 1.1, Kilometers, "1.1"},
|
||||
{Distance(1151, Meters), 1.2, Kilometers, "1.2"},
|
||||
{Distance(1500, Meters), 1.5, Kilometers, "1.5"},
|
||||
{Distance(1549.9, Meters), 1.5, Kilometers, "1.5"},
|
||||
{Distance(1550, Meters), 1.6, Kilometers, "1.6"},
|
||||
{Distance(1551, Meters), 1.6, Kilometers, "1.6"},
|
||||
{Distance(9949, Meters), 9.9, Kilometers, "9.9"},
|
||||
{Distance(9992, Meters), 10, Kilometers, "10"},
|
||||
{Distance(10000, Meters), 10, Kilometers, "10"},
|
||||
{Distance(10499.9, Meters), 10, Kilometers, "10"},
|
||||
{Distance(10501, Meters), 11, Kilometers, "11"},
|
||||
{Distance(101'001, Meters), 101, Kilometers, "101"},
|
||||
{Distance(101'999, Meters), 102, Kilometers, "102"},
|
||||
{Distance(287'386, Meters), 287, Kilometers, "287"},
|
||||
|
||||
// From Feet to Miles
|
||||
{Distance(999, Feet), 0.2, Miles, "0.2"},
|
||||
{Distance(1000, Feet), 0.2, Miles, "0.2"},
|
||||
{Distance(1150, Feet), 0.2, Miles, "0.2"},
|
||||
{Distance(5280, Feet), 1.0, Miles, "1.0"},
|
||||
{Distance(7920, Feet), 1.5, Miles, "1.5"},
|
||||
{Distance(10560, Feet), 2.0, Miles, "2.0"},
|
||||
{Distance(100'000, Feet), 19, Miles, "19"},
|
||||
{Distance(285'120, Feet), 54, Miles, "54"},
|
||||
{Distance(633'547, Feet), 120, Miles, "120"},
|
||||
{Distance(633'600, Feet), 120, Miles, "120"},
|
||||
{Distance(633'653, Feet), 120, Miles, "120"},
|
||||
{Distance(999'999, Feet), 189, Miles, "189"},
|
||||
};
|
||||
|
||||
// clang-format on
|
||||
for (auto const & [distance, formattedDistance, formattedUnits, formattedDistanceStringInUsLocale] : testData)
|
||||
{
|
||||
Distance const formatted = distance.GetFormattedDistance();
|
||||
// Run two times to verify that nothing breaks after second format
|
||||
for (auto const & d : {formatted, formatted.GetFormattedDistance()})
|
||||
{
|
||||
TEST_ALMOST_EQUAL_ULPS(d.GetDistance(), formattedDistance, (distance));
|
||||
TEST_EQUAL(d.GetUnits(), formattedUnits, (distance));
|
||||
auto const formattedString = MakeDistanceStr(formattedDistanceStringInUsLocale, formattedUnits);
|
||||
TEST_EQUAL(d.ToString(), formattedString, (distance));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace platform
|
||||
|
|
@ -0,0 +1,613 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "platform/chunks_download_strategy.hpp"
|
||||
#include "platform/http_request.hpp"
|
||||
#include "platform/platform.hpp"
|
||||
|
||||
#include "coding/file_reader.hpp"
|
||||
#include "coding/file_writer.hpp"
|
||||
#include "coding/internal/file_data.hpp"
|
||||
|
||||
#include "base/logging.hpp"
|
||||
#include "base/std_serialization.hpp"
|
||||
|
||||
#include <QtCore/QCoreApplication>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "defines.hpp"
|
||||
|
||||
namespace downloader_test
|
||||
{
|
||||
using namespace downloader;
|
||||
using namespace std::placeholders;
|
||||
using std::bind, std::string, std::vector;
|
||||
|
||||
char constexpr kTestUrl1[] = "http://localhost:34568/unit_tests/1.txt";
|
||||
char constexpr kTestUrl404[] = "http://localhost:34568/unit_tests/notexisting_unittest";
|
||||
char constexpr kTestUrlBigFile[] = "http://localhost:34568/unit_tests/47kb.file";
|
||||
|
||||
// Should match file size in tools/python/ResponseProvider.py
|
||||
int constexpr kBigFileSize = 47684;
|
||||
|
||||
class DownloadObserver
|
||||
{
|
||||
bool m_progressWasCalled;
|
||||
// Chunked downloads can return one status per chunk (thread).
|
||||
vector<DownloadStatus> m_statuses;
|
||||
// Interrupt download after this number of chunks
|
||||
int m_chunksToFail;
|
||||
base::ScopedLogLevelChanger const m_debugLogLevel;
|
||||
|
||||
public:
|
||||
DownloadObserver() : m_chunksToFail(-1), m_debugLogLevel(LDEBUG) { Reset(); }
|
||||
|
||||
void CancelDownloadOnGivenChunk(int chunksToFail) { m_chunksToFail = chunksToFail; }
|
||||
|
||||
void Reset()
|
||||
{
|
||||
m_progressWasCalled = false;
|
||||
m_statuses.clear();
|
||||
}
|
||||
|
||||
void TestOk()
|
||||
{
|
||||
TEST_NOT_EQUAL(0, m_statuses.size(), ("Observer was not called."));
|
||||
TEST(m_progressWasCalled, ("Download progress wasn't called"));
|
||||
for (auto const & status : m_statuses)
|
||||
TEST_EQUAL(status, DownloadStatus::Completed, ());
|
||||
}
|
||||
|
||||
void TestFailed()
|
||||
{
|
||||
TEST_NOT_EQUAL(0, m_statuses.size(), ("Observer was not called."));
|
||||
for (auto const & status : m_statuses)
|
||||
TEST_EQUAL(status, DownloadStatus::Failed, ());
|
||||
}
|
||||
|
||||
void TestFileNotFound()
|
||||
{
|
||||
TEST_NOT_EQUAL(0, m_statuses.size(), ("Observer was not called."));
|
||||
for (auto const & status : m_statuses)
|
||||
TEST_EQUAL(status, DownloadStatus::FileNotFound, ());
|
||||
}
|
||||
|
||||
void OnDownloadProgress(HttpRequest & request)
|
||||
{
|
||||
m_progressWasCalled = true;
|
||||
TEST_EQUAL(request.GetStatus(), DownloadStatus::InProgress, ());
|
||||
|
||||
// Cancel download if needed
|
||||
if (m_chunksToFail != -1)
|
||||
{
|
||||
--m_chunksToFail;
|
||||
if (m_chunksToFail == 0)
|
||||
{
|
||||
m_chunksToFail = -1;
|
||||
LOG(LINFO, ("Download canceled"));
|
||||
QCoreApplication::quit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnDownloadFinish(HttpRequest & request)
|
||||
{
|
||||
auto const status = request.GetStatus();
|
||||
m_statuses.emplace_back(status);
|
||||
TEST(status != DownloadStatus::InProgress, ());
|
||||
QCoreApplication::quit();
|
||||
}
|
||||
};
|
||||
|
||||
struct CancelDownload
|
||||
{
|
||||
void OnProgress(HttpRequest & request)
|
||||
{
|
||||
TEST_GREATER(request.GetData().size(), 0, ());
|
||||
delete &request;
|
||||
QCoreApplication::quit();
|
||||
}
|
||||
void OnFinish(HttpRequest &) { TEST(false, ("Should be never called")); }
|
||||
};
|
||||
|
||||
struct DeleteOnFinish
|
||||
{
|
||||
void OnProgress(HttpRequest & request) { TEST_GREATER(request.GetData().size(), 0, ()); }
|
||||
void OnFinish(HttpRequest & request)
|
||||
{
|
||||
delete &request;
|
||||
QCoreApplication::quit();
|
||||
}
|
||||
};
|
||||
|
||||
UNIT_TEST(DownloaderSimpleGet)
|
||||
{
|
||||
DownloadObserver observer;
|
||||
auto const MakeRequest = [&observer](string const & url)
|
||||
{
|
||||
return HttpRequest::Get(url, bind(&DownloadObserver::OnDownloadFinish, &observer, _1),
|
||||
bind(&DownloadObserver::OnDownloadProgress, &observer, _1));
|
||||
};
|
||||
|
||||
{
|
||||
// simple success case
|
||||
std::unique_ptr<HttpRequest> const request{MakeRequest(kTestUrl1)};
|
||||
// wait until download is finished
|
||||
QCoreApplication::exec();
|
||||
observer.TestOk();
|
||||
TEST_EQUAL(request->GetData(), "Test1", ());
|
||||
}
|
||||
|
||||
observer.Reset();
|
||||
{
|
||||
// We DO NOT SUPPORT redirects to avoid data corruption when downloading mwm files
|
||||
std::unique_ptr<HttpRequest> const request{MakeRequest("http://localhost:34568/unit_tests/permanent")};
|
||||
QCoreApplication::exec();
|
||||
observer.TestFailed();
|
||||
TEST_EQUAL(request->GetData().size(), 0, (request->GetData()));
|
||||
}
|
||||
|
||||
observer.Reset();
|
||||
{
|
||||
// fail case 404
|
||||
std::unique_ptr<HttpRequest> const request{MakeRequest(kTestUrl404)};
|
||||
QCoreApplication::exec();
|
||||
observer.TestFileNotFound();
|
||||
TEST_EQUAL(request->GetData().size(), 0, (request->GetData()));
|
||||
}
|
||||
|
||||
observer.Reset();
|
||||
{
|
||||
// fail case not existing host
|
||||
std::unique_ptr<HttpRequest> const request{MakeRequest("http://not-valid-host123532.ath.cx")};
|
||||
QCoreApplication::exec();
|
||||
observer.TestFailed();
|
||||
TEST_EQUAL(request->GetData().size(), 0, (request->GetData()));
|
||||
}
|
||||
|
||||
{
|
||||
// cancel download in the middle of the progress
|
||||
CancelDownload canceler;
|
||||
// should be deleted in canceler
|
||||
HttpRequest::Get(kTestUrlBigFile, bind(&CancelDownload::OnFinish, &canceler, _1),
|
||||
bind(&CancelDownload::OnProgress, &canceler, _1));
|
||||
QCoreApplication::exec();
|
||||
}
|
||||
|
||||
observer.Reset();
|
||||
{
|
||||
// https success case
|
||||
std::unique_ptr<HttpRequest> const request{MakeRequest("https://github.com")};
|
||||
// wait until download is finished
|
||||
QCoreApplication::exec();
|
||||
observer.TestOk();
|
||||
TEST_GREATER(request->GetData().size(), 0, ());
|
||||
}
|
||||
|
||||
{
|
||||
// Delete request at the end of successful download
|
||||
DeleteOnFinish deleter;
|
||||
// should be deleted in deleter on finish
|
||||
HttpRequest::Get(kTestUrl1, bind(&DeleteOnFinish::OnFinish, &deleter, _1),
|
||||
bind(&DeleteOnFinish::OnProgress, &deleter, _1));
|
||||
QCoreApplication::exec();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: This test sometimes fails on CI. Reasons are unknown.
|
||||
#ifndef OMIM_OS_MAC
|
||||
UNIT_TEST(DownloaderSimplePost)
|
||||
{
|
||||
// simple success case
|
||||
string const postData = "{\"jsonKey\":\"jsonValue\"}";
|
||||
DownloadObserver observer;
|
||||
std::unique_ptr<HttpRequest> const request{HttpRequest::PostJson(
|
||||
"http://localhost:34568/unit_tests/post.php", postData, bind(&DownloadObserver::OnDownloadFinish, &observer, _1),
|
||||
bind(&DownloadObserver::OnDownloadProgress, &observer, _1))};
|
||||
// wait until download is finished
|
||||
QCoreApplication::exec();
|
||||
observer.TestOk();
|
||||
TEST_EQUAL(request->GetData(), postData, ());
|
||||
}
|
||||
#endif
|
||||
|
||||
UNIT_TEST(ChunksDownloadStrategy)
|
||||
{
|
||||
vector<string> const servers = {"UrlOfServer1", "UrlOfServer2", "UrlOfServer3"};
|
||||
|
||||
typedef std::pair<int64_t, int64_t> RangeT;
|
||||
RangeT const R1{0, 249}, R2{250, 499}, R3{500, 749}, R4{750, 800};
|
||||
|
||||
int64_t constexpr kFileSize = 800;
|
||||
int64_t constexpr kChunkSize = 250;
|
||||
ChunksDownloadStrategy strategy(servers);
|
||||
strategy.InitChunks(kFileSize, kChunkSize);
|
||||
|
||||
string s1;
|
||||
RangeT r1;
|
||||
TEST_EQUAL(strategy.NextChunk(s1, r1), ChunksDownloadStrategy::ENextChunk, ());
|
||||
|
||||
string s2;
|
||||
RangeT r2;
|
||||
TEST_EQUAL(strategy.NextChunk(s2, r2), ChunksDownloadStrategy::ENextChunk, ());
|
||||
|
||||
string s3;
|
||||
RangeT r3;
|
||||
TEST_EQUAL(strategy.NextChunk(s3, r3), ChunksDownloadStrategy::ENextChunk, ());
|
||||
|
||||
string sEmpty;
|
||||
RangeT rEmpty;
|
||||
TEST_EQUAL(strategy.NextChunk(sEmpty, rEmpty), ChunksDownloadStrategy::ENoFreeServers, ());
|
||||
TEST_EQUAL(strategy.NextChunk(sEmpty, rEmpty), ChunksDownloadStrategy::ENoFreeServers, ());
|
||||
|
||||
TEST(s1 != s2 && s2 != s3 && s3 != s1, (s1, s2, s3));
|
||||
|
||||
TEST(r1 != r2 && r2 != r3 && r3 != r1, (r1, r2, r3));
|
||||
TEST(r1 == R1 || r1 == R2 || r1 == R3 || r1 == R4, (r1));
|
||||
TEST(r2 == R1 || r2 == R2 || r2 == R3 || r2 == R4, (r2));
|
||||
TEST(r3 == R1 || r3 == R2 || r3 == R3 || r3 == R4, (r3));
|
||||
|
||||
strategy.ChunkFinished(true, r1);
|
||||
|
||||
string s4;
|
||||
RangeT r4;
|
||||
TEST_EQUAL(strategy.NextChunk(s4, r4), ChunksDownloadStrategy::ENextChunk, ());
|
||||
TEST_EQUAL(s4, s1, ());
|
||||
TEST(r4 != r1 && r4 != r2 && r4 != r3, (r4));
|
||||
|
||||
TEST_EQUAL(strategy.NextChunk(sEmpty, rEmpty), ChunksDownloadStrategy::ENoFreeServers, ());
|
||||
TEST_EQUAL(strategy.NextChunk(sEmpty, rEmpty), ChunksDownloadStrategy::ENoFreeServers, ());
|
||||
|
||||
strategy.ChunkFinished(false, r2);
|
||||
|
||||
TEST_EQUAL(strategy.NextChunk(sEmpty, rEmpty), ChunksDownloadStrategy::ENoFreeServers, ());
|
||||
|
||||
strategy.ChunkFinished(true, r4);
|
||||
|
||||
string s5;
|
||||
RangeT r5;
|
||||
TEST_EQUAL(strategy.NextChunk(s5, r5), ChunksDownloadStrategy::ENextChunk, ());
|
||||
TEST_EQUAL(s5, s4, (s5, s4));
|
||||
TEST_EQUAL(r5, r2, ());
|
||||
|
||||
TEST_EQUAL(strategy.NextChunk(sEmpty, rEmpty), ChunksDownloadStrategy::ENoFreeServers, ());
|
||||
TEST_EQUAL(strategy.NextChunk(sEmpty, rEmpty), ChunksDownloadStrategy::ENoFreeServers, ());
|
||||
|
||||
strategy.ChunkFinished(true, r5);
|
||||
|
||||
// 3rd is still alive here
|
||||
TEST_EQUAL(strategy.NextChunk(sEmpty, rEmpty), ChunksDownloadStrategy::ENoFreeServers, ());
|
||||
TEST_EQUAL(strategy.NextChunk(sEmpty, rEmpty), ChunksDownloadStrategy::ENoFreeServers, ());
|
||||
|
||||
strategy.ChunkFinished(true, r3);
|
||||
|
||||
TEST_EQUAL(strategy.NextChunk(sEmpty, rEmpty), ChunksDownloadStrategy::EDownloadSucceeded, ());
|
||||
TEST_EQUAL(strategy.NextChunk(sEmpty, rEmpty), ChunksDownloadStrategy::EDownloadSucceeded, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(ChunksDownloadStrategyFAIL)
|
||||
{
|
||||
vector<string> const servers = {"UrlOfServer1", "UrlOfServer2"};
|
||||
|
||||
typedef std::pair<int64_t, int64_t> RangeT;
|
||||
|
||||
int64_t constexpr kFileSize = 800;
|
||||
int64_t constexpr kChunkSize = 250;
|
||||
ChunksDownloadStrategy strategy(servers);
|
||||
strategy.InitChunks(kFileSize, kChunkSize);
|
||||
|
||||
string s1;
|
||||
RangeT r1;
|
||||
TEST_EQUAL(strategy.NextChunk(s1, r1), ChunksDownloadStrategy::ENextChunk, ());
|
||||
|
||||
string s2;
|
||||
RangeT r2;
|
||||
TEST_EQUAL(strategy.NextChunk(s2, r2), ChunksDownloadStrategy::ENextChunk, ());
|
||||
TEST_EQUAL(strategy.NextChunk(s2, r2), ChunksDownloadStrategy::ENoFreeServers, ());
|
||||
|
||||
strategy.ChunkFinished(false, r1);
|
||||
|
||||
TEST_EQUAL(strategy.NextChunk(s2, r2), ChunksDownloadStrategy::ENoFreeServers, ());
|
||||
|
||||
strategy.ChunkFinished(false, r2);
|
||||
|
||||
TEST_EQUAL(strategy.NextChunk(s2, r2), ChunksDownloadStrategy::EDownloadFailed, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(ChunksDownloadStrategyDynamicChunks)
|
||||
{
|
||||
vector<string> const servers = {"UrlOfServer1", "UrlOfServer2"};
|
||||
|
||||
typedef std::pair<int64_t, int64_t> RangeT;
|
||||
|
||||
string url;
|
||||
ChunksDownloadStrategy strategy(servers);
|
||||
|
||||
// Small 1MB file - one chunk
|
||||
strategy.InitChunks(1024 * 1024, 0);
|
||||
RangeT const R11{0, 1024 * 1024 - 1};
|
||||
RangeT r1;
|
||||
TEST_EQUAL(strategy.NextChunk(url, r1), ChunksDownloadStrategy::ENextChunk, ());
|
||||
RangeT rEmpty;
|
||||
TEST_EQUAL(strategy.NextChunk(url, rEmpty), ChunksDownloadStrategy::ENoFreeServers, ());
|
||||
TEST(r1 == R11, (r1));
|
||||
|
||||
// Small 1MB+1b file - 2 chunks
|
||||
strategy = ChunksDownloadStrategy(servers);
|
||||
strategy.InitChunks(1024 * 1024 + 1, 0);
|
||||
RangeT const R21{0, 1024 * 1024 - 1}, R22{1024 * 1024, 1024 * 1024};
|
||||
TEST_EQUAL(strategy.NextChunk(url, r1), ChunksDownloadStrategy::ENextChunk, ());
|
||||
RangeT r2;
|
||||
TEST_EQUAL(strategy.NextChunk(url, r2), ChunksDownloadStrategy::ENextChunk, ());
|
||||
TEST_EQUAL(strategy.NextChunk(url, rEmpty), ChunksDownloadStrategy::ENoFreeServers, ());
|
||||
TEST(r1 == R21 && r2 == R22, (r1, r2));
|
||||
|
||||
// Big 200MB file - 5MB chunks
|
||||
strategy = ChunksDownloadStrategy(servers);
|
||||
strategy.InitChunks(200 * 1024 * 1024, 0);
|
||||
RangeT const R31{0, 5 * 1024 * 1024 - 1}, R32{5 * 1024 * 1024, 2 * 5 * 1024 * 1024 - 1};
|
||||
TEST_EQUAL(strategy.NextChunk(url, r1), ChunksDownloadStrategy::ENextChunk, ());
|
||||
TEST_EQUAL(strategy.NextChunk(url, r2), ChunksDownloadStrategy::ENextChunk, ());
|
||||
TEST(r1 == R31 && r2 == R32, (r1, r2));
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
string ReadFileAsString(string const & file)
|
||||
{
|
||||
try
|
||||
{
|
||||
FileReader f(file);
|
||||
string s;
|
||||
f.ReadAsString(s);
|
||||
return s;
|
||||
}
|
||||
catch (FileReader::Exception const &)
|
||||
{
|
||||
TEST(false, ("File ", file, " should exist"));
|
||||
return {};
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void FinishDownloadSuccess(string const & file)
|
||||
{
|
||||
TEST(base::DeleteFileX(file), ("Result file should present on success"));
|
||||
|
||||
uint64_t size;
|
||||
TEST(!base::GetFileSize(file + DOWNLOADING_FILE_EXTENSION, size), ("No downloading file on success"));
|
||||
TEST(!base::GetFileSize(file + RESUME_FILE_EXTENSION, size), ("No resume file on success"));
|
||||
}
|
||||
|
||||
void FinishDownloadFail(string const & file)
|
||||
{
|
||||
uint64_t size;
|
||||
TEST(!base::GetFileSize(file, size), ("No result file on fail"));
|
||||
|
||||
(void)base::DeleteFileX(file + DOWNLOADING_FILE_EXTENSION);
|
||||
|
||||
TEST(base::DeleteFileX(file + RESUME_FILE_EXTENSION), ("Resume file should present on fail"));
|
||||
}
|
||||
|
||||
void DeleteTempDownloadFiles()
|
||||
{
|
||||
// Remove data from previously failed files.
|
||||
|
||||
// Get regexp like this: (\.downloading3$|\.resume3$)
|
||||
string const regexp = "(\\" RESUME_FILE_EXTENSION "$|\\" DOWNLOADING_FILE_EXTENSION "$)";
|
||||
|
||||
Platform::FilesList files;
|
||||
Platform::GetFilesByRegExp(".", regexp, files);
|
||||
for (Platform::FilesList::iterator it = files.begin(); it != files.end(); ++it)
|
||||
FileWriter::DeleteFileX(*it);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
UNIT_TEST(DownloadChunks)
|
||||
{
|
||||
string const kFileName = "some_downloader_test_file";
|
||||
|
||||
// remove data from previously failed files
|
||||
DeleteTempDownloadFiles();
|
||||
|
||||
vector<string> urls = {kTestUrl1, kTestUrl1};
|
||||
int64_t fileSize = 5;
|
||||
|
||||
DownloadObserver observer;
|
||||
auto const MakeRequest = [&](int64_t chunkSize)
|
||||
{
|
||||
return HttpRequest::GetFile(urls, kFileName, fileSize, bind(&DownloadObserver::OnDownloadFinish, &observer, _1),
|
||||
bind(&DownloadObserver::OnDownloadProgress, &observer, _1), chunkSize);
|
||||
};
|
||||
|
||||
{
|
||||
// should use only one thread
|
||||
std::unique_ptr<HttpRequest> const request{MakeRequest(512 * 1024)};
|
||||
// wait until download is finished
|
||||
QCoreApplication::exec();
|
||||
observer.TestOk();
|
||||
TEST_EQUAL(request->GetData(), kFileName, ());
|
||||
TEST_EQUAL(ReadFileAsString(kFileName), "Test1", ());
|
||||
FinishDownloadSuccess(kFileName);
|
||||
}
|
||||
|
||||
observer.Reset();
|
||||
urls = {kTestUrlBigFile, kTestUrlBigFile, kTestUrlBigFile};
|
||||
fileSize = 5;
|
||||
{
|
||||
// 3 threads - fail, because of invalid size
|
||||
[[maybe_unused]] std::unique_ptr<HttpRequest> const request{MakeRequest(2048)};
|
||||
// wait until download is finished
|
||||
QCoreApplication::exec();
|
||||
observer.TestFailed();
|
||||
FinishDownloadFail(kFileName);
|
||||
}
|
||||
|
||||
observer.Reset();
|
||||
urls = {kTestUrlBigFile, kTestUrlBigFile, kTestUrlBigFile};
|
||||
fileSize = kBigFileSize;
|
||||
{
|
||||
// 3 threads - succeeded
|
||||
[[maybe_unused]] std::unique_ptr<HttpRequest> const request{MakeRequest(2048)};
|
||||
// wait until download is finished
|
||||
QCoreApplication::exec();
|
||||
observer.TestOk();
|
||||
FinishDownloadSuccess(kFileName);
|
||||
}
|
||||
|
||||
observer.Reset();
|
||||
urls = {kTestUrlBigFile, kTestUrl1, kTestUrl404};
|
||||
fileSize = kBigFileSize;
|
||||
{
|
||||
// 3 threads with only one valid url - succeeded
|
||||
[[maybe_unused]] std::unique_ptr<HttpRequest> const request{MakeRequest(2048)};
|
||||
// wait until download is finished
|
||||
QCoreApplication::exec();
|
||||
observer.TestOk();
|
||||
FinishDownloadSuccess(kFileName);
|
||||
}
|
||||
|
||||
observer.Reset();
|
||||
urls = {kTestUrlBigFile, kTestUrlBigFile};
|
||||
fileSize = 12345;
|
||||
{
|
||||
// 2 threads and all points to file with invalid size - fail
|
||||
[[maybe_unused]] std::unique_ptr<HttpRequest> const request{MakeRequest(2048)};
|
||||
// wait until download is finished
|
||||
QCoreApplication::exec();
|
||||
observer.TestFailed();
|
||||
FinishDownloadFail(kFileName);
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
int64_t constexpr beg1 = 123, end1 = 1230, beg2 = 44000, end2 = 47683;
|
||||
|
||||
struct ResumeChecker
|
||||
{
|
||||
size_t m_counter;
|
||||
ResumeChecker() : m_counter(0) {}
|
||||
|
||||
void OnProgress(HttpRequest & request)
|
||||
{
|
||||
if (m_counter == 0)
|
||||
{
|
||||
TEST_EQUAL(request.GetProgress().m_bytesDownloaded, beg2, ());
|
||||
TEST_EQUAL(request.GetProgress().m_bytesTotal, kBigFileSize, ());
|
||||
}
|
||||
else if (m_counter == 1)
|
||||
{
|
||||
TEST_EQUAL(request.GetProgress().m_bytesDownloaded, kBigFileSize, ());
|
||||
TEST_EQUAL(request.GetProgress().m_bytesTotal, kBigFileSize, ());
|
||||
}
|
||||
else
|
||||
{
|
||||
TEST(false, ("Progress should be called exactly 2 times"));
|
||||
}
|
||||
++m_counter;
|
||||
}
|
||||
|
||||
void OnFinish(HttpRequest & request)
|
||||
{
|
||||
TEST_EQUAL(request.GetStatus(), DownloadStatus::Completed, ());
|
||||
QCoreApplication::exit();
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
UNIT_TEST(DownloadResumeChunks)
|
||||
{
|
||||
string const FILENAME = "some_test_filename_12345";
|
||||
string const RESUME_FILENAME = FILENAME + RESUME_FILE_EXTENSION;
|
||||
string const DOWNLOADING_FILENAME = FILENAME + DOWNLOADING_FILE_EXTENSION;
|
||||
|
||||
// remove data from previously failed files
|
||||
DeleteTempDownloadFiles();
|
||||
|
||||
vector<string> urls = {kTestUrlBigFile};
|
||||
|
||||
// 1st step - download full file
|
||||
{
|
||||
DownloadObserver observer;
|
||||
|
||||
std::unique_ptr<HttpRequest> const request(
|
||||
HttpRequest::GetFile(urls, FILENAME, kBigFileSize, bind(&DownloadObserver::OnDownloadFinish, &observer, _1),
|
||||
bind(&DownloadObserver::OnDownloadProgress, &observer, _1)));
|
||||
|
||||
QCoreApplication::exec();
|
||||
|
||||
observer.TestOk();
|
||||
|
||||
uint64_t size;
|
||||
TEST(!base::GetFileSize(RESUME_FILENAME, size), ("No resume file on success"));
|
||||
}
|
||||
|
||||
// 2nd step - mark some file blocks as not downloaded
|
||||
{
|
||||
// to substitute temporary not fully downloaded file
|
||||
TEST(base::RenameFileX(FILENAME, DOWNLOADING_FILENAME), ());
|
||||
|
||||
FileWriter f(DOWNLOADING_FILENAME, FileWriter::OP_WRITE_EXISTING);
|
||||
f.Seek(beg1);
|
||||
char b1[end1 - beg1 + 1] = {0};
|
||||
f.Write(b1, ARRAY_SIZE(b1));
|
||||
|
||||
f.Seek(beg2);
|
||||
char b2[end2 - beg2 + 1] = {0};
|
||||
f.Write(b2, ARRAY_SIZE(b2));
|
||||
|
||||
ChunksDownloadStrategy strategy((vector<string>()));
|
||||
strategy.AddChunk(std::make_pair(int64_t(0), beg1 - 1), ChunksDownloadStrategy::CHUNK_COMPLETE);
|
||||
strategy.AddChunk(std::make_pair(beg1, end1), ChunksDownloadStrategy::CHUNK_FREE);
|
||||
strategy.AddChunk(std::make_pair(end1 + 1, beg2 - 1), ChunksDownloadStrategy::CHUNK_COMPLETE);
|
||||
strategy.AddChunk(std::make_pair(beg2, end2), ChunksDownloadStrategy::CHUNK_FREE);
|
||||
|
||||
strategy.SaveChunks(kBigFileSize, RESUME_FILENAME);
|
||||
}
|
||||
|
||||
// 3rd step - check that resume works
|
||||
{
|
||||
ResumeChecker checker;
|
||||
std::unique_ptr<HttpRequest> const request(HttpRequest::GetFile(urls, FILENAME, kBigFileSize,
|
||||
bind(&ResumeChecker::OnFinish, &checker, _1),
|
||||
bind(&ResumeChecker::OnProgress, &checker, _1)));
|
||||
QCoreApplication::exec();
|
||||
|
||||
FinishDownloadSuccess(FILENAME);
|
||||
}
|
||||
}
|
||||
|
||||
// Unit test with forcible canceling of http request
|
||||
UNIT_TEST(DownloadResumeChunksWithCancel)
|
||||
{
|
||||
string const FILENAME = "some_test_filename_12345";
|
||||
|
||||
// remove data from previously failed files
|
||||
DeleteTempDownloadFiles();
|
||||
|
||||
vector<string> urls = {kTestUrlBigFile};
|
||||
|
||||
DownloadObserver observer;
|
||||
|
||||
int arrCancelChunks[] = {1, 3, 10, 15, 20, 0};
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(arrCancelChunks); ++i)
|
||||
{
|
||||
if (arrCancelChunks[i] > 0)
|
||||
observer.CancelDownloadOnGivenChunk(arrCancelChunks[i]);
|
||||
|
||||
std::unique_ptr<HttpRequest> const request(
|
||||
HttpRequest::GetFile(urls, FILENAME, kBigFileSize, bind(&DownloadObserver::OnDownloadFinish, &observer, _1),
|
||||
bind(&DownloadObserver::OnDownloadProgress, &observer, _1), 1024, false));
|
||||
|
||||
QCoreApplication::exec();
|
||||
}
|
||||
|
||||
observer.TestOk();
|
||||
|
||||
FinishDownloadSuccess(FILENAME);
|
||||
}
|
||||
|
||||
} // namespace downloader_test
|
||||
125
libs/platform/platform_tests/downloader_utils_tests.cpp
Normal file
125
libs/platform/platform_tests/downloader_utils_tests.cpp
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "platform/downloader_utils.hpp"
|
||||
#include "platform/local_country_file_utils.hpp"
|
||||
#include "platform/mwm_version.hpp"
|
||||
#include "platform/platform.hpp"
|
||||
#include "platform/servers_list.hpp"
|
||||
|
||||
#include "base/file_name_utils.hpp"
|
||||
|
||||
UNIT_TEST(Downloader_GetFilePathByUrl)
|
||||
{
|
||||
{
|
||||
std::string const mwmName = "Luna";
|
||||
std::string const fileName = platform::GetFileName(mwmName, MapFileType::Map);
|
||||
int64_t const dataVersion = version::FOR_TESTING_MWM1;
|
||||
int64_t const diffVersion = 0;
|
||||
MapFileType const fileType = MapFileType::Map;
|
||||
|
||||
auto const path = platform::GetFileDownloadPath(dataVersion, mwmName, fileType);
|
||||
|
||||
auto const url = downloader::GetFileDownloadUrl(fileName, dataVersion, diffVersion);
|
||||
auto const resultPath = downloader::GetFilePathByUrl(url);
|
||||
|
||||
TEST_EQUAL(path, resultPath, ());
|
||||
}
|
||||
{
|
||||
std::string const mwmName = "Luna";
|
||||
std::string const fileName = platform::GetFileName(mwmName, MapFileType::Diff);
|
||||
int64_t const dataVersion = version::FOR_TESTING_MWM2;
|
||||
int64_t const diffVersion = version::FOR_TESTING_MWM1;
|
||||
MapFileType const fileType = MapFileType::Diff;
|
||||
|
||||
auto const path = platform::GetFileDownloadPath(dataVersion, mwmName, fileType);
|
||||
|
||||
auto const url = downloader::GetFileDownloadUrl(fileName, dataVersion, diffVersion);
|
||||
auto const resultPath = downloader::GetFilePathByUrl(url);
|
||||
|
||||
TEST_EQUAL(path, resultPath, ());
|
||||
}
|
||||
|
||||
TEST_EQUAL(downloader::GetFilePathByUrl("/maps/220314/Belarus_Brest Region.mwm"),
|
||||
base::JoinPath(GetPlatform().WritableDir(), "220314/Belarus_Brest Region.mwm.ready"), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(Downloader_IsUrlSupported)
|
||||
{
|
||||
std::string const mwmName = "Luna";
|
||||
|
||||
std::string fileName = platform::GetFileName(mwmName, MapFileType::Map);
|
||||
int64_t dataVersion = version::FOR_TESTING_MWM1;
|
||||
int64_t diffVersion = 0;
|
||||
|
||||
auto url = downloader::GetFileDownloadUrl(fileName, dataVersion, diffVersion);
|
||||
TEST(downloader::IsUrlSupported(url), ());
|
||||
TEST(downloader::IsUrlSupported("maps/991215/Luna.mwm"), ());
|
||||
TEST(downloader::IsUrlSupported("maps/0/Luna.mwm"), ());
|
||||
TEST(!downloader::IsUrlSupported("maps/x/Luna.mwm"), ());
|
||||
TEST(!downloader::IsUrlSupported("macarena/0/Luna.mwm"), ());
|
||||
TEST(!downloader::IsUrlSupported("/hack/maps/0/Luna.mwm"), ());
|
||||
TEST(!downloader::IsUrlSupported("0/Luna.mwm"), ());
|
||||
TEST(!downloader::IsUrlSupported("maps/0/Luna"), ());
|
||||
TEST(!downloader::IsUrlSupported("0/Luna.mwm"), ());
|
||||
TEST(!downloader::IsUrlSupported("Luna.mwm"), ());
|
||||
TEST(!downloader::IsUrlSupported("Luna"), ());
|
||||
|
||||
fileName = platform::GetFileName(mwmName, MapFileType::Diff);
|
||||
diffVersion = version::FOR_TESTING_MWM1;
|
||||
url = downloader::GetFileDownloadUrl(fileName, dataVersion, diffVersion);
|
||||
TEST(downloader::IsUrlSupported(url), ());
|
||||
TEST(downloader::IsUrlSupported("diffs/991215/991215/Luna.mwmdiff"), ());
|
||||
TEST(downloader::IsUrlSupported("diffs/0/0/Luna.mwmdiff"), ());
|
||||
TEST(!downloader::IsUrlSupported("diffs/x/0/Luna.mwmdiff"), ());
|
||||
TEST(!downloader::IsUrlSupported("diffs/0/x/Luna.mwmdiff"), ());
|
||||
TEST(!downloader::IsUrlSupported("diffs/x/x/Luna.mwmdiff"), ());
|
||||
TEST(!downloader::IsUrlSupported("beefs/0/0/Luna.mwmdiff"), ());
|
||||
TEST(!downloader::IsUrlSupported("diffs/0/0/Luna.mwmdiff.f"), ());
|
||||
TEST(!downloader::IsUrlSupported("maps/diffs/0/0/Luna.mwmdiff"), ());
|
||||
TEST(!downloader::IsUrlSupported("diffs/0/0/Luna"), ());
|
||||
TEST(!downloader::IsUrlSupported("0/0/Luna.mwmdiff"), ());
|
||||
TEST(!downloader::IsUrlSupported("diffs/0/Luna.mwmdiff"), ());
|
||||
TEST(!downloader::IsUrlSupported("diffs/0"), ());
|
||||
TEST(!downloader::IsUrlSupported("diffs/0/Luna.mwmdiff"), ());
|
||||
TEST(!downloader::IsUrlSupported("diffs/Luna.mwmdiff"), ());
|
||||
TEST(!downloader::IsUrlSupported("Luna.mwmdiff"), ());
|
||||
TEST(!downloader::IsUrlSupported("Luna"), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(Downloader_ParseMetaConfig)
|
||||
{
|
||||
std::optional<downloader::MetaConfig> cfg;
|
||||
|
||||
TEST((cfg = downloader::ParseMetaConfig(R"([ "https://url1/", "https://url2/" ])")), ());
|
||||
TEST_EQUAL(cfg->m_serversList.size(), 2, ());
|
||||
TEST_EQUAL(cfg->m_serversList[0], "https://url1/", ());
|
||||
TEST_EQUAL(cfg->m_serversList[1], "https://url2/", ());
|
||||
|
||||
TEST((cfg = downloader::ParseMetaConfig(R"(
|
||||
{
|
||||
"servers": [ "https://url1/", "https://url2/" ],
|
||||
"settings": {
|
||||
"DonateUrl": "value1",
|
||||
"NY": "value2",
|
||||
"key3": "value3"
|
||||
}
|
||||
}
|
||||
)")),
|
||||
());
|
||||
TEST_EQUAL(cfg->m_serversList.size(), 2, ());
|
||||
TEST_EQUAL(cfg->m_serversList[0], "https://url1/", ());
|
||||
TEST_EQUAL(cfg->m_serversList[1], "https://url2/", ());
|
||||
TEST_EQUAL(cfg->m_settings.size(), 2, ()); // "key3" is ignored
|
||||
TEST_EQUAL(cfg->m_settings["DonateUrl"], "value1", ());
|
||||
TEST_EQUAL(cfg->m_settings["NY"], "value2", ());
|
||||
|
||||
TEST(!downloader::ParseMetaConfig(R"(broken json)"), ());
|
||||
|
||||
TEST(!downloader::ParseMetaConfig(R"([])"), ());
|
||||
|
||||
TEST(!downloader::ParseMetaConfig(R"({})"), ());
|
||||
|
||||
TEST(!downloader::ParseMetaConfig(R"({"no_servers": "invalid"})"), ());
|
||||
|
||||
TEST(!downloader::ParseMetaConfig(R"({"servers": "invalid"})"), ());
|
||||
}
|
||||
118
libs/platform/platform_tests/duration_tests.cpp
Normal file
118
libs/platform/platform_tests/duration_tests.cpp
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "platform/duration.hpp"
|
||||
|
||||
#include <chrono>
|
||||
|
||||
namespace platform
|
||||
{
|
||||
using std::chrono::duration_cast, std::chrono::seconds, std::chrono::minutes, std::chrono::hours, std::chrono::days;
|
||||
|
||||
struct TestData
|
||||
{
|
||||
struct Duration
|
||||
{
|
||||
days m_days;
|
||||
hours m_hours;
|
||||
minutes m_minutes;
|
||||
seconds m_seconds;
|
||||
std::string result;
|
||||
|
||||
Duration(long days, long hours, long minutes, long seconds, std::string const & result)
|
||||
: m_days(days)
|
||||
, m_hours(hours)
|
||||
, m_minutes(minutes)
|
||||
, m_seconds(seconds)
|
||||
, result(result)
|
||||
{}
|
||||
|
||||
long Seconds() const
|
||||
{
|
||||
return (duration_cast<seconds>(m_days) + duration_cast<seconds>(m_hours) + duration_cast<seconds>(m_minutes) +
|
||||
m_seconds)
|
||||
.count();
|
||||
}
|
||||
};
|
||||
|
||||
Locale m_locale;
|
||||
std::vector<Duration> m_duration;
|
||||
|
||||
constexpr TestData(Locale locale, std::vector<Duration> duration) : m_locale(locale), m_duration(duration) {}
|
||||
};
|
||||
|
||||
Locale GetLocale(std::string const & language)
|
||||
{
|
||||
Locale locale;
|
||||
locale.m_language = language;
|
||||
return locale;
|
||||
}
|
||||
/*
|
||||
Localized string cannot be retrieved from the app target bundle during the tests execution
|
||||
and the platform::GetLocalizedString will return the same string as the input ("minute", "hour" etc).
|
||||
This is why the expectation strings are not explicit.
|
||||
*/
|
||||
|
||||
auto const m = Duration::GetUnitsString(Duration::Units::Minutes);
|
||||
auto const h = Duration::GetUnitsString(Duration::Units::Hours);
|
||||
auto const d = Duration::GetUnitsString(Duration::Units::Days);
|
||||
|
||||
UNIT_TEST(Duration_AllUnits)
|
||||
{
|
||||
TestData const testData[] = {
|
||||
{GetLocale("en"),
|
||||
{{0, 0, 0, 0, "0" + m},
|
||||
{0, 0, 0, 30, "0" + m},
|
||||
{0, 0, 0, 59, "0" + m},
|
||||
{0, 0, 1, 0, "1" + m},
|
||||
{0, 0, 1, 59, "1" + m},
|
||||
{0, 0, 60, 0, "1" + h},
|
||||
{0, 0, 123, 0, "2" + h + kNonBreakingSpace + "3" + m},
|
||||
{0, 3, 0, 0, "3" + h},
|
||||
{0, 24, 0, 0, "1" + d},
|
||||
{4, 0, 0, 0, "4" + d},
|
||||
{1, 2, 3, 0, "1" + d + kNonBreakingSpace + "2" + h + kNonBreakingSpace + "3" + m},
|
||||
{1, 0, 15, 0, "1" + d + kNonBreakingSpace + "15" + m},
|
||||
{0, 15, 1, 0, "15" + h + kNonBreakingSpace + "1" + m},
|
||||
{1, 15, 0, 0, "1" + d + kNonBreakingSpace + "15" + h},
|
||||
{15, 0, 10, 0, "15" + d + kNonBreakingSpace + "10" + m},
|
||||
{15, 15, 15, 0, "15" + d + kNonBreakingSpace + "15" + h + kNonBreakingSpace + "15" + m}}},
|
||||
};
|
||||
|
||||
for (auto const & data : testData)
|
||||
{
|
||||
for (auto const & dataDuration : data.m_duration)
|
||||
{
|
||||
auto const duration = Duration(dataDuration.Seconds());
|
||||
auto durationStr = duration.GetLocalizedString(
|
||||
{Duration::Units::Days, Duration::Units::Hours, Duration::Units::Minutes}, data.m_locale);
|
||||
TEST_EQUAL(durationStr, dataDuration.result, ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST(Duration_Localization)
|
||||
{
|
||||
TestData const testData[] = {
|
||||
// en
|
||||
{GetLocale("en"), {{1, 2, 3, 0, "1" + d + kNonBreakingSpace + "2" + h + kNonBreakingSpace + "3" + m}}},
|
||||
// ru (narrow spacing between number and unit)
|
||||
{GetLocale("ru"),
|
||||
{{1, 2, 3, 0,
|
||||
"1" + kNarrowNonBreakingSpace + d + kNonBreakingSpace + "2" + kNarrowNonBreakingSpace + h + kNonBreakingSpace +
|
||||
"3" + kNarrowNonBreakingSpace + m}}},
|
||||
// zh (no spacings)
|
||||
{GetLocale("zh"), {{1, 2, 3, 0, "1" + d + "2" + h + "3" + m}}}};
|
||||
|
||||
for (auto const & data : testData)
|
||||
{
|
||||
for (auto const & duration : data.m_duration)
|
||||
{
|
||||
auto const durationStr =
|
||||
Duration(duration.Seconds())
|
||||
.GetLocalizedString({Duration::Units::Days, Duration::Units::Hours, Duration::Units::Minutes},
|
||||
data.m_locale);
|
||||
TEST_EQUAL(durationStr, duration.result, ());
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace platform
|
||||
120
libs/platform/platform_tests/get_text_by_id_tests.cpp
Normal file
120
libs/platform/platform_tests/get_text_by_id_tests.cpp
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "platform/get_text_by_id.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
UNIT_TEST(GetTextByIdEnglishTest)
|
||||
{
|
||||
std::string const shortJson =
|
||||
"\
|
||||
{\
|
||||
\"make_a_slight_right_turn\":\"Make a slight right turn.\",\
|
||||
\"in_900_meters\":\"In nine hundred meters.\",\
|
||||
\"then\":\"Then.\",\
|
||||
\"in_1_mile\":\"In one mile.\"\
|
||||
}";
|
||||
|
||||
auto getEnglish = platform::ForTestingGetTextByIdFactory(shortJson, "en");
|
||||
TEST_EQUAL((*getEnglish)("make_a_slight_right_turn"), "Make a slight right turn.", ());
|
||||
TEST_EQUAL((*getEnglish)("in_900_meters"), "In nine hundred meters.", ());
|
||||
TEST_EQUAL((*getEnglish)("then"), "Then.", ());
|
||||
TEST_EQUAL((*getEnglish)("in_1_mile"), "In one mile.", ());
|
||||
|
||||
TEST_EQUAL((*getEnglish)("some_nonexistent_key"), "", ());
|
||||
TEST_EQUAL((*getEnglish)("some_nonexistent_key"), "", ());
|
||||
TEST_EQUAL((*getEnglish)(""), "", ());
|
||||
TEST_EQUAL((*getEnglish)(" "), "", ());
|
||||
}
|
||||
|
||||
UNIT_TEST(GetTextByIdRussianTest)
|
||||
{
|
||||
std::string const shortJson =
|
||||
"\
|
||||
{\
|
||||
\"in_800_meters\":\"Через восемьсот метров.\",\
|
||||
\"make_a_slight_right_turn\":\"Держитесь правее.\",\
|
||||
\"take_the_6_exit\":\"Сверните на шестой съезд.\",\
|
||||
\"in_1_mile\":\"Через одну милю.\"\
|
||||
}";
|
||||
|
||||
auto getRussian = platform::ForTestingGetTextByIdFactory(shortJson, "ru");
|
||||
TEST_EQUAL((*getRussian)("in_800_meters"), "Через восемьсот метров.", ());
|
||||
TEST_EQUAL((*getRussian)("make_a_slight_right_turn"), "Держитесь правее.", ());
|
||||
TEST_EQUAL((*getRussian)("take_the_6_exit"), "Сверните на шестой съезд.", ());
|
||||
TEST_EQUAL((*getRussian)("in_1_mile"), "Через одну милю.", ());
|
||||
|
||||
TEST_EQUAL((*getRussian)("some_nonexistent_key"), "", ());
|
||||
TEST_EQUAL((*getRussian)("some_nonexistent_key"), "", ());
|
||||
TEST_EQUAL((*getRussian)(""), "", ());
|
||||
TEST_EQUAL((*getRussian)(" "), "", ());
|
||||
}
|
||||
|
||||
UNIT_TEST(GetTextByIdKoreanTest)
|
||||
{
|
||||
std::string const shortJson =
|
||||
"\
|
||||
{\
|
||||
\"in_700_meters\":\"700 미터 앞\",\
|
||||
\"make_a_right_turn\":\"우회전입니다.\",\
|
||||
\"take_the_5_exit\":\"다섯 번째 출구입니다.\",\
|
||||
\"in_5000_feet\":\"5000피트 앞\"\
|
||||
}";
|
||||
|
||||
auto getKorean = platform::ForTestingGetTextByIdFactory(shortJson, "ko");
|
||||
TEST_EQUAL((*getKorean)("in_700_meters"), "700 미터 앞", ());
|
||||
TEST_EQUAL((*getKorean)("make_a_right_turn"), "우회전입니다.", ());
|
||||
TEST_EQUAL((*getKorean)("take_the_5_exit"), "다섯 번째 출구입니다.", ());
|
||||
TEST_EQUAL((*getKorean)("in_5000_feet"), "5000피트 앞", ());
|
||||
|
||||
TEST_EQUAL((*getKorean)("some_nonexistent_key"), "", ());
|
||||
TEST_EQUAL((*getKorean)("some_nonexistent_key"), "", ());
|
||||
TEST_EQUAL((*getKorean)(""), "", ());
|
||||
TEST_EQUAL((*getKorean)(" "), "", ());
|
||||
}
|
||||
|
||||
UNIT_TEST(GetTextByIdArabicTest)
|
||||
{
|
||||
std::string const shortJson =
|
||||
"\
|
||||
{\
|
||||
\"in_1_kilometer\":\"بعد كيلو متر واحدٍ\",\
|
||||
\"leave_the_roundabout\":\"اخرج من الطريق الدوار\",\
|
||||
\"take_the_3_exit\":\"اسلك المخرج الثالث\",\
|
||||
\"in_4000_feet\":\"بعد 4000 قدم\"\
|
||||
}";
|
||||
|
||||
auto getArabic = platform::ForTestingGetTextByIdFactory(shortJson, "ar");
|
||||
TEST_EQUAL((*getArabic)("in_1_kilometer"), "بعد كيلو متر واحدٍ", ());
|
||||
TEST_EQUAL((*getArabic)("leave_the_roundabout"), "اخرج من الطريق الدوار", ());
|
||||
TEST_EQUAL((*getArabic)("take_the_3_exit"), "اسلك المخرج الثالث", ());
|
||||
TEST_EQUAL((*getArabic)("in_4000_feet"), "بعد 4000 قدم", ());
|
||||
|
||||
TEST_EQUAL((*getArabic)("some_nonexistent_key"), "", ());
|
||||
TEST_EQUAL((*getArabic)("some_nonexistent_key"), "", ());
|
||||
TEST_EQUAL((*getArabic)(""), "", ());
|
||||
TEST_EQUAL((*getArabic)(" "), "", ());
|
||||
}
|
||||
|
||||
UNIT_TEST(GetTextByIdFrenchTest)
|
||||
{
|
||||
std::string const shortJson =
|
||||
"\
|
||||
{\
|
||||
\"in_1_5_kilometers\":\"Dans un virgule cinq kilomètre.\",\
|
||||
\"enter_the_roundabout\":\"Prenez le rond-point.\",\
|
||||
\"take_the_2_exit\":\"Prenez la deuxième sortie.\",\
|
||||
\"in_3500_feet\":\"Dans trois mille cinq cents pieds.\"\
|
||||
}";
|
||||
|
||||
auto getFrench = platform::ForTestingGetTextByIdFactory(shortJson, "fr");
|
||||
TEST_EQUAL((*getFrench)("in_1_5_kilometers"), "Dans un virgule cinq kilomètre.", ());
|
||||
TEST_EQUAL((*getFrench)("enter_the_roundabout"), "Prenez le rond-point.", ());
|
||||
TEST_EQUAL((*getFrench)("take_the_2_exit"), "Prenez la deuxième sortie.", ());
|
||||
TEST_EQUAL((*getFrench)("in_3500_feet"), "Dans trois mille cinq cents pieds.", ());
|
||||
|
||||
TEST_EQUAL((*getFrench)("some_nonexistent_key"), "", ());
|
||||
TEST_EQUAL((*getFrench)("some_nonexistent_key"), "", ());
|
||||
TEST_EQUAL((*getFrench)(""), "", ());
|
||||
TEST_EQUAL((*getFrench)(" "), "", ());
|
||||
}
|
||||
90
libs/platform/platform_tests/glaze_test.cpp
Normal file
90
libs/platform/platform_tests/glaze_test.cpp
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "glaze/json.hpp"
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
enum class LocationSource
|
||||
{
|
||||
GPS,
|
||||
Network,
|
||||
Unknown
|
||||
};
|
||||
|
||||
// If enumeration should be represented as string instead of integer in JSON,
|
||||
// then enum should be declared in the global namespace.
|
||||
template <>
|
||||
struct glz::meta<LocationSource>
|
||||
{
|
||||
using enum LocationSource;
|
||||
static constexpr auto value = glz::enumerate(GPS, Network, Unknown);
|
||||
};
|
||||
|
||||
// For our test macros.
|
||||
std::string DebugPrint(LocationSource source)
|
||||
{
|
||||
return std::string{glz::get_enum_name(source)};
|
||||
}
|
||||
|
||||
namespace glaze_test
|
||||
{
|
||||
struct Location
|
||||
{
|
||||
LocationSource source;
|
||||
double latitude;
|
||||
double longitude;
|
||||
double accuracy;
|
||||
std::optional<double> altitude;
|
||||
std::optional<double> altitudeAccuracy;
|
||||
};
|
||||
|
||||
struct AccessToken
|
||||
{
|
||||
Location location;
|
||||
std::string accessToken;
|
||||
};
|
||||
|
||||
UNIT_TEST(Glaze_Smoke)
|
||||
{
|
||||
std::string_view constexpr fullJsonWithComments = R"({
|
||||
"location": {
|
||||
"source": "GPS", // Where the location data comes from.
|
||||
"latitude": 47.3345141,
|
||||
"longitude": 8.5312839,
|
||||
"accuracy": 22,
|
||||
"altitude": 100.5,
|
||||
"altitudeAccuracy": 5.0
|
||||
},
|
||||
/* Access token for authentication
|
||||
* This token is used to access protected resources.
|
||||
*/
|
||||
"accessToken": "2:vC65Xv0mxMtsNVf4:hY5YSIkuFfnAU77z"
|
||||
})";
|
||||
|
||||
AccessToken token;
|
||||
auto error = glz::read_jsonc(token, fullJsonWithComments);
|
||||
TEST(!error, (glz::format_error(error, fullJsonWithComments)));
|
||||
|
||||
TEST_EQUAL(token.location.source, LocationSource::GPS, ());
|
||||
TEST_EQUAL(token.location.latitude, 47.3345141, ());
|
||||
TEST_EQUAL(token.location.longitude, 8.5312839, ());
|
||||
TEST_EQUAL(token.location.accuracy, 22.0, ());
|
||||
TEST_EQUAL(token.location.altitude, 100.5, ());
|
||||
TEST_EQUAL(token.location.altitudeAccuracy, 5.0, ());
|
||||
TEST_EQUAL(token.accessToken, "2:vC65Xv0mxMtsNVf4:hY5YSIkuFfnAU77z", ());
|
||||
|
||||
std::string_view constexpr partialJson =
|
||||
R"({"location":{"source":"Network","latitude":47.3345141,"longitude":8.5312839,"accuracy":22},"accessToken":""})";
|
||||
|
||||
token.location.source = LocationSource::Network;
|
||||
token.location.altitude = {};
|
||||
token.location.altitudeAccuracy = {};
|
||||
token.accessToken = {};
|
||||
|
||||
std::string buffer;
|
||||
error = glz::write_json(token, buffer);
|
||||
TEST(!error, (glz::format_error(error, "Failed to write JSON")));
|
||||
TEST_EQUAL(buffer, partialJson, ());
|
||||
}
|
||||
} // namespace glaze_test
|
||||
45
libs/platform/platform_tests/jansson_test.cpp
Normal file
45
libs/platform/platform_tests/jansson_test.cpp
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "cppjansson/cppjansson.hpp"
|
||||
|
||||
UNIT_TEST(Jansson_Smoke)
|
||||
{
|
||||
char * savedLocale = setlocale(LC_NUMERIC, "C");
|
||||
|
||||
// char const * str = "{\"location\":{\"latitude\":47.383333,\"longitude\":8.533333,"
|
||||
// "\"accuracy\":18000.0},\"access_token\":\"2:6aOjM2IAoPMaweWN:txhu5LpkRkLVb3u3\"}";
|
||||
|
||||
char const * str =
|
||||
"{\"location\":{\"latitude\":47.3345141,\"longitude\":8.5312839,"
|
||||
"\"accuracy\":22.0},\"access_token\":\"2:vC65Xv0mxMtsNVf4:hY5YSIkuFfnAU77z\"}";
|
||||
|
||||
base::Json root(str);
|
||||
TEST(json_is_object(root.get()), ());
|
||||
json_t * location = json_object_get(root.get(), "location");
|
||||
TEST(json_is_object(location), ());
|
||||
|
||||
json_t * lat = json_object_get(location, "latitude");
|
||||
TEST(json_is_real(lat), ());
|
||||
TEST_ALMOST_EQUAL_ULPS(json_real_value(lat), 47.3345141, ());
|
||||
|
||||
json_t * lon = json_object_get(location, "longitude");
|
||||
TEST(json_is_real(lon), ());
|
||||
TEST_ALMOST_EQUAL_ULPS(json_real_value(lon), 8.5312839, ());
|
||||
|
||||
json_t * acc = json_object_get(location, "accuracy");
|
||||
TEST(json_is_real(acc), ());
|
||||
TEST_ALMOST_EQUAL_ULPS(json_real_value(acc), 22.0, ());
|
||||
|
||||
bool wasException = false;
|
||||
try
|
||||
{
|
||||
base::Json invalid("{asd]");
|
||||
}
|
||||
catch (base::Json::Exception const &)
|
||||
{
|
||||
wasException = true;
|
||||
}
|
||||
TEST(wasException, ());
|
||||
|
||||
setlocale(LC_NUMERIC, savedLocale);
|
||||
}
|
||||
33
libs/platform/platform_tests/language_test.cpp
Normal file
33
libs/platform/platform_tests/language_test.cpp
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "platform/preferred_languages.hpp"
|
||||
|
||||
#include "base/logging.hpp"
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
|
||||
UNIT_TEST(LangNormalize_Smoke)
|
||||
{
|
||||
char const * arr1[] = {"en", "en-GB", "zh", "es-SP", "zh-penyn", "en-US", "ru_RU", "es"};
|
||||
char const * arr2[] = {"en", "en", "zh", "es", "zh", "en", "ru", "es"};
|
||||
static_assert(ARRAY_SIZE(arr1) == ARRAY_SIZE(arr2), "");
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(arr1); ++i)
|
||||
TEST_EQUAL(arr2[i], languages::Normalize(arr1[i]), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(PrefLanguages_Smoke)
|
||||
{
|
||||
std::string s = languages::GetPreferred();
|
||||
TEST(!s.empty(), ());
|
||||
LOG(LINFO, ("Preferred langs:", s));
|
||||
|
||||
s = languages::GetCurrentOrig();
|
||||
TEST(!s.empty(), ());
|
||||
LOG(LINFO, ("Current original lang:", s));
|
||||
|
||||
s = languages::GetCurrentNorm();
|
||||
TEST(!s.empty(), ());
|
||||
LOG(LINFO, ("Current normalized lang:", s));
|
||||
}
|
||||
349
libs/platform/platform_tests/local_country_file_tests.cpp
Normal file
349
libs/platform/platform_tests/local_country_file_tests.cpp
Normal file
|
|
@ -0,0 +1,349 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "platform/country_file.hpp"
|
||||
#include "platform/local_country_file.hpp"
|
||||
#include "platform/local_country_file_utils.hpp"
|
||||
#include "platform/mwm_version.hpp"
|
||||
#include "platform/platform.hpp"
|
||||
#include "platform/platform_tests_support/scoped_dir.hpp"
|
||||
#include "platform/platform_tests_support/scoped_file.hpp"
|
||||
#include "platform/settings.hpp"
|
||||
|
||||
#include "coding/file_writer.hpp"
|
||||
#include "coding/internal/file_data.hpp"
|
||||
|
||||
#include "base/file_name_utils.hpp"
|
||||
#include "base/logging.hpp"
|
||||
#include "base/scope_guard.hpp"
|
||||
|
||||
#include "defines.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
namespace local_country_file_tests
|
||||
{
|
||||
using platform::CountryFile;
|
||||
using platform::LocalCountryFile;
|
||||
using platform::tests_support::ScopedDir;
|
||||
using platform::tests_support::ScopedFile;
|
||||
|
||||
// Checks that all unsigned numbers less than 10 ^ 18 can be parsed as
|
||||
// a timestamp.
|
||||
UNIT_TEST(LocalCountryFile_ParseVersion)
|
||||
{
|
||||
using namespace platform;
|
||||
|
||||
int64_t version = 0;
|
||||
TEST(ParseVersion("1", version), ());
|
||||
TEST_EQUAL(version, 1, ());
|
||||
|
||||
TEST(ParseVersion("141010", version), ());
|
||||
TEST_EQUAL(version, 141010, ());
|
||||
|
||||
TEST(ParseVersion("150309", version), ());
|
||||
TEST_EQUAL(version, 150309, ());
|
||||
|
||||
TEST(!ParseVersion("2111225", version), ()); // too many digits
|
||||
TEST(!ParseVersion("00000000000000000000000000000000123", version), ());
|
||||
|
||||
TEST(!ParseVersion("", version), ());
|
||||
TEST(!ParseVersion("150309 ", version), ());
|
||||
TEST(!ParseVersion(" 150309", version), ());
|
||||
TEST(!ParseVersion("-150309", version), ());
|
||||
TEST(!ParseVersion("just string", version), ());
|
||||
}
|
||||
|
||||
// Checks basic functionality of LocalCountryFile.
|
||||
UNIT_TEST(LocalCountryFile_Smoke)
|
||||
{
|
||||
CountryFile countryFile("TestCountry", 1 /* size */, "sha1");
|
||||
LocalCountryFile localFile("/test-dir", countryFile, 150309);
|
||||
|
||||
TEST_EQUAL("/test-dir/TestCountry" DATA_FILE_EXTENSION, localFile.GetPath(MapFileType::Map), ());
|
||||
|
||||
// Not synced with disk yet.
|
||||
TEST(!localFile.HasFiles(), ());
|
||||
|
||||
TEST(!localFile.OnDisk(MapFileType::Map), ());
|
||||
TEST(!localFile.OnDisk(MapFileType::Diff), ());
|
||||
|
||||
TEST_EQUAL("/test-dir", localFile.GetDirectory(), ());
|
||||
|
||||
TEST_EQUAL(0, localFile.GetSize(MapFileType::Map), ());
|
||||
TEST_EQUAL(0, localFile.GetSize(MapFileType::Diff), ());
|
||||
|
||||
TEST_EQUAL(150309, localFile.GetVersion(), ());
|
||||
}
|
||||
|
||||
// Creates test country map file and checks sync-with-disk functionality.
|
||||
UNIT_TEST(LocalCountryFile_DiskFiles)
|
||||
{
|
||||
Platform & platform = GetPlatform();
|
||||
|
||||
CountryFile countryFile("TestCountry", 1 /* size */, "sha1");
|
||||
|
||||
for (int64_t version : {1, 150312})
|
||||
{
|
||||
LocalCountryFile localFile(platform.WritableDir(), countryFile, version);
|
||||
TEST(!localFile.OnDisk(MapFileType::Map), ());
|
||||
TEST(!localFile.OnDisk(MapFileType::Diff), ());
|
||||
|
||||
std::string const mapFileName = countryFile.GetFileName(MapFileType::Map);
|
||||
std::string const mapFileContents("map");
|
||||
ScopedFile testMapFile(mapFileName, mapFileContents);
|
||||
|
||||
localFile.SyncWithDisk();
|
||||
TEST(localFile.OnDisk(MapFileType::Map), ());
|
||||
TEST(!localFile.OnDisk(MapFileType::Diff), ());
|
||||
TEST_EQUAL(mapFileContents.size(), localFile.GetSize(MapFileType::Map), ());
|
||||
|
||||
localFile.SyncWithDisk();
|
||||
TEST(localFile.OnDisk(MapFileType::Map), ());
|
||||
TEST_EQUAL(mapFileContents.size(), localFile.GetSize(MapFileType::Map), ());
|
||||
|
||||
localFile.DeleteFromDisk(MapFileType::Map);
|
||||
TEST(!testMapFile.Exists(), (testMapFile, "wasn't deleted by LocalCountryFile."));
|
||||
testMapFile.Reset();
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST(LocalCountryFile_CleanupMapFiles)
|
||||
{
|
||||
Platform & platform = GetPlatform();
|
||||
std::string const mapsDir = platform.WritableDir();
|
||||
|
||||
// Two fake directories for test country files and indexes.
|
||||
ScopedDir dir3("3");
|
||||
ScopedDir dir4("4");
|
||||
|
||||
ScopedDir absentCountryIndexesDir(dir4, "Absent");
|
||||
ScopedDir irelandIndexesDir(dir4, "Ireland");
|
||||
|
||||
CountryFile irelandFile("Ireland");
|
||||
|
||||
LocalCountryFile irelandLocalFile(dir4.GetFullPath(), irelandFile, 4 /* version */);
|
||||
ScopedFile irelandMapFile(dir4, irelandFile, MapFileType::Map);
|
||||
|
||||
// Check FindAllLocalMaps()
|
||||
std::vector<LocalCountryFile> localFiles;
|
||||
FindAllLocalMapsAndCleanup(4 /* latestVersion */, localFiles);
|
||||
TEST(base::IsExist(localFiles, irelandLocalFile), (irelandLocalFile, localFiles));
|
||||
|
||||
irelandLocalFile.SyncWithDisk();
|
||||
TEST(irelandLocalFile.OnDisk(MapFileType::Map), ());
|
||||
irelandLocalFile.DeleteFromDisk(MapFileType::Map);
|
||||
TEST(!irelandMapFile.Exists(), (irelandMapFile));
|
||||
irelandMapFile.Reset();
|
||||
|
||||
TEST(!dir3.Exists(), ("Empty directory", dir3, "wasn't removed."));
|
||||
dir3.Reset();
|
||||
|
||||
TEST(dir4.Exists(), ());
|
||||
|
||||
// Useless CountryIndexes::DeleteFromDisk calls are removed.
|
||||
// TEST(!absentCountryIndexesDir.Exists(), ("Indexes for absent country weren't deleted."));
|
||||
// absentCountryIndexesDir.Reset();
|
||||
|
||||
TEST(irelandIndexesDir.Exists(), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(LocalCountryFile_CleanupPartiallyDownloadedFiles)
|
||||
{
|
||||
ScopedDir dataDir("101008");
|
||||
auto const DataFilePath = [&dataDir](char const * file) { return dataDir.GetRelativePath() + "/" + file; };
|
||||
|
||||
ScopedDir oldDir("101009");
|
||||
ScopedDir latestDir("101010");
|
||||
|
||||
ScopedFile toBeDeleted[] = {
|
||||
{DataFilePath("Ireland.mwm.ready"), ScopedFile::Mode::Create},
|
||||
{DataFilePath("Netherlands.mwm.routing.downloading2"), ScopedFile::Mode::Create},
|
||||
{DataFilePath("Germany.mwm.ready3"), ScopedFile::Mode::Create},
|
||||
{DataFilePath("UK_England.mwm.resume4"), ScopedFile::Mode::Create},
|
||||
{base::JoinPath(oldDir.GetRelativePath(), "Russia_Central.mwm.downloading"), ScopedFile::Mode::Create}};
|
||||
|
||||
ScopedFile toBeKept[] = {
|
||||
{DataFilePath("Italy.mwm"), ScopedFile::Mode::Create},
|
||||
{DataFilePath("Spain.mwm"), ScopedFile::Mode::Create},
|
||||
{DataFilePath("Spain.mwm.routing"), ScopedFile::Mode::Create},
|
||||
{base::JoinPath(latestDir.GetRelativePath(), "Russia_Southern.mwm.downloading"), ScopedFile::Mode::Create}};
|
||||
|
||||
platform::CleanupMapsDirectory(101010 /* latestVersion */);
|
||||
|
||||
for (ScopedFile & file : toBeDeleted)
|
||||
{
|
||||
TEST(!file.Exists(), (file));
|
||||
file.Reset();
|
||||
}
|
||||
TEST(!oldDir.Exists(), (oldDir));
|
||||
oldDir.Reset();
|
||||
|
||||
for (ScopedFile & file : toBeKept)
|
||||
TEST(file.Exists(), (file));
|
||||
|
||||
TEST(latestDir.Exists(), (latestDir));
|
||||
TEST(dataDir.Exists(), (dataDir));
|
||||
}
|
||||
|
||||
// Creates test-dir and following files:
|
||||
// * test-dir/Ireland.mwm
|
||||
// * test-dir/Netherlands.mwm
|
||||
// * test-dir/Netherlands.mwm.routing
|
||||
// After that, checks that FindAllLocalMapsInDirectory() correctly finds all created files.
|
||||
UNIT_TEST(LocalCountryFile_DirectoryLookup)
|
||||
{
|
||||
// This tests creates a map file for Ireland and map + routing files
|
||||
// for Netherlands in a test directory.
|
||||
CountryFile const irelandFile("Ireland");
|
||||
CountryFile const netherlandsFile("Netherlands");
|
||||
|
||||
ScopedDir testDir("test-dir");
|
||||
|
||||
ScopedFile testIrelandMapFile(testDir, irelandFile, MapFileType::Map);
|
||||
ScopedFile testNetherlandsMapFile(testDir, netherlandsFile, MapFileType::Map);
|
||||
|
||||
std::vector<LocalCountryFile> localFiles;
|
||||
FindAllLocalMapsInDirectoryAndCleanup(testDir.GetFullPath(), 150309 /* version */, -1 /* latestVersion */,
|
||||
localFiles);
|
||||
std::sort(localFiles.begin(), localFiles.end());
|
||||
for (LocalCountryFile & localFile : localFiles)
|
||||
localFile.SyncWithDisk();
|
||||
|
||||
LocalCountryFile expectedIrelandFile(testDir.GetFullPath(), irelandFile, 150309);
|
||||
expectedIrelandFile.SyncWithDisk();
|
||||
|
||||
LocalCountryFile expectedNetherlandsFile(testDir.GetFullPath(), netherlandsFile, 150309);
|
||||
expectedNetherlandsFile.SyncWithDisk();
|
||||
|
||||
std::vector expectedLocalFiles = {expectedIrelandFile, expectedNetherlandsFile};
|
||||
std::sort(expectedLocalFiles.begin(), expectedLocalFiles.end());
|
||||
TEST_EQUAL(expectedLocalFiles, localFiles, ());
|
||||
}
|
||||
|
||||
// Creates directory 010101 and 010101/Italy.mwm file. After that,
|
||||
// checks that this file will be recognized as a map file for Italy
|
||||
// with version 010101. Also, checks that World.mwm and
|
||||
// WorldCoasts.mwm exist in writable dir.
|
||||
UNIT_TEST(LocalCountryFile_AllLocalFilesLookup)
|
||||
{
|
||||
CountryFile const italyFile("Italy");
|
||||
|
||||
ScopedDir testDir("10101");
|
||||
|
||||
settings::Delete("LastMigration");
|
||||
|
||||
ScopedFile testItalyMapFile(testDir, italyFile, MapFileType::Map);
|
||||
|
||||
std::vector<LocalCountryFile> localFiles;
|
||||
FindAllLocalMapsAndCleanup(10101 /* latestVersion */, localFiles);
|
||||
std::multiset<LocalCountryFile> localFilesSet(localFiles.begin(), localFiles.end());
|
||||
|
||||
bool worldFound = false;
|
||||
bool worldCoastsFound = false;
|
||||
for (auto const & file : localFiles)
|
||||
{
|
||||
// With the new concepts, World mwm files have valid version.
|
||||
if (file.GetCountryName() == WORLD_FILE_NAME)
|
||||
{
|
||||
worldFound = true;
|
||||
TEST_NOT_EQUAL(0, file.GetVersion(), (file));
|
||||
}
|
||||
if (file.GetCountryName() == WORLD_COASTS_FILE_NAME)
|
||||
{
|
||||
worldCoastsFound = true;
|
||||
TEST_NOT_EQUAL(0, file.GetVersion(), (file));
|
||||
}
|
||||
}
|
||||
TEST(worldFound, ());
|
||||
TEST(worldCoastsFound, ());
|
||||
|
||||
LocalCountryFile expectedItalyFile(testDir.GetFullPath(), italyFile, 10101);
|
||||
TEST_EQUAL(1, localFilesSet.count(expectedItalyFile), (localFiles));
|
||||
}
|
||||
|
||||
UNIT_TEST(LocalCountryFile_PreparePlaceForCountryFiles)
|
||||
{
|
||||
Platform & platform = GetPlatform();
|
||||
|
||||
CountryFile italyFile("Italy");
|
||||
LocalCountryFile expectedItalyFile(platform.WritableDir(), italyFile, 0 /* version */);
|
||||
auto italyLocalFile = PreparePlaceForCountryFiles(0 /* version */, italyFile);
|
||||
TEST(italyLocalFile.get(), ());
|
||||
TEST_EQUAL(expectedItalyFile, *italyLocalFile, ());
|
||||
|
||||
ScopedDir directoryForV1("1");
|
||||
|
||||
CountryFile germanyFile("Germany");
|
||||
LocalCountryFile expectedGermanyFile(directoryForV1.GetFullPath(), germanyFile, 1 /* version */);
|
||||
auto germanyLocalFile = PreparePlaceForCountryFiles(1 /* version */, germanyFile);
|
||||
TEST(germanyLocalFile.get(), ());
|
||||
TEST_EQUAL(expectedGermanyFile, *germanyLocalFile, ());
|
||||
|
||||
CountryFile franceFile("France");
|
||||
LocalCountryFile expectedFranceFile(directoryForV1.GetFullPath(), franceFile, 1 /* version */);
|
||||
auto franceLocalFile = PreparePlaceForCountryFiles(1 /* version */, franceFile);
|
||||
TEST(franceLocalFile.get(), ());
|
||||
TEST_EQUAL(expectedFranceFile, *franceLocalFile, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(LocalCountryFile_CountryIndexes)
|
||||
{
|
||||
using platform::CountryIndexes;
|
||||
|
||||
ScopedDir testDir("101010");
|
||||
|
||||
CountryFile germanyFile("Germany");
|
||||
LocalCountryFile germanyLocalFile(testDir.GetFullPath(), germanyFile, 101010 /* version */);
|
||||
TEST_EQUAL(base::JoinPath(germanyLocalFile.GetDirectory(), germanyFile.GetName()),
|
||||
CountryIndexes::IndexesDir(germanyLocalFile), ());
|
||||
CountryIndexes::PreparePlaceOnDisk(germanyLocalFile);
|
||||
|
||||
auto const bitsPath = CountryIndexes::GetPath(germanyLocalFile, CountryIndexes::Index::Bits);
|
||||
TEST(!Platform::IsFileExistsByFullPath(bitsPath), (bitsPath));
|
||||
{
|
||||
FileWriter writer(bitsPath);
|
||||
std::string const contents = "bits index";
|
||||
writer.Write(contents.data(), contents.size());
|
||||
}
|
||||
TEST(Platform::IsFileExistsByFullPath(bitsPath), (bitsPath));
|
||||
|
||||
TEST(CountryIndexes::DeleteFromDisk(germanyLocalFile), ("Can't delete indexes for:", germanyLocalFile));
|
||||
|
||||
TEST(!Platform::IsFileExistsByFullPath(bitsPath), (bitsPath));
|
||||
}
|
||||
|
||||
UNIT_TEST(LocalCountryFile_DoNotDeleteUserFiles)
|
||||
{
|
||||
using platform::CountryIndexes;
|
||||
|
||||
base::ScopedLogLevelChanger const criticalLogLevel(LCRITICAL);
|
||||
|
||||
ScopedDir testDir("101010");
|
||||
|
||||
CountryFile germanyFile("Germany");
|
||||
LocalCountryFile germanyLocalFile(testDir.GetFullPath(), germanyFile, 101010 /* version */);
|
||||
CountryIndexes::PreparePlaceOnDisk(germanyLocalFile);
|
||||
|
||||
auto const userFilePath = base::JoinPath(CountryIndexes::IndexesDir(germanyLocalFile), "user-data.txt");
|
||||
{
|
||||
FileWriter writer(userFilePath);
|
||||
std::string const data = "user data";
|
||||
writer.Write(data.data(), data.size());
|
||||
}
|
||||
TEST(!CountryIndexes::DeleteFromDisk(germanyLocalFile), ("Indexes dir should not be deleted for:", germanyLocalFile));
|
||||
|
||||
TEST(base::DeleteFileX(userFilePath), ("Can't delete test file:", userFilePath));
|
||||
TEST(CountryIndexes::DeleteFromDisk(germanyLocalFile), ("Can't delete indexes for:", germanyLocalFile));
|
||||
}
|
||||
|
||||
UNIT_TEST(LocalCountryFile_MakeTemporary)
|
||||
{
|
||||
auto const path = GetPlatform().WritablePathForFile("minsk-pass" DATA_FILE_EXTENSION);
|
||||
LocalCountryFile file = LocalCountryFile::MakeTemporary(path);
|
||||
TEST_EQUAL(file.GetPath(MapFileType::Map), path, ());
|
||||
}
|
||||
|
||||
} // namespace local_country_file_tests
|
||||
39
libs/platform/platform_tests/location_test.cpp
Normal file
39
libs/platform/platform_tests/location_test.cpp
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "platform/location.hpp"
|
||||
|
||||
UNIT_TEST(IsLatValid)
|
||||
{
|
||||
TEST(location::IsLatValid(35.), ());
|
||||
TEST(location::IsLatValid(-35.), ());
|
||||
TEST(!location::IsLatValid(0.), ());
|
||||
TEST(!location::IsLatValid(100.), ());
|
||||
TEST(!location::IsLatValid(-99.), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(IsLonValid)
|
||||
{
|
||||
TEST(location::IsLonValid(135.), ());
|
||||
TEST(location::IsLonValid(-35.), ());
|
||||
TEST(!location::IsLonValid(0.), ());
|
||||
TEST(!location::IsLonValid(200.), ());
|
||||
TEST(!location::IsLonValid(-199.), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(AngleToBearing)
|
||||
{
|
||||
TEST_ALMOST_EQUAL_ULPS(location::AngleToBearing(0.), 90., ());
|
||||
TEST_ALMOST_EQUAL_ULPS(location::AngleToBearing(30.), 60., ());
|
||||
TEST_ALMOST_EQUAL_ULPS(location::AngleToBearing(100.), 350., ());
|
||||
TEST_ALMOST_EQUAL_ULPS(location::AngleToBearing(370.), 80., ());
|
||||
TEST_ALMOST_EQUAL_ULPS(location::AngleToBearing(-370.), 100., ());
|
||||
}
|
||||
|
||||
UNIT_TEST(BearingToAngle)
|
||||
{
|
||||
TEST_ALMOST_EQUAL_ULPS(location::BearingToAngle(0.), 90., ());
|
||||
TEST_ALMOST_EQUAL_ULPS(location::BearingToAngle(30.), 60., ());
|
||||
TEST_ALMOST_EQUAL_ULPS(location::BearingToAngle(100.), 350., ());
|
||||
TEST_ALMOST_EQUAL_ULPS(location::BearingToAngle(370.), 80., ());
|
||||
TEST_ALMOST_EQUAL_ULPS(location::AngleToBearing(-370.), 100., ());
|
||||
}
|
||||
183
libs/platform/platform_tests/measurement_tests.cpp
Normal file
183
libs/platform/platform_tests/measurement_tests.cpp
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "platform/measurement_utils.hpp"
|
||||
|
||||
#include "base/math.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
using namespace measurement_utils;
|
||||
using namespace platform;
|
||||
|
||||
std::string AddGroupingSeparators(std::string const & valueString, std::string const & groupingSeparator)
|
||||
{
|
||||
std::string out(valueString);
|
||||
|
||||
if (out.size() > 4 && !groupingSeparator.empty())
|
||||
for (int pos = out.size() - 3; pos > 0; pos -= 3)
|
||||
out.insert(pos, groupingSeparator);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
UNIT_TEST(LatLonToDMS_Origin)
|
||||
{
|
||||
TEST_EQUAL(FormatLatLonAsDMS(0, 0, false), "00°00′00″ 00°00′00″", ());
|
||||
TEST_EQUAL(FormatLatLonAsDMS(0, 0, false, 3), "00°00′00″ 00°00′00″", ());
|
||||
}
|
||||
|
||||
UNIT_TEST(LatLonToDMS_Rounding)
|
||||
{
|
||||
// Here and after data is from Wiki: http://bit.ly/datafotformatingtest
|
||||
// Boston
|
||||
TEST_EQUAL(FormatLatLonAsDMS(42.358056, -71.063611, false, 0), "42°21′29″N 71°03′49″W", ());
|
||||
// Minsk
|
||||
TEST_EQUAL(FormatLatLonAsDMS(53.916667, 27.55, false, 0), "53°55′00″N 27°33′00″E", ());
|
||||
// Rio
|
||||
TEST_EQUAL(FormatLatLonAsDMS(-22.908333, -43.196389, false, 0), "22°54′30″S 43°11′47″W", ());
|
||||
}
|
||||
|
||||
UNIT_TEST(LatLonToDMS_NoRounding)
|
||||
{
|
||||
// Paris
|
||||
TEST_EQUAL(FormatLatLonAsDMS(48.8567, 2.3508, false, 2), "48°51′24.12″N 02°21′02.88″E", ());
|
||||
// Vatican
|
||||
TEST_EQUAL(FormatLatLonAsDMS(41.904, 12.453, false, 2), "41°54′14.4″N 12°27′10.8″E", ());
|
||||
|
||||
TEST_EQUAL(FormatLatLonAsDMS(21.981112, -159.371112, false, 2), "21°58′52″N 159°22′16″W", ());
|
||||
}
|
||||
|
||||
UNIT_TEST(FormatOsmLink)
|
||||
{
|
||||
// Zero point
|
||||
TEST_EQUAL(FormatOsmLink(0, 0, 5), "https://osm.org/go/wAAAA-?m", ());
|
||||
// Eifel tower
|
||||
TEST_EQUAL(FormatOsmLink(48.85825, 2.29450, 15), "https://osm.org/go/0BOdUs9e--?m", ());
|
||||
// Buenos Aires
|
||||
TEST_EQUAL(FormatOsmLink(-34.6061, -58.4360, 10), "https://osm.org/go/Mnx6SB?m", ());
|
||||
|
||||
// Formally, lat = -90 and lat = 90 are the same for OSM links, but Mercator is valid until 85.
|
||||
auto link = FormatOsmLink(-90, -180, 10);
|
||||
TEST(link == "https://osm.org/go/AAAAAA?m" || link == "https://osm.org/go/~~~~~~?m", (link));
|
||||
link = FormatOsmLink(90, 180, 10);
|
||||
TEST(link == "https://osm.org/go/AAAAAA?m" || link == "https://osm.org/go/~~~~~~?m", (link));
|
||||
}
|
||||
|
||||
UNIT_TEST(FormatSpeedNumeric)
|
||||
{
|
||||
TEST_EQUAL(FormatSpeedNumeric(10, Units::Metric), "36", ());
|
||||
TEST_EQUAL(FormatSpeedNumeric(1, Units::Metric), "4", ());
|
||||
|
||||
TEST_EQUAL(FormatSpeedNumeric(10, Units::Imperial), "22", ());
|
||||
TEST_EQUAL(FormatSpeedNumeric(1, Units::Imperial), "2", ());
|
||||
}
|
||||
|
||||
UNIT_TEST(OSMDistanceToMetersString)
|
||||
{
|
||||
TEST_EQUAL(OSMDistanceToMetersString(""), "", ());
|
||||
TEST_EQUAL(OSMDistanceToMetersString("INF"), "", ());
|
||||
TEST_EQUAL(OSMDistanceToMetersString("NAN"), "", ());
|
||||
TEST_EQUAL(OSMDistanceToMetersString("not a number"), "", ());
|
||||
TEST_EQUAL(OSMDistanceToMetersString("10й"), "10", ());
|
||||
TEST_EQUAL(OSMDistanceToMetersString("0"), "0", ());
|
||||
TEST_EQUAL(OSMDistanceToMetersString("0.0"), "0", ());
|
||||
TEST_EQUAL(OSMDistanceToMetersString("0.0000000"), "0", ());
|
||||
TEST_EQUAL(OSMDistanceToMetersString("22.5"), "22.5", ());
|
||||
TEST_EQUAL(OSMDistanceToMetersString("+21.5"), "21.5", ());
|
||||
TEST_EQUAL(OSMDistanceToMetersString("1e+2"), "100", ());
|
||||
TEST_EQUAL(OSMDistanceToMetersString("5 метров"), "5", ());
|
||||
TEST_EQUAL(OSMDistanceToMetersString(" 4.4 "), "4.4", ());
|
||||
TEST_EQUAL(OSMDistanceToMetersString("8-15"), "15", ());
|
||||
TEST_EQUAL(OSMDistanceToMetersString("8-15 ft"), "4.57", ());
|
||||
TEST_EQUAL(OSMDistanceToMetersString("8-й километр"), "8", ());
|
||||
// Do not support lists for distance values.
|
||||
TEST_EQUAL(OSMDistanceToMetersString("8;9;10"), "", ());
|
||||
TEST_EQUAL(OSMDistanceToMetersString("8;9;10 meters"), "", ());
|
||||
TEST_EQUAL(OSMDistanceToMetersString("8;9;10 km"), "", ());
|
||||
TEST_EQUAL(OSMDistanceToMetersString("10;20!111"), "", ());
|
||||
TEST_EQUAL(OSMDistanceToMetersString("10;20\""), "", ());
|
||||
TEST_EQUAL(OSMDistanceToMetersString("-100.3"), "-100.3", ());
|
||||
TEST_EQUAL(OSMDistanceToMetersString("99.0000000"), "99", ());
|
||||
TEST_EQUAL(OSMDistanceToMetersString("8900.000023"), "8900", ());
|
||||
TEST_EQUAL(OSMDistanceToMetersString("-300.9999"), "-301", ());
|
||||
TEST_EQUAL(OSMDistanceToMetersString("-300.9"), "-300.9", ());
|
||||
TEST_EQUAL(OSMDistanceToMetersString("15 m"), "15", ());
|
||||
TEST_EQUAL(OSMDistanceToMetersString("15.9 m"), "15.9", ());
|
||||
TEST_EQUAL(OSMDistanceToMetersString("15.9m"), "15.9", ());
|
||||
TEST_EQUAL(OSMDistanceToMetersString("3000 ft"), "914.4", ());
|
||||
TEST_EQUAL(OSMDistanceToMetersString("3000ft"), "914.4", ());
|
||||
TEST_EQUAL(OSMDistanceToMetersString("100 feet"), "30.48", ());
|
||||
TEST_EQUAL(OSMDistanceToMetersString("100feet"), "30.48", ());
|
||||
TEST_EQUAL(OSMDistanceToMetersString("3 nmi"), "5556", ());
|
||||
TEST_EQUAL(OSMDistanceToMetersString("3 mi"), "4828.03", ());
|
||||
TEST_EQUAL(OSMDistanceToMetersString("3.3 km"), "3300", ());
|
||||
TEST_EQUAL(OSMDistanceToMetersString("105'"), "32", ());
|
||||
TEST_EQUAL(OSMDistanceToMetersString("11'"), "3.35", ());
|
||||
TEST_EQUAL(OSMDistanceToMetersString("11 3\""), "11", ());
|
||||
TEST_EQUAL(OSMDistanceToMetersString("11 3'"), "11", ());
|
||||
TEST_EQUAL(OSMDistanceToMetersString("11\"'"), "0.28", ());
|
||||
TEST_EQUAL(OSMDistanceToMetersString("11'\""), "3.35", ());
|
||||
TEST_EQUAL(OSMDistanceToMetersString("11'4\""), "3.45", ());
|
||||
TEST_EQUAL(OSMDistanceToMetersString("11\""), "0.28", ());
|
||||
TEST_EQUAL(OSMDistanceToMetersString("100 \""), "100", ());
|
||||
|
||||
TEST_EQUAL(OSMDistanceToMetersString("0", false), "", ());
|
||||
TEST_EQUAL(OSMDistanceToMetersString("-15", false), "", ());
|
||||
TEST_EQUAL(OSMDistanceToMetersString("15.12345", false, 1), "15.1", ());
|
||||
TEST_EQUAL(OSMDistanceToMetersString("15.123", false, 4), "15.123", ());
|
||||
TEST_EQUAL(OSMDistanceToMetersString("15.654321", true, 1), "15.7", ());
|
||||
}
|
||||
|
||||
UNIT_TEST(UnitsConversion)
|
||||
{
|
||||
double const kEps = 1e-5;
|
||||
TEST(AlmostEqualAbs(MilesToMeters(MetersToMiles(1000.0)), 1000.0, kEps), ());
|
||||
TEST(AlmostEqualAbs(MilesToMeters(1.0), 1609.344, kEps), ());
|
||||
|
||||
TEST(AlmostEqualAbs(MiphToKmph(KmphToMiph(100.0)), 100.0, kEps), ());
|
||||
TEST(AlmostEqualAbs(MiphToKmph(100.0), 160.9344, kEps), (MiphToKmph(100.0)));
|
||||
|
||||
TEST(AlmostEqualAbs(ToSpeedKmPH(100.0, Units::Imperial), 160.9344, kEps), ());
|
||||
TEST(AlmostEqualAbs(ToSpeedKmPH(100.0, Units::Metric), 100.0, kEps), ());
|
||||
|
||||
TEST(AlmostEqualAbs(KmphToMps(3.6), 1.0, kEps), ());
|
||||
TEST(AlmostEqualAbs(MpsToKmph(1.0), 3.6, kEps), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(ToStringPrecisionLocale)
|
||||
{
|
||||
double d1 = 9.8;
|
||||
int pr1 = 1;
|
||||
|
||||
double d2 = 12345.0;
|
||||
int pr2 = 0;
|
||||
std::string d2String("12345");
|
||||
|
||||
struct TestData
|
||||
{
|
||||
std::string localeName;
|
||||
std::string d1String;
|
||||
};
|
||||
|
||||
TestData testData[] = {// Locale name , Decimal
|
||||
{"en_US.UTF-8", "9.8"},
|
||||
{"es_ES.UTF-8", "9,8"},
|
||||
{"fr_FR.UTF-8", "9,8"},
|
||||
{"ru_RU.UTF-8", "9,8"}};
|
||||
|
||||
for (TestData const & data : testData)
|
||||
{
|
||||
Locale loc;
|
||||
|
||||
if (!GetLocale(data.localeName, loc))
|
||||
{
|
||||
std::cout << "Locale '" << data.localeName << "' not found!! Skipping test..." << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
TEST_EQUAL(measurement_utils::ToStringPrecisionLocale(loc, d1, pr1), data.d1String, ());
|
||||
TEST_EQUAL(measurement_utils::ToStringPrecisionLocale(loc, d2, pr2),
|
||||
AddGroupingSeparators(d2String, loc.m_groupingSeparator), ());
|
||||
}
|
||||
}
|
||||
62
libs/platform/platform_tests/meta_config_tests.cpp
Normal file
62
libs/platform/platform_tests/meta_config_tests.cpp
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "platform/servers_list.hpp"
|
||||
|
||||
#include "cppjansson/cppjansson.hpp"
|
||||
|
||||
using namespace downloader;
|
||||
|
||||
UNIT_TEST(MetaConfig_JSONParser_OldFormat)
|
||||
{
|
||||
std::string oldFormatJson = R"(["http://url1", "http://url2", "http://url3"])";
|
||||
auto result = ParseMetaConfig(oldFormatJson);
|
||||
TEST(result.has_value(), ());
|
||||
TEST_EQUAL(result->m_serversList.size(), 3, ());
|
||||
TEST_EQUAL(result->m_serversList[0], "http://url1", ());
|
||||
TEST_EQUAL(result->m_serversList[1], "http://url2", ());
|
||||
TEST_EQUAL(result->m_serversList[2], "http://url3", ());
|
||||
TEST(result->m_settings.empty(), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(MetaConfig_JSONParser_InvalidJSON)
|
||||
{
|
||||
std::string invalidJson = R"({"servers": ["http://url1", "http://url2")";
|
||||
auto result = ParseMetaConfig(invalidJson);
|
||||
TEST(!result.has_value(), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(MetaConfig_JSONParser_EmptyServersList)
|
||||
{
|
||||
std::string emptyServersJson = R"({"servers": []})";
|
||||
auto result = ParseMetaConfig(emptyServersJson);
|
||||
TEST(!result.has_value(), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(MetaConfig_JSONParser_NewFormatWithoutProducts)
|
||||
{
|
||||
std::string newFormatJson = R"({
|
||||
"servers": ["http://url1", "http://url2"],
|
||||
"settings": {
|
||||
"DonateUrl": "value1",
|
||||
"key2": "value2"
|
||||
}
|
||||
})";
|
||||
auto result = ParseMetaConfig(newFormatJson);
|
||||
TEST(result.has_value(), ());
|
||||
TEST_EQUAL(result->m_serversList.size(), 2, ());
|
||||
TEST_EQUAL(result->m_serversList[0], "http://url1", ());
|
||||
TEST_EQUAL(result->m_serversList[1], "http://url2", ());
|
||||
TEST_EQUAL(result->m_settings.size(), 1, ());
|
||||
TEST_EQUAL(result->m_settings["DonateUrl"], "value1", ());
|
||||
}
|
||||
|
||||
UNIT_TEST(MetaConfig_JSONParser_MissingServersKey)
|
||||
{
|
||||
std::string missingServersJson = R"({
|
||||
"settings": {
|
||||
"key1": "value1"
|
||||
}
|
||||
})";
|
||||
auto result = ParseMetaConfig(missingServersJson);
|
||||
TEST(!result.has_value(), ("JSON shouldn't be parsed without 'servers' key"));
|
||||
}
|
||||
334
libs/platform/platform_tests/platform_test.cpp
Normal file
334
libs/platform/platform_tests/platform_test.cpp
Normal file
|
|
@ -0,0 +1,334 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "platform/mwm_version.hpp"
|
||||
#include "platform/platform.hpp"
|
||||
#include "platform/platform_tests_support/scoped_file.hpp"
|
||||
|
||||
#include "coding/file_writer.hpp"
|
||||
#include "coding/internal/file_data.hpp"
|
||||
|
||||
#include "base/file_name_utils.hpp"
|
||||
#include "base/logging.hpp"
|
||||
#include "base/scope_guard.hpp"
|
||||
#include "base/stl_helpers.hpp"
|
||||
|
||||
#include <functional>
|
||||
#include <initializer_list>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
#include "defines.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
char const * TEST_FILE_NAME = "some_temporary_unit_test_file.tmp";
|
||||
|
||||
void CheckFilesPresence(std::string const & baseDir, unsigned typeMask,
|
||||
std::initializer_list<std::pair<std::string, size_t>> const & files)
|
||||
{
|
||||
Platform::TFilesWithType fwts;
|
||||
Platform::GetFilesByType(baseDir, typeMask, fwts);
|
||||
|
||||
std::multiset<std::string> filesSet;
|
||||
for (auto const & fwt : fwts)
|
||||
filesSet.insert(fwt.first);
|
||||
|
||||
for (auto const & file : files)
|
||||
TEST_EQUAL(filesSet.count(file.first), file.second, (file.first, file.second));
|
||||
}
|
||||
} // namespace
|
||||
|
||||
UNIT_TEST(WritableDir)
|
||||
{
|
||||
std::string const path = GetPlatform().WritableDir() + TEST_FILE_NAME;
|
||||
|
||||
try
|
||||
{
|
||||
base::FileData f(path, base::FileData::Op::WRITE_TRUNCATE);
|
||||
}
|
||||
catch (Writer::OpenException const &)
|
||||
{
|
||||
LOG(LCRITICAL, ("Can't create file", path));
|
||||
return;
|
||||
}
|
||||
|
||||
base::DeleteFileX(path);
|
||||
}
|
||||
|
||||
UNIT_TEST(WritablePathForFile)
|
||||
{
|
||||
Platform & pl = GetPlatform();
|
||||
std::string const p1 = base::JoinPath(pl.WritableDir(), TEST_FILE_NAME);
|
||||
std::string const p2 = pl.WritablePathForFile(TEST_FILE_NAME);
|
||||
TEST_EQUAL(p1, p2, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(GetReader)
|
||||
{
|
||||
char const * NON_EXISTING_FILE = "mgbwuerhsnmbui45efhdbn34.tmp";
|
||||
char const * arr[] = {"symbols/mdpi/light/symbols.sdf", "classificator.txt", "minsk-pass.mwm"};
|
||||
|
||||
Platform & p = GetPlatform();
|
||||
for (size_t i = 0; i < ARRAY_SIZE(arr); ++i)
|
||||
{
|
||||
ReaderPtr<Reader> r = p.GetReader(arr[i]);
|
||||
TEST_GREATER(r.Size(), 0, ("File should exist!"));
|
||||
}
|
||||
|
||||
bool wasException = false;
|
||||
try
|
||||
{
|
||||
ReaderPtr<Reader> r = p.GetReader(NON_EXISTING_FILE);
|
||||
}
|
||||
catch (FileAbsentException const &)
|
||||
{
|
||||
wasException = true;
|
||||
}
|
||||
TEST_EQUAL(wasException, true, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(GetFilesInDir_Smoke)
|
||||
{
|
||||
Platform & pl = GetPlatform();
|
||||
Platform::FilesList files1, files2;
|
||||
|
||||
std::string const dir = pl.ResourcesDir();
|
||||
|
||||
pl.GetFilesByExt(dir, DATA_FILE_EXTENSION, files1);
|
||||
TEST_GREATER(files1.size(), 0, (dir, "folder should contain some data files"));
|
||||
|
||||
TEST(base::IsExist(files1, "minsk-pass.mwm"), ());
|
||||
|
||||
pl.GetFilesByRegExp(dir, boost::regex(".*\\" + DATA_FILE_EXTENSION + "$"), files2);
|
||||
TEST_EQUAL(files1, files2, ());
|
||||
|
||||
files1.clear();
|
||||
pl.GetFilesByExt(dir, ".dsa", files1);
|
||||
TEST_EQUAL(files1.size(), 0, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(DirsRoutines)
|
||||
{
|
||||
std::string const baseDir = GetPlatform().WritableDir();
|
||||
std::string const testDir = base::JoinPath(baseDir, "test-dir");
|
||||
std::string const testFile = base::JoinPath(testDir, "test-file");
|
||||
|
||||
TEST(!Platform::IsFileExistsByFullPath(testDir), ());
|
||||
TEST_EQUAL(Platform::MkDir(testDir), Platform::ERR_OK, ());
|
||||
|
||||
TEST(Platform::IsFileExistsByFullPath(testDir), ());
|
||||
TEST(Platform::IsDirectoryEmpty(testDir), ());
|
||||
|
||||
{
|
||||
FileWriter writer(testFile);
|
||||
}
|
||||
TEST(!Platform::IsDirectoryEmpty(testDir), ());
|
||||
FileWriter::DeleteFileX(testFile);
|
||||
|
||||
TEST_EQUAL(Platform::RmDir(testDir), Platform::ERR_OK, ());
|
||||
|
||||
TEST(!Platform::IsFileExistsByFullPath(testDir), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(GetFilesByType)
|
||||
{
|
||||
std::string const kTestDirBaseName = "test-dir";
|
||||
std::string const kTestFileBaseName = "test-file";
|
||||
|
||||
std::string const baseDir = GetPlatform().WritableDir();
|
||||
|
||||
std::string const testDir = base::JoinPath(baseDir, kTestDirBaseName);
|
||||
TEST_EQUAL(Platform::MkDir(testDir), Platform::ERR_OK, ());
|
||||
SCOPE_GUARD(removeTestDir, bind(&Platform::RmDir, testDir));
|
||||
|
||||
std::string const testFile = base::JoinPath(baseDir, kTestFileBaseName);
|
||||
TEST(!Platform::IsFileExistsByFullPath(testFile), ());
|
||||
{
|
||||
FileWriter writer(testFile);
|
||||
}
|
||||
TEST(Platform::IsFileExistsByFullPath(testFile), ());
|
||||
SCOPE_GUARD(removeTestFile, bind(FileWriter::DeleteFileX, testFile));
|
||||
|
||||
CheckFilesPresence(baseDir, Platform::EFileType::Directory,
|
||||
{{
|
||||
kTestDirBaseName, 1 /* present */
|
||||
},
|
||||
{
|
||||
kTestFileBaseName, 0 /* not present */
|
||||
}});
|
||||
CheckFilesPresence(baseDir, Platform::EFileType::Regular,
|
||||
{{
|
||||
kTestDirBaseName, 0 /* not present */
|
||||
},
|
||||
{
|
||||
kTestFileBaseName, 1 /* present */
|
||||
}});
|
||||
CheckFilesPresence(baseDir, Platform::EFileType::Directory | Platform::EFileType::Regular,
|
||||
{{
|
||||
kTestDirBaseName, 1 /* present */
|
||||
},
|
||||
{
|
||||
kTestFileBaseName, 1 /* present */
|
||||
}});
|
||||
}
|
||||
|
||||
UNIT_TEST(GetFileSize)
|
||||
{
|
||||
Platform & pl = GetPlatform();
|
||||
uint64_t size = 123141;
|
||||
TEST(!pl.GetFileSizeByName("adsmngfuwrbfyfwe", size), ());
|
||||
TEST(!pl.IsFileExistsByFullPath("adsmngfuwrbfyfwe"), ());
|
||||
|
||||
char const kContent[] = "HOHOHO";
|
||||
size_t const kSize = ARRAY_SIZE(kContent);
|
||||
std::string const fileName = pl.WritablePathForFile(TEST_FILE_NAME);
|
||||
{
|
||||
FileWriter testFile(fileName);
|
||||
testFile.Write(kContent, kSize);
|
||||
}
|
||||
size = 0;
|
||||
TEST(Platform::GetFileSizeByFullPath(fileName, size), ());
|
||||
TEST_EQUAL(size, kSize, ());
|
||||
|
||||
FileWriter::DeleteFileX(fileName);
|
||||
TEST(!pl.IsFileExistsByFullPath(fileName), ());
|
||||
|
||||
{
|
||||
FileWriter testFile(fileName);
|
||||
testFile.Write(kContent, kSize);
|
||||
}
|
||||
size = 0;
|
||||
TEST(pl.GetFileSizeByName(TEST_FILE_NAME, size), ());
|
||||
TEST_EQUAL(size, kSize, ());
|
||||
|
||||
FileWriter::DeleteFileX(fileName);
|
||||
}
|
||||
|
||||
UNIT_TEST(CpuCores)
|
||||
{
|
||||
int const coresNum = GetPlatform().CpuCores();
|
||||
TEST_GREATER(coresNum, 0, ());
|
||||
TEST_LESS_OR_EQUAL(coresNum, 128, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(GetWritableStorageStatus)
|
||||
{
|
||||
TEST_EQUAL(Platform::STORAGE_OK, GetPlatform().GetWritableStorageStatus(100000), ());
|
||||
TEST_EQUAL(Platform::NOT_ENOUGH_SPACE, GetPlatform().GetWritableStorageStatus(uint64_t(-1)), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(RmDirRecursively)
|
||||
{
|
||||
std::string const testDir1 = base::JoinPath(GetPlatform().WritableDir(), "test_dir1");
|
||||
TEST_EQUAL(Platform::MkDir(testDir1), Platform::ERR_OK, ());
|
||||
SCOPE_GUARD(removeTestDir1, bind(&Platform::RmDir, testDir1));
|
||||
|
||||
std::string const testDir2 = base::JoinPath(testDir1, "test_dir2");
|
||||
TEST_EQUAL(Platform::MkDir(testDir2), Platform::ERR_OK, ());
|
||||
SCOPE_GUARD(removeTestDir2, bind(&Platform::RmDir, testDir2));
|
||||
|
||||
std::string const filePath = base::JoinPath(testDir2, "test_file");
|
||||
{
|
||||
FileWriter testFile(filePath);
|
||||
testFile.Write("HOHOHO", 6);
|
||||
}
|
||||
SCOPE_GUARD(removeTestFile, bind(&base::DeleteFileX, filePath));
|
||||
|
||||
TEST(Platform::IsFileExistsByFullPath(filePath), ());
|
||||
TEST(Platform::IsFileExistsByFullPath(testDir1), ());
|
||||
TEST(Platform::IsFileExistsByFullPath(testDir2), ());
|
||||
|
||||
TEST_EQUAL(Platform::ERR_DIRECTORY_NOT_EMPTY, Platform::RmDir(testDir1), ());
|
||||
|
||||
TEST(Platform::IsFileExistsByFullPath(filePath), ());
|
||||
TEST(Platform::IsFileExistsByFullPath(testDir1), ());
|
||||
TEST(Platform::IsFileExistsByFullPath(testDir2), ());
|
||||
|
||||
TEST(Platform::RmDirRecursively(testDir1), ());
|
||||
|
||||
TEST(!Platform::IsFileExistsByFullPath(filePath), ());
|
||||
TEST(!Platform::IsFileExistsByFullPath(testDir1), ());
|
||||
TEST(!Platform::IsFileExistsByFullPath(testDir2), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(MkDirRecursively)
|
||||
{
|
||||
using namespace platform::tests_support;
|
||||
auto const writablePath = GetPlatform().WritableDir();
|
||||
auto const workPath = base::JoinPath(writablePath, "MkDirRecursively");
|
||||
auto const resetDir = [](std::string const & path)
|
||||
{
|
||||
if (Platform::IsFileExistsByFullPath(path) && !Platform::RmDirRecursively(path))
|
||||
return false;
|
||||
|
||||
return Platform::MkDirChecked(path);
|
||||
};
|
||||
|
||||
CHECK(resetDir(workPath), ());
|
||||
auto const path = base::JoinPath(workPath, "test1", "test2", "test3");
|
||||
TEST(Platform::MkDirRecursively(path), ());
|
||||
TEST(Platform::IsFileExistsByFullPath(path), ());
|
||||
TEST(Platform::IsDirectory(path), ());
|
||||
|
||||
CHECK(resetDir(workPath), ());
|
||||
auto const filePath = base::JoinPath(workPath, "test1");
|
||||
SCOPE_GUARD(removeTestFile, bind(&base::DeleteFileX, filePath));
|
||||
{
|
||||
FileWriter testFile(filePath);
|
||||
}
|
||||
|
||||
TEST(!Platform::MkDirRecursively(path), ());
|
||||
TEST(!Platform::IsFileExistsByFullPath(path), ());
|
||||
|
||||
CHECK(Platform::RmDirRecursively(workPath), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(Platform_ThreadRunner)
|
||||
{
|
||||
{
|
||||
Platform::ThreadRunner m_runner;
|
||||
|
||||
bool called = false;
|
||||
GetPlatform().RunTask(Platform::Thread::File, [&called]
|
||||
{
|
||||
called = true;
|
||||
testing::Notify();
|
||||
});
|
||||
testing::Wait();
|
||||
|
||||
TEST(called, ());
|
||||
}
|
||||
|
||||
GetPlatform().RunTask(Platform::Thread::File, []
|
||||
{
|
||||
TEST(false, ("The task must not be posted when thread runner is dead. "
|
||||
"But app must not be crashed. It is normal behaviour during destruction"));
|
||||
});
|
||||
}
|
||||
|
||||
UNIT_TEST(GetFileCreationTime_GetFileModificationTime)
|
||||
{
|
||||
auto const now = std::time(nullptr);
|
||||
|
||||
std::string_view constexpr kContent{"HOHOHO"};
|
||||
std::string const fileName = GetPlatform().WritablePathForFile(TEST_FILE_NAME);
|
||||
{
|
||||
FileWriter testFile(fileName);
|
||||
testFile.Write(kContent.data(), kContent.size());
|
||||
}
|
||||
SCOPE_GUARD(removeTestFile, bind(&base::DeleteFileX, fileName));
|
||||
|
||||
auto const creationTime = Platform::GetFileCreationTime(fileName);
|
||||
TEST_GREATER_OR_EQUAL(creationTime, now, ());
|
||||
|
||||
{
|
||||
FileWriter testFile(fileName);
|
||||
testFile.Write(kContent.data(), kContent.size());
|
||||
}
|
||||
|
||||
auto const modificationTime = Platform::GetFileModificationTime(fileName);
|
||||
TEST_GREATER_OR_EQUAL(modificationTime, creationTime, ());
|
||||
}
|
||||
69
libs/platform/platform_tests/utm_mgrs_utils_tests.cpp
Normal file
69
libs/platform/platform_tests/utm_mgrs_utils_tests.cpp
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "platform/utm_mgrs_utils.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
using namespace utm_mgrs_utils;
|
||||
|
||||
UNIT_TEST(FormatUTM)
|
||||
{
|
||||
TEST_EQUAL(FormatUTM(42.0, -93.0), "15T 500000 4649776", ());
|
||||
TEST_EQUAL(FormatUTM(31.77597, 35.23406), "36R 711554 3517777", ());
|
||||
TEST_EQUAL(FormatUTM(-34.81449, -58.54016), "21H 359135 6146448", ());
|
||||
TEST_EQUAL(FormatUTM(36.2361322, -115.0820944), "11S 672349 4011845", ());
|
||||
|
||||
TEST_EQUAL(FormatUTM(50.77535, 6.08389), "32U 294409 5628898", ());
|
||||
TEST_EQUAL(FormatUTM(40.71435, -74.00597), "18T 583960 4507523", ());
|
||||
TEST_EQUAL(FormatUTM(-41.28646, 174.77624), "60G 313784 5427057", ());
|
||||
TEST_EQUAL(FormatUTM(-33.92487, 18.42406), "34H 261878 6243186", ());
|
||||
TEST_EQUAL(FormatUTM(-32.89018, -68.84405), "19H 514586 6360877", ());
|
||||
TEST_EQUAL(FormatUTM(64.83778, -147.71639), "6W 466013 7190568", ());
|
||||
TEST_EQUAL(FormatUTM(56.79680, -5.00601), "30V 377486 6296562", ());
|
||||
TEST_EQUAL(FormatUTM(84, -5.00601), "30X 476594 9328501", ());
|
||||
|
||||
TEST_EQUAL(FormatUTM(84.644103, 3.000009), "", ()); // Latitude limit exceeded.
|
||||
TEST_EQUAL(FormatUTM(12.016469, 188.0), "", ());
|
||||
}
|
||||
|
||||
UNIT_TEST(FormatMGRS)
|
||||
{
|
||||
TEST_EQUAL(FormatMGRS(42.0, -93.0, 5), "15T WG 00000 49776", ());
|
||||
TEST_EQUAL(FormatMGRS(31.77597, 35.23406, 5), "36R YA 11554 17776", ());
|
||||
TEST_EQUAL(FormatMGRS(-34.81449, -58.54016, 5), "21H UB 59135 46447", ());
|
||||
TEST_EQUAL(FormatMGRS(36.2361322, -115.0820944, 5), "11S PA 72349 11844", ());
|
||||
TEST_EQUAL(FormatMGRS(36.2361322, -115.0820944, 4), "11S PA 7234 1184", ());
|
||||
TEST_EQUAL(FormatMGRS(36.2361322, -115.0820944, 3), "11S PA 723 118", ());
|
||||
TEST_EQUAL(FormatMGRS(36.2361322, -115.0820944, 2), "11S PA 72 11", ());
|
||||
TEST_EQUAL(FormatMGRS(36.2361322, -115.0820944, 1), "11S PA 7 1", ());
|
||||
|
||||
TEST_EQUAL(FormatMGRS(84.644103, 3.000009, 5), "", ()); // Some converters generate string "Z AB 31142 05767"
|
||||
TEST_EQUAL(FormatMGRS(-81.016469, 8.745519, 5), "", ()); // Some converters generate string "B BX 51947 87732"
|
||||
TEST_EQUAL(FormatMGRS(12.016469, 188.0, 2), "", ());
|
||||
|
||||
// Test data from https://s3.amazonaws.com/mgrs.io/mgrsToGeo_WE.txt
|
||||
TEST_EQUAL(FormatMGRS(0.000005, 0.304981, 5), "31N BA 00000 00000", ());
|
||||
TEST_EQUAL(FormatMGRS(4.518520, 48.296629, 5), "39N TF 00000 00000", ());
|
||||
TEST_EQUAL(FormatMGRS(9.045438, 50.090125, 5), "39P VL 00000 00000", ());
|
||||
TEST_EQUAL(FormatMGRS(63.115494, 91.017708, 5), "46V DR 00000 00000", ());
|
||||
TEST_EQUAL(FormatMGRS(40.626644, 137.364687, 5), "53T QF 00000 00000", ());
|
||||
TEST_EQUAL(FormatMGRS(0.000005, -4.797048, 5), "30N UF 00000 00000", ());
|
||||
TEST_EQUAL(FormatMGRS(0.000005, -0.592324, 5), "30N YF 67993 00000", ());
|
||||
TEST_EQUAL(FormatMGRS(0.000005, 6.592333, 5), "32N KF 32007 00000", ());
|
||||
TEST_EQUAL(FormatMGRS(0.000005, 54.592333, 5), "40N BF 32007 00000", ());
|
||||
TEST_EQUAL(FormatMGRS(76.463950, 58.675211, 5), "40X EK 43763 87577", ());
|
||||
TEST_EQUAL(FormatMGRS(-49.578078, 85.150396, 5), "45F UF 66291 06635", ());
|
||||
TEST_EQUAL(FormatMGRS(-45.089793, 132.812340, 5), "53G LL 27848 04746", ());
|
||||
TEST_EQUAL(FormatMGRS(4.514602, 138.603457, 5), "54N TK 34069 99447", ());
|
||||
TEST_EQUAL(FormatMGRS(-67.547521, -142.303616, 5), "07D DF 44443 06997", ());
|
||||
TEST_EQUAL(FormatMGRS(-62.908852, -154.887008, 5), "05E ML 04130 23160", ());
|
||||
TEST_EQUAL(FormatMGRS(4.514602, -144.603447, 5), "06N YK 65931 99447", ());
|
||||
TEST_EQUAL(FormatMGRS(4.514602, -137.396543, 5), "08N KK 34069 99447", ());
|
||||
TEST_EQUAL(FormatMGRS(9.028532, -144.637149, 5), "06P YQ 59760 98847", ());
|
||||
TEST_EQUAL(FormatMGRS(54.109208, -60.059588, 5), "20U PE 92211 99669", ());
|
||||
TEST_EQUAL(FormatMGRS(54.109208, -53.940397, 5), "22U CE 07789 99669", ());
|
||||
TEST_EQUAL(FormatMGRS(-45.089793, -53.187660, 5), "22G CR 27848 04746", ());
|
||||
TEST_EQUAL(FormatMGRS(-31.596034, -18.161583, 5), "27J YF 69322 00842", ());
|
||||
TEST_EQUAL(FormatMGRS(-22.559756, -11.111475, 5), "29K KR 82882 03678", ());
|
||||
TEST_EQUAL(FormatMGRS(0.000005, 0.592333, 5), "31N BA 32007 00000", ());
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue