Merge commit '6bee8866de99a602039feef463c22c972f0f86aa' as 'third_party/vtzero'

This commit is contained in:
Michael Krasnyk
2018-04-19 22:03:52 +03:00
75 changed files with 28148 additions and 0 deletions
+81
View File
@@ -0,0 +1,81 @@
#-----------------------------------------------------------------------------
#
# CMake config
#
# vtzero tests
#
#-----------------------------------------------------------------------------
if(Boost_FOUND)
message(STATUS "Boost library found: enable testing with boost::variant")
add_definitions(-DVTZERO_TEST_WITH_VARIANT)
include_directories(SYSTEM ${Boost_INCLUDE_DIRS})
else()
message(STATUS "Boost library not found: disable testing with boost::variant")
endif()
include_directories(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/catch")
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/include")
set(TEST_SOURCES builder
builder_linestring
builder_point
builder_polygon
exceptions
feature
geometry
geometry_linestring
geometry_point
geometry_polygon
index
layer
output
point
property_map
property_value
types
vector_tile)
string(REGEX REPLACE "([^;]+)" "t/test_\\1.cpp" _test_sources "${TEST_SOURCES}")
add_executable(unit-tests test_main.cpp ${_test_sources})
add_executable(fixture-tests test_main.cpp fixture_tests.cpp)
add_test(NAME unit-tests
COMMAND unit-tests
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
set(_fixtures ${MVT_FIXTURES}/fixtures)
if(EXISTS ${_fixtures})
message(STATUS "Found test fixtures. Enabled mvt fixture tests.")
add_test(NAME fixture-tests
COMMAND fixture-tests)
set_tests_properties(fixture-tests PROPERTIES
ENVIRONMENT "FIXTURES_DIR=${_fixtures}")
if(NOT WIN32)
set(_real_world_dir ${MVT_FIXTURES}/real-world)
file(GLOB real_world ${_real_world_dir}/bangkok/*
${_real_world_dir}/chicago/*
${_real_world_dir}/nepal/*
${_real_world_dir}/norway/*
${_real_world_dir}/sanfrancisco/*
${_real_world_dir}/uruguay/*)
if(NOT "${real_world}" STREQUAL "")
execute_process(COMMAND cat ${real_world}
OUTPUT_FILE ${CMAKE_CURRENT_BINARY_DIR}/real-world-all.mvt)
add_test(NAME vtzero-show-real-world
COMMAND vtzero-show ${CMAKE_BINARY_DIR}/test/real-world-all.mvt)
endif()
endif()
else()
message(WARNING "Disabled mvt fixture tests, because fixtures not found.\n Install them by calling 'git submodule update --init' in ${CMAKE_SOURCE_DIR}.")
endif()
#-----------------------------------------------------------------------------
File diff suppressed because it is too large Load Diff
Binary file not shown.
File diff suppressed because it is too large Load Diff
+37
View File
@@ -0,0 +1,37 @@
#ifndef TEST_HPP
#define TEST_HPP
#include <catch.hpp>
#include <stdexcept>
// Define vtzero_assert() to throw this error. This allows the tests to
// check that the assert fails.
struct assert_error : public std::runtime_error {
explicit assert_error(const char* what_arg) : std::runtime_error(what_arg) {
}
};
#define vtzero_assert(x) if (!(x)) { throw assert_error{#x}; }
#define vtzero_assert_in_noexcept_function(x) if (!(x)) { got_an_assert = true; }
extern bool got_an_assert;
#define REQUIRE_ASSERT(x) x; REQUIRE(got_an_assert); got_an_assert = false;
#include <vtzero/output.hpp>
std::string load_test_tile();
struct mypoint {
int64_t p1;
int64_t p2;
};
inline vtzero::point create_vtzero_point(mypoint p) noexcept {
return {static_cast<int32_t>(p.p1),
static_cast<int32_t>(p.p2)};
}
#endif // TEST_HPP
Submodule third_party/vtzero/test/mvt-fixtures added at 6ff9cefd59
+408
View File
@@ -0,0 +1,408 @@
#include <test.hpp>
#include <vtzero/builder.hpp>
#include <vtzero/index.hpp>
#include <vtzero/output.hpp>
#include <cstdint>
#include <string>
#include <type_traits>
template <typename T>
struct movable_not_copyable {
constexpr static bool value = !std::is_copy_constructible<T>::value &&
!std::is_copy_assignable<T>::value &&
std::is_nothrow_move_constructible<T>::value &&
std::is_nothrow_move_assignable<T>::value;
};
static_assert(movable_not_copyable<vtzero::tile_builder>::value, "tile_builder should be nothrow movable, but not copyable");
static_assert(movable_not_copyable<vtzero::point_feature_builder>::value, "point_feature_builder should be nothrow movable, but not copyable");
static_assert(movable_not_copyable<vtzero::linestring_feature_builder>::value, "linestring_feature_builder should be nothrow movable, but not copyable");
static_assert(movable_not_copyable<vtzero::polygon_feature_builder>::value, "polygon_feature_builder should be nothrow movable, but not copyable");
static_assert(movable_not_copyable<vtzero::geometry_feature_builder>::value, "geometry_feature_builder should be nothrow movable, but not copyable");
TEST_CASE("Create tile from existing layers") {
const auto buffer = load_test_tile();
vtzero::vector_tile tile{buffer};
vtzero::tile_builder tbuilder;
SECTION("add_existing_layer(layer)") {
while (auto layer = tile.next_layer()) {
tbuilder.add_existing_layer(layer);
}
}
SECTION("add_existing_layer(data_view)") {
while (auto layer = tile.next_layer()) {
tbuilder.add_existing_layer(layer.data());
}
}
const std::string data = tbuilder.serialize();
REQUIRE(data == buffer);
}
TEST_CASE("Create layer based on existing layer") {
const auto buffer = load_test_tile();
vtzero::vector_tile tile{buffer};
const auto layer = tile.get_layer_by_name("place_label");
vtzero::tile_builder tbuilder;
vtzero::layer_builder lbuilder{tbuilder, layer};
vtzero::point_feature_builder fbuilder{lbuilder};
fbuilder.set_id(42);
fbuilder.add_point(10, 20);
fbuilder.commit();
const std::string data = tbuilder.serialize();
vtzero::vector_tile new_tile{data};
const auto new_layer = new_tile.next_layer();
REQUIRE(std::string(new_layer.name()) == "place_label");
REQUIRE(new_layer.version() == 1);
REQUIRE(new_layer.extent() == 4096);
}
TEST_CASE("Create layer and add keys/values") {
vtzero::tile_builder tbuilder;
vtzero::layer_builder lbuilder{tbuilder, "name"};
const auto ki1 = lbuilder.add_key_without_dup_check("key1");
const auto ki2 = lbuilder.add_key("key2");
const auto ki3 = lbuilder.add_key("key1");
REQUIRE(ki1 != ki2);
REQUIRE(ki1 == ki3);
const auto vi1 = lbuilder.add_value_without_dup_check(vtzero::encoded_property_value{"value1"});
vtzero::encoded_property_value value2{"value2"};
const auto vi2 = lbuilder.add_value_without_dup_check(vtzero::property_value{value2.data()});
const auto vi3 = lbuilder.add_value(vtzero::encoded_property_value{"value1"});
const auto vi4 = lbuilder.add_value(vtzero::encoded_property_value{19});
const auto vi5 = lbuilder.add_value(vtzero::encoded_property_value{19.0});
const auto vi6 = lbuilder.add_value(vtzero::encoded_property_value{22});
vtzero::encoded_property_value nineteen{19};
const auto vi7 = lbuilder.add_value(vtzero::property_value{nineteen.data()});
REQUIRE(vi1 != vi2);
REQUIRE(vi1 == vi3);
REQUIRE(vi1 != vi4);
REQUIRE(vi1 != vi5);
REQUIRE(vi1 != vi6);
REQUIRE(vi4 != vi5);
REQUIRE(vi4 != vi6);
REQUIRE(vi4 == vi7);
}
TEST_CASE("Committing a feature succeeds after a geometry was added") {
vtzero::tile_builder tbuilder;
vtzero::layer_builder lbuilder{tbuilder, "test"};
{ // explicit commit after geometry
vtzero::point_feature_builder fbuilder{lbuilder};
fbuilder.set_id(1);
fbuilder.add_point(10, 10);
fbuilder.commit();
}
{ // explicit commit after properties
vtzero::point_feature_builder fbuilder{lbuilder};
fbuilder.set_id(2);
fbuilder.add_point(10, 10);
fbuilder.add_property("foo", vtzero::encoded_property_value{"bar"});
fbuilder.commit();
}
{ // extra commits or rollbacks are okay but no other calls
vtzero::point_feature_builder fbuilder{lbuilder};
fbuilder.set_id(3);
fbuilder.add_point(10, 10);
fbuilder.add_property("foo", vtzero::encoded_property_value{"bar"});
fbuilder.commit();
SECTION("superfluous commit()") {
fbuilder.commit();
}
SECTION("superfluous rollback()") {
fbuilder.rollback();
}
REQUIRE_THROWS_AS(fbuilder.set_id(10), const assert_error&);
REQUIRE_THROWS_AS(fbuilder.add_point(20, 20), const assert_error&);
REQUIRE_THROWS_AS(fbuilder.add_property("x", "y"), const assert_error&);
}
const std::string data = tbuilder.serialize();
vtzero::vector_tile tile{data};
auto layer = tile.next_layer();
uint64_t n = 1;
while (auto feature = layer.next_feature()) {
REQUIRE(feature.id() == n++);
}
REQUIRE(n == 4);
}
TEST_CASE("Committing a feature fails with assert if no geometry was added") {
vtzero::tile_builder tbuilder;
vtzero::layer_builder lbuilder{tbuilder, "test"};
SECTION("explicit immediate commit") {
vtzero::point_feature_builder fbuilder{lbuilder};
REQUIRE_THROWS_AS(fbuilder.commit(), const assert_error&);
}
SECTION("explicit commit after setting id") {
vtzero::point_feature_builder fbuilder{lbuilder};
fbuilder.set_id(2);
REQUIRE_THROWS_AS(fbuilder.commit(), const assert_error&);
}
}
TEST_CASE("Rollback feature") {
vtzero::tile_builder tbuilder;
vtzero::layer_builder lbuilder{tbuilder, "test"};
{
vtzero::point_feature_builder fbuilder{lbuilder};
fbuilder.set_id(1);
fbuilder.add_point(10, 10);
fbuilder.commit();
}
{ // immediate rollback
vtzero::point_feature_builder fbuilder{lbuilder};
fbuilder.set_id(2);
fbuilder.rollback();
}
{ // rollback after setting id
vtzero::point_feature_builder fbuilder{lbuilder};
fbuilder.set_id(3);
fbuilder.rollback();
}
{ // rollback after geometry
vtzero::point_feature_builder fbuilder{lbuilder};
fbuilder.set_id(4);
fbuilder.add_point(20, 20);
fbuilder.rollback();
}
{ // rollback after properties
vtzero::point_feature_builder fbuilder{lbuilder};
fbuilder.set_id(5);
fbuilder.add_point(20, 20);
fbuilder.add_property("foo", vtzero::encoded_property_value{"bar"});
fbuilder.rollback();
}
{ // implicit rollback after geometry
vtzero::point_feature_builder fbuilder{lbuilder};
fbuilder.set_id(6);
fbuilder.add_point(10, 10);
}
{ // implicit rollback after properties
vtzero::point_feature_builder fbuilder{lbuilder};
fbuilder.set_id(7);
fbuilder.add_point(10, 10);
fbuilder.add_property("foo", vtzero::encoded_property_value{"bar"});
}
{
vtzero::point_feature_builder fbuilder{lbuilder};
fbuilder.set_id(8);
fbuilder.add_point(30, 30);
fbuilder.commit();
}
const std::string data = tbuilder.serialize();
vtzero::vector_tile tile{data};
auto layer = tile.next_layer();
auto feature = layer.next_feature();
REQUIRE(feature.id() == 1);
feature = layer.next_feature();
REQUIRE(feature.id() == 8);
feature = layer.next_feature();
REQUIRE_FALSE(feature);
}
static bool vector_tile_equal(const std::string& t1, const std::string& t2) {
vtzero::vector_tile vt1{t1};
vtzero::vector_tile vt2{t2};
for (auto l1 = vt1.next_layer(), l2 = vt2.next_layer();
l1 && l2;
l1 = vt1.next_layer(), l2 = vt2.next_layer()) {
if (l1.empty()) {
l1 = vt1.next_layer();
if (!l1) {
return true;
}
}
if (l2.empty()) {
l2 = vt2.next_layer();
if (!l2) {
return true;
}
}
if (!l1 ||
!l2 ||
l1.version() != l2.version() ||
l1.extent() != l2.extent() ||
l1.num_features() != l2.num_features() ||
l1.name() != l2.name()) {
return false;
}
for (auto f1 = l1.next_feature(), f2 = l2.next_feature();
f1 && f2;
f1 = l1.next_feature(), f2 = l2.next_feature()) {
if (f1.id() != f2.id() ||
f1.geometry_type() != f2.geometry_type() ||
f1.num_properties() != f2.num_properties() ||
f1.geometry().data() != f2.geometry().data()) {
return false;
}
for (auto p1 = f1.next_property(), p2 = f2.next_property();
p1 && p2;
p1 = f1.next_property(), p2 = f2.next_property()) {
if (p1.key() != p2.key() || p1.value() != p2.value()) {
return false;
}
}
}
}
return true;
}
TEST_CASE("Copy tile") {
const auto buffer = load_test_tile();
vtzero::vector_tile tile{buffer};
vtzero::tile_builder tbuilder;
while (auto layer = tile.next_layer()) {
vtzero::layer_builder lbuilder{tbuilder, layer};
while (auto feature = layer.next_feature()) {
lbuilder.add_feature(feature);
}
}
const std::string data = tbuilder.serialize();
REQUIRE(vector_tile_equal(buffer, data));
}
TEST_CASE("Copy tile using geometry_feature_builder") {
const auto buffer = load_test_tile();
vtzero::vector_tile tile{buffer};
vtzero::tile_builder tbuilder;
while (auto layer = tile.next_layer()) {
vtzero::layer_builder lbuilder{tbuilder, layer};
while (auto feature = layer.next_feature()) {
vtzero::geometry_feature_builder fbuilder{lbuilder};
fbuilder.set_id(feature.id());
fbuilder.set_geometry(feature.geometry());
while (auto property = feature.next_property()) {
fbuilder.add_property(property.key(), property.value());
}
fbuilder.commit();
}
}
const std::string data = tbuilder.serialize();
REQUIRE(vector_tile_equal(buffer, data));
}
TEST_CASE("Copy only point geometries using geometry_feature_builder") {
const auto buffer = load_test_tile();
vtzero::vector_tile tile{buffer};
vtzero::tile_builder tbuilder;
int n = 0;
while (auto layer = tile.next_layer()) {
vtzero::layer_builder lbuilder{tbuilder, layer};
while (auto feature = layer.next_feature()) {
vtzero::geometry_feature_builder fbuilder{lbuilder};
fbuilder.set_id(feature.id());
if (feature.geometry().type() == vtzero::GeomType::POINT) {
fbuilder.set_geometry(feature.geometry());
while (auto property = feature.next_property()) {
fbuilder.add_property(property.key(), property.value());
}
fbuilder.commit();
++n;
} else {
fbuilder.rollback();
}
}
}
REQUIRE(n == 17);
const std::string data = tbuilder.serialize();
n = 0;
vtzero::vector_tile result_tile{data};
while (auto layer = result_tile.next_layer()) {
while (auto feature = layer.next_feature()) {
++n;
}
}
REQUIRE(n == 17);
}
TEST_CASE("Build point feature from container with too many points") {
// fake container pretending to contain too many points
struct test_container {
std::size_t size() const noexcept {
return 1ul << 29u;
}
vtzero::point* begin() const noexcept {
return nullptr;
}
vtzero::point* end() const noexcept {
return nullptr;
}
};
vtzero::tile_builder tbuilder;
vtzero::layer_builder lbuilder{tbuilder, "test"};
vtzero::point_feature_builder fbuilder{lbuilder};
fbuilder.set_id(1);
test_container tc;
REQUIRE_THROWS_AS(fbuilder.add_points_from_container(tc), const vtzero::geometry_exception&);
}
TEST_CASE("Moving a feature builder is allowed") {
vtzero::tile_builder tbuilder;
vtzero::layer_builder lbuilder{tbuilder, "test"};
vtzero::point_feature_builder fbuilder{lbuilder};
auto fbuilder2 = std::move(fbuilder);
vtzero::point_feature_builder fbuilder3{std::move(fbuilder2)};
}
+312
View File
@@ -0,0 +1,312 @@
#include <test.hpp>
#include <vtzero/builder.hpp>
#include <vtzero/geometry.hpp>
#include <vtzero/index.hpp>
#include <cstdint>
#include <string>
#include <type_traits>
#include <vector>
using ls_type = std::vector<std::vector<vtzero::point>>;
struct linestring_handler {
ls_type data;
void linestring_begin(uint32_t count) {
data.emplace_back();
data.back().reserve(count);
}
void linestring_point(const vtzero::point point) {
data.back().push_back(point);
}
void linestring_end() const noexcept {
}
};
static void test_linestring_builder(bool with_id, bool with_prop) {
vtzero::tile_builder tbuilder;
vtzero::layer_builder lbuilder{tbuilder, "test"};
{
vtzero::linestring_feature_builder fbuilder{lbuilder};
if (with_id) {
fbuilder.set_id(17);
}
fbuilder.add_linestring(3);
fbuilder.set_point(10, 20);
fbuilder.set_point(vtzero::point{20, 30});
fbuilder.set_point(mypoint{30, 40});
if (with_prop) {
fbuilder.add_property("foo", "bar");
}
fbuilder.commit();
}
const std::string data = tbuilder.serialize();
vtzero::vector_tile tile{data};
auto layer = tile.next_layer();
REQUIRE(layer.name() == "test");
REQUIRE(layer.version() == 2);
REQUIRE(layer.extent() == 4096);
REQUIRE(layer.num_features() == 1);
const auto feature = layer.next_feature();
REQUIRE(feature.id() == (with_id ? 17 : 0));
linestring_handler handler;
vtzero::decode_linestring_geometry(feature.geometry(), handler);
const ls_type result = {{{10, 20}, {20, 30}, {30, 40}}};
REQUIRE(handler.data == result);
}
TEST_CASE("linestring builder without id/without properties") {
test_linestring_builder(false, false);
}
TEST_CASE("linestring builder without id/with properties") {
test_linestring_builder(false, true);
}
TEST_CASE("linestring builder with id/without properties") {
test_linestring_builder(true, false);
}
TEST_CASE("linestring builder with id/with properties") {
test_linestring_builder(true, true);
}
TEST_CASE("Calling add_linestring() with bad values throws assert") {
vtzero::tile_builder tbuilder;
vtzero::layer_builder lbuilder{tbuilder, "test"};
vtzero::linestring_feature_builder fbuilder{lbuilder};
SECTION("0") {
REQUIRE_THROWS_AS(fbuilder.add_linestring(0), const assert_error&);
}
SECTION("1") {
REQUIRE_THROWS_AS(fbuilder.add_linestring(1), const assert_error&);
}
SECTION("2^29") {
REQUIRE_THROWS_AS(fbuilder.add_linestring(1ul << 29u), const assert_error&);
}
}
static void test_multilinestring_builder(bool with_id, bool with_prop) {
vtzero::tile_builder tbuilder;
vtzero::layer_builder lbuilder{tbuilder, "test"};
vtzero::linestring_feature_builder fbuilder{lbuilder};
if (with_id) {
fbuilder.set_id(17);
}
fbuilder.add_linestring(3);
fbuilder.set_point(10, 20);
fbuilder.set_point(vtzero::point{20, 30});
fbuilder.set_point(mypoint{30, 40});
fbuilder.add_linestring(2);
fbuilder.set_point(1, 2);
fbuilder.set_point(2, 1);
if (with_prop) {
fbuilder.add_property("foo", vtzero::encoded_property_value{"bar"});
}
fbuilder.commit();
const std::string data = tbuilder.serialize();
vtzero::vector_tile tile{data};
auto layer = tile.next_layer();
REQUIRE(layer.name() == "test");
REQUIRE(layer.version() == 2);
REQUIRE(layer.extent() == 4096);
REQUIRE(layer.num_features() == 1);
const auto feature = layer.next_feature();
REQUIRE(feature.id() == (with_id ? 17 : 0));
linestring_handler handler;
vtzero::decode_linestring_geometry(feature.geometry(), handler);
const ls_type result = {{{10, 20}, {20, 30}, {30, 40}}, {{1, 2}, {2, 1}}};
REQUIRE(handler.data == result);
}
TEST_CASE("Multilinestring builder without id/without properties") {
test_multilinestring_builder(false, false);
}
TEST_CASE("Multilinestring builder without id/with properties") {
test_multilinestring_builder(false, true);
}
TEST_CASE("Multilinestring builder with id/without properties") {
test_multilinestring_builder(true, false);
}
TEST_CASE("Multilinestring builder with id/with properties") {
test_multilinestring_builder(true, true);
}
TEST_CASE("Calling add_linestring() twice throws assert") {
vtzero::tile_builder tbuilder;
vtzero::layer_builder lbuilder{tbuilder, "test"};
vtzero::linestring_feature_builder fbuilder{lbuilder};
fbuilder.add_linestring(3);
REQUIRE_ASSERT(fbuilder.add_linestring(2));
}
TEST_CASE("Calling linestring_feature_builder::set_point() throws assert") {
vtzero::tile_builder tbuilder;
vtzero::layer_builder lbuilder{tbuilder, "test"};
vtzero::linestring_feature_builder fbuilder{lbuilder};
REQUIRE_THROWS_AS(fbuilder.set_point(10, 10), const assert_error&);
}
TEST_CASE("Calling linestring_feature_builder::set_point() with same point throws") {
vtzero::tile_builder tbuilder;
vtzero::layer_builder lbuilder{tbuilder, "test"};
vtzero::linestring_feature_builder fbuilder{lbuilder};
fbuilder.add_linestring(2);
fbuilder.set_point(10, 10);
REQUIRE_THROWS_AS(fbuilder.set_point(10, 10), const vtzero::geometry_exception&);
}
TEST_CASE("Calling linestring_feature_builder::set_point() too often throws assert") {
vtzero::tile_builder tbuilder;
vtzero::layer_builder lbuilder{tbuilder, "test"};
vtzero::linestring_feature_builder fbuilder{lbuilder};
fbuilder.add_linestring(2);
fbuilder.set_point(10, 20);
fbuilder.set_point(20, 20);
REQUIRE_THROWS_AS(fbuilder.set_point(30, 20), const assert_error&);
}
TEST_CASE("Add linestring from container") {
const ls_type points = {{{10, 20}, {20, 30}, {30, 40}}};
vtzero::tile_builder tbuilder;
vtzero::layer_builder lbuilder{tbuilder, "test"};
{
vtzero::linestring_feature_builder fbuilder{lbuilder};
#if 0
SECTION("using iterators") {
fbuilder.add_linestring(points[0].cbegin(), points[0].cend());
}
SECTION("using iterators and size") {
fbuilder.add_linestring(points[0].cbegin(), points[0].cend(), static_cast<uint32_t>(points[0].size()));
}
#endif
SECTION("using container directly") {
fbuilder.add_linestring_from_container(points[0]);
}
fbuilder.commit();
}
const std::string data = tbuilder.serialize();
vtzero::vector_tile tile{data};
auto layer = tile.next_layer();
REQUIRE(layer);
REQUIRE(layer.name() == "test");
REQUIRE(layer.version() == 2);
REQUIRE(layer.extent() == 4096);
REQUIRE(layer.num_features() == 1);
const auto feature = layer.next_feature();
linestring_handler handler;
vtzero::decode_linestring_geometry(feature.geometry(), handler);
REQUIRE(handler.data == points);
}
#if 0
TEST_CASE("Add linestring from iterator with wrong count throws assert") {
const std::vector<vtzero::point> points = {{10, 20}, {20, 30}, {30, 40}};
vtzero::tile_builder tbuilder;
vtzero::layer_builder lbuilder{tbuilder, "test"};
vtzero::linestring_feature_builder fbuilder{lbuilder};
REQUIRE_THROWS_AS(fbuilder.add_linestring(points.cbegin(),
points.cend(),
static_cast<uint32_t>(points.size() + 1)), const assert_error&);
}
#endif
TEST_CASE("Adding several linestrings with feature rollback in the middle") {
vtzero::tile_builder tbuilder;
vtzero::layer_builder lbuilder{tbuilder, "test"};
{
vtzero::linestring_feature_builder fbuilder{lbuilder};
fbuilder.set_id(1);
fbuilder.add_linestring(2);
fbuilder.set_point(10, 10);
fbuilder.set_point(20, 20);
fbuilder.commit();
}
try {
vtzero::linestring_feature_builder fbuilder{lbuilder};
fbuilder.set_id(2);
fbuilder.add_linestring(2);
fbuilder.set_point(10, 10);
fbuilder.set_point(10, 10);
fbuilder.commit();
} catch (vtzero::geometry_exception&) {
}
{
vtzero::linestring_feature_builder fbuilder{lbuilder};
fbuilder.set_id(3);
fbuilder.add_linestring(2);
fbuilder.set_point(10, 20);
fbuilder.set_point(20, 10);
fbuilder.commit();
}
const std::string data = tbuilder.serialize();
vtzero::vector_tile tile{data};
auto layer = tile.next_layer();
REQUIRE(layer);
REQUIRE(layer.name() == "test");
REQUIRE(layer.num_features() == 2);
auto feature = layer.next_feature();
REQUIRE(feature.id() == 1);
feature = layer.next_feature();
REQUIRE(feature.id() == 3);
}
+279
View File
@@ -0,0 +1,279 @@
#include <test.hpp>
#include <vtzero/builder.hpp>
#include <vtzero/geometry.hpp>
#include <vtzero/index.hpp>
#include <cstdint>
#include <string>
#include <type_traits>
#include <vector>
struct point_handler {
std::vector<vtzero::point> data;
void points_begin(uint32_t count) {
data.reserve(count);
}
void points_point(const vtzero::point point) {
data.push_back(point);
}
void points_end() const noexcept {
}
};
static void test_point_builder(bool with_id, bool with_prop) {
vtzero::tile_builder tbuilder;
vtzero::layer_builder lbuilder{tbuilder, "test"};
{
vtzero::point_feature_builder fbuilder{lbuilder};
if (with_id) {
fbuilder.set_id(17);
}
SECTION("add point using coordinates / property using key/value") {
fbuilder.add_point(10, 20);
if (with_prop) {
fbuilder.add_property("foo", vtzero::encoded_property_value{"bar"});
}
}
SECTION("add point using vtzero::point / property using key/value") {
fbuilder.add_point(vtzero::point{10, 20});
if (with_prop) {
fbuilder.add_property("foo", vtzero::encoded_property_value{22});
}
}
SECTION("add point using mypoint / property using property") {
vtzero::encoded_property_value pv{3.5};
vtzero::property p{"foo", vtzero::property_value{pv.data()}};
fbuilder.add_point(mypoint{10, 20});
if (with_prop) {
fbuilder.add_property(p);
}
}
fbuilder.commit();
}
const std::string data = tbuilder.serialize();
vtzero::vector_tile tile{data};
auto layer = tile.next_layer();
REQUIRE(layer.name() == "test");
REQUIRE(layer.version() == 2);
REQUIRE(layer.extent() == 4096);
REQUIRE(layer.num_features() == 1);
const auto feature = layer.next_feature();
REQUIRE(feature.id() == (with_id ? 17 : 0));
point_handler handler;
vtzero::decode_point_geometry(feature.geometry(), handler);
const std::vector<vtzero::point> result = {{10, 20}};
REQUIRE(handler.data == result);
}
TEST_CASE("Point builder without id/without properties") {
test_point_builder(false, false);
}
TEST_CASE("Point builder without id/with properties") {
test_point_builder(false, true);
}
TEST_CASE("Point builder with id/without properties") {
test_point_builder(true, false);
}
TEST_CASE("Point builder with id/with properties") {
test_point_builder(true, true);
}
TEST_CASE("Calling add_points() with bad values throws assert") {
vtzero::tile_builder tbuilder;
vtzero::layer_builder lbuilder{tbuilder, "test"};
vtzero::point_feature_builder fbuilder{lbuilder};
SECTION("0") {
REQUIRE_THROWS_AS(fbuilder.add_points(0), const assert_error&);
}
SECTION("2^29") {
REQUIRE_THROWS_AS(fbuilder.add_points(1ul << 29u), const assert_error&);
}
}
static void test_multipoint_builder(bool with_id, bool with_prop) {
vtzero::tile_builder tbuilder;
vtzero::layer_builder lbuilder{tbuilder, "test"};
vtzero::point_feature_builder fbuilder{lbuilder};
if (with_id) {
fbuilder.set_id(17);
}
fbuilder.add_points(3);
fbuilder.set_point(10, 20);
fbuilder.set_point(vtzero::point{20, 30});
fbuilder.set_point(mypoint{30, 40});
if (with_prop) {
fbuilder.add_property("foo", vtzero::encoded_property_value{"bar"});
}
fbuilder.commit();
const std::string data = tbuilder.serialize();
vtzero::vector_tile tile{data};
auto layer = tile.next_layer();
REQUIRE(layer.name() == "test");
REQUIRE(layer.version() == 2);
REQUIRE(layer.extent() == 4096);
REQUIRE(layer.num_features() == 1);
const auto feature = layer.next_feature();
REQUIRE(feature.id() == (with_id ? 17 : 0));
point_handler handler;
vtzero::decode_point_geometry(feature.geometry(), handler);
const std::vector<vtzero::point> result = {{10, 20}, {20, 30}, {30, 40}};
REQUIRE(handler.data == result);
}
TEST_CASE("Multipoint builder without id/without properties") {
test_multipoint_builder(false, false);
}
TEST_CASE("Multipoint builder without id/with properties") {
test_multipoint_builder(false, true);
}
TEST_CASE("Multipoint builder with id/without properties") {
test_multipoint_builder(true, false);
}
TEST_CASE("Multipoint builder with id/with properties") {
test_multipoint_builder(true, true);
}
TEST_CASE("Calling add_point() and then other geometry functions throws assert") {
vtzero::tile_builder tbuilder;
vtzero::layer_builder lbuilder{tbuilder, "test"};
vtzero::point_feature_builder fbuilder{lbuilder};
fbuilder.add_point(10, 20);
SECTION("add_point()") {
REQUIRE_THROWS_AS(fbuilder.add_point(10, 20), const assert_error&);
}
SECTION("add_points()") {
REQUIRE_THROWS_AS(fbuilder.add_points(2), const assert_error&);
}
SECTION("set_point()") {
REQUIRE_THROWS_AS(fbuilder.set_point(10, 10), const assert_error&);
}
}
TEST_CASE("Calling point_feature_builder::set_point() throws assert") {
vtzero::tile_builder tbuilder;
vtzero::layer_builder lbuilder{tbuilder, "test"};
vtzero::point_feature_builder fbuilder{lbuilder};
REQUIRE_THROWS_AS(fbuilder.set_point(10, 10), const assert_error&);
}
TEST_CASE("Calling add_points() and then other geometry functions throws assert") {
vtzero::tile_builder tbuilder;
vtzero::layer_builder lbuilder{tbuilder, "test"};
vtzero::point_feature_builder fbuilder{lbuilder};
fbuilder.add_points(2);
SECTION("add_point()") {
REQUIRE_THROWS_AS(fbuilder.add_point(10, 20), const assert_error&);
}
SECTION("add_points()") {
REQUIRE_THROWS_AS(fbuilder.add_points(2), const assert_error&);
}
}
TEST_CASE("Calling point_feature_builder::set_point() too often throws assert") {
vtzero::tile_builder tbuilder;
vtzero::layer_builder lbuilder{tbuilder, "test"};
vtzero::point_feature_builder fbuilder{lbuilder};
fbuilder.add_points(2);
fbuilder.set_point(10, 20);
fbuilder.set_point(20, 20);
REQUIRE_THROWS_AS(fbuilder.set_point(30, 20), const assert_error&);
}
TEST_CASE("Add points from container") {
const std::vector<vtzero::point> points = {{10, 20}, {20, 30}, {30, 40}};
vtzero::tile_builder tbuilder;
vtzero::layer_builder lbuilder{tbuilder, "test"};
{
vtzero::point_feature_builder fbuilder{lbuilder};
/* SECTION("using iterators") {
fbuilder.add_points(points.cbegin(), points.cend());
}
SECTION("using iterators and size") {
fbuilder.add_points(points.cbegin(), points.cend(), static_cast<uint32_t>(points.size()));
}*/
SECTION("using container directly") {
fbuilder.add_points_from_container(points);
}
fbuilder.commit();
}
const std::string data = tbuilder.serialize();
vtzero::vector_tile tile{data};
auto layer = tile.next_layer();
REQUIRE(layer);
REQUIRE(layer.name() == "test");
REQUIRE(layer.version() == 2);
REQUIRE(layer.extent() == 4096);
REQUIRE(layer.num_features() == 1);
const auto feature = layer.next_feature();
point_handler handler;
vtzero::decode_point_geometry(feature.geometry(), handler);
REQUIRE(handler.data == points);
}
/*
TEST_CASE("Add points from iterator with wrong count throws assert") {
const std::vector<vtzero::point> points = {{10, 20}, {20, 30}, {30, 40}};
vtzero::tile_builder tbuilder;
vtzero::layer_builder lbuilder{tbuilder, "test"};
vtzero::point_feature_builder fbuilder{lbuilder};
REQUIRE_THROWS_AS(fbuilder.add_points(points.cbegin(),
points.cend(),
static_cast<uint32_t>(points.size() + 1)), const assert_error&);
}*/
+307
View File
@@ -0,0 +1,307 @@
#include <test.hpp>
#include <vtzero/builder.hpp>
#include <vtzero/geometry.hpp>
#include <vtzero/index.hpp>
#include <cstdint>
#include <string>
#include <type_traits>
#include <vector>
using polygon_type = std::vector<std::vector<vtzero::point>>;
struct polygon_handler {
polygon_type data;
void ring_begin(uint32_t count) {
data.emplace_back();
data.back().reserve(count);
}
void ring_point(const vtzero::point point) {
data.back().push_back(point);
}
void ring_end(vtzero::ring_type /* type */) const noexcept {
}
};
static void test_polygon_builder(bool with_id, bool with_prop) {
vtzero::tile_builder tbuilder;
vtzero::layer_builder lbuilder{tbuilder, "test"};
{
vtzero::polygon_feature_builder fbuilder{lbuilder};
if (with_id) {
fbuilder.set_id(17);
}
fbuilder.add_ring(4);
fbuilder.set_point(10, 20);
fbuilder.set_point(vtzero::point{20, 30});
fbuilder.set_point(mypoint{30, 40});
fbuilder.set_point(10, 20);
if (with_prop) {
fbuilder.add_property("foo", "bar");
}
fbuilder.commit();
}
const std::string data = tbuilder.serialize();
vtzero::vector_tile tile{data};
auto layer = tile.next_layer();
REQUIRE(layer.name() == "test");
REQUIRE(layer.version() == 2);
REQUIRE(layer.extent() == 4096);
REQUIRE(layer.num_features() == 1);
const auto feature = layer.next_feature();
REQUIRE(feature.id() == (with_id ? 17 : 0));
polygon_handler handler;
vtzero::decode_polygon_geometry(feature.geometry(), handler);
const polygon_type result = {{{10, 20}, {20, 30}, {30, 40}, {10, 20}}};
REQUIRE(handler.data == result);
}
TEST_CASE("polygon builder without id/without properties") {
test_polygon_builder(false, false);
}
TEST_CASE("polygon builder without id/with properties") {
test_polygon_builder(false, true);
}
TEST_CASE("polygon builder with id/without properties") {
test_polygon_builder(true, false);
}
TEST_CASE("polygon builder with id/with properties") {
test_polygon_builder(true, true);
}
TEST_CASE("Calling add_ring() with bad values throws assert") {
vtzero::tile_builder tbuilder;
vtzero::layer_builder lbuilder{tbuilder, "test"};
vtzero::polygon_feature_builder fbuilder{lbuilder};
SECTION("0") {
REQUIRE_THROWS_AS(fbuilder.add_ring(0), const assert_error&);
}
SECTION("1") {
REQUIRE_THROWS_AS(fbuilder.add_ring(1), const assert_error&);
}
SECTION("2") {
REQUIRE_THROWS_AS(fbuilder.add_ring(2), const assert_error&);
}
SECTION("3") {
REQUIRE_THROWS_AS(fbuilder.add_ring(3), const assert_error&);
}
SECTION("2^29") {
REQUIRE_THROWS_AS(fbuilder.add_ring(1ul << 29u), const assert_error&);
}
}
static void test_multipolygon_builder(bool with_id, bool with_prop) {
vtzero::tile_builder tbuilder;
vtzero::layer_builder lbuilder{tbuilder, "test"};
vtzero::polygon_feature_builder fbuilder{lbuilder};
if (with_id) {
fbuilder.set_id(17);
}
fbuilder.add_ring(4);
fbuilder.set_point(10, 20);
fbuilder.set_point(vtzero::point{20, 30});
fbuilder.set_point(mypoint{30, 40});
fbuilder.set_point(10, 20);
fbuilder.add_ring(5);
fbuilder.set_point(1, 1);
fbuilder.set_point(2, 1);
fbuilder.set_point(2, 2);
fbuilder.set_point(1, 2);
if (with_id) {
fbuilder.set_point(1, 1);
} else {
fbuilder.close_ring();
}
if (with_prop) {
fbuilder.add_property("foo", vtzero::encoded_property_value{"bar"});
}
fbuilder.commit();
const std::string data = tbuilder.serialize();
vtzero::vector_tile tile{data};
auto layer = tile.next_layer();
REQUIRE(layer.name() == "test");
REQUIRE(layer.version() == 2);
REQUIRE(layer.extent() == 4096);
REQUIRE(layer.num_features() == 1);
const auto feature = layer.next_feature();
REQUIRE(feature.id() == (with_id ? 17 : 0));
polygon_handler handler;
vtzero::decode_polygon_geometry(feature.geometry(), handler);
const polygon_type result = {{{10, 20}, {20, 30}, {30, 40}, {10, 20}},
{{1, 1}, {2, 1}, {2, 2}, {1, 2}, {1, 1}}};
REQUIRE(handler.data == result);
}
TEST_CASE("Multipolygon builder without id/without properties") {
test_multipolygon_builder(false, false);
}
TEST_CASE("Multipolygon builder without id/with properties") {
test_multipolygon_builder(false, true);
}
TEST_CASE("Multipolygon builder with id/without properties") {
test_multipolygon_builder(true, false);
}
TEST_CASE("Multipolygon builder with id/with properties") {
test_multipolygon_builder(true, true);
}
TEST_CASE("Calling add_ring() twice throws assert") {
vtzero::tile_builder tbuilder;
vtzero::layer_builder lbuilder{tbuilder, "test"};
vtzero::polygon_feature_builder fbuilder{lbuilder};
fbuilder.add_ring(4);
REQUIRE_ASSERT(fbuilder.add_ring(4));
}
TEST_CASE("Calling polygon_feature_builder::set_point()/close_ring() throws assert") {
vtzero::tile_builder tbuilder;
vtzero::layer_builder lbuilder{tbuilder, "test"};
vtzero::polygon_feature_builder fbuilder{lbuilder};
SECTION("set_point") {
REQUIRE_THROWS_AS(fbuilder.set_point(10, 10), const assert_error&);
}
SECTION("close_ring") {
REQUIRE_THROWS_AS(fbuilder.close_ring(), const assert_error&);
}
}
TEST_CASE("Calling polygon_feature_builder::set_point()/close_ring() too often throws assert") {
vtzero::tile_builder tbuilder;
vtzero::layer_builder lbuilder{tbuilder, "test"};
vtzero::polygon_feature_builder fbuilder{lbuilder};
fbuilder.add_ring(4);
fbuilder.set_point(10, 20);
fbuilder.set_point(20, 20);
fbuilder.set_point(30, 20);
fbuilder.set_point(10, 20);
SECTION("set_point") {
REQUIRE_THROWS_AS(fbuilder.set_point(50, 20), const assert_error&);
}
SECTION("close_ring") {
REQUIRE_THROWS_AS(fbuilder.close_ring(), const assert_error&);
}
}
TEST_CASE("Calling polygon_feature_builder::set_point() with same point throws") {
vtzero::tile_builder tbuilder;
vtzero::layer_builder lbuilder{tbuilder, "test"};
vtzero::polygon_feature_builder fbuilder{lbuilder};
fbuilder.add_ring(4);
fbuilder.set_point(10, 10);
REQUIRE_THROWS_AS(fbuilder.set_point(10, 10), const vtzero::geometry_exception&);
}
TEST_CASE("Calling polygon_feature_builder::set_point() creating unclosed ring throws") {
vtzero::tile_builder tbuilder;
vtzero::layer_builder lbuilder{tbuilder, "test"};
vtzero::polygon_feature_builder fbuilder{lbuilder};
fbuilder.add_ring(4);
fbuilder.set_point(10, 10);
fbuilder.set_point(10, 20);
fbuilder.set_point(20, 20);
REQUIRE_THROWS_AS(fbuilder.set_point(20, 30), const vtzero::geometry_exception&);
}
TEST_CASE("Add polygon from container") {
const polygon_type points = {{{10, 20}, {20, 30}, {30, 40}, {10, 20}}};
vtzero::tile_builder tbuilder;
vtzero::layer_builder lbuilder{tbuilder, "test"};
{
vtzero::polygon_feature_builder fbuilder{lbuilder};
#if 0
SECTION("using iterators") {
fbuilder.add_ring(points[0].cbegin(), points[0].cend());
}
SECTION("using iterators and size") {
fbuilder.add_ring(points[0].cbegin(), points[0].cend(), static_cast<uint32_t>(points[0].size()));
}
#endif
SECTION("using container directly") {
fbuilder.add_ring_from_container(points[0]);
}
fbuilder.commit();
}
const std::string data = tbuilder.serialize();
vtzero::vector_tile tile{data};
auto layer = tile.next_layer();
REQUIRE(layer);
REQUIRE(layer.name() == "test");
REQUIRE(layer.version() == 2);
REQUIRE(layer.extent() == 4096);
REQUIRE(layer.num_features() == 1);
const auto feature = layer.next_feature();
polygon_handler handler;
vtzero::decode_polygon_geometry(feature.geometry(), handler);
REQUIRE(handler.data == points);
}
#if 0
TEST_CASE("Add polygon from iterator with wrong count throws assert") {
const std::vector<vtzero::point> points = {{10, 20}, {20, 30}, {30, 40}, {10, 20}};
vtzero::tile_builder tbuilder;
vtzero::layer_builder lbuilder{tbuilder, "test"};
vtzero::polygon_feature_builder fbuilder{lbuilder};
REQUIRE_THROWS_AS(fbuilder.add_ring(points.cbegin(),
points.cend(),
static_cast<uint32_t>(points.size() + 1)), const assert_error&);
}
#endif
+42
View File
@@ -0,0 +1,42 @@
#include <test.hpp>
#include <vtzero/exception.hpp>
#include <string>
TEST_CASE("construct format_exception with const char*") {
vtzero::format_exception e{"broken"};
REQUIRE(std::string{e.what()} == "broken");
}
TEST_CASE("construct format_exception with const std::string") {
vtzero::format_exception e{std::string{"broken"}};
REQUIRE(std::string{e.what()} == "broken");
}
TEST_CASE("construct geometry_exception with const char*") {
vtzero::geometry_exception e{"broken"};
REQUIRE(std::string{e.what()} == "broken");
}
TEST_CASE("construct geometry_exception with std::string") {
vtzero::geometry_exception e{std::string{"broken"}};
REQUIRE(std::string{e.what()} == "broken");
}
TEST_CASE("construct type_exception") {
vtzero::type_exception e;
REQUIRE(std::string{e.what()} == "wrong property value type");
}
TEST_CASE("construct version_exception") {
vtzero::version_exception e{42};
REQUIRE(std::string{e.what()} == "unknown vector tile version: 42");
}
TEST_CASE("construct out_of_range_exception") {
vtzero::out_of_range_exception e{99};
REQUIRE(std::string{e.what()} == "index out of range: 99");
}
+97
View File
@@ -0,0 +1,97 @@
#include <test.hpp>
#include <vtzero/feature.hpp>
#include <vtzero/layer.hpp>
#include <vtzero/vector_tile.hpp>
TEST_CASE("default constructed feature") {
vtzero::feature feature{};
REQUIRE_FALSE(feature.valid());
REQUIRE_FALSE(feature);
REQUIRE(feature.id() == 0);
REQUIRE_FALSE(feature.has_id());
REQUIRE(feature.geometry_type() == vtzero::GeomType::UNKNOWN);
REQUIRE_ASSERT(feature.geometry());
REQUIRE(feature.empty());
REQUIRE(feature.num_properties() == 0);
}
TEST_CASE("read a feature") {
const auto data = load_test_tile();
vtzero::vector_tile tile{data};
auto layer = tile.get_layer_by_name("bridge");
REQUIRE(layer.valid());
auto feature = layer.next_feature();
REQUIRE(feature.valid());
REQUIRE(feature);
REQUIRE(feature.id() == 0);
REQUIRE(feature.has_id());
REQUIRE(feature.geometry_type() == vtzero::GeomType::LINESTRING);
REQUIRE_FALSE(feature.empty());
REQUIRE(feature.num_properties() == 4);
}
TEST_CASE("iterate over all properties of a feature") {
const auto data = load_test_tile();
vtzero::vector_tile tile{data};
auto layer = tile.get_layer_by_name("bridge");
auto feature = layer.next_feature();
int count = 0;
SECTION("external iterator") {
while (auto p = feature.next_property()) {
++count;
if (p.key() == "type") {
REQUIRE(p.value().type() == vtzero::property_value_type::string_value);
REQUIRE(p.value().string_value() == "primary");
}
}
}
SECTION("internal iterator") {
feature.for_each_property([&count](const vtzero::property& p) {
++count;
if (p.key() == "type") {
REQUIRE(p.value().type() == vtzero::property_value_type::string_value);
REQUIRE(p.value().string_value() == "primary");
}
return true;
});
}
REQUIRE(count == 4);
}
TEST_CASE("iterate over some properties of a feature") {
const auto data = load_test_tile();
vtzero::vector_tile tile{data};
auto layer = tile.get_layer_by_name("bridge");
REQUIRE(layer.valid());
auto feature = layer.next_feature();
REQUIRE(feature.valid());
int count = 0;
SECTION("external iterator") {
while (auto p = feature.next_property()) {
++count;
if (p.key() == "oneway") {
break;
}
}
}
SECTION("internal iterator") {
feature.for_each_property([&count](const vtzero::property& p) {
++count;
return p.key() != "oneway";
});
}
REQUIRE(count == 2);
}
+334
View File
@@ -0,0 +1,334 @@
#include <test.hpp>
#include <vtzero/geometry.hpp>
#include <cstdint>
#include <limits>
#include <vector>
using container = std::vector<uint32_t>;
using iterator = container::const_iterator;
TEST_CASE("geometry_decoder") {
const container g = {};
vtzero::detail::geometry_decoder<iterator> decoder{g.cbegin(), g.cend(), g.size() / 2};
REQUIRE(decoder.count() == 0);
REQUIRE(decoder.done());
REQUIRE_FALSE(decoder.next_command(vtzero::detail::CommandId::MOVE_TO));
REQUIRE_THROWS_AS(decoder.next_point(), const assert_error&);
}
TEST_CASE("geometry_decoder with point") {
const container g = {9, 50, 34};
vtzero::detail::geometry_decoder<iterator> decoder{g.cbegin(), g.cend(), g.size() / 2};
REQUIRE(decoder.count() == 0);
REQUIRE_FALSE(decoder.done());
REQUIRE_THROWS_AS(decoder.next_point(), const assert_error&);
SECTION("trying to get LineTo command") {
REQUIRE_THROWS_AS(decoder.next_command(vtzero::detail::CommandId::LINE_TO), const vtzero::geometry_exception&);
}
SECTION("trying to get ClosePath command") {
REQUIRE_THROWS_WITH(decoder.next_command(vtzero::detail::CommandId::CLOSE_PATH), "expected command 7 but got 1");
}
SECTION("trying to get MoveTo command") {
REQUIRE(decoder.next_command(vtzero::detail::CommandId::MOVE_TO));
REQUIRE_THROWS_AS(decoder.next_command(vtzero::detail::CommandId::MOVE_TO), const assert_error&);
REQUIRE(decoder.count() == 1);
REQUIRE(decoder.next_point() == vtzero::point(25, 17));
REQUIRE(decoder.done());
REQUIRE_FALSE(decoder.next_command(vtzero::detail::CommandId::MOVE_TO));
}
}
TEST_CASE("geometry_decoder with incomplete point") {
container g = {9, 50, 34};
SECTION("half a point") {
g.pop_back();
}
SECTION("missing point") {
g.pop_back();
g.pop_back();
}
vtzero::detail::geometry_decoder<iterator> decoder{g.cbegin(), g.cend(), 100};
REQUIRE(decoder.count() == 0);
REQUIRE_FALSE(decoder.done());
REQUIRE(decoder.next_command(vtzero::detail::CommandId::MOVE_TO));
REQUIRE(decoder.count() == 1);
REQUIRE_THROWS_AS(decoder.next_point(), const vtzero::geometry_exception&);
}
TEST_CASE("geometry_decoder with multipoint") {
const container g = {17, 10, 14, 3, 9};
vtzero::detail::geometry_decoder<iterator> decoder{g.cbegin(), g.cend(), g.size() / 2};
REQUIRE(decoder.count() == 0);
REQUIRE_FALSE(decoder.done());
REQUIRE(decoder.next_command(vtzero::detail::CommandId::MOVE_TO));
REQUIRE(decoder.count() == 2);
REQUIRE(decoder.next_point() == vtzero::point(5, 7));
REQUIRE(decoder.count() == 1);
REQUIRE(decoder.next_point() == vtzero::point(3, 2));
REQUIRE(decoder.count() == 0);
REQUIRE(decoder.done());
REQUIRE_FALSE(decoder.next_command(vtzero::detail::CommandId::MOVE_TO));
}
TEST_CASE("geometry_decoder with linestring") {
const container g = {9, 4, 4, 18, 0, 16, 16, 0};
vtzero::detail::geometry_decoder<iterator> decoder{g.cbegin(), g.cend(), g.size() / 2};
REQUIRE(decoder.count() == 0);
REQUIRE_FALSE(decoder.done());
REQUIRE(decoder.next_command(vtzero::detail::CommandId::MOVE_TO));
REQUIRE(decoder.count() == 1);
REQUIRE(decoder.next_point() == vtzero::point(2, 2));
REQUIRE(decoder.next_command(vtzero::detail::CommandId::LINE_TO));
REQUIRE(decoder.count() == 2);
REQUIRE(decoder.next_point() == vtzero::point(2, 10));
REQUIRE(decoder.count() == 1);
REQUIRE(decoder.next_point() == vtzero::point(10, 10));
REQUIRE(decoder.count() == 0);
REQUIRE(decoder.done());
REQUIRE_FALSE(decoder.next_command(vtzero::detail::CommandId::MOVE_TO));
}
TEST_CASE("geometry_decoder with linestring with equal points") {
const container g = {9, 4, 4, 18, 0, 16, 0, 0};
vtzero::detail::geometry_decoder<iterator> decoder{g.cbegin(), g.cend(), g.size() / 2};
REQUIRE(decoder.count() == 0);
REQUIRE_FALSE(decoder.done());
REQUIRE(decoder.next_command(vtzero::detail::CommandId::MOVE_TO));
REQUIRE(decoder.count() == 1);
REQUIRE(decoder.next_point() == vtzero::point(2, 2));
REQUIRE(decoder.next_command(vtzero::detail::CommandId::LINE_TO));
REQUIRE(decoder.count() == 2);
REQUIRE(decoder.next_point() == vtzero::point(2, 10));
REQUIRE(decoder.count() == 1);
REQUIRE(decoder.next_point() == vtzero::point(2, 10));
REQUIRE(decoder.count() == 0);
REQUIRE(decoder.done());
}
TEST_CASE("geometry_decoder with multilinestring") {
const container g = {9, 4, 4, 18, 0, 16, 16, 0, 9, 17, 17, 10, 4, 8};
vtzero::detail::geometry_decoder<iterator> decoder{g.cbegin(), g.cend(), g.size() / 2};
REQUIRE(decoder.count() == 0);
REQUIRE_FALSE(decoder.done());
REQUIRE(decoder.next_command(vtzero::detail::CommandId::MOVE_TO));
REQUIRE(decoder.count() == 1);
REQUIRE(decoder.next_point() == vtzero::point(2, 2));
REQUIRE(decoder.next_command(vtzero::detail::CommandId::LINE_TO));
REQUIRE(decoder.count() == 2);
REQUIRE(decoder.next_point() == vtzero::point(2, 10));
REQUIRE(decoder.count() == 1);
REQUIRE(decoder.next_point() == vtzero::point(10, 10));
REQUIRE(decoder.count() == 0);
REQUIRE(decoder.next_command(vtzero::detail::CommandId::MOVE_TO));
REQUIRE(decoder.count() == 1);
REQUIRE(decoder.next_point() == vtzero::point(1, 1));
REQUIRE(decoder.count() == 0);
REQUIRE(decoder.next_command(vtzero::detail::CommandId::LINE_TO));
REQUIRE(decoder.count() == 1);
REQUIRE(decoder.next_point() == vtzero::point(3, 5));
REQUIRE(decoder.count() == 0);
REQUIRE(decoder.done());
REQUIRE_FALSE(decoder.next_command(vtzero::detail::CommandId::MOVE_TO));
}
TEST_CASE("geometry_decoder with polygon") {
const container g = {9, 6, 12, 18, 10, 12, 24, 44, 15};
vtzero::detail::geometry_decoder<iterator> decoder{g.cbegin(), g.cend(), g.size() / 2};
REQUIRE(decoder.count() == 0);
REQUIRE_FALSE(decoder.done());
REQUIRE(decoder.next_command(vtzero::detail::CommandId::MOVE_TO));
REQUIRE(decoder.count() == 1);
REQUIRE(decoder.next_point() == vtzero::point(3, 6));
REQUIRE(decoder.next_command(vtzero::detail::CommandId::LINE_TO));
REQUIRE(decoder.count() == 2);
REQUIRE(decoder.next_point() == vtzero::point(8, 12));
REQUIRE(decoder.count() == 1);
REQUIRE(decoder.next_point() == vtzero::point(20, 34));
REQUIRE(decoder.count() == 0);
REQUIRE(decoder.next_command(vtzero::detail::CommandId::CLOSE_PATH));
REQUIRE(decoder.count() == 0);
REQUIRE(decoder.done());
REQUIRE_FALSE(decoder.next_command(vtzero::detail::CommandId::MOVE_TO));
}
TEST_CASE("geometry_decoder with polygon with wrong ClosePath count 2") {
const container g = {9, 6, 12, 18, 10, 12, 24, 44, 23};
vtzero::detail::geometry_decoder<iterator> decoder{g.cbegin(), g.cend(), g.size() / 2};
REQUIRE(decoder.count() == 0);
REQUIRE_FALSE(decoder.done());
REQUIRE(decoder.next_command(vtzero::detail::CommandId::MOVE_TO));
REQUIRE(decoder.next_point() == vtzero::point(3, 6));
REQUIRE(decoder.next_command(vtzero::detail::CommandId::LINE_TO));
REQUIRE(decoder.next_point() == vtzero::point(8, 12));
REQUIRE(decoder.next_point() == vtzero::point(20, 34));
REQUIRE_THROWS_AS(decoder.next_command(vtzero::detail::CommandId::CLOSE_PATH), const vtzero::geometry_exception&);
REQUIRE_THROWS_WITH(decoder.next_command(vtzero::detail::CommandId::CLOSE_PATH), "ClosePath command count is not 1");
}
TEST_CASE("geometry_decoder with polygon with wrong ClosePath count 0") {
const container g = {9, 6, 12, 18, 10, 12, 24, 44, 7};
vtzero::detail::geometry_decoder<iterator> decoder{g.cbegin(), g.cend(), g.size() / 2};
REQUIRE(decoder.count() == 0);
REQUIRE_FALSE(decoder.done());
REQUIRE(decoder.next_command(vtzero::detail::CommandId::MOVE_TO));
REQUIRE(decoder.next_point() == vtzero::point(3, 6));
REQUIRE(decoder.next_command(vtzero::detail::CommandId::LINE_TO));
REQUIRE(decoder.next_point() == vtzero::point(8, 12));
REQUIRE(decoder.next_point() == vtzero::point(20, 34));
REQUIRE_THROWS_AS(decoder.next_command(vtzero::detail::CommandId::CLOSE_PATH), const vtzero::geometry_exception&);
REQUIRE_THROWS_WITH(decoder.next_command(vtzero::detail::CommandId::CLOSE_PATH), "ClosePath command count is not 1");
}
TEST_CASE("geometry_decoder with multipolygon") {
const container g = {9, 0, 0, 26, 20, 0, 0, 20, 19, 0, 15, 9, 22, 2, 26, 18,
0, 0, 18, 17, 0, 15, 9, 4, 13, 26, 0, 8, 8, 0, 0, 7, 15};
vtzero::detail::geometry_decoder<iterator> decoder{g.cbegin(), g.cend(), g.size() / 2};
REQUIRE(decoder.count() == 0);
REQUIRE_FALSE(decoder.done());
REQUIRE(decoder.next_command(vtzero::detail::CommandId::MOVE_TO));
REQUIRE(decoder.count() == 1);
REQUIRE(decoder.next_point() == vtzero::point(0, 0));
REQUIRE(decoder.next_command(vtzero::detail::CommandId::LINE_TO));
REQUIRE(decoder.count() == 3);
REQUIRE(decoder.next_point() == vtzero::point(10, 0));
REQUIRE(decoder.count() == 2);
REQUIRE(decoder.next_point() == vtzero::point(10, 10));
REQUIRE(decoder.count() == 1);
REQUIRE(decoder.next_point() == vtzero::point(0, 10));
REQUIRE(decoder.count() == 0);
REQUIRE(decoder.next_command(vtzero::detail::CommandId::CLOSE_PATH));
REQUIRE(decoder.count() == 0);
REQUIRE(decoder.next_command(vtzero::detail::CommandId::MOVE_TO));
REQUIRE(decoder.count() == 1);
REQUIRE(decoder.next_point() == vtzero::point(11, 11));
REQUIRE(decoder.next_command(vtzero::detail::CommandId::LINE_TO));
REQUIRE(decoder.count() == 3);
REQUIRE(decoder.next_point() == vtzero::point(20, 11));
REQUIRE(decoder.count() == 2);
REQUIRE(decoder.next_point() == vtzero::point(20, 20));
REQUIRE(decoder.count() == 1);
REQUIRE(decoder.next_point() == vtzero::point(11, 20));
REQUIRE(decoder.count() == 0);
REQUIRE(decoder.next_command(vtzero::detail::CommandId::CLOSE_PATH));
REQUIRE(decoder.count() == 0);
REQUIRE(decoder.next_command(vtzero::detail::CommandId::MOVE_TO));
REQUIRE(decoder.count() == 1);
REQUIRE(decoder.next_point() == vtzero::point(13, 13));
REQUIRE(decoder.next_command(vtzero::detail::CommandId::LINE_TO));
REQUIRE(decoder.count() == 3);
REQUIRE(decoder.next_point() == vtzero::point(13, 17));
REQUIRE(decoder.count() == 2);
REQUIRE(decoder.next_point() == vtzero::point(17, 17));
REQUIRE(decoder.count() == 1);
REQUIRE(decoder.next_point() == vtzero::point(17, 13));
REQUIRE(decoder.count() == 0);
REQUIRE(decoder.next_command(vtzero::detail::CommandId::CLOSE_PATH));
REQUIRE(decoder.count() == 0);
REQUIRE(decoder.done());
REQUIRE_FALSE(decoder.next_command(vtzero::detail::CommandId::MOVE_TO));
}
TEST_CASE("geometry_decoder decoding linestring with int32 overflow in x coordinate") {
const container g = {vtzero::detail::command_move_to(1),
protozero::encode_zigzag32(std::numeric_limits<int32_t>::max()),
protozero::encode_zigzag32(0),
vtzero::detail::command_line_to(1),
protozero::encode_zigzag32(1),
protozero::encode_zigzag32(1)
};
vtzero::detail::geometry_decoder<iterator> decoder{g.cbegin(), g.cend(), g.size() / 2};
REQUIRE(decoder.count() == 0);
REQUIRE_FALSE(decoder.done());
REQUIRE(decoder.next_command(vtzero::detail::CommandId::MOVE_TO));
REQUIRE(decoder.count() == 1);
REQUIRE(decoder.next_point() == vtzero::point(std::numeric_limits<int32_t>::max(), 0));
REQUIRE(decoder.next_command(vtzero::detail::CommandId::LINE_TO));
REQUIRE(decoder.count() == 1);
REQUIRE(decoder.next_point() == vtzero::point(std::numeric_limits<int32_t>::min(), 1));
}
TEST_CASE("geometry_decoder decoding linestring with int32 overflow in y coordinate") {
const container g = {vtzero::detail::command_move_to(1),
protozero::encode_zigzag32(0),
protozero::encode_zigzag32(std::numeric_limits<int32_t>::min()),
vtzero::detail::command_line_to(1),
protozero::encode_zigzag32(-1),
protozero::encode_zigzag32(-1)
};
vtzero::detail::geometry_decoder<iterator> decoder{g.cbegin(), g.cend(), g.size() / 2};
REQUIRE(decoder.count() == 0);
REQUIRE_FALSE(decoder.done());
REQUIRE(decoder.next_command(vtzero::detail::CommandId::MOVE_TO));
REQUIRE(decoder.count() == 1);
REQUIRE(decoder.next_point() == vtzero::point(0, std::numeric_limits<int32_t>::min()));
REQUIRE(decoder.next_command(vtzero::detail::CommandId::LINE_TO));
REQUIRE(decoder.count() == 1);
REQUIRE(decoder.next_point() == vtzero::point(-1, std::numeric_limits<int32_t>::max()));
}
TEST_CASE("geometry_decoder with multipoint with a huge count") {
const uint32_t huge_value = (1ul << 29u) - 1;
const container g = {vtzero::detail::command_move_to(huge_value), 10, 10};
vtzero::detail::geometry_decoder<iterator> decoder{g.cbegin(), g.cend(), g.size() / 2};
REQUIRE(decoder.count() == 0);
REQUIRE_FALSE(decoder.done());
REQUIRE_THROWS_AS(decoder.next_command(vtzero::detail::CommandId::MOVE_TO), const vtzero::geometry_exception&);
}
TEST_CASE("geometry_decoder with multipoint with not enough points") {
const container g = {vtzero::detail::command_move_to(2), 10};
vtzero::detail::geometry_decoder<iterator> decoder{g.cbegin(), g.cend(), 1};
REQUIRE(decoder.count() == 0);
REQUIRE_FALSE(decoder.done());
REQUIRE_THROWS_AS(decoder.next_command(vtzero::detail::CommandId::MOVE_TO), const vtzero::geometry_exception&);
}
+160
View File
@@ -0,0 +1,160 @@
#include <test.hpp>
#include <vtzero/geometry.hpp>
#include <cstdint>
#include <vector>
using container = std::vector<uint32_t>;
using iterator = container::const_iterator;
class dummy_geom_handler {
int value = 0;
public:
void linestring_begin(const uint32_t /*count*/) noexcept {
++value;
}
void linestring_point(const vtzero::point /*point*/) noexcept {
value += 100;
}
void linestring_end() noexcept {
value += 10000;
}
int result() const noexcept {
return value;
}
}; // class dummy_geom_handler
TEST_CASE("Calling decode_linestring_geometry() with empty input") {
const container g;
vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
dummy_geom_handler handler;
decoder.decode_linestring(dummy_geom_handler{});
REQUIRE(handler.result() == 0);
}
TEST_CASE("Calling decode_linestring_geometry() with a valid linestring") {
const container g = {9, 4, 4, 18, 0, 16, 16, 0};
vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
REQUIRE(decoder.decode_linestring(dummy_geom_handler{}) == 10301);
}
TEST_CASE("Calling decode_linestring_geometry() with a valid multilinestring") {
const container g = {9, 4, 4, 18, 0, 16, 16, 0, 9, 17, 17, 10, 4, 8};
vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
dummy_geom_handler handler;
decoder.decode_linestring(handler);
REQUIRE(handler.result() == 20502);
}
TEST_CASE("Calling decode_linestring_geometry() with a point geometry fails") {
const container g = {9, 50, 34}; // this is a point geometry
vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
SECTION("check exception type") {
REQUIRE_THROWS_AS(decoder.decode_linestring(dummy_geom_handler{}),
const vtzero::geometry_exception&);
}
SECTION("check exception message") {
REQUIRE_THROWS_WITH(decoder.decode_linestring(dummy_geom_handler{}),
"expected LineTo command (spec 4.3.4.3)");
}
}
TEST_CASE("Calling decode_linestring_geometry() with a polygon geometry fails") {
const container g = {9, 6, 12, 18, 10, 12, 24, 44, 15}; // this is a polygon geometry
vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
SECTION("check exception type") {
REQUIRE_THROWS_AS(decoder.decode_linestring(dummy_geom_handler{}),
const vtzero::geometry_exception&);
}
SECTION("check exception message") {
REQUIRE_THROWS_WITH(decoder.decode_linestring(dummy_geom_handler{}),
"expected command 1 but got 7");
}
}
TEST_CASE("Calling decode_linestring_geometry() with something other than MoveTo command") {
const container g = {vtzero::detail::command_line_to(3)};
vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
SECTION("check exception type") {
REQUIRE_THROWS_AS(decoder.decode_linestring(dummy_geom_handler{}),
const vtzero::geometry_exception&);
}
SECTION("check exception message") {
REQUIRE_THROWS_WITH(decoder.decode_linestring(dummy_geom_handler{}),
"expected command 1 but got 2");
}
}
TEST_CASE("Calling decode_linestring_geometry() with a count of 0") {
const container g = {vtzero::detail::command_move_to(0)};
vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
SECTION("check exception type") {
REQUIRE_THROWS_AS(decoder.decode_linestring(dummy_geom_handler{}),
const vtzero::geometry_exception&);
}
SECTION("check exception message") {
REQUIRE_THROWS_WITH(decoder.decode_linestring(dummy_geom_handler{}),
"MoveTo command count is not 1 (spec 4.3.4.3)");
}
}
TEST_CASE("Calling decode_linestring_geometry() with a count of 2") {
const container g = {vtzero::detail::command_move_to(2), 10, 20, 20, 10};
vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
SECTION("check exception type") {
REQUIRE_THROWS_AS(decoder.decode_linestring(dummy_geom_handler{}),
const vtzero::geometry_exception&);
}
SECTION("check exception message") {
REQUIRE_THROWS_WITH(decoder.decode_linestring(dummy_geom_handler{}),
"MoveTo command count is not 1 (spec 4.3.4.3)");
}
}
TEST_CASE("Calling decode_linestring_geometry() with 2nd command not a LineTo") {
const container g = {vtzero::detail::command_move_to(1), 3, 4,
vtzero::detail::command_move_to(1)};
vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
SECTION("check exception type") {
REQUIRE_THROWS_AS(decoder.decode_linestring(dummy_geom_handler{}),
const vtzero::geometry_exception&);
}
SECTION("check exception message") {
REQUIRE_THROWS_WITH(decoder.decode_linestring(dummy_geom_handler{}),
"expected command 2 but got 1");
}
}
TEST_CASE("Calling decode_linestring_geometry() with LineTo and 0 count") {
const container g = {vtzero::detail::command_move_to(1), 3, 4,
vtzero::detail::command_line_to(0)};
vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
SECTION("check exception type") {
REQUIRE_THROWS_AS(decoder.decode_linestring(dummy_geom_handler{}),
const vtzero::geometry_exception&);
}
SECTION("check exception message") {
REQUIRE_THROWS_WITH(decoder.decode_linestring(dummy_geom_handler{}),
"LineTo command count is zero (spec 4.3.4.3)");
}
}
+135
View File
@@ -0,0 +1,135 @@
#include <test.hpp>
#include <vtzero/geometry.hpp>
#include <cstdint>
#include <vector>
using container = std::vector<uint32_t>;
using iterator = container::const_iterator;
class dummy_geom_handler {
int value = 0;
public:
void points_begin(const uint32_t /*count*/) noexcept {
++value;
}
void points_point(const vtzero::point /*point*/) noexcept {
value += 100;
}
void points_end() noexcept {
value += 10000;
}
int result() const noexcept {
return value;
}
}; // class dummy_geom_handler
TEST_CASE("Calling decode_point() with empty input") {
const container g;
vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
SECTION("check exception type") {
REQUIRE_THROWS_AS(decoder.decode_point(dummy_geom_handler{}),
const vtzero::geometry_exception&);
}
SECTION("check exception message") {
REQUIRE_THROWS_WITH(decoder.decode_point(dummy_geom_handler{}),
"expected MoveTo command (spec 4.3.4.2)");
}
}
TEST_CASE("Calling decode_point() with a valid point") {
const container g = {9, 50, 34};
vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
dummy_geom_handler handler;
decoder.decode_point(handler);
REQUIRE(handler.result() == 10101);
}
TEST_CASE("Calling decode_point() with a valid multipoint") {
const container g = {17, 10, 14, 3, 9};
vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
REQUIRE(decoder.decode_point(dummy_geom_handler{}) == 10201);
}
TEST_CASE("Calling decode_point() with a linestring geometry fails") {
const container g = {9, 4, 4, 18, 0, 16, 16, 0}; // this is a linestring geometry
vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
SECTION("check exception type") {
REQUIRE_THROWS_AS(decoder.decode_point(dummy_geom_handler{}),
const vtzero::geometry_exception&);
}
SECTION("check exception message") {
REQUIRE_THROWS_WITH(decoder.decode_point(dummy_geom_handler{}),
"additional data after end of geometry (spec 4.3.4.2)");
}
}
TEST_CASE("Calling decode_point() with a polygon geometry fails") {
const container g = {9, 6, 12, 18, 10, 12, 24, 44, 15}; // this is a polygon geometry
vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
SECTION("check exception type") {
REQUIRE_THROWS_AS(decoder.decode_point(dummy_geom_handler{}),
const vtzero::geometry_exception&);
}
SECTION("check exception message") {
REQUIRE_THROWS_WITH(decoder.decode_point(dummy_geom_handler{}),
"additional data after end of geometry (spec 4.3.4.2)");
}
}
TEST_CASE("Calling decode_point() with something other than MoveTo command") {
const container g = {vtzero::detail::command_line_to(3)};
vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
SECTION("check exception type") {
REQUIRE_THROWS_AS(decoder.decode_point(dummy_geom_handler{}),
const vtzero::geometry_exception&);
}
SECTION("check exception message") {
REQUIRE_THROWS_WITH(decoder.decode_point(dummy_geom_handler{}),
"expected command 1 but got 2");
}
}
TEST_CASE("Calling decode_point() with a count of 0") {
const container g = {vtzero::detail::command_move_to(0)};
vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
SECTION("check exception type") {
REQUIRE_THROWS_AS(decoder.decode_point(dummy_geom_handler{}),
const vtzero::geometry_exception&);
}
SECTION("check exception message") {
REQUIRE_THROWS_WITH(decoder.decode_point(dummy_geom_handler{}),
"MoveTo command count is zero (spec 4.3.4.2)");
}
}
TEST_CASE("Calling decode_point() with more data then expected") {
const container g = {9, 50, 34, 9};
vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
SECTION("check exception type") {
REQUIRE_THROWS_AS(decoder.decode_point(dummy_geom_handler{}),
const vtzero::geometry_exception&);
}
SECTION("check exception message") {
REQUIRE_THROWS_WITH(decoder.decode_point(dummy_geom_handler{}),
"additional data after end of geometry (spec 4.3.4.2)");
}
}
+204
View File
@@ -0,0 +1,204 @@
#include <test.hpp>
#include <vtzero/geometry.hpp>
#include <cstdint>
#include <vector>
using container = std::vector<uint32_t>;
using iterator = container::const_iterator;
class dummy_geom_handler {
int value = 0;
public:
void ring_begin(const uint32_t /*count*/) noexcept {
++value;
}
void ring_point(const vtzero::point /*point*/) noexcept {
value += 100;
}
void ring_end(vtzero::ring_type /*is_outer*/) noexcept {
value += 10000;
}
int result() const noexcept {
return value;
}
}; // class dummy_geom_handler
TEST_CASE("Calling decode_polygon_geometry() with empty input") {
const container g;
vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
dummy_geom_handler handler;
decoder.decode_polygon(dummy_geom_handler{});
REQUIRE(handler.result() == 0);
}
TEST_CASE("Calling decode_polygon_geometry() with a valid polygon") {
const container g = {9, 6, 12, 18, 10, 12, 24, 44, 15};
vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
REQUIRE(decoder.decode_polygon(dummy_geom_handler{}) == 10401);
}
TEST_CASE("Calling decode_polygon_geometry() with a duplicate end point") {
const container g = {9, 6, 12, 26, 10, 12, 24, 44, 33, 55, 15};
vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
dummy_geom_handler handler;
decoder.decode_polygon(handler);
REQUIRE(handler.result() == 10501);
}
TEST_CASE("Calling decode_polygon_geometry() with a valid multipolygon") {
const container g = {9, 0, 0, 26, 20, 0, 0, 20, 19, 0, 15, 9, 22, 2, 26, 18,
0, 0, 18, 17, 0, 15, 9, 4, 13, 26, 0, 8, 8, 0, 0, 7, 15};
vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
dummy_geom_handler handler;
decoder.decode_polygon(handler);
REQUIRE(handler.result() == 31503);
}
TEST_CASE("Calling decode_polygon_geometry() with a point geometry fails") {
const container g = {9, 50, 34}; // this is a point geometry
vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
SECTION("check exception type") {
REQUIRE_THROWS_AS(decoder.decode_polygon(dummy_geom_handler{}),
const vtzero::geometry_exception&);
}
SECTION("check exception message") {
REQUIRE_THROWS_WITH(decoder.decode_polygon(dummy_geom_handler{}),
"expected LineTo command (spec 4.3.4.4)");
}
}
TEST_CASE("Calling decode_polygon_geometry() with a linestring geometry fails") {
const container g = {9, 4, 4, 18, 0, 16, 16, 0}; // this is a linestring geometry
vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
SECTION("check exception type") {
REQUIRE_THROWS_AS(decoder.decode_polygon(dummy_geom_handler{}),
const vtzero::geometry_exception&);
}
SECTION("check exception message") {
REQUIRE_THROWS_WITH(decoder.decode_polygon(dummy_geom_handler{}),
"expected ClosePath command (4.3.4.4)");
}
}
TEST_CASE("Calling decode_polygon_geometry() with something other than MoveTo command") {
const container g = {vtzero::detail::command_line_to(3)};
vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
SECTION("check exception type") {
REQUIRE_THROWS_AS(decoder.decode_polygon(dummy_geom_handler{}),
const vtzero::geometry_exception&);
}
SECTION("check exception message") {
REQUIRE_THROWS_WITH(decoder.decode_polygon(dummy_geom_handler{}),
"expected command 1 but got 2");
}
}
TEST_CASE("Calling decode_polygon_geometry() with a count of 0") {
const container g = {vtzero::detail::command_move_to(0)};
vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
SECTION("check exception type") {
REQUIRE_THROWS_AS(decoder.decode_polygon(dummy_geom_handler{}),
const vtzero::geometry_exception&);
}
SECTION("check exception message") {
REQUIRE_THROWS_WITH(decoder.decode_polygon(dummy_geom_handler{}),
"MoveTo command count is not 1 (spec 4.3.4.4)");
}
}
TEST_CASE("Calling decode_polygon_geometry() with a count of 2") {
const container g = {vtzero::detail::command_move_to(2), 1, 2, 3, 4};
vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
SECTION("check exception type") {
REQUIRE_THROWS_AS(decoder.decode_polygon(dummy_geom_handler{}),
const vtzero::geometry_exception&);
}
SECTION("check exception message") {
REQUIRE_THROWS_WITH(decoder.decode_polygon(dummy_geom_handler{}),
"MoveTo command count is not 1 (spec 4.3.4.4)");
}
}
TEST_CASE("Calling decode_polygon_geometry() with 2nd command not a LineTo") {
const container g = {vtzero::detail::command_move_to(1), 3, 4,
vtzero::detail::command_move_to(1)};
vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
SECTION("check exception type") {
REQUIRE_THROWS_AS(decoder.decode_polygon(dummy_geom_handler{}),
const vtzero::geometry_exception&);
}
SECTION("check exception message") {
REQUIRE_THROWS_WITH(decoder.decode_polygon(dummy_geom_handler{}),
"expected command 2 but got 1");
}
}
TEST_CASE("Calling decode_polygon_geometry() with LineTo and 0 count") {
const container g = {vtzero::detail::command_move_to(1), 3, 4,
vtzero::detail::command_line_to(0),
vtzero::detail::command_close_path()};
vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
dummy_geom_handler handler;
decoder.decode_polygon(handler);
REQUIRE(handler.result() == 10201);
}
TEST_CASE("Calling decode_polygon_geometry() with LineTo and 1 count") {
const container g = {vtzero::detail::command_move_to(1), 3, 4,
vtzero::detail::command_line_to(1), 5, 6,
vtzero::detail::command_close_path()};
vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
dummy_geom_handler handler;
decoder.decode_polygon(handler);
REQUIRE(handler.result() == 10301);
}
TEST_CASE("Calling decode_polygon_geometry() with 3nd command not a ClosePath") {
const container g = {vtzero::detail::command_move_to(1), 3, 4,
vtzero::detail::command_line_to(2), 4, 5, 6, 7,
vtzero::detail::command_line_to(0)};
vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
SECTION("check exception type") {
REQUIRE_THROWS_AS(decoder.decode_polygon(dummy_geom_handler{}),
const vtzero::geometry_exception&);
}
SECTION("check exception message") {
REQUIRE_THROWS_WITH(decoder.decode_polygon(dummy_geom_handler{}),
"expected command 7 but got 2");
}
}
TEST_CASE("Calling decode_polygon_geometry() on polygon with zero area") {
const container g = {vtzero::detail::command_move_to(1), 0, 0,
vtzero::detail::command_line_to(3), 2, 0, 0, 4, 2, 0,
vtzero::detail::command_close_path()};
vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
dummy_geom_handler handler;
decoder.decode_polygon(handler);
REQUIRE(handler.result() == 10501);
}
+343
View File
@@ -0,0 +1,343 @@
#include <test.hpp>
#include <vtzero/builder.hpp>
#include <vtzero/index.hpp>
#include <map>
#include <string>
#include <unordered_map>
TEST_CASE("add keys to layer using key index built into layer") {
static constexpr const int max_keys = 100;
vtzero::tile_builder tbuilder;
vtzero::layer_builder lbuilder{tbuilder, "test"};
for (int n = 0; n < max_keys; ++n) {
const auto key = std::to_string(n);
const auto idx = lbuilder.add_key(key);
REQUIRE(n == idx.value());
}
for (int n = 0; n < max_keys; n += 2) {
const auto key = std::to_string(n);
const auto idx = lbuilder.add_key(key);
REQUIRE(n == idx.value());
}
}
TEST_CASE("add values to layer using value index built into layer") {
static constexpr const int max_values = 100;
vtzero::tile_builder tbuilder;
vtzero::layer_builder lbuilder{tbuilder, "test"};
for (int n = 0; n < max_values; ++n) {
const auto value = std::to_string(n);
const auto idx = lbuilder.add_value(vtzero::encoded_property_value{value});
REQUIRE(n == idx.value());
}
for (int n = 0; n < max_values; n += 2) {
const auto value = std::to_string(n);
const auto idx = lbuilder.add_value(vtzero::encoded_property_value{value});
REQUIRE(n == idx.value());
}
}
template <typename TIndex>
static void test_key_index() {
vtzero::tile_builder tbuilder;
vtzero::layer_builder lbuilder{tbuilder, "test"};
TIndex index{lbuilder};
const auto i1 = index({"foo"});
const auto i2 = index({"bar"});
const auto i3 = index({"baz"});
const auto i4 = index({"foo"});
const auto i5 = index({"foo"});
const auto i6 = index({""});
const auto i7 = index({"bar"});
REQUIRE(i1 != i2);
REQUIRE(i1 != i3);
REQUIRE(i1 == i4);
REQUIRE(i1 == i5);
REQUIRE(i1 != i6);
REQUIRE(i1 != i7);
REQUIRE(i2 != i3);
REQUIRE(i2 != i4);
REQUIRE(i2 != i5);
REQUIRE(i2 != i6);
REQUIRE(i2 == i7);
REQUIRE(i3 != i4);
REQUIRE(i3 != i5);
REQUIRE(i3 != i6);
REQUIRE(i3 != i7);
REQUIRE(i4 == i5);
REQUIRE(i4 != i6);
REQUIRE(i4 != i7);
REQUIRE(i5 != i6);
REQUIRE(i5 != i7);
REQUIRE(i6 != i7);
}
TEST_CASE("key index based on std::unordered_map") {
test_key_index<vtzero::key_index<std::unordered_map>>();
}
TEST_CASE("key index based on std::map") {
test_key_index<vtzero::key_index<std::map>>();
}
template <typename TIndex>
static void test_value_index_internal() {
vtzero::tile_builder tbuilder;
vtzero::layer_builder lbuilder{tbuilder, "test"};
TIndex index{lbuilder};
const auto i1 = index(vtzero::encoded_property_value{"foo"});
const auto i2 = index(vtzero::encoded_property_value{"bar"});
const auto i3 = index(vtzero::encoded_property_value{88});
const auto i4 = index(vtzero::encoded_property_value{"foo"});
const auto i5 = index(vtzero::encoded_property_value{77});
const auto i6 = index(vtzero::encoded_property_value{1.5});
const auto i7 = index(vtzero::encoded_property_value{"bar"});
REQUIRE(i1 != i2);
REQUIRE(i1 != i3);
REQUIRE(i1 == i4);
REQUIRE(i1 != i5);
REQUIRE(i1 != i6);
REQUIRE(i1 != i7);
REQUIRE(i2 != i3);
REQUIRE(i2 != i4);
REQUIRE(i2 != i5);
REQUIRE(i2 != i6);
REQUIRE(i2 == i7);
REQUIRE(i3 != i4);
REQUIRE(i3 != i5);
REQUIRE(i3 != i6);
REQUIRE(i3 != i7);
REQUIRE(i4 != i5);
REQUIRE(i4 != i6);
REQUIRE(i4 != i7);
REQUIRE(i5 != i6);
REQUIRE(i5 != i7);
REQUIRE(i6 != i7);
}
TEST_CASE("internal value index based on std::unordered_map") {
test_value_index_internal<vtzero::value_index_internal<std::unordered_map>>();
}
TEST_CASE("internal value index based on std::map") {
test_value_index_internal<vtzero::value_index_internal<std::map>>();
}
TEST_CASE("external value index") {
vtzero::tile_builder tbuilder;
vtzero::layer_builder lbuilder{tbuilder, "test"};
vtzero::value_index<vtzero::string_value_type, std::string, std::map> string_index{lbuilder};
vtzero::value_index<vtzero::int_value_type, int, std::unordered_map> int_index{lbuilder};
vtzero::value_index<vtzero::sint_value_type, int, std::unordered_map> sint_index{lbuilder};
const auto i1 = string_index("foo");
const auto i2 = string_index("bar");
const auto i3 = int_index(6);
const auto i4 = sint_index(6);
const auto i5 = string_index(std::string{"foo"});
const auto i6 = int_index(6);
const auto i7 = sint_index(2);
const auto i8 = sint_index(5);
const auto i9 = sint_index(6);
REQUIRE(i1 != i2);
REQUIRE(i1 != i3);
REQUIRE(i1 != i4);
REQUIRE(i1 == i5);
REQUIRE(i1 != i6);
REQUIRE(i1 != i7);
REQUIRE(i1 != i7);
REQUIRE(i1 != i9);
REQUIRE(i2 != i3);
REQUIRE(i2 != i4);
REQUIRE(i2 != i5);
REQUIRE(i2 != i6);
REQUIRE(i2 != i7);
REQUIRE(i2 != i8);
REQUIRE(i2 != i9);
REQUIRE(i3 != i4);
REQUIRE(i3 != i5);
REQUIRE(i3 == i6);
REQUIRE(i3 != i7);
REQUIRE(i3 != i8);
REQUIRE(i3 != i9);
REQUIRE(i4 != i5);
REQUIRE(i4 != i6);
REQUIRE(i4 != i7);
REQUIRE(i4 != i8);
REQUIRE(i4 == i9);
REQUIRE(i5 != i6);
REQUIRE(i5 != i7);
REQUIRE(i5 != i8);
REQUIRE(i5 != i9);
REQUIRE(i6 != i7);
REQUIRE(i6 != i8);
REQUIRE(i6 != i9);
REQUIRE(i7 != i8);
REQUIRE(i7 != i9);
REQUIRE(i8 != i9);
}
TEST_CASE("bool value index") {
vtzero::tile_builder tbuilder;
vtzero::layer_builder lbuilder{tbuilder, "test"};
vtzero::value_index_bool index{lbuilder};
const auto i1 = index(false);
const auto i2 = index(true);
const auto i3 = index(true);
const auto i4 = index(false);
REQUIRE(i1 != i2);
REQUIRE(i1 != i3);
REQUIRE(i1 == i4);
REQUIRE(i2 == i3);
REQUIRE(i2 != i4);
REQUIRE(i3 != i4);
}
TEST_CASE("small unsigned int value index") {
vtzero::tile_builder tbuilder;
vtzero::layer_builder lbuilder{tbuilder, "test"};
vtzero::value_index_small_uint index{lbuilder};
const auto i1 = index(12);
const auto i2 = index(4);
const auto i3 = index(0);
const auto i4 = index(100);
const auto i5 = index(4);
const auto i6 = index(12);
REQUIRE(i1 != i2);
REQUIRE(i1 != i3);
REQUIRE(i1 != i4);
REQUIRE(i1 != i5);
REQUIRE(i1 == i6);
REQUIRE(i2 != i3);
REQUIRE(i2 != i4);
REQUIRE(i2 == i5);
REQUIRE(i2 != i6);
REQUIRE(i3 != i4);
REQUIRE(i3 != i5);
REQUIRE(i3 != i6);
REQUIRE(i4 != i5);
REQUIRE(i4 != i6);
REQUIRE(i5 != i6);
}
TEST_CASE("add features using a key index") {
vtzero::tile_builder tbuilder;
vtzero::layer_builder lbuilder{tbuilder, "test"};
vtzero::point_feature_builder fbuilder{lbuilder};
fbuilder.set_id(7);
fbuilder.add_point(10, 20);
SECTION("no index") {
fbuilder.add_property("some_key", 12);
}
SECTION("key index using unordered_map") {
vtzero::key_index<std::unordered_map> index{lbuilder};
fbuilder.add_property(index("some_key"), 12);
}
SECTION("key index using map") {
vtzero::key_index<std::map> index{lbuilder};
fbuilder.add_property(index("some_key"), 12);
}
fbuilder.commit();
const std::string data = tbuilder.serialize();
// ============
vtzero::vector_tile tile{data};
REQUIRE(tile.count_layers() == 1);
auto layer = tile.next_layer();
REQUIRE(layer.num_features() == 1);
auto feature = layer.next_feature();
REQUIRE(feature.id() == 7);
const auto property = feature.next_property();
REQUIRE(property.value().int_value() == 12);
}
TEST_CASE("add features using a value index") {
vtzero::tile_builder tbuilder;
vtzero::layer_builder lbuilder{tbuilder, "test"};
const auto key = lbuilder.add_key("some_key");
vtzero::point_feature_builder fbuilder{lbuilder};
fbuilder.set_id(17);
fbuilder.add_point(10, 20);
SECTION("no index") {
fbuilder.add_property(key, vtzero::sint_value_type{12});
}
SECTION("external value index using unordered_map") {
vtzero::value_index<vtzero::sint_value_type, int, std::unordered_map> index{lbuilder};
fbuilder.add_property(key, index(12));
}
SECTION("external value index using map") {
vtzero::value_index<vtzero::sint_value_type, int, std::map> index{lbuilder};
fbuilder.add_property(key, index(12));
}
SECTION("property_value_type index") {
vtzero::value_index_internal<std::unordered_map> index{lbuilder};
fbuilder.add_property(key, index(vtzero::encoded_property_value{vtzero::sint_value_type{12}}));
}
fbuilder.commit();
const std::string data = tbuilder.serialize();
// ============
vtzero::vector_tile tile{data};
REQUIRE(tile.count_layers() == 1);
auto layer = tile.next_layer();
REQUIRE(layer.num_features() == 1);
auto feature = layer.next_feature();
REQUIRE(feature.id() == 17);
const auto property = feature.next_property();
REQUIRE(property.value().sint_value() == 12);
}
+155
View File
@@ -0,0 +1,155 @@
#include <test.hpp>
#include <vtzero/layer.hpp>
#include <vtzero/vector_tile.hpp>
#include <cstddef>
TEST_CASE("default constructed layer") {
vtzero::layer layer{};
REQUIRE_FALSE(layer.valid());
REQUIRE_FALSE(layer);
REQUIRE(layer.data() == vtzero::data_view{});
REQUIRE_ASSERT(layer.version());
REQUIRE_ASSERT(layer.extent());
REQUIRE_ASSERT(layer.name());
REQUIRE(layer.empty());
REQUIRE(layer.num_features() == 0);
REQUIRE_THROWS_AS(layer.key_table(), const assert_error&);
REQUIRE_THROWS_AS(layer.value_table(), const assert_error&);
REQUIRE_THROWS_AS(layer.key(0), const assert_error&);
REQUIRE_THROWS_AS(layer.value(0), const assert_error&);
REQUIRE_THROWS_AS(layer.get_feature_by_id(0), const assert_error&);
REQUIRE_THROWS_AS(layer.next_feature(), const assert_error&);
REQUIRE_ASSERT(layer.reset_feature());
}
TEST_CASE("read a layer") {
const auto data = load_test_tile();
vtzero::vector_tile tile{data};
auto layer = tile.get_layer_by_name("bridge");
REQUIRE(layer.valid());
REQUIRE(layer);
REQUIRE(layer.version() == 1);
REQUIRE(layer.extent() == 4096);
REQUIRE(layer.name() == "bridge");
REQUIRE_FALSE(layer.empty());
REQUIRE(layer.num_features() == 2);
const auto& kt = layer.key_table();
REQUIRE(kt.size() == 4);
REQUIRE(kt[0] == "class");
const auto& vt = layer.value_table();
REQUIRE(vt.size() == 4);
REQUIRE(vt[0].type() == vtzero::property_value_type::string_value);
REQUIRE(vt[0].string_value() == "main");
REQUIRE(vt[1].type() == vtzero::property_value_type::int_value);
REQUIRE(vt[1].int_value() == 0);
REQUIRE(layer.key(0) == "class");
REQUIRE(layer.key(1) == "oneway");
REQUIRE(layer.key(2) == "osm_id");
REQUIRE(layer.key(3) == "type");
REQUIRE_THROWS_AS(layer.key(4), const vtzero::out_of_range_exception&);
REQUIRE(layer.value(0).string_value() == "main");
REQUIRE(layer.value(1).int_value() == 0);
REQUIRE(layer.value(2).string_value() == "primary");
REQUIRE(layer.value(3).string_value() == "tertiary");
REQUIRE_THROWS_AS(layer.value(4), const vtzero::out_of_range_exception&);
}
TEST_CASE("access features in a layer by id") {
const auto data = load_test_tile();
vtzero::vector_tile tile{data};
auto layer = tile.get_layer_by_name("building");
REQUIRE(layer);
REQUIRE(layer.num_features() == 937);
const auto feature = layer.get_feature_by_id(122);
REQUIRE(feature.id() == 122);
REQUIRE(feature.num_properties() == 0);
REQUIRE(feature.geometry_type() == vtzero::GeomType::POLYGON);
REQUIRE(feature.geometry().type() == vtzero::GeomType::POLYGON);
REQUIRE_FALSE(feature.geometry().data().empty());
REQUIRE_FALSE(layer.get_feature_by_id(844));
REQUIRE_FALSE(layer.get_feature_by_id(999999));
}
TEST_CASE("iterate over all features in a layer") {
const auto data = load_test_tile();
vtzero::vector_tile tile{data};
auto layer = tile.get_layer_by_name("building");
REQUIRE(layer);
std::size_t count = 0;
SECTION("external iterator") {
while (auto feature = layer.next_feature()) {
++count;
}
}
SECTION("internal iterator") {
const bool done = layer.for_each_feature([&count](const vtzero::feature& /*feature*/) noexcept {
++count;
return true;
});
REQUIRE(done);
}
REQUIRE(count == 937);
}
TEST_CASE("iterate over some features in a layer") {
const auto data = load_test_tile();
vtzero::vector_tile tile{data};
auto layer = tile.get_layer_by_name("building");
REQUIRE(layer);
uint64_t id_sum = 0;
SECTION("external iterator") {
while (auto feature = layer.next_feature()) {
if (feature.id() == 10) {
break;
}
id_sum += feature.id();
}
}
SECTION("internal iterator") {
const bool done = layer.for_each_feature([&id_sum](const vtzero::feature& feature) noexcept {
if (feature.id() == 10) {
return false;
}
id_sum += feature.id();
return true;
});
REQUIRE_FALSE(done);
}
const uint64_t expected = (10 - 1) * 10 / 2;
REQUIRE(id_sum == expected);
layer.reset_feature();
auto feature = layer.next_feature();
REQUIRE(feature);
REQUIRE(feature.id() == 1);
}
+42
View File
@@ -0,0 +1,42 @@
#include <test.hpp>
#include <sstream>
#include <string>
template <typename T>
std::string get_output(T v) {
std::stringstream ss;
ss << v;
return ss.str();
}
TEST_CASE("output GeomType") {
REQUIRE(get_output(vtzero::GeomType::UNKNOWN) == "unknown");
REQUIRE(get_output(vtzero::GeomType::POINT) == "point");
REQUIRE(get_output(vtzero::GeomType::LINESTRING) == "linestring");
REQUIRE(get_output(vtzero::GeomType::POLYGON) == "polygon");
}
TEST_CASE("output property_value_type") {
REQUIRE(get_output(vtzero::property_value_type::sint_value) == "sint");
}
TEST_CASE("output index_value") {
REQUIRE(get_output(vtzero::index_value{}) == "invalid");
REQUIRE(get_output(vtzero::index_value{5}) == "5");
}
TEST_CASE("output index_value_pair") {
const auto in = vtzero::index_value{};
const auto v2 = vtzero::index_value{2};
const auto v5 = vtzero::index_value{5};
REQUIRE(get_output(vtzero::index_value_pair{in, v2}) == "invalid");
REQUIRE(get_output(vtzero::index_value_pair{v2, v5}) == "[2,5]");
}
TEST_CASE("output point") {
REQUIRE(get_output(vtzero::point{}) == "(0,0)");
REQUIRE(get_output(vtzero::point{4, 7}) == "(4,7)");
}
+25
View File
@@ -0,0 +1,25 @@
#include <test.hpp>
#include <vtzero/geometry.hpp>
TEST_CASE("default constructed point") {
vtzero::point p{};
REQUIRE(p.x == 0);
REQUIRE(p.y == 0);
}
TEST_CASE("point") {
vtzero::point p1{4, 5};
vtzero::point p2{5, 4};
vtzero::point p3{4, 5};
REQUIRE(p1.x == 4);
REQUIRE(p1.y == 5);
REQUIRE_FALSE(p1 == p2);
REQUIRE(p1 != p2);
REQUIRE(p1 == p3);
}
+62
View File
@@ -0,0 +1,62 @@
#include <test.hpp>
#include <vtzero/builder.hpp>
#ifdef VTZERO_TEST_WITH_VARIANT
# include <boost/variant.hpp>
using variant_type = boost::variant<std::string, float, double, int64_t, uint64_t, bool>;
#endif
#include <map>
#include <string>
#include <unordered_map>
TEST_CASE("property map") {
vtzero::tile_builder tile;
vtzero::layer_builder layer_points{tile, "points"};
{
vtzero::point_feature_builder fbuilder{layer_points};
fbuilder.set_id(1);
fbuilder.add_points(1);
fbuilder.set_point(10, 10);
fbuilder.add_property("foo", "bar");
fbuilder.add_property("x", "y");
fbuilder.add_property("abc", "def");
fbuilder.commit();
}
std::string data = tile.serialize();
vtzero::vector_tile vt{data};
REQUIRE(vt.count_layers() == 1);
auto layer = vt.next_layer();
REQUIRE(layer.valid());
REQUIRE(layer.num_features() == 1);
const auto feature = layer.next_feature();
REQUIRE(feature.valid());
REQUIRE(feature.num_properties() == 3);
#ifdef VTZERO_TEST_WITH_VARIANT
SECTION("std::map") {
using prop_map_type = std::map<std::string, variant_type>;
auto map = vtzero::create_properties_map<prop_map_type>(feature);
REQUIRE(map.size() == 3);
REQUIRE(boost::get<std::string>(map["foo"]) == "bar");
REQUIRE(boost::get<std::string>(map["x"]) == "y");
REQUIRE(boost::get<std::string>(map["abc"]) == "def");
}
SECTION("std::unordered_map") {
using prop_map_type = std::unordered_map<std::string, variant_type>;
auto map = vtzero::create_properties_map<prop_map_type>(feature);
REQUIRE(map.size() == 3);
REQUIRE(boost::get<std::string>(map["foo"]) == "bar");
REQUIRE(boost::get<std::string>(map["x"]) == "y");
REQUIRE(boost::get<std::string>(map["abc"]) == "def");
}
#endif
}
+407
View File
@@ -0,0 +1,407 @@
#include <test.hpp>
#include <vtzero/encoded_property_value.hpp>
#include <vtzero/property.hpp>
#include <vtzero/property_value.hpp>
#include <vtzero/types.hpp>
#ifdef VTZERO_TEST_WITH_VARIANT
# include <boost/variant.hpp>
using variant_type = boost::variant<std::string, float, double, int64_t, uint64_t, bool>;
struct variant_mapping : vtzero::property_value_mapping {
using float_type = int64_t;
using double_type = int64_t;
};
#endif
#include <string>
struct visitor_test_void {
int x = 0;
template <typename T>
void operator()(T /*value*/) {
x = 1;
}
void operator()(vtzero::data_view /*value*/) {
x = 2;
}
};
struct visitor_test_int {
template <typename T>
int operator()(T /*value*/) {
return 1;
}
int operator()(vtzero::data_view /*value*/) {
return 2;
}
};
struct visitor_test_to_string {
template <typename T>
std::string operator()(T value) {
return std::to_string(value);
}
std::string operator()(vtzero::data_view value) {
return std::string{value.data(), value.size()};
}
};
struct string_conv {
std::string s;
template <typename T>
explicit string_conv(T value) :
s(std::to_string(value)) {
}
explicit operator std::string() {
return s;
}
};
struct string_mapping : vtzero::property_value_mapping {
using string_type = std::string;
using float_type = string_conv;
using double_type = string_conv;
using int_type = string_conv;
using uint_type = string_conv;
using bool_type = string_conv;
};
TEST_CASE("default constructed property_value") {
vtzero::property_value pv;
REQUIRE_FALSE(pv.valid());
REQUIRE(pv.data().data() == nullptr);
REQUIRE(pv == vtzero::property_value{});
REQUIRE_FALSE(pv != vtzero::property_value{});
}
TEST_CASE("empty property_value") {
char x[1] = {0};
vtzero::data_view dv{x, 0};
vtzero::property_value pv{dv};
REQUIRE(pv.valid());
REQUIRE_THROWS_AS(pv.type(), const vtzero::format_exception&);
}
TEST_CASE("string value") {
vtzero::encoded_property_value epv{"foo"};
vtzero::property_value pv{epv.data()};
REQUIRE(pv.string_value() == "foo");
visitor_test_void vt;
vtzero::apply_visitor(vt, pv);
REQUIRE(vt.x == 2);
const auto result = vtzero::apply_visitor(visitor_test_int{}, pv);
REQUIRE(result == 2);
const auto str = vtzero::apply_visitor(visitor_test_to_string{}, pv);
REQUIRE(str == "foo");
const std::string cs = vtzero::convert_property_value<std::string, string_mapping>(pv);
REQUIRE(cs == "foo");
#ifdef VTZERO_TEST_WITH_VARIANT
const auto vari = vtzero::convert_property_value<variant_type>(pv);
REQUIRE(boost::get<std::string>(vari) == "foo");
const auto conv = vtzero::convert_property_value<variant_type, variant_mapping>(pv);
REQUIRE(boost::get<std::string>(conv) == "foo");
#endif
}
TEST_CASE("float value") {
vtzero::encoded_property_value epv{1.2f};
vtzero::property_value pv{epv.data()};
REQUIRE(pv.float_value() == Approx(1.2));
visitor_test_void vt;
vtzero::apply_visitor(vt, pv);
REQUIRE(vt.x == 1);
const auto result = vtzero::apply_visitor(visitor_test_int{}, pv);
REQUIRE(result == 1);
const std::string cs = vtzero::convert_property_value<std::string, string_mapping>(pv);
REQUIRE(cs == "1.200000");
#ifdef VTZERO_TEST_WITH_VARIANT
const auto vari = vtzero::convert_property_value<variant_type>(pv);
REQUIRE(boost::get<float>(vari) == Approx(1.2));
const auto conv = vtzero::convert_property_value<variant_type, variant_mapping>(pv);
REQUIRE(boost::get<int64_t>(conv) == 1);
#endif
}
TEST_CASE("double value") {
vtzero::encoded_property_value epv{3.4};
vtzero::property_value pv{epv.data()};
REQUIRE(pv.double_value() == Approx(3.4));
const auto result = vtzero::apply_visitor(visitor_test_int{}, pv);
REQUIRE(result == 1);
const std::string cs = vtzero::convert_property_value<std::string, string_mapping>(pv);
REQUIRE(cs == "3.400000");
}
TEST_CASE("int value") {
vtzero::encoded_property_value epv{vtzero::int_value_type{42}};
vtzero::property_value pv{epv.data()};
REQUIRE(pv.int_value() == 42);
const auto str = vtzero::apply_visitor(visitor_test_to_string{}, pv);
REQUIRE(str == "42");
const std::string cs = vtzero::convert_property_value<std::string, string_mapping>(pv);
REQUIRE(cs == "42");
}
TEST_CASE("uint value") {
vtzero::encoded_property_value epv{vtzero::uint_value_type{99}};
vtzero::property_value pv{epv.data()};
REQUIRE(pv.uint_value() == 99);
const auto str = vtzero::apply_visitor(visitor_test_to_string{}, pv);
REQUIRE(str == "99");
const std::string cs = vtzero::convert_property_value<std::string, string_mapping>(pv);
REQUIRE(cs == "99");
}
TEST_CASE("sint value") {
vtzero::encoded_property_value epv{vtzero::sint_value_type{42}};
vtzero::property_value pv{epv.data()};
REQUIRE(pv.sint_value() == 42);
const auto str = vtzero::apply_visitor(visitor_test_to_string{}, pv);
REQUIRE(str == "42");
const std::string cs = vtzero::convert_property_value<std::string, string_mapping>(pv);
REQUIRE(cs == "42");
}
TEST_CASE("bool value") {
vtzero::encoded_property_value epv{true};
vtzero::property_value pv{epv.data()};
REQUIRE(pv.bool_value());
const auto str = vtzero::apply_visitor(visitor_test_to_string{}, pv);
REQUIRE(str == "1");
const std::string cs = vtzero::convert_property_value<std::string, string_mapping>(pv);
REQUIRE(cs == "1");
}
TEST_CASE("property and property_value equality comparisons") {
vtzero::encoded_property_value t{true};
vtzero::encoded_property_value f{false};
vtzero::encoded_property_value v1{vtzero::int_value_type{1}};
vtzero::encoded_property_value vs{"foo"};
REQUIRE(t == t);
REQUIRE_FALSE(t != t);
REQUIRE_FALSE(t == f);
REQUIRE_FALSE(t == v1);
REQUIRE_FALSE(t == vs);
using pv = vtzero::property_value;
REQUIRE(pv{t.data()} == pv{t.data()});
REQUIRE_FALSE(pv{t.data()} != pv{t.data()});
REQUIRE_FALSE(pv{t.data()} == pv{f.data()});
REQUIRE_FALSE(pv{t.data()} == pv{v1.data()});
REQUIRE_FALSE(pv{t.data()} == pv{vs.data()});
}
TEST_CASE("property and property_value ordering") {
using pv = vtzero::property_value;
vtzero::encoded_property_value t{true};
vtzero::encoded_property_value f{false};
REQUIRE_FALSE(t < f);
REQUIRE_FALSE(t <= f);
REQUIRE(t > f);
REQUIRE(t >= f);
REQUIRE_FALSE(pv{t.data()} < pv{f.data()});
REQUIRE_FALSE(pv{t.data()} <= pv{f.data()});
REQUIRE(pv{t.data()} > pv{f.data()});
REQUIRE(pv{t.data()} >= pv{f.data()});
vtzero::encoded_property_value v1{vtzero::int_value_type{22}};
vtzero::encoded_property_value v2{vtzero::int_value_type{17}};
REQUIRE_FALSE(v1 < v2);
REQUIRE_FALSE(v1 <= v2);
REQUIRE(v1 > v2);
REQUIRE(v1 >= v2);
REQUIRE_FALSE(pv{v1.data()} < pv{v2.data()});
REQUIRE_FALSE(pv{v1.data()} <= pv{v2.data()});
REQUIRE(pv{v1.data()} > pv{v2.data()});
REQUIRE(pv{v1.data()} >= pv{v2.data()});
vtzero::encoded_property_value vsf{"foo"};
vtzero::encoded_property_value vsb{"bar"};
vtzero::encoded_property_value vsx{"foobar"};
REQUIRE_FALSE(vsf < vsb);
REQUIRE_FALSE(vsf <= vsb);
REQUIRE(vsf > vsb);
REQUIRE(vsf >= vsb);
REQUIRE_FALSE(pv{vsf.data()} < pv{vsb.data()});
REQUIRE_FALSE(pv{vsf.data()} <= pv{vsb.data()});
REQUIRE(pv{vsf.data()} > pv{vsb.data()});
REQUIRE(pv{vsf.data()} >= pv{vsb.data()});
REQUIRE(vsf < vsx);
REQUIRE(vsf <= vsx);
REQUIRE_FALSE(vsf > vsx);
REQUIRE_FALSE(vsf >= vsx);
REQUIRE(pv{vsf.data()} < pv{vsx.data()});
REQUIRE(pv{vsf.data()} <= pv{vsx.data()});
REQUIRE_FALSE(pv{vsf.data()} > pv{vsx.data()});
REQUIRE_FALSE(pv{vsf.data()} >= pv{vsx.data()});
}
TEST_CASE("default constructed property") {
vtzero::property p;
REQUIRE_FALSE(p.valid());
REQUIRE_FALSE(p);
REQUIRE(p.key().data() == nullptr);
REQUIRE(p.value().data().data() == nullptr);
}
TEST_CASE("valid property") {
vtzero::data_view k{"key"};
vtzero::encoded_property_value epv{"value"};
vtzero::property_value pv{epv.data()};
vtzero::property p{k, pv};
REQUIRE(p.key() == "key");
REQUIRE(p.value().string_value() == "value");
}
TEST_CASE("create encoded property values from different string types") {
const std::string v{"value"};
vtzero::encoded_property_value epv1{vtzero::string_value_type{"value"}};
vtzero::encoded_property_value epv2{"value"};
vtzero::encoded_property_value epv3{v};
vtzero::encoded_property_value epv4{vtzero::data_view{v}};
vtzero::encoded_property_value epv5{"valuexxxxxxxxx", 5};
REQUIRE(epv1 == epv2);
REQUIRE(epv1 == epv3);
REQUIRE(epv1 == epv4);
REQUIRE(epv1 == epv5);
}
TEST_CASE("create encoded property values from different floating point types") {
vtzero::encoded_property_value f1{vtzero::float_value_type{3.2f}};
vtzero::encoded_property_value f2{3.2f};
vtzero::encoded_property_value d1{vtzero::double_value_type{3.2}};
vtzero::encoded_property_value d2{3.2};
REQUIRE(f1 == f2);
REQUIRE(d1 == d2);
vtzero::property_value pvf{f1.data()};
vtzero::property_value pvd{d1.data()};
REQUIRE(pvf.float_value() == Approx(pvd.double_value()));
}
TEST_CASE("create encoded property values from different integer types") {
vtzero::encoded_property_value i1{vtzero::int_value_type{7}};
vtzero::encoded_property_value i2{int64_t(7)};
vtzero::encoded_property_value i3{int32_t(7)};
vtzero::encoded_property_value i4{int16_t(7)};
vtzero::encoded_property_value u1{vtzero::uint_value_type{7}};
vtzero::encoded_property_value u2{uint64_t(7)};
vtzero::encoded_property_value u3{uint32_t(7)};
vtzero::encoded_property_value u4{uint16_t(7)};
vtzero::encoded_property_value s1{vtzero::sint_value_type{7}};
REQUIRE(i1 == i2);
REQUIRE(i1 == i3);
REQUIRE(i1 == i4);
REQUIRE(u1 == u2);
REQUIRE(u1 == u3);
REQUIRE(u1 == u4);
REQUIRE_FALSE(i1 == u1);
REQUIRE_FALSE(i1 == s1);
REQUIRE_FALSE(u1 == s1);
REQUIRE(i1.hash() == i2.hash());
REQUIRE(u1.hash() == u2.hash());
vtzero::property_value pvi{i1.data()};
vtzero::property_value pvu{u1.data()};
vtzero::property_value pvs{s1.data()};
REQUIRE(pvi.int_value() == pvu.uint_value());
REQUIRE(pvi.int_value() == pvs.sint_value());
}
TEST_CASE("create encoded property values from different bool types") {
vtzero::encoded_property_value b1{vtzero::bool_value_type{true}};
vtzero::encoded_property_value b2{true};
REQUIRE(b1 == b2);
REQUIRE(b1.hash() == b2.hash());
}
TEST_CASE("property equality comparison operator") {
std::string k = "key";
vtzero::encoded_property_value epv1{"value"};
vtzero::encoded_property_value epv2{"another value"};
vtzero::property_value pv1{epv1.data()};
vtzero::property_value pv2{epv2.data()};
vtzero::property p1{k, pv1};
vtzero::property p2{k, pv1};
vtzero::property p3{k, pv2};
REQUIRE(p1 == p2);
REQUIRE_FALSE(p1 == p3);
}
TEST_CASE("property inequality comparison operator") {
std::string k1 = "key";
std::string k2 = "another_key";
vtzero::encoded_property_value epv1{"value"};
vtzero::encoded_property_value epv2{"another value"};
vtzero::property_value pv1{epv1.data()};
vtzero::property_value pv2{epv2.data()};
vtzero::property p1{k1, pv1};
vtzero::property p2{k1, pv1};
vtzero::property p3{k1, pv2};
vtzero::property p4{k2, pv2};
REQUIRE_FALSE(p1 != p2);
REQUIRE(p1 != p3);
REQUIRE(p3 != p4);
}
+116
View File
@@ -0,0 +1,116 @@
#include <test.hpp>
#include <vtzero/types.hpp>
#include <string>
TEST_CASE("default constructed string_value_type") {
vtzero::string_value_type v;
REQUIRE(v.value.data() == nullptr);
}
TEST_CASE("string_value_type with value") {
vtzero::string_value_type v{"foo"};
REQUIRE(v.value.data()[0] == 'f');
REQUIRE(v.value.size() == 3);
}
TEST_CASE("default constructed float_value_type") {
vtzero::float_value_type v;
REQUIRE(v.value == Approx(0.0));
}
TEST_CASE("float_value_type with value") {
float x = 2.7f;
vtzero::float_value_type v{x};
REQUIRE(v.value == Approx(x));
}
TEST_CASE("default constructed double_value_type") {
vtzero::double_value_type v;
REQUIRE(v.value == Approx(0.0));
}
TEST_CASE("double_value_type with value") {
double x = 2.7;
vtzero::double_value_type v{x};
REQUIRE(v.value == Approx(x));
}
TEST_CASE("default constructed int_value_type") {
vtzero::int_value_type v;
REQUIRE(v.value == 0);
}
TEST_CASE("int_value_type with value") {
vtzero::int_value_type v{123};
REQUIRE(v.value == 123);
}
TEST_CASE("default constructed uint_value_type") {
vtzero::uint_value_type v;
REQUIRE(v.value == 0);
}
TEST_CASE("uint_value_type with value") {
vtzero::uint_value_type v{123};
REQUIRE(v.value == 123);
}
TEST_CASE("default constructed sint_value_type") {
vtzero::sint_value_type v;
REQUIRE(v.value == 0);
}
TEST_CASE("sint_value_type with value") {
vtzero::sint_value_type v{-14};
REQUIRE(v.value == -14);
}
TEST_CASE("default constructed bool_value_type") {
vtzero::bool_value_type v;
REQUIRE_FALSE(v.value);
}
TEST_CASE("bool_value_type with value") {
bool x = true;
vtzero::bool_value_type v{x};
REQUIRE(v.value);
}
TEST_CASE("property_value_type names") {
REQUIRE(std::string{vtzero::property_value_type_name(vtzero::property_value_type::string_value)} == "string");
REQUIRE(std::string{vtzero::property_value_type_name(vtzero::property_value_type::float_value)} == "float");
REQUIRE(std::string{vtzero::property_value_type_name(vtzero::property_value_type::double_value)} == "double");
REQUIRE(std::string{vtzero::property_value_type_name(vtzero::property_value_type::int_value)} == "int");
REQUIRE(std::string{vtzero::property_value_type_name(vtzero::property_value_type::uint_value)} == "uint");
REQUIRE(std::string{vtzero::property_value_type_name(vtzero::property_value_type::sint_value)} == "sint");
REQUIRE(std::string{vtzero::property_value_type_name(vtzero::property_value_type::bool_value)} == "bool");
}
TEST_CASE("default constructed index value") {
vtzero::index_value v;
REQUIRE_FALSE(v.valid());
REQUIRE_ASSERT(v.value());
}
TEST_CASE("valid index value") {
vtzero::index_value v{32};
REQUIRE(v.valid());
REQUIRE(v.value() == 32);
}
TEST_CASE("default constructed geometry") {
vtzero::geometry geom;
REQUIRE(geom.type() == vtzero::GeomType::UNKNOWN);
REQUIRE(geom.data().empty());
}
TEST_CASE("GeomType names") {
REQUIRE(std::string{vtzero::geom_type_name(vtzero::GeomType::UNKNOWN)} == "unknown");
REQUIRE(std::string{vtzero::geom_type_name(vtzero::GeomType::POINT)} == "point");
REQUIRE(std::string{vtzero::geom_type_name(vtzero::GeomType::LINESTRING)} == "linestring");
REQUIRE(std::string{vtzero::geom_type_name(vtzero::GeomType::POLYGON)} == "polygon");
}
+139
View File
@@ -0,0 +1,139 @@
#include <test.hpp>
#include <vtzero/vector_tile.hpp>
#include <string>
#include <vector>
TEST_CASE("open a vector tile with string") {
const auto data = load_test_tile();
REQUIRE(vtzero::is_vector_tile(data));
vtzero::vector_tile tile{data};
REQUIRE_FALSE(tile.empty());
REQUIRE(tile.count_layers() == 12);
}
TEST_CASE("open a vector tile with data_view") {
const auto data = load_test_tile();
const vtzero::data_view dv{data};
vtzero::vector_tile tile{dv};
REQUIRE_FALSE(tile.empty());
REQUIRE(tile.count_layers() == 12);
}
TEST_CASE("open a vector tile with pointer and size") {
const auto data = load_test_tile();
vtzero::vector_tile tile{data.data(), data.size()};
REQUIRE_FALSE(tile.empty());
REQUIRE(tile.count_layers() == 12);
}
TEST_CASE("get layer by index") {
const auto data = load_test_tile();
vtzero::vector_tile tile{data};
auto layer = tile.get_layer(0);
REQUIRE(layer);
REQUIRE(layer.name() == "landuse");
layer = tile.get_layer(1);
REQUIRE(layer);
REQUIRE(layer.name() == "waterway");
layer = tile.get_layer(11);
REQUIRE(layer);
REQUIRE(layer.name() == "waterway_label");
layer = tile.get_layer(12);
REQUIRE_FALSE(layer);
}
TEST_CASE("get layer by name") {
const auto data = load_test_tile();
vtzero::vector_tile tile{data};
auto layer = tile.get_layer_by_name("landuse");
REQUIRE(layer);
REQUIRE(layer.name() == "landuse");
layer = tile.get_layer_by_name(std::string{"road"});
REQUIRE(layer);
REQUIRE(layer.name() == "road");
const vtzero::data_view name{"poi_label"};
layer = tile.get_layer_by_name(name);
REQUIRE(layer);
REQUIRE(layer.name() == "poi_label");
layer = tile.get_layer_by_name("unknown");
REQUIRE_FALSE(layer);
}
TEST_CASE("iterate over layers") {
const auto data = load_test_tile();
vtzero::vector_tile tile{data};
std::vector<std::string> names;
SECTION("external iterator") {
while (auto layer = tile.next_layer()) {
names.emplace_back(layer.name());
}
}
SECTION("internal iterator") {
const bool done = tile.for_each_layer([&names](const vtzero::layer& layer) {
names.emplace_back(layer.name());
return true;
});
REQUIRE(done);
}
REQUIRE(names.size() == 12);
static std::vector<std::string> expected = {
"landuse", "waterway", "water", "barrier_line", "building", "road",
"bridge", "place_label", "water_label", "poi_label", "road_label",
"waterway_label"
};
REQUIRE(names == expected);
tile.reset_layer();
int num = 0;
while (auto layer = tile.next_layer()) {
++num;
}
REQUIRE(num == 12);
}
TEST_CASE("iterate over some of the layers") {
const auto data = load_test_tile();
vtzero::vector_tile tile{data};
int num_layers = 0;
SECTION("external iterator") {
while (auto layer = tile.next_layer()) {
++num_layers;
if (layer.name() == "water") {
break;
}
}
}
SECTION("internal iterator") {
const bool done = tile.for_each_layer([&num_layers](const vtzero::layer& layer) noexcept {
++num_layers;
return layer.name() != "water";
});
REQUIRE_FALSE(done);
}
REQUIRE(num_layers == 3);
}
+25
View File
@@ -0,0 +1,25 @@
#define CATCH_CONFIG_MAIN
#include "catch.hpp"
#include <test.hpp>
#include <fstream>
#include <stdexcept>
#include <string>
bool got_an_assert = false;
std::string load_test_tile() {
std::string path{"data/mapbox-streets-v6-14-8714-8017.mvt"};
std::ifstream stream{path, std::ios_base::in|std::ios_base::binary};
if (!stream.is_open()) {
throw std::runtime_error{"could not open: '" + path + "'"};
}
const std::string message{std::istreambuf_iterator<char>(stream.rdbuf()),
std::istreambuf_iterator<char>()};
stream.close();
return message;
}