/// @file fuzz_boolean.cpp /// @brief B-Rep 布尔随机参数模糊测试 + 持续运行模式 /// /// 测试策略: /// 1. 随机尺寸的盒子/圆柱/球体对做布尔运算 /// 2. 随机偏移后的布尔运算 /// 3. 连续布尔链式模糊测试 /// 4. 验证结果的合法性 /// 5. 持续运行模式 #include #include "vde/brep/brep.h" #include "vde/brep/brep_boolean.h" #include "vde/brep/modeling.h" #include "vde/brep/brep_validate.h" #include "vde/brep/brep_heal.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_box() { return make_box(rand_range(0.5, 10.0), rand_range(0.5, 10.0), rand_range(0.5, 10.0)); } BrepModel rand_cylinder() { return make_cylinder(rand_range(0.2, 5.0), rand_range(0.5, 10.0), static_cast(rand_range(8, 64))); } BrepModel rand_sphere() { return make_sphere(rand_range(0.3, 5.0), static_cast(rand_range(8, 32)), static_cast(rand_range(4, 16))); } BrepModel rand_primitive() { int choice = static_cast(rand_range(0, 3)); switch (choice) { case 0: return rand_box(); case 1: return rand_cylinder(); default: return rand_sphere(); } } } // anonymous // ═══════════════════════════════════════════════ // 随机盒子布尔测试 // ═══════════════════════════════════════════════ TEST(FuzzBoolean, RandomBoxUnion) { for (int i = 0; i < 50; ++i) { auto a = rand_box(); auto b = rand_box(); EXPECT_NO_THROW({ auto u = brep_union(a, b); EXPECT_TRUE(u.is_valid()); // 结果不应为空体 EXPECT_GT(u.num_vertices(), 0u); // 验证 auto result = validate(u); (void)result; }); } } TEST(FuzzBoolean, RandomBoxIntersection) { for (int i = 0; i < 50; ++i) { auto a = rand_box(); auto b = rand_box(); EXPECT_NO_THROW({ auto inter = brep_intersection(a, b); EXPECT_TRUE(inter.is_valid()); }); } } TEST(FuzzBoolean, RandomBoxDifference) { for (int i = 0; i < 50; ++i) { auto a = rand_box(); auto b = rand_box(); EXPECT_NO_THROW({ auto diff = brep_difference(a, b); EXPECT_TRUE(diff.is_valid()); }); } } // ═══════════════════════════════════════════════ // 随机基本体布尔混合测试 // ═══════════════════════════════════════════════ TEST(FuzzBoolean, RandomMixedPrimitives) { for (int i = 0; i < 60; ++i) { auto a = rand_primitive(); auto b = rand_primitive(); EXPECT_NO_THROW({ auto u = brep_union(a, b); EXPECT_TRUE(u.is_valid()) << "union failed at iteration " << i; auto inter = brep_intersection(a, b); EXPECT_TRUE(inter.is_valid()) << "intersection failed at iteration " << i; auto diff = brep_difference(a, b); EXPECT_TRUE(diff.is_valid()) << "difference failed at iteration " << i; }); } } // ═══════════════════════════════════════════════ // 随机布尔链(连续多个布尔操作) // ═══════════════════════════════════════════════ TEST(FuzzBoolean, RandomBooleanChain) { for (int i = 0; i < 20; ++i) { EXPECT_NO_THROW({ auto result = rand_primitive(); int chain_len = static_cast(rand_range(2, 6)); for (int j = 0; j < chain_len; ++j) { auto other = rand_primitive(); int op_choice = static_cast(rand_range(0, 3)); switch (op_choice) { case 0: result = brep_union(result, other); break; case 1: result = brep_intersection(result, other); break; default: result = brep_difference(result, other); break; } ASSERT_TRUE(result.is_valid()) << "chain failed at step " << j << " of chain " << i; } // 最终结果应仍有效 EXPECT_TRUE(result.is_valid()); }); } } // ═══════════════════════════════════════════════ // 自交操作模糊测试 // ═══════════════════════════════════════════════ TEST(FuzzBoolean, RandomSelfOperations) { for (int i = 0; i < 30; ++i) { auto body = rand_primitive(); EXPECT_NO_THROW({ auto u = brep_union(body, body); EXPECT_TRUE(u.is_valid()); auto inter = brep_intersection(body, body); EXPECT_TRUE(inter.is_valid()); auto diff = brep_difference(body, body); EXPECT_TRUE(diff.is_valid()); }); } } // ═══════════════════════════════════════════════ // 持续运行模式 // ═══════════════════════════════════════════════ TEST(FuzzBoolean, 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 a = rand_primitive(); auto b = rand_primitive(); // 三项布尔操作都必须成功 auto u = brep_union(a, b); ASSERT_TRUE(u.is_valid()) << "union failed at iteration " << iteration; auto inter = brep_intersection(a, b); ASSERT_TRUE(inter.is_valid()) << "intersection failed at iteration " << iteration; auto diff = brep_difference(a, b); ASSERT_TRUE(diff.is_valid()) << "difference failed at iteration " << iteration; // 验证 auto vr_u = validate(u); (void)vr_u; auto vr_i = validate(inter); (void)vr_i; if (iteration % 1000 == 0) { std::cout << "[FuzzBoolean] iteration=" << iteration << " union_faces=" << u.num_faces() << " intersection_faces=" << inter.num_faces() << std::endl; } } }