/// @file fuzz_format.cpp /// @brief 格式往返模糊测试(IGES/STEP)+ 持续运行模式 /// /// 测试策略: /// 1. 随机生成 B-Rep 体 → IGES 导出 → IGES 导入 → 验证一致性 /// 2. 随机生成 B-Rep 体 → STEP 导出 → STEP 导入 → 验证一致性 /// 3. 极端尺寸的格式往返 /// 4. 多体格式往返 /// 5. 持续运行模式 #include #include "vde/brep/brep.h" #include "vde/brep/modeling.h" #include "vde/brep/iges_export.h" #include "vde/brep/iges_import.h" #include "vde/brep/step_export.h" #include "vde/brep/step_import.h" #include "vde/core/point.h" #include #include #include #include using namespace vde::brep; using namespace vde::core; static std::mt19937 s_rng(42); namespace { double rand_range(double lo, double hi) { return std::uniform_real_distribution(lo, hi)(s_rng); } BrepModel rand_body() { int choice = static_cast(rand_range(0, 3)); switch (choice) { case 0: return make_box(rand_range(0.5, 10.0), rand_range(0.5, 10.0), rand_range(0.5, 10.0)); case 1: return make_cylinder(rand_range(0.3, 5.0), rand_range(0.5, 10.0), static_cast(rand_range(8, 32))); default: return make_sphere(rand_range(0.3, 5.0), static_cast(rand_range(8, 24)), static_cast(rand_range(4, 12))); } } } // anonymous // ═══════════════════════════════════════════════ // IGES 随机往返 // ═══════════════════════════════════════════════ TEST(FuzzFormat, Iges_RandomRoundTrip) { for (int i = 0; i < 30; ++i) { auto body = rand_body(); EXPECT_TRUE(body.is_valid()); // 导出 IGES std::string iges; EXPECT_NO_THROW({ iges = export_iges({body}); }); EXPECT_FALSE(iges.empty()) << "IGES export failed at iteration " << i; // 重新导入 std::vector loaded; EXPECT_NO_THROW({ loaded = import_iges_from_string(iges); }); EXPECT_FALSE(loaded.empty()) << "IGES import failed at iteration " << i; // 验证导入体 for (auto& lb : loaded) { EXPECT_TRUE(lb.is_valid()) << "imported body invalid at iteration " << i; } } } TEST(FuzzFormat, Iges_MultiBodyRoundTrip) { for (int i = 0; i < 15; ++i) { int count = static_cast(rand_range(2, 5)); std::vector bodies; for (int j = 0; j < count; ++j) { bodies.push_back(rand_body()); } std::string iges; EXPECT_NO_THROW({ iges = export_iges(bodies); }); EXPECT_FALSE(iges.empty()); std::vector loaded; EXPECT_NO_THROW({ loaded = import_iges_from_string(iges); }); EXPECT_FALSE(loaded.empty()); EXPECT_GE(loaded.size(), 1u); // 可能合并或保留多个体 for (auto& lb : loaded) { EXPECT_TRUE(lb.is_valid()); } } } TEST(FuzzFormat, Iges_ExtremeSizes) { // 极端尺寸的 IGES 往返 double sizes[] = {1e-3, 1e-1, 1.0, 10.0, 100.0, 1000.0}; for (double s : sizes) { auto body = make_box(s, s * 0.5, s * 2.0); EXPECT_NO_THROW({ std::string iges = export_iges({body}); EXPECT_FALSE(iges.empty()); auto loaded = import_iges_from_string(iges); EXPECT_FALSE(loaded.empty()); EXPECT_TRUE(loaded[0].is_valid()); }) << "failed at size=" << s; } } // ═══════════════════════════════════════════════ // STEP 随机往返 // ═══════════════════════════════════════════════ TEST(FuzzFormat, Step_RandomRoundTrip) { for (int i = 0; i < 30; ++i) { auto body = rand_body(); EXPECT_TRUE(body.is_valid()); std::string step; EXPECT_NO_THROW({ step = export_step({body}); }); EXPECT_FALSE(step.empty()) << "STEP export failed at iteration " << i; std::vector loaded; EXPECT_NO_THROW({ loaded = import_step_from_string(step); }); EXPECT_FALSE(loaded.empty()) << "STEP import failed at iteration " << i; for (auto& lb : loaded) { EXPECT_TRUE(lb.is_valid()) << "imported body invalid at iteration " << i; } } } TEST(FuzzFormat, Step_MultiBodyRoundTrip) { for (int i = 0; i < 15; ++i) { int count = static_cast(rand_range(2, 5)); std::vector bodies; for (int j = 0; j < count; ++j) { bodies.push_back(rand_body()); } std::string step; EXPECT_NO_THROW({ step = export_step(bodies); }); EXPECT_FALSE(step.empty()); std::vector loaded; EXPECT_NO_THROW({ loaded = import_step_from_string(step); }); EXPECT_FALSE(loaded.empty()); for (auto& lb : loaded) { EXPECT_TRUE(lb.is_valid()); } } } TEST(FuzzFormat, Step_ExtremeSizes) { double sizes[] = {1e-3, 1e-1, 1.0, 10.0, 100.0, 1000.0}; for (double s : sizes) { auto body = make_box(s, s * 0.5, s * 2.0); EXPECT_NO_THROW({ std::string step = export_step({body}); EXPECT_FALSE(step.empty()); auto loaded = import_step_from_string(step); EXPECT_FALSE(loaded.empty()); EXPECT_TRUE(loaded[0].is_valid()); }) << "failed at size=" << s; } } // ═══════════════════════════════════════════════ // 交叉格式往返(IGES → STEP → IGES) // ═══════════════════════════════════════════════ TEST(FuzzFormat, CrossFormat_IGES_to_STEP) { for (int i = 0; i < 15; ++i) { auto body = rand_body(); EXPECT_NO_THROW({ // IGES export → STEP import std::string iges = export_iges({body}); auto from_iges = import_iges_from_string(iges); EXPECT_FALSE(from_iges.empty()); // STEP export → IGES import std::string step = export_step({body}); auto from_step = import_step_from_string(step); EXPECT_FALSE(from_step.empty()); // Both should be valid EXPECT_TRUE(from_iges[0].is_valid()); EXPECT_TRUE(from_step[0].is_valid()); }); } } TEST(FuzzFormat, CrossFormat_STEP_to_IGES) { for (int i = 0; i < 15; ++i) { auto body = rand_body(); EXPECT_NO_THROW({ // STEP → IGES std::string step = export_step({body}); auto from_step = import_step_from_string(step); ASSERT_FALSE(from_step.empty()); std::string iges = export_iges(from_step); auto from_iges = import_iges_from_string(iges); EXPECT_FALSE(from_iges.empty()); EXPECT_TRUE(from_iges[0].is_valid()); }); } } // ═══════════════════════════════════════════════ // 布尔运算后的格式往返 // ═══════════════════════════════════════════════ TEST(FuzzFormat, BooleanThenRoundTrip) { for (int i = 0; i < 10; ++i) { auto a = rand_body(); auto b = rand_body(); EXPECT_NO_THROW({ // 先做布尔运算 auto u = brep_union(a, b); // IGES 往返 std::string iges = export_iges({u}); auto from_iges = import_iges_from_string(iges); EXPECT_FALSE(from_iges.empty()); EXPECT_TRUE(from_iges[0].is_valid()); // STEP 往返 std::string step = export_step({u}); auto from_step = import_step_from_string(step); EXPECT_FALSE(from_step.empty()); EXPECT_TRUE(from_step[0].is_valid()); }); } } // ═══════════════════════════════════════════════ // 持续运行模式 // ═══════════════════════════════════════════════ TEST(FuzzFormat, ContinuousFuzz) { const char* forever = std::getenv("VDE_FUZZ_FOREVER"); if (!forever || std::string(forever) != "1") { GTEST_SKIP() << "设置 VDE_FUZZ_FOREVER=1 启用持续模糊测试"; } int iteration = 0; while (true) { ++iteration; auto body = rand_body(); ASSERT_TRUE(body.is_valid()); // IGES 往返 std::string iges = export_iges({body}); ASSERT_FALSE(iges.empty()); auto from_iges = import_iges_from_string(iges); ASSERT_FALSE(from_iges.empty()) << "IGES import failed at iteration " << iteration; ASSERT_TRUE(from_iges[0].is_valid()); // STEP 往返 std::string step = export_step({body}); ASSERT_FALSE(step.empty()); auto from_step = import_step_from_string(step); ASSERT_FALSE(from_step.empty()) << "STEP import failed at iteration " << iteration; ASSERT_TRUE(from_step[0].is_valid()); if (iteration % 1000 == 0) { std::cout << "[FuzzFormat] iteration=" << iteration << " iges_len=" << iges.size() << " step_len=" << step.size() << std::endl; } } }