#include #include #include #include #include using container = std::vector; using iterator = container::const_iterator; TEST_CASE("geometry_decoder") { const container g = {}; vtzero::detail::geometry_decoder 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 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 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 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 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 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 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 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 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 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 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::max()), protozero::encode_zigzag32(0), vtzero::detail::command_line_to(1), protozero::encode_zigzag32(1), protozero::encode_zigzag32(1) }; vtzero::detail::geometry_decoder 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::max(), 0)); REQUIRE(decoder.next_command(vtzero::detail::CommandId::LINE_TO)); REQUIRE(decoder.count() == 1); REQUIRE(decoder.next_point() == vtzero::point(std::numeric_limits::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::min()), vtzero::detail::command_line_to(1), protozero::encode_zigzag32(-1), protozero::encode_zigzag32(-1) }; vtzero::detail::geometry_decoder 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::min())); REQUIRE(decoder.next_command(vtzero::detail::CommandId::LINE_TO)); REQUIRE(decoder.count() == 1); REQUIRE(decoder.next_point() == vtzero::point(-1, std::numeric_limits::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 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 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&); }