refactor timezoner a bit for unit tests, add initial unit tests
This commit is contained in:
parent
f268163ea0
commit
ca353eb7db
@ -3,6 +3,7 @@
|
||||
|
||||
#include "util/log.hpp"
|
||||
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/geometry.hpp>
|
||||
#include <boost/geometry/index/rtree.hpp>
|
||||
|
||||
@ -31,13 +32,14 @@ class Timezoner
|
||||
public:
|
||||
Timezoner() = default;
|
||||
|
||||
Timezoner(std::string tz_filename, std::time_t utc_time_now);
|
||||
Timezoner(const char geojson[], std::time_t utc_time_now);
|
||||
Timezoner(const boost::filesystem::path &tz_shapes_filename, std::time_t utc_time_now);
|
||||
|
||||
struct tm operator()(const point_t &point) const;
|
||||
|
||||
private:
|
||||
void LoadLocalTimesRTree(const std::string &tz_shapes_filename, std::time_t utc_time);
|
||||
void ValidateFeature(const rapidjson::Value &feature, const std::string &filename);
|
||||
void ValidateFeature(const rapidjson::Value &feature);
|
||||
void ValidateCoordinate(const rapidjson::Value &coordinate);
|
||||
void LoadLocalTimesRTree(rapidjson::Document &geojson, std::time_t utc_time);
|
||||
|
||||
struct tm default_time;
|
||||
rtree_t rtree;
|
||||
|
@ -2,6 +2,8 @@
|
||||
#include "util/log.hpp"
|
||||
#include "util/timezones.hpp"
|
||||
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/scope_exit.hpp>
|
||||
|
||||
#include "rapidjson/document.h"
|
||||
@ -19,73 +21,29 @@ namespace osrm
|
||||
namespace updater
|
||||
{
|
||||
|
||||
Timezoner::Timezoner(std::string tz_filename, std::time_t utc_time_now)
|
||||
Timezoner::Timezoner(const char geojson[], std::time_t utc_time_now)
|
||||
{
|
||||
util::Log() << "Time zone validation based on UTC time : " << utc_time_now;
|
||||
// Thread safety: MT-Unsafe const:env
|
||||
default_time = *gmtime(&utc_time_now);
|
||||
LoadLocalTimesRTree(tz_filename, utc_time_now);
|
||||
rapidjson::Document doc;
|
||||
doc.Parse(geojson);
|
||||
LoadLocalTimesRTree(doc, utc_time_now);
|
||||
}
|
||||
|
||||
void Timezoner::ValidateFeature(const rapidjson::Value &feature, const std::string &filename)
|
||||
Timezoner::Timezoner(const boost::filesystem::path &tz_shapes_filename, std::time_t utc_time_now)
|
||||
{
|
||||
if (!feature.HasMember("type"))
|
||||
{
|
||||
throw osrm::util::exception("Failed to parse " + filename +
|
||||
". Feature is missing type member.");
|
||||
} else if (!feature["type"].IsString())
|
||||
{
|
||||
throw osrm::util::exception("Failed to parse " + filename +
|
||||
". Feature non-string type member.");
|
||||
}
|
||||
if (!feature.HasMember("properties"))
|
||||
{
|
||||
throw osrm::util::exception("Failed to parse " + filename +
|
||||
". Feature is missing properties member.");
|
||||
}
|
||||
else if (!feature.GetObject()["properties"].IsObject())
|
||||
{
|
||||
throw osrm::util::exception("Failed to parse " + filename +
|
||||
". Feature has non-object properties member.");
|
||||
}
|
||||
if (!feature["properties"].GetObject().HasMember("TZID"))
|
||||
{
|
||||
throw osrm::util::exception("Failed to parse " + filename +
|
||||
". Feature is missing TZID member in properties.");
|
||||
}
|
||||
else if (!feature["properties"].GetObject()["TZID"].IsString())
|
||||
{
|
||||
throw osrm::util::exception("Failed to parse " + filename +
|
||||
". Feature has non-string TZID value.");
|
||||
}
|
||||
if (!feature.HasMember("geometry"))
|
||||
{
|
||||
throw osrm::util::exception("Failed to parse " + filename +
|
||||
". Feature is missing geometry member.");
|
||||
}
|
||||
else if (!feature.GetObject()["geometry"].IsObject())
|
||||
{
|
||||
throw osrm::util::exception("Failed to parse " + filename +
|
||||
". Feature non-object geometry member.");
|
||||
}
|
||||
util::Log() << "Time zone validation based on UTC time : " << utc_time_now;
|
||||
// Thread safety: MT-Unsafe const:env
|
||||
default_time = *gmtime(&utc_time_now);
|
||||
|
||||
if (!feature["geometry"].GetObject().HasMember("type"))
|
||||
throw osrm::util::exception("Failed to parse " + filename +
|
||||
". Feature geometry is missing type member.");
|
||||
if (!feature["geometry"].GetObject().HasMember("coordinates"))
|
||||
throw osrm::util::exception("Failed to parse " + filename +
|
||||
". Feature geometry is missing coordinates member.");
|
||||
}
|
||||
|
||||
void Timezoner::LoadLocalTimesRTree(const std::string &tz_shapes_filename, std::time_t utc_time)
|
||||
{
|
||||
if (tz_shapes_filename.empty())
|
||||
throw osrm::util::exception("Missing time zone geojson file");
|
||||
std::ifstream file(tz_shapes_filename.data());
|
||||
boost::filesystem::ifstream file(tz_shapes_filename);
|
||||
if (!file.is_open())
|
||||
throw osrm::util::exception("failed to open " + tz_shapes_filename);
|
||||
throw osrm::util::exception("failed to open " + tz_shapes_filename.string());
|
||||
|
||||
util::Log() << "Parsing " + tz_shapes_filename;
|
||||
util::Log() << "Parsing " + tz_shapes_filename.string();
|
||||
rapidjson::IStreamWrapper isw(file);
|
||||
rapidjson::Document geojson;
|
||||
geojson.ParseStream(isw);
|
||||
@ -93,15 +51,89 @@ void Timezoner::LoadLocalTimesRTree(const std::string &tz_shapes_filename, std::
|
||||
{
|
||||
auto error_code = geojson.GetParseError();
|
||||
auto error_offset = geojson.GetErrorOffset();
|
||||
throw osrm::util::exception("Failed to parse " + tz_shapes_filename + " with error " +
|
||||
throw osrm::util::exception("Failed to parse " + tz_shapes_filename.string() + " with error " +
|
||||
std::to_string(error_code) + ". JSON malformed at " + std::to_string(error_offset));
|
||||
}
|
||||
if (!geojson.HasMember("FeatureCollection"))
|
||||
throw osrm::util::exception("Failed to parse " + tz_shapes_filename +
|
||||
". Expecting a geojson feature collection.");
|
||||
if (!geojson["FeatureCollection"].GetObject().HasMember("features"))
|
||||
throw osrm::util::exception("Failed to parse " + tz_shapes_filename +
|
||||
". Missing features list.");
|
||||
LoadLocalTimesRTree(geojson, utc_time_now);
|
||||
}
|
||||
|
||||
void Timezoner::ValidateCoordinate(const rapidjson::Value &coordinate)
|
||||
{
|
||||
if (!coordinate.IsArray())
|
||||
throw osrm::util::exception("Failed to parse time zone file. Feature geometry has a non-array coordinate.");
|
||||
if (coordinate.Capacity() != 2)
|
||||
{
|
||||
throw osrm::util::exception("Failed to parse time zone file. Feature geometry has a malformed coordinate with more than 2 values.");
|
||||
} else {
|
||||
for (rapidjson::SizeType i = 0; i < coordinate.Size(); i++)
|
||||
{
|
||||
if (!coordinate[i].IsNumber() && !coordinate[i].IsDouble())
|
||||
throw osrm::util::exception("Failed to parse time zone file. Feature geometry has a non-number coordinate.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Timezoner::ValidateFeature(const rapidjson::Value &feature)
|
||||
{
|
||||
if (!feature.HasMember("type"))
|
||||
{
|
||||
throw osrm::util::exception("Failed to parse time zone file. Feature is missing type member.");
|
||||
} else if (!feature["type"].IsString())
|
||||
{
|
||||
throw osrm::util::exception("Failed to parse time zone file. Feature has non-string type member.");
|
||||
}
|
||||
if (!feature.HasMember("properties"))
|
||||
{
|
||||
throw osrm::util::exception("Failed to parse time zone file. Feature is missing properties member.");
|
||||
}
|
||||
else if (!feature.GetObject()["properties"].IsObject())
|
||||
{
|
||||
throw osrm::util::exception("Failed to parse time zone file. Feature has non-object properties member.");
|
||||
}
|
||||
if (!feature["properties"].GetObject().HasMember("TZID"))
|
||||
{
|
||||
throw osrm::util::exception("Failed to parse time zone file. Feature is missing TZID member in properties.");
|
||||
}
|
||||
else if (!feature["properties"].GetObject()["TZID"].IsString())
|
||||
{
|
||||
throw osrm::util::exception("Failed to parse time zone file. Feature has non-string TZID value.");
|
||||
}
|
||||
if (!feature.HasMember("geometry"))
|
||||
{
|
||||
throw osrm::util::exception("Failed to parse time zone file. Feature is missing geometry member.");
|
||||
}
|
||||
else if (!feature.GetObject()["geometry"].IsObject())
|
||||
{
|
||||
throw osrm::util::exception("Failed to parse time zone file. Feature non-object geometry member.");
|
||||
}
|
||||
|
||||
if (!feature["geometry"].GetObject().HasMember("type"))
|
||||
{
|
||||
throw osrm::util::exception("Failed to parse time zone file. Feature geometry is missing type member.");
|
||||
} else if (!feature["geometry"].GetObject()["type"].IsString()) {
|
||||
throw osrm::util::exception("Failed to parse time zone file. Feature geometry has non-string type member.");
|
||||
}
|
||||
if (!feature["geometry"].GetObject().HasMember("coordinates"))
|
||||
{
|
||||
throw osrm::util::exception("Failed to parse time zone file. Feature geometry is missing coordinates member.");
|
||||
} else if (!feature["geometry"].GetObject()["coordinates"].IsArray()) {
|
||||
throw osrm::util::exception("Failed to parse time zone file. Feature geometry has a non-array coordinates member.");
|
||||
}
|
||||
const auto coord_array = feature["geometry"].GetObject()["coordinates"].GetArray();
|
||||
if (coord_array.Empty())
|
||||
throw osrm::util::exception("Failed to parse time zone file. Feature geometry coordinates member is empty.");
|
||||
if (!coord_array[0].IsArray())
|
||||
throw osrm::util::exception("Failed to parse time zone file. Feature geometry coordinates array has non-array outer ring.");
|
||||
}
|
||||
|
||||
void Timezoner::LoadLocalTimesRTree(rapidjson::Document &geojson, std::time_t utc_time)
|
||||
{
|
||||
if (!geojson.HasMember("type"))
|
||||
throw osrm::util::exception("Failed to parse time zone file. Missing type member.");
|
||||
if (!geojson["type"].IsString())
|
||||
throw osrm::util::exception("Failed to parse time zone file. Missing string-based type member.");
|
||||
if (!geojson.HasMember("features"))
|
||||
throw osrm::util::exception("Failed to parse time zone file. Missing features list.");
|
||||
|
||||
// Lambda function that returns local time in the tzname time zone
|
||||
// Thread safety: MT-Unsafe const:env
|
||||
@ -120,11 +152,11 @@ void Timezoner::LoadLocalTimesRTree(const std::string &tz_shapes_filename, std::
|
||||
return it->second;
|
||||
};
|
||||
BOOST_ASSERT(geojson["features"].IsArray());
|
||||
const rapidjson::Value &features_array = geojson["features"].GetArray();
|
||||
const auto &features_array = geojson["features"].GetArray();
|
||||
std::vector<rtree_t::value_type> polygons;
|
||||
for (rapidjson::SizeType i = 0; i < features_array.Size(); i++)
|
||||
{
|
||||
ValidateFeature(features_array[i], tz_shapes_filename);
|
||||
ValidateFeature(features_array[i]);
|
||||
const std::string &feat_type = features_array[i].GetObject()["geometry"].GetObject()["type"].GetString();
|
||||
if (feat_type == "polygon")
|
||||
{
|
||||
@ -137,7 +169,7 @@ void Timezoner::LoadLocalTimesRTree(const std::string &tz_shapes_filename, std::
|
||||
.GetArray();
|
||||
for (rapidjson::SizeType i = 0; i < coords_outer_array.Size(); ++i)
|
||||
{
|
||||
// polygon.outer().emplace_back(object->padfX[vertex], object->padfY[vertex]);
|
||||
ValidateCoordinate(coords_outer_array[i]);
|
||||
const auto &coords = coords_outer_array[i].GetArray();
|
||||
polygon.outer().emplace_back(coords[0].GetDouble(), coords[1].GetDouble());
|
||||
}
|
||||
@ -151,9 +183,10 @@ void Timezoner::LoadLocalTimesRTree(const std::string &tz_shapes_filename, std::
|
||||
}
|
||||
else
|
||||
{
|
||||
util::Log() << "Skipping non-polygon shape in timezone file " + tz_shapes_filename;
|
||||
util::Log(logDEBUG) << "Skipping non-polygon shape in timezone file";
|
||||
}
|
||||
}
|
||||
util::Log() << "Parsed " << polygons.size() << "time zone polygons." << std::endl;
|
||||
// Create R-tree for collected shape polygons
|
||||
rtree = rtree_t(polygons);
|
||||
}
|
||||
|
@ -14,6 +14,10 @@ file(GLOB CustomizerTestsSources
|
||||
customizer_tests.cpp
|
||||
customizer/*.cpp)
|
||||
|
||||
file(GLOB UpdaterTestsSources
|
||||
updater_tests.cpp
|
||||
updater/*.cpp)
|
||||
|
||||
file(GLOB LibraryTestsSources
|
||||
library_tests.cpp
|
||||
library/*.cpp)
|
||||
@ -55,6 +59,11 @@ add_executable(customizer-tests
|
||||
${CustomizerTestsSources}
|
||||
$<TARGET_OBJECTS:CUSTOMIZER> $<TARGET_OBJECTS:UPDATER> $<TARGET_OBJECTS:UTIL>)
|
||||
|
||||
add_executable(updater-tests
|
||||
EXCLUDE_FROM_ALL
|
||||
${UpdaterTestsSources}
|
||||
$<TARGET_OBJECTS:UPDATER> $<TARGET_OBJECTS:UPDATER> $<TARGET_OBJECTS:UTIL>)
|
||||
|
||||
add_executable(library-tests
|
||||
EXCLUDE_FROM_ALL
|
||||
${LibraryTestsSources})
|
||||
@ -82,6 +91,7 @@ if(NOT WIN32 AND NOT Boost_USE_STATIC_LIBS)
|
||||
add_definitions(-DBOOST_TEST_DYN_LINK)
|
||||
endif()
|
||||
|
||||
set(UPDATER_TEST_DATA_DIR "${CMAKE_SOURCE_DIR}/unit_tests/updater")
|
||||
set(TEST_DATA_DIR "${CMAKE_SOURCE_DIR}/test/data")
|
||||
add_dependencies(library-tests osrm-extract osrm-contract osrm-partition)
|
||||
# We can't run this Makefile on windows
|
||||
@ -93,6 +103,7 @@ target_compile_definitions(extractor-tests PRIVATE COMPILE_DEFINITIONS OSRM_FIXT
|
||||
target_compile_definitions(library-tests PRIVATE COMPILE_DEFINITIONS OSRM_TEST_DATA_DIR="${TEST_DATA_DIR}")
|
||||
target_compile_definitions(library-extract-tests PRIVATE COMPILE_DEFINITIONS OSRM_TEST_DATA_DIR="${TEST_DATA_DIR}")
|
||||
target_compile_definitions(library-contract-tests PRIVATE COMPILE_DEFINITIONS OSRM_TEST_DATA_DIR="${TEST_DATA_DIR}")
|
||||
target_compile_definitions(updater-tests PRIVATE COMPILE_DEFINITIONS TEST_DATA_DIR="${UPDATER_TEST_DATA_DIR}")
|
||||
|
||||
target_include_directories(engine-tests PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_include_directories(library-tests PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
@ -101,16 +112,18 @@ target_include_directories(library-contract-tests PUBLIC ${CMAKE_CURRENT_SOURCE_
|
||||
target_include_directories(util-tests PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_include_directories(partition-tests PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_include_directories(customizer-tests PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_include_directories(updater-tests PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
target_link_libraries(engine-tests ${ENGINE_LIBRARIES} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} ${MAYBE_SHAPEFILE})
|
||||
target_link_libraries(extractor-tests ${EXTRACTOR_LIBRARIES} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} ${MAYBE_SHAPEFILE})
|
||||
target_link_libraries(partition-tests ${PARTITIONER_LIBRARIES} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} ${MAYBE_SHAPEFILE})
|
||||
target_link_libraries(customizer-tests ${CUSTOMIZER_LIBRARIES} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} ${MAYBE_SHAPEFILE})
|
||||
target_link_libraries(engine-tests ${ENGINE_LIBRARIES} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
|
||||
target_link_libraries(extractor-tests ${EXTRACTOR_LIBRARIES} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
|
||||
target_link_libraries(partition-tests ${PARTITIONER_LIBRARIES} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
|
||||
target_link_libraries(customizer-tests ${CUSTOMIZER_LIBRARIES} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
|
||||
target_link_libraries(updater-tests ${UPDATER_LIBRARIES} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
|
||||
target_link_libraries(library-tests osrm ${ENGINE_LIBRARIES} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
|
||||
target_link_libraries(library-extract-tests osrm_extract ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
|
||||
target_link_libraries(library-contract-tests osrm_contract ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
|
||||
target_link_libraries(server-tests osrm ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} ${MAYBE_SHAPEFILE})
|
||||
target_link_libraries(util-tests ${UTIL_LIBRARIES} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} ${MAYBE_SHAPEFILE})
|
||||
target_link_libraries(server-tests osrm ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
|
||||
target_link_libraries(util-tests ${UTIL_LIBRARIES} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
|
||||
|
||||
add_custom_target(tests
|
||||
DEPENDS engine-tests extractor-tests partition-tests customizer-tests library-tests library-extract-tests server-tests util-tests)
|
||||
DEPENDS engine-tests extractor-tests partition-tests updater-tests customizer-tests library-tests library-extract-tests server-tests util-tests)
|
||||
|
38
unit_tests/updater/test.geojson
Normal file
38
unit_tests/updater/test.geojson
Normal file
@ -0,0 +1,38 @@
|
||||
{
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {
|
||||
"TZID": "Europe\\/Berlin"
|
||||
},
|
||||
"geometry": {
|
||||
"type": "Polygon",
|
||||
"coordinates": [
|
||||
[
|
||||
[
|
||||
8.28369140625,
|
||||
48.88277959345126
|
||||
],
|
||||
[
|
||||
8.57757568359375,
|
||||
48.88277959345126
|
||||
],
|
||||
[
|
||||
8.57757568359375,
|
||||
49.07206662261101
|
||||
],
|
||||
[
|
||||
8.28369140625,
|
||||
49.07206662261101
|
||||
],
|
||||
[
|
||||
8.28369140625,
|
||||
48.88277959345126
|
||||
]
|
||||
], []
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
62
unit_tests/updater/timezoner.cpp
Normal file
62
unit_tests/updater/timezoner.cpp
Normal file
@ -0,0 +1,62 @@
|
||||
#include "util/exception.hpp"
|
||||
#include "util/timezones.hpp"
|
||||
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(timezoner)
|
||||
|
||||
using namespace osrm;
|
||||
using namespace osrm::updater;
|
||||
|
||||
BOOST_AUTO_TEST_CASE(timezoner_test)
|
||||
{
|
||||
const char json[] =
|
||||
"{ \"type\" : \"FeatureCollection\", \"features\": ["
|
||||
"{ \"type\" : \"Feature\","
|
||||
"\"properties\" : { \"TZID\" : \"Europe/Berlin\"}, \"geometry\" : { \"type\": \"polygon\", "
|
||||
"\"coordinates\": [[[8.28369,48.88277], [8.57757, "
|
||||
"48.88277], [8.57757, 49.07206], [8.28369, "
|
||||
"49.07206], [8.28369, 48.88277]]] }} ]}";
|
||||
std::time_t now = time(0);
|
||||
BOOST_CHECK_NO_THROW(Timezoner tz(json, now));
|
||||
|
||||
boost::filesystem::path test_path(TEST_DATA_DIR "/test.geojson");
|
||||
BOOST_CHECK_NO_THROW(Timezoner tz(test_path, now));
|
||||
|
||||
// missing opening bracket
|
||||
const char bad[] =
|
||||
"\"type\" : \"FeatureCollection\", \"features\": ["
|
||||
"{ \"type\" : \"Feature\","
|
||||
"\"properties\" : { \"TZID\" : \"Europe/Berlin\"}, \"geometry\" : { \"type\": \"polygon\", "
|
||||
"\"coordinates\": [[[8.28369,48.88277], [8.57757, "
|
||||
"48.88277], [8.57757, 49.07206], [8.28369, "
|
||||
"49.07206], [8.28369, 48.88277]]] }} ]}";
|
||||
BOOST_CHECK_THROW(Timezoner tz(bad, now), util::exception);
|
||||
|
||||
// missing/malformed FeatureCollection type field
|
||||
const char missing_type[] =
|
||||
"{ \"FeatureCollection\", \"features\": ["
|
||||
"{ \"type\" : \"Feature\","
|
||||
"\"properties\" : { \"TZID\" : \"Europe/Berlin\"}, \"geometry\" : { \"type\": \"polygon\", "
|
||||
"\"coordinates\": [[[8.28369,48.88277], [8.57757, "
|
||||
"48.88277], [8.57757, 49.07206], [8.28369, "
|
||||
"49.07206], [8.28369, 48.88277]]] }} ]}";
|
||||
BOOST_CHECK_THROW(Timezoner tz(missing_type, now), util::exception);
|
||||
|
||||
const char missing_featc[] =
|
||||
"{ \"type\" : \"Collection\", \"features\": ["
|
||||
"{ \"type\" : \"Feature\","
|
||||
"\"properties\" : { \"TZID\" : \"Europe/Berlin\"}, \"geometry\" : { \"type\": \"polygon\", "
|
||||
"\"coordinates\": [[[8.28369,48.88277], [8.57757, "
|
||||
"48.88277], [8.57757, 49.07206], [8.28369, "
|
||||
"49.07206], [8.28369, 48.88277]]] }} ]}";
|
||||
BOOST_CHECK_THROW(Timezoner tz(missing_featc, now), util::exception);
|
||||
|
||||
// missing features list
|
||||
const char missing_features[] =
|
||||
"{ \"type\" : \"FeatureCollection\", \"features\": null }";
|
||||
BOOST_CHECK_THROW(Timezoner tz(missing_features, now), util::exception);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
7
unit_tests/updater_tests.cpp
Normal file
7
unit_tests/updater_tests.cpp
Normal file
@ -0,0 +1,7 @@
|
||||
#define BOOST_TEST_MODULE customizer tests
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
/*
|
||||
* This file will contain an automatically generated main function.
|
||||
*/
|
Loading…
Reference in New Issue
Block a user