335 lines
14 KiB
C++
335 lines
14 KiB
C++
|
|
#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(), 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(), assert_error);
|
|
|
|
SECTION("trying to get LineTo command") {
|
|
REQUIRE_THROWS_AS(decoder.next_command(vtzero::detail::CommandId::LINE_TO), 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), 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(), 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), 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), 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), 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), vtzero::geometry_exception);
|
|
}
|
|
|