#include #include #include #include #include "parse.hpp" #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; scan_result.line_data = { {17u, "f 1/1/1 2/2/2 3/3/2"}, {19u, "f 4/3/2 5/2/1 6/1/2"}, {21u, "f 7/2/2 8/3/2 9/1/1"}, {23u, "f 8/1/1 5/2/2 3/3/2"}, {25u, "f 2/1/1 6/2/2 4/3/2"} }; scan_result.category_map = { {"f", {17u, 19u, 21u, 23u, 25u}} }; const auto face_data = wavefront::parse_face_data(scan_result); EXPECT_EQ(face_data.triangle_list.size(), 5u); EXPECT_EQ(face_data.index_position_set.size(), 9u); EXPECT_TRUE(face_data.index_position_set.contains(1)); EXPECT_TRUE(face_data.index_position_set.contains(9)); EXPECT_EQ(face_data.index_normal_set.size(), 2u); EXPECT_TRUE(face_data.index_normal_set.contains(1)); EXPECT_TRUE(face_data.index_normal_set.contains(2)); EXPECT_EQ(face_data.index_texcoord_set.size(), 3u); EXPECT_TRUE(face_data.index_texcoord_set.contains(1)); EXPECT_TRUE(face_data.index_texcoord_set.contains(3)); const auto &first_triangle = face_data.triangle_list.at(0); EXPECT_EQ(first_triangle[0].face_line_number, 17u); EXPECT_EQ(first_triangle[0].position_index, 1); EXPECT_EQ(first_triangle[0].texcoord_index, 1); EXPECT_EQ(first_triangle[0].normal_index, 1); } TEST(ParseCoordinateData, MapsCoordinatesWithoutParsingFaces) { wavefront::scan_result scan_result; scan_result.total_lines = 26; scan_result.line_data = { {3u, "v 0.1 0.2 0.3"}, {4u, "v 0.2 0.3 0.4"}, {5u, "v 0.3 0.4 0.5"}, {6u, "v 1.1 1.2 1.3"}, {7u, "v 1.2 1.3 1.4"}, {8u, "v 1.3 1.4 1.5"}, {9u, "v 2.1 2.2 2.3"}, {10u, "v 2.2 2.3 2.4"}, {11u, "v 2.3 2.4 2.5"}, {12u, "vn 0.15 0.25 0.35"}, {13u, "vn 0.25 0.35 0.45"}, {14u, "vn 0.35 0.45 0.55"}, {15u, "vt 0.9 0.8"}, {16u, "vt 0.8 0.7"}, {17u, "f 1/1/1 2/2/2 3/3/2"}, {19u, "f 4/3/2 5/2/1 6/1/2"}, {21u, "f 7/2/2 8/3/2 9/1/1"}, {23u, "f 8/1/1 5/2/2 3/3/2"}, {25u, "f 2/1/1 6/2/2 4/3/2"} }; scan_result.category_map = { {"v", {0u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u, 11u}}, {"vn", {0u, 12u, 13u, 14u}}, {"vt", {0u, 15u, 16u}}, {"f", {17u, 19u, 21u, 23u, 25u}} }; wavefront::wavefront_face_data_result_t face_data; face_data.index_position_set = {1, 2, 3, 4, 5, 6, 7, 8, 9}; face_data.index_normal_set = {1, 2, 3}; face_data.index_texcoord_set = {1, 2}; face_data.triangle_list = { {{{17u, 1, 1, 1}, {17u, 2, 2, 2}, {17u, 3, 3, 2}}}, {{{19u, 4, 3, 2}, {19u, 5, 2, 1}, {19u, 6, 1, 2}}}, {{{21u, 7, 2, 2}, {21u, 8, 3, 2}, {21u, 9, 1, 1}}}, {{{23u, 8, 1, 1}, {23u, 5, 2, 2}, {23u, 3, 3, 2}}}, {{{25u, 2, 1, 1}, {25u, 6, 2, 2}, {25u, 4, 3, 2}}} }; const auto coordinate_data = wavefront::parse_coordinate_data(scan_result, face_data); ASSERT_EQ(coordinate_data.position_coordinates.size(), 9u); 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); 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); 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); } 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"); } } }