1
0

Compare commits

..

2 Commits

Author SHA1 Message Date
f10c2d4886 test: parse.underflow 2026-02-22 00:06:05 +02:00
114d0bc014 unit test: parse 2026-02-21 17:48:53 +02:00
2 changed files with 222 additions and 32 deletions

View File

@@ -11,6 +11,10 @@ namespace wavefront {
using namespace std::string_literals;
coordinate_data_t<FloatType> 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<FloatType, 3> position_coordinates;

View File

@@ -1,4 +1,6 @@
#include <string>
#include <variant>
#include <vector>
#include <gtest/gtest.h>
@@ -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,210 @@ namespace {
const auto coordinate_data = wavefront::parse_coordinate_data<float>(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<InvalidNumberCase> {
};
static std::string build_line_with_invalid_number(
const std::string &line_type,
std::size_t invalid_index
) {
std::vector<std::string> 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 &param = 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<float>(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<float>(scan_result, face_data);
FAIL() << "Expected parse_error";
} catch (const wavefront::parse_error &ex) {
EXPECT_EQ(std::string(ex.what()), "Missing required \"v\" data");
}
}
struct UnderflowCase {
std::string line_type;
std::size_t number_count;
std::string expected_message;
};
class ParseCoordinateDataUnderflowTest
: public ::testing::TestWithParam<UnderflowCase> {
};
static std::string build_line_with_count(
const std::string &line_type,
std::size_t number_count
) {
std::vector<std::string> values;
if (line_type == "vt") {
values = {"0.9", "0.8", "0.7"};
} else {
values = {"0.1", "0.2", "0.3"};
}
std::string line = line_type;
for (std::size_t i = 0; i < number_count && i < values.size(); ++i) {
line += " ";
line += values[i];
}
return line;
}
TEST_P(ParseCoordinateDataUnderflowTest, ThrowsOnInsufficientNumbers) {
const auto &param = 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_count(param.line_type, param.number_count)}
};
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<float>(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,
ParseCoordinateDataUnderflowTest,
::testing::Values(
UnderflowCase{"v", 0u, "[3]: Line \"v\" must contain at least 3 numbers"},
UnderflowCase{"v", 1u, "[3]: Line \"v\" must contain at least 3 numbers"},
UnderflowCase{"v", 2u, "[3]: Line \"v\" must contain at least 3 numbers"},
UnderflowCase{"vn", 0u, "[3]: Line \"vn\" must contain exactly 3 numbers"},
UnderflowCase{"vn", 1u, "[3]: Line \"vn\" must contain exactly 3 numbers"},
UnderflowCase{"vn", 2u, "[3]: Line \"vn\" must contain exactly 3 numbers"},
UnderflowCase{"vt", 0u, "[3]: Unable to parse \"vt\" line: expected minimum one number"}
)
);
}