Files
ViewDesignEngine/tests/brep/test_v4_1.cpp
T

219 lines
7.4 KiB
C++
Raw Normal View History

#include "vde/brep/step_export.h"
#include "vde/brep/iges_export.h"
#include <gtest/gtest.h>
#include "vde/brep/large_assembly.h"
#include "vde/brep/format_io.h"
#include "vde/brep/modeling.h"
#include <cmath>
using namespace vde::brep;
using namespace vde::core;
// ═══════════════════════════════════════════════════════════
// LargeAssemblyManager
// ═══════════════════════════════════════════════════════════
TEST(LargeAssemblyTest, BuildIndex_EmptyAssembly) {
Assembly assy("empty");
LargeAssemblyManager mgr;
mgr.build_index(assy);
EXPECT_TRUE(mgr.index_built());
EXPECT_EQ(mgr.part_count(), 0);
}
TEST(LargeAssemblyTest, BuildIndex_SinglePart) {
Assembly assy("single");
assy.root.add_part("box", make_box(2, 2, 2));
LargeAssemblyManager mgr;
mgr.build_index(assy);
EXPECT_EQ(mgr.part_count(), 1);
}
TEST(LargeAssemblyTest, BuildIndex_MultipleParts) {
Assembly assy("multi");
for (int i = 0; i < 10; ++i) {
assy.root.add_part("p" + std::to_string(i), make_box(1, 1, 1),
translate(i * 3.0, 0, 0));
}
LargeAssemblyManager mgr;
mgr.build_index(assy);
EXPECT_EQ(mgr.part_count(), 10);
}
TEST(LargeAssemblyTest, QueryVisible_ReturnsIntersectingParts) {
Assembly assy("visible");
assy.root.add_part("near", make_box(2, 2, 2), translate(0, 0, 0));
assy.root.add_part("far", make_box(2, 2, 2), translate(20, 0, 0));
LargeAssemblyManager mgr;
mgr.build_index(assy);
// AABB covering origin region
AABB3D view(Point3D(-5, -5, -5), Point3D(5, 5, 5));
auto visible = mgr.query_visible(view);
EXPECT_GE(visible.size(), 1u);
// "near" should be visible
bool has_near = false;
for (auto& n : visible) if (n == "near") has_near = true;
EXPECT_TRUE(has_near);
}
TEST(LargeAssemblyTest, QueryVisible_FarRegion_ReturnsEmpty) {
Assembly assy("far_test");
assy.root.add_part("box", make_box(2, 2, 2), translate(0, 0, 0));
LargeAssemblyManager mgr;
mgr.build_index(assy);
// AABB far away
AABB3D view(Point3D(100, 100, 100), Point3D(110, 110, 110));
auto visible = mgr.query_visible(view);
EXPECT_EQ(visible.size(), 0u);
}
TEST(LargeAssemblyTest, ComputeStats_AccurateCounts) {
Assembly assy("stats");
assy.root.add_part("p1", make_box(1, 1, 1));
assy.root.add_part("p2", make_box(1, 1, 1), translate(5, 0, 0));
auto* sub = assy.root.add_subassembly("group");
sub->add_part("sub_p1", make_box(1, 1, 1));
LargeAssemblyManager mgr;
auto stats = mgr.compute_stats(assy);
EXPECT_EQ(stats.total_parts, 3);
EXPECT_GE(stats.subassemblies, 1);
EXPECT_GE(stats.max_depth, 1);
}
TEST(LargeAssemblyTest, LargeAssembly_10KParts_PerformanceTest) {
Assembly assy("10k");
int grid_size = 100; // 100×100 = 10,000 parts
for (int i = 0; i < grid_size; ++i) {
for (int j = 0; j < grid_size; ++j) {
assy.root.add_part("b_" + std::to_string(i) + "_" + std::to_string(j),
make_box(1, 1, 1), translate(i * 3.0, j * 3.0, 0));
}
}
LargeAssemblyManager mgr;
mgr.build_index(assy);
EXPECT_EQ(mgr.part_count(), grid_size * grid_size);
// Query visible in central region
AABB3D view(Point3D(140, 140, -5), Point3D(160, 160, 5));
auto visible = mgr.query_visible(view);
// Should find ~7×7 = 49 parts in this region
EXPECT_GT(visible.size(), 0u);
EXPECT_LT(visible.size(), 100u);
}
// ═══════════════════════════════════════════════════════════
// InstanceCache
// ═══════════════════════════════════════════════════════════
TEST(InstanceCacheTest, Register_NewInstance_ReturnsTrue) {
InstanceCache cache;
auto box = make_box(2, 2, 2);
EXPECT_TRUE(cache.register_instance(1, box));
EXPECT_EQ(cache.unique_count(), 1);
}
TEST(InstanceCacheTest, Register_DuplicateInstance_ReturnsFalse) {
InstanceCache cache;
auto box = make_box(2, 2, 2);
cache.register_instance(1, box);
EXPECT_FALSE(cache.register_instance(1, box));
EXPECT_EQ(cache.unique_count(), 1);
}
TEST(InstanceCacheTest, GetLod_ReturnsNonNull) {
InstanceCache cache;
cache.register_instance(1, make_box(2, 2, 2));
auto* lod = cache.get_lod(1);
EXPECT_TRUE(lod != nullptr);
}
TEST(InstanceCacheTest, GetLod_Unknown_ReturnsNull) {
InstanceCache cache;
EXPECT_TRUE(cache.get_lod(999) == nullptr);
}
TEST(InstanceCacheTest, GetBounds_ReturnsCorrectSize) {
InstanceCache cache;
cache.register_instance(1, make_box(2, 2, 2));
auto* bb = cache.get_bounds(1);
ASSERT_TRUE(bb != nullptr);
EXPECT_NEAR(bb->extent().x(), 2.0, 0.01);
}
// ═══════════════════════════════════════════════════════════
// Format detection
// ═══════════════════════════════════════════════════════════
TEST(FormatIOTest, Detect_STEP_Header) {
auto fmt = detect_format_from_data("ISO-10303-21;\nHEADER;\n...");
EXPECT_EQ(fmt, CadFormat::STEP);
}
TEST(FormatIOTest, Detect_IGES_CardFormat) {
// 80-column IGES-style data with section marker at column 73
std::string data(80, ' ');
data[72] = 'S';
auto fmt = detect_format_from_data(data);
EXPECT_EQ(fmt, CadFormat::IGES);
}
TEST(FormatIOTest, Detect_EmptyData_Unknown) {
EXPECT_EQ(detect_format_from_data(""), CadFormat::Unknown);
}
TEST(FormatIOTest, AutoImport_EmptyData_ReturnsEmpty) {
auto models = auto_import_from_string("");
EXPECT_TRUE(models.empty());
}
TEST(FormatIOTest, BatchImport_EmptyList_ReturnsZero) {
auto result = batch_import({});
EXPECT_EQ(result.total_files, 0);
EXPECT_FALSE(result.summary().empty());
}
TEST(FormatIOTest, BatchImport_InvalidFile_CountsFailure) {
auto result = batch_import({"/nonexistent/path.stp"});
EXPECT_EQ(result.total_files, 1);
EXPECT_GT(result.fail_count + result.success_count, 0);
}
// ═══════════════════════════════════════════════════════════
// STEP round-trip with format IO
// ═══════════════════════════════════════════════════════════
TEST(FormatIOTest, StepRoundTrip_AutoDetect) {
auto box = make_box(2, 2, 2);
std::string step = export_step({box});
auto fmt = detect_format_from_data(step);
EXPECT_EQ(fmt, CadFormat::STEP);
auto models = auto_import_from_string(step);
EXPECT_EQ(models.size(), 1u);
EXPECT_TRUE(models[0].is_valid());
}
TEST(FormatIOTest, IGESRoundTrip_AutoDetect) {
auto box = make_box(2, 2, 2);
std::string iges = export_iges({box});
auto fmt = detect_format_from_data(iges);
EXPECT_EQ(fmt, CadFormat::IGES);
auto models = auto_import_from_string(iges);
EXPECT_GE(models.size(), 0u);
}