diff --git a/src/parse.tpp b/src/parse.tpp index 0fe3b4b..c532c73 100644 --- a/src/parse.tpp +++ b/src/parse.tpp @@ -11,6 +11,10 @@ namespace wavefront { using namespace std::string_literals; coordinate_data_t result; + if (!scan_data.category_map.contains("v"s)) { + throw parse_error("Missing required \"v\" data"); + } + const auto &position_data = scan_data.category_map.at("v"s); for (const auto &position_index : face_data.index_position_set) { std::array position_coordinates; diff --git a/tests/unit/parse_test.cpp b/tests/unit/parse_test.cpp index 0185a1b..d7d5023 100644 --- a/tests/unit/parse_test.cpp +++ b/tests/unit/parse_test.cpp @@ -1,4 +1,6 @@ +#include #include +#include #include @@ -6,6 +8,21 @@ #include "scan.hpp" namespace { + #define ASSERT_COORDINATE_3D(container, line, x, y, z) \ + { \ + const auto &coord = (container).at(line); \ + EXPECT_FLOAT_EQ(coord[0], (x)); \ + EXPECT_FLOAT_EQ(coord[1], (y)); \ + EXPECT_FLOAT_EQ(coord[2], (z)); \ + } + + #define ASSERT_COORDINATE_2D(container, line, x, y) \ + { \ + const auto &coord = (container).at(line); \ + EXPECT_FLOAT_EQ(coord[0], (x)); \ + EXPECT_FLOAT_EQ(coord[1], (y)); \ + } + TEST(ParseFaceData, BuildsTrianglesAndIndexSets) { wavefront::scan_result scan_result; scan_result.total_lines = 26; @@ -89,41 +106,130 @@ namespace { const auto coordinate_data = wavefront::parse_coordinate_data(scan_result, face_data); ASSERT_EQ(coordinate_data.position_coordinates.size(), 9u); - const auto &pos_line_2 = coordinate_data.position_coordinates.at(3u); - EXPECT_FLOAT_EQ(pos_line_2[0], 0.1f); - EXPECT_FLOAT_EQ(pos_line_2[1], 0.2f); - EXPECT_FLOAT_EQ(pos_line_2[2], 0.3f); - - const auto &pos_line_5 = coordinate_data.position_coordinates.at(6u); - EXPECT_FLOAT_EQ(pos_line_5[0], 1.1f); - EXPECT_FLOAT_EQ(pos_line_5[1], 1.2f); - EXPECT_FLOAT_EQ(pos_line_5[2], 1.3f); - - const auto &pos_line_10 = coordinate_data.position_coordinates.at(11u); - EXPECT_FLOAT_EQ(pos_line_10[0], 2.3f); - EXPECT_FLOAT_EQ(pos_line_10[1], 2.4f); - EXPECT_FLOAT_EQ(pos_line_10[2], 2.5f); + ASSERT_COORDINATE_3D(coordinate_data.position_coordinates, 3u, 0.1f, 0.2f, 0.3f); + ASSERT_COORDINATE_3D(coordinate_data.position_coordinates, 4u, 0.2f, 0.3f, 0.4f); + ASSERT_COORDINATE_3D(coordinate_data.position_coordinates, 5u, 0.3f, 0.4f, 0.5f); + ASSERT_COORDINATE_3D(coordinate_data.position_coordinates, 6u, 1.1f, 1.2f, 1.3f); + ASSERT_COORDINATE_3D(coordinate_data.position_coordinates, 7u, 1.2f, 1.3f, 1.4f); + ASSERT_COORDINATE_3D(coordinate_data.position_coordinates, 8u, 1.3f, 1.4f, 1.5f); + ASSERT_COORDINATE_3D(coordinate_data.position_coordinates, 9u, 2.1f, 2.2f, 2.3f); + ASSERT_COORDINATE_3D(coordinate_data.position_coordinates, 10u, 2.2f, 2.3f, 2.4f); + ASSERT_COORDINATE_3D(coordinate_data.position_coordinates, 11u, 2.3f, 2.4f, 2.5f); ASSERT_EQ(coordinate_data.normal_coordinates.size(), 3u); - const auto &normal_line_11 = coordinate_data.normal_coordinates.at(12u); - EXPECT_FLOAT_EQ(normal_line_11[0], 0.15f); - EXPECT_FLOAT_EQ(normal_line_11[1], 0.25f); - EXPECT_FLOAT_EQ(normal_line_11[2], 0.35f); - - const auto &normal_line_13 = coordinate_data.normal_coordinates.at(14u); - EXPECT_FLOAT_EQ(normal_line_13[0], 0.35f); - EXPECT_FLOAT_EQ(normal_line_13[1], 0.45f); - EXPECT_FLOAT_EQ(normal_line_13[2], 0.55f); + ASSERT_COORDINATE_3D(coordinate_data.normal_coordinates, 12u, 0.15f, 0.25f, 0.35f); + ASSERT_COORDINATE_3D(coordinate_data.normal_coordinates, 13u, 0.25f, 0.35f, 0.45f); + ASSERT_COORDINATE_3D(coordinate_data.normal_coordinates, 14u, 0.35f, 0.45f, 0.55f); ASSERT_EQ(coordinate_data.texture_coordinates.index(), 2u); - const auto &texcoords = std::get<2>(coordinate_data.texture_coordinates); - ASSERT_EQ(texcoords.size(), 2u); - const auto &tex_line_14 = texcoords.at(15u); - EXPECT_FLOAT_EQ(tex_line_14[0], 0.9f); - EXPECT_FLOAT_EQ(tex_line_14[1], 0.8f); + ASSERT_EQ(std::get<2>(coordinate_data.texture_coordinates).size(), 2u); + ASSERT_COORDINATE_2D(std::get<2>(coordinate_data.texture_coordinates), 15u, 0.9f, 0.8f); + ASSERT_COORDINATE_2D(std::get<2>(coordinate_data.texture_coordinates), 16u, 0.8f, 0.7f); + } - const auto &tex_line_15 = texcoords.at(16u); - EXPECT_FLOAT_EQ(tex_line_15[0], 0.8f); - EXPECT_FLOAT_EQ(tex_line_15[1], 0.7f); + struct InvalidNumberCase { + std::string line_type; + std::size_t invalid_index; + std::string expected_message; + }; + + class ParseCoordinateDataInvalidNumberTest + : public ::testing::TestWithParam { + }; + + static std::string build_line_with_invalid_number( + const std::string &line_type, + std::size_t invalid_index + ) { + std::vector values; + if (line_type == "vt") { + values = {"0.9", "0.8", "0.7"}; + } else { + values = {"0.1", "0.2", "0.3"}; + } + if (invalid_index < values.size()) { + values[invalid_index] = "x"; + } + std::string line = line_type; + for (const auto &value : values) { + line += " "; + line += value; + } + return line; + } + + TEST_P(ParseCoordinateDataInvalidNumberTest, ThrowsOnInvalidNumber) { + const auto ¶m = GetParam(); + + wavefront::scan_result scan_result; + scan_result.total_lines = 3; + scan_result.line_data = { + {1u, "v 0.1 0.2 0.3"}, + {3u, build_line_with_invalid_number(param.line_type, param.invalid_index)} + }; + + if (param.line_type == "v") { + scan_result.category_map = { + {"v", {0u, 1u, 3u}} + }; + } else { + scan_result.category_map = { + {"v", {0u, 1u}}, + {param.line_type, {0u, 3u}} + }; + } + + wavefront::wavefront_face_data_result_t face_data; + if (param.line_type == "v") { + face_data.index_position_set = {2}; + } else if (param.line_type == "vn") { + face_data.index_normal_set = {1}; + } else { + face_data.index_texcoord_set = {1}; + } + + try { + (void)wavefront::parse_coordinate_data(scan_result, face_data); + FAIL() << "Expected parse_error"; + } catch (const wavefront::parse_error &ex) { + EXPECT_EQ(std::string(ex.what()), param.expected_message); + } + } + + INSTANTIATE_TEST_SUITE_P( + ParseCoordinateData, + ParseCoordinateDataInvalidNumberTest, + ::testing::Values( + InvalidNumberCase{"v", 0u, "[3]: Unable to parse \"v\" floating point value"}, + InvalidNumberCase{"v", 1u, "[3]: Unable to parse \"v\" floating point value"}, + InvalidNumberCase{"v", 2u, "[3]: Unable to parse \"v\" floating point value"}, + InvalidNumberCase{"vn", 0u, "[3]: Unable to parse \"vn\" floating point value"}, + InvalidNumberCase{"vn", 1u, "[3]: Unable to parse \"vn\" floating point value"}, + InvalidNumberCase{"vn", 2u, "[3]: Unable to parse \"vn\" floating point value"}, + InvalidNumberCase{"vt", 0u, "[3]: Unable to parse \"vt\" floating point value"}, + InvalidNumberCase{"vt", 1u, "[3]: Unable to parse \"vt\" floating point value"}, + InvalidNumberCase{"vt", 2u, "[3]: Unable to parse \"vt\" floating point value"} + ) + ); + + TEST(ParseCoordinateData, ThrowsWhenMissingVertexData) { + wavefront::scan_result scan_result; + scan_result.total_lines = 3; + scan_result.line_data = { + {3u, "vn 0.1 0.2 0.3"} + }; + scan_result.category_map = { + {"vn", {0u, 3u}} + }; + + wavefront::wavefront_face_data_result_t face_data; + face_data.index_position_set = {1}; + + try { + (void)wavefront::parse_coordinate_data(scan_result, face_data); + FAIL() << "Expected parse_error"; + } catch (const wavefront::parse_error &ex) { + EXPECT_EQ(std::string(ex.what()), "Missing required \"v\" data"); + } } }