/// @file regression_extreme.cpp /// @brief 极端坐标回归测试 /// /// 覆盖场景: /// 1. 极小坐标(1e-15) /// 2. 极大坐标(1e15) /// 3. NaN 输入 /// 4. Inf 输入 /// /// 每个测试:构造极端体 → 布尔/修复/验证 → 断言不崩溃 #include #include "vde/brep/brep.h" #include "vde/brep/modeling.h" #include "vde/brep/brep_boolean.h" #include "vde/brep/brep_validate.h" #include "vde/brep/brep_heal.h" #include "vde/core/point.h" #include #include using namespace vde::brep; using namespace vde::core; // ── 极小坐标测试 ── TEST(RegressionExtreme, TinyCoordinates_1eMinus15) { // 极小的盒子:尺寸为 1e-15 double s = 1e-15; EXPECT_NO_THROW({ auto tiny = make_box(s, s, s); // 验证合法性 EXPECT_TRUE(tiny.is_valid()); // 布尔运算:与正常盒子 auto box = make_box(1.0, 1.0, 1.0); auto u = brep_union(tiny, box); EXPECT_TRUE(u.is_valid()); auto i = brep_intersection(tiny, box); EXPECT_TRUE(i.is_valid()); // 导出网格 auto mesh = tiny.to_mesh(); (void)mesh; }); } TEST(RegressionExtreme, TinyCoordinates_1eMinus10) { double s = 1e-10; EXPECT_NO_THROW({ auto tiny = make_box(s, s, s); EXPECT_TRUE(tiny.is_valid()); auto mesh = tiny.to_mesh(); (void)mesh; // 修复流水线 BrepModel copy = tiny; heal_topology(copy, s * 0.1); }); } TEST(RegressionExtreme, TinyCoordinates_Mixed) { // 一个维度极小,其他正常 EXPECT_NO_THROW({ auto thin = make_box(1e-15, 1.0, 1.0); EXPECT_NO_THROW({ thin.is_valid(); }); auto result = validate(thin); (void)result; auto mesh = thin.to_mesh(); (void)mesh; }); } // ── 极大坐标测试 ── TEST(RegressionExtreme, HugeCoordinates_1e15) { double s = 1e15; EXPECT_NO_THROW({ auto huge = make_box(s, s, s); // 基本验证不崩溃 EXPECT_TRUE(huge.is_valid()); // 包围盒计算 auto bb = huge.bounds(); EXPECT_TRUE(std::isfinite(bb.min().x())); EXPECT_TRUE(std::isfinite(bb.max().x())); // 布尔自交 auto u = brep_union(huge, huge); EXPECT_TRUE(u.is_valid()); // 网格导出(大尺寸模型) auto mesh = huge.to_mesh(0.01 * s); (void)mesh; }); } TEST(RegressionExtreme, HugeVsTiny) { // 巨大体与极小体的布尔 EXPECT_NO_THROW({ auto huge = make_box(1e12, 1e12, 1e12); auto tiny = make_box(1e-12, 1e-12, 1e-12); auto u = brep_union(huge, tiny); EXPECT_TRUE(u.is_valid()); auto i = brep_intersection(huge, tiny); EXPECT_TRUE(i.is_valid()); }); } // ── NaN 输入测试 ── TEST(RegressionExtreme, NaN_Handling) { double nan = std::numeric_limits::quiet_NaN(); // make_box 应对 NaN 表现得优雅(返回无效体或抛出,但绝不能崩溃) EXPECT_NO_THROW({ auto body = make_box(nan, 1.0, 1.0); (void)body; }); EXPECT_NO_THROW({ auto body = make_box(1.0, nan, 1.0); (void)body; }); EXPECT_NO_THROW({ auto body = make_box(1.0, 1.0, nan); (void)body; }); EXPECT_NO_THROW({ auto body = make_box(nan, nan, nan); (void)body; }); } TEST(RegressionExtreme, NaN_BooleanResilience) { // 若 NaN 产生了有效的 body,检查布尔运算不崩溃 auto good = make_box(2.0, 2.0, 2.0); // 将所有尝试包裹在 EXPECT_NO_THROW 中 EXPECT_NO_THROW({ try { auto bad = make_box(std::numeric_limits::quiet_NaN(), 1.0, 1.0); auto u = brep_union(good, bad); (void)u; } catch (...) { // 允许抛异常但不应崩溃 } }); } // ── Inf 输入测试 ── TEST(RegressionExtreme, Inf_Handling) { double inf = std::numeric_limits::infinity(); EXPECT_NO_THROW({ auto body = make_box(inf, 1.0, 1.0); (void)body; }); EXPECT_NO_THROW({ auto body = make_box(1.0, inf, 1.0); (void)body; }); EXPECT_NO_THROW({ auto body = make_box(1.0, 1.0, inf); (void)body; }); } // ── 极大值 vs 极小值布尔 ── TEST(RegressionExtreme, MaxDouble_Boolean) { double big = 1e100; double small = 1e-100; EXPECT_NO_THROW({ auto a = make_box(big, 1.0, 1.0); auto b = make_box(small, 1.0, 1.0); auto u = brep_union(a, b); (void)u.is_valid(); }); } // ── 边界值批处理 ── TEST(RegressionExtreme, BoundaryValuesBatch) { // 一系列边界值,确保每个都不会崩溃 double values[] = { 0.0, std::numeric_limits::min(), std::numeric_limits::denorm_min(), std::numeric_limits::epsilon(), 1e-15, 1e-10, 1e-5, 1.0, 10.0, 100.0, 1e5, 1e10, 1e15, std::numeric_limits::max() * 0.5, }; for (double v : values) { if (!std::isfinite(v)) continue; EXPECT_NO_THROW({ auto body = make_box(v, v, v); body.is_valid(); auto mesh = body.to_mesh(); (void)mesh; }) << "failed at v=" << v; } // 混合边界值布尔 auto a = make_box(values[0], 1.0, 1.0); for (int i = 1; i < 10; ++i) { if (!std::isfinite(values[i])) continue; EXPECT_NO_THROW({ auto b = make_box(values[i], 1.0, 1.0); auto u = brep_union(a, b); (void)u.is_valid(); }) << "failed at i=" << i; } }