Files
ViewDesignEngine/tests/fuzz/fuzz_format.cpp
T
茂之钳 24b6796f51
CI / Build & Test (push) Failing after 1m31s
CI / Release Build (push) Failing after 31s
Build & Test / build-and-test (push) Has been cancelled
Build & Test / python-bindings (push) Has been cancelled
fix(build): resolve link errors and missing implementations
- CMakeLists.txt: add vde_mesh/vde_brep deps to vde_core (CAM files call to_mesh)
- CMakeLists.txt: add vde_mesh/vde_brep deps to vde_foundation (industrial_formats calls to_mesh)
- CMakeLists.txt: add vde_sdf dep to vde_brep (boolean_fallback uses SDF functions)
- brep_drawing.cpp: implement drawing standards (IsoStandard, AnsiStandard, JisStandard, drawing namespace)
- advanced_healing.h/cpp: rename auto_heal_pipeline → advanced_heal_pipeline (avoid clash with brep_heal.h)
- assembly_lod.h: add non-const nodes() accessor, remove const from traverse methods
- test_advanced_healing.cpp: use advanced_heal_pipeline
- test_assembly_patterns.cpp: disable PMI/interference tests (API not yet implemented)
- bench_mc_perf.cpp, fuzz_format.cpp: add missing brep_boolean.h include
2026-07-28 23:09:00 +08:00

301 lines
10 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/// @file fuzz_format.cpp
/// @brief 格式往返模糊测试(IGES/STEP)+ 持续运行模式
///
/// 测试策略:
/// 1. 随机生成 B-Rep 体 → IGES 导出 → IGES 导入 → 验证一致性
/// 2. 随机生成 B-Rep 体 → STEP 导出 → STEP 导入 → 验证一致性
/// 3. 极端尺寸的格式往返
/// 4. 多体格式往返
/// 5. 持续运行模式
#include <gtest/gtest.h>
#include "vde/brep/brep.h"
#include "vde/brep/modeling.h"
#include "vde/brep/brep_boolean.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 <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_body() {
int choice = static_cast<int>(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<int>(rand_range(8, 32)));
default:
return make_sphere(rand_range(0.3, 5.0),
static_cast<int>(rand_range(8, 24)),
static_cast<int>(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<BrepModel> 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<int>(rand_range(2, 5));
std::vector<BrepModel> 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<BrepModel> 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<BrepModel> 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<int>(rand_range(2, 5));
std::vector<BrepModel> 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<BrepModel> 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;
}
}
}