#include #include "vde/brep/brep.h" #include "vde/brep/modeling.h" #include "vde/brep/incremental_mesh.h" #include using namespace vde::brep; using namespace vde::core; // ═══════════════════════════════════════════════════════════ // Basic Operations // ═══════════════════════════════════════════════════════════ TEST(IncrementalMeshTest, EmptyMesher) { IncrementalMesher mesher; EXPECT_EQ(mesher.dirty_count(), 0); EXPECT_EQ(mesher.total_faces(), 0); EXPECT_EQ(mesher.hit_rate(), 0.0); EXPECT_EQ(mesher.memory_estimate(), 0u); } TEST(IncrementalMeshTest, RebuildAll_UnitBox) { auto box = make_box(2, 2, 2); IncrementalMesher mesher; int count = mesher.rebuild_all(box, 0.01); EXPECT_GT(count, 0); EXPECT_EQ(mesher.dirty_count(), 0); } TEST(IncrementalMeshTest, RebuildAll_Cylinder) { auto cyl = make_cylinder(2, 6, 32); IncrementalMesher mesher; int count = mesher.rebuild_all(cyl); EXPECT_GT(count, 0); } // ═══════════════════════════════════════════════════════════ // Invalidate & Incremental Rebuild // ═══════════════════════════════════════════════════════════ TEST(IncrementalMeshTest, InvalidateFace_MarksDirty) { IncrementalMesher mesher; mesher.invalidate_face(0); EXPECT_EQ(mesher.dirty_count(), 1); } TEST(IncrementalMeshTest, InvalidateFace_ThenRebuild) { auto box = make_box(2, 2, 2); IncrementalMesher mesher; // Full rebuild first mesher.rebuild_all(box); // Invalidate one face mesher.invalidate_face(0); EXPECT_EQ(mesher.dirty_count(), 1); // Rebuild only dirty int count = mesher.rebuild_dirty(box); EXPECT_GT(count, 0); EXPECT_EQ(mesher.dirty_count(), 0); } TEST(IncrementalMeshTest, RebuildDirty_Empty) { auto box = make_box(2, 2, 2); IncrementalMesher mesher; // No faces marked dirty → rebuild_dirty should do nothing int count = mesher.rebuild_dirty(box); EXPECT_EQ(count, 0); } TEST(IncrementalMeshTest, MultipleInvalidates) { auto box = make_box(2, 2, 2); IncrementalMesher mesher; mesher.rebuild_all(box); mesher.invalidate_face(0); mesher.invalidate_face(1); mesher.invalidate_face(0); // duplicate — should still be 2 dirty EXPECT_EQ(mesher.dirty_count(), 2); int count = mesher.rebuild_dirty(box); EXPECT_GE(count, 2); EXPECT_EQ(mesher.dirty_count(), 0); } // ═══════════════════════════════════════════════════════════ // Cache // ═══════════════════════════════════════════════════════════ TEST(IncrementalMeshTest, GetMesh_AfterRebuild) { auto box = make_box(2, 2, 2); IncrementalMesher mesher; mesher.rebuild_all(box); const auto* mesh = mesher.get_mesh(0); EXPECT_TRUE(mesh != nullptr); EXPECT_GT(mesher.cache_hits(), 0); } TEST(IncrementalMeshTest, GetMesh_AfterInvalidate) { auto box = make_box(2, 2, 2); IncrementalMesher mesher; mesher.rebuild_all(box); mesher.invalidate_face(0); const auto* mesh = mesher.get_mesh(0); EXPECT_TRUE(mesh == nullptr); // dirty face → cache miss EXPECT_GT(mesher.cache_misses(), 0); } TEST(IncrementalMeshTest, GetMesh_InvalidFaceId) { auto box = make_box(2, 2, 2); IncrementalMesher mesher; mesher.rebuild_all(box); const auto* mesh = mesher.get_mesh(999); EXPECT_TRUE(mesh == nullptr); } TEST(IncrementalMeshTest, HitRate_AfterRebuild) { auto box = make_box(2, 2, 2); IncrementalMesher mesher; mesher.rebuild_all(box); // Access a cached mesh → hit mesher.get_mesh(0); EXPECT_GT(mesher.hit_rate(), 0.0); } // ═══════════════════════════════════════════════════════════ // Merged Mesh // ═══════════════════════════════════════════════════════════ TEST(IncrementalMeshTest, MergedMesh_AfterFullRebuild) { auto box = make_box(2, 2, 2); IncrementalMesher mesher; mesher.rebuild_all(box); auto merged = mesher.merged_mesh(); EXPECT_GT(merged.num_vertices(), 0u); EXPECT_GT(merged.num_faces(), 0u); } TEST(IncrementalMeshTest, MergedMesh_AfterPartialInvalidate) { auto box = make_box(2, 2, 2); IncrementalMesher mesher; mesher.rebuild_all(box); // Invalidate one face → merged mesh should miss it mesher.invalidate_face(0); auto merged = mesher.merged_mesh(); // Still should produce a valid (but partial) mesh EXPECT_GE(merged.num_vertices(), 0u); } // ═══════════════════════════════════════════════════════════ // Clear & Memory // ═══════════════════════════════════════════════════════════ TEST(IncrementalMeshTest, ClearAll) { auto box = make_box(2, 2, 2); IncrementalMesher mesher; mesher.rebuild_all(box); EXPECT_GT(mesher.total_faces(), 0); mesher.clear_all(); EXPECT_EQ(mesher.total_faces(), 0); EXPECT_EQ(mesher.dirty_count(), 0); EXPECT_EQ(mesher.hit_rate(), 0.0); } TEST(IncrementalMeshTest, MemoryEstimate) { auto box = make_box(2, 2, 2); IncrementalMesher mesher; mesher.rebuild_all(box); size_t mem = mesher.memory_estimate(); EXPECT_GT(mem, 0u); }