Files
ViewDesignEngine/tests/fuzz/fuzz_boolean.cpp
T

223 lines
7.2 KiB
C++
Raw Normal View History

/// @file fuzz_boolean.cpp
/// @brief B-Rep 布尔随机参数模糊测试 + 持续运行模式
///
/// 测试策略:
/// 1. 随机尺寸的盒子/圆柱/球体对做布尔运算
/// 2. 随机偏移后的布尔运算
/// 3. 连续布尔链式模糊测试
/// 4. 验证结果的合法性
/// 5. 持续运行模式
#include <gtest/gtest.h>
#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 <cmath>
#include <random>
#include <string>
#include <cstdlib>
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<double>(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<int>(rand_range(8, 64)));
}
BrepModel rand_sphere() {
return make_sphere(rand_range(0.3, 5.0),
static_cast<int>(rand_range(8, 32)),
static_cast<int>(rand_range(4, 16)));
}
BrepModel rand_primitive() {
int choice = static_cast<int>(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<int>(rand_range(2, 6));
for (int j = 0; j < chain_len; ++j) {
auto other = rand_primitive();
int op_choice = static_cast<int>(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;
}
}
}