#include #include "vde/brep/brep.h" #include "vde/brep/modeling.h" #include "vde/brep/iges_export.h" #include #include #include using namespace vde::brep; using namespace vde::core; // ═══════════════════════════════════════════════════════════ // IGES export — section structure tests // ═══════════════════════════════════════════════════════════ TEST(IgesExportTest, ExportBox_HasSections) { auto box = make_box(2, 3, 4); std::string iges = export_iges({box}); // Must have all 5 sections EXPECT_NE(iges.find("S0000001"), std::string::npos) << "Missing Start section"; EXPECT_NE(iges.find("G0000001"), std::string::npos) << "Missing Global section"; EXPECT_NE(iges.find("D0000001"), std::string::npos) << "Missing DE section"; EXPECT_NE(iges.find("P0000001"), std::string::npos) << "Missing PD section"; EXPECT_NE(iges.find("T0000001"), std::string::npos) << "Missing Terminate section"; } TEST(IgesExportTest, ExportBox_HasEightyColumns) { auto box = make_box(1, 1, 1); std::string iges = export_iges({box}); std::istringstream iss(iges); std::string line; while (std::getline(iss, line)) { if (line.empty()) continue; EXPECT_EQ(line.size(), 80u) << "Line not 80 chars: " << line.substr(0, 40) << "..."; } } TEST(IgesExportTest, ExportBox_ContainsPointEntity) { auto box = make_box(1, 1, 1); std::string iges = export_iges({box}); // DE section should have type 116 (Point) entries EXPECT_NE(iges.find(" 116"), std::string::npos) << "Missing Point(116) entities"; } TEST(IgesExportTest, ExportBox_ContainsLineEntity) { auto box = make_box(1, 1, 1); std::string iges = export_iges({box}); // Should have type 110 (Line) — box edges are straight EXPECT_NE(iges.find(" 110"), std::string::npos) << "Missing Line(110) entities"; } TEST(IgesExportTest, ExportBox_ContainsPlaneEntity) { auto box = make_box(1, 1, 1); std::string iges = export_iges({box}); // Box faces should be detected as planes (108) EXPECT_NE(iges.find(" 108"), std::string::npos) << "Missing Plane(108) entities"; } TEST(IgesExportTest, ExportBox_ContainsTopologyEntities) { auto box = make_box(1, 1, 1); std::string iges = export_iges({box}); EXPECT_NE(iges.find(" 502"), std::string::npos) << "Missing Vertex(502)"; EXPECT_NE(iges.find(" 504"), std::string::npos) << "Missing Edge(504)"; EXPECT_NE(iges.find(" 508"), std::string::npos) << "Missing Loop(508)"; EXPECT_NE(iges.find(" 510"), std::string::npos) << "Missing Face(510)"; EXPECT_NE(iges.find(" 514"), std::string::npos) << "Missing Shell(514)"; EXPECT_NE(iges.find(" 186"), std::string::npos) << "Missing MSBO(186)"; } // ═══════════════════════════════════════════════════════════ // Cylinder export // ═══════════════════════════════════════════════════════════ TEST(IgesExportTest, ExportCylinder_HasValidSections) { auto cyl = make_cylinder(1.0, 4.0); std::string iges = export_iges({cyl}); EXPECT_NE(iges.find("S0000001"), std::string::npos); EXPECT_NE(iges.find("G0000001"), std::string::npos); EXPECT_NE(iges.find("T0000001"), std::string::npos); } TEST(IgesExportTest, ExportCylinder_ContainsSurfaceEntity) { auto cyl = make_cylinder(1.0, 4.0); std::string iges = export_iges({cyl}); // Cylinder surface is curved → B-Spline surface (128) EXPECT_NE(iges.find(" 128"), std::string::npos) << "Missing B-Spline Surface(128)"; } // ═══════════════════════════════════════════════════════════ // Sphere export // ═══════════════════════════════════════════════════════════ TEST(IgesExportTest, ExportSphere_HasValidSections) { auto sphere = make_sphere(2.0); std::string iges = export_iges({sphere}); EXPECT_NE(iges.find("S0000001"), std::string::npos); EXPECT_NE(iges.find("G0000001"), std::string::npos); EXPECT_NE(iges.find("T0000001"), std::string::npos); } TEST(IgesExportTest, ExportSphere_ContainsBsplineSurface) { auto sphere = make_sphere(2.0); std::string iges = export_iges({sphere}); // Sphere should have B-Spline surfaces (128) EXPECT_NE(iges.find(" 128"), std::string::npos) << "Sphere should export B-Spline surfaces (type 128)"; } // ═══════════════════════════════════════════════════════════ // Multiple bodies // ═══════════════════════════════════════════════════════════ TEST(IgesExportTest, ExportMultipleBodies_HasMultipleSolids) { auto box1 = make_box(1, 1, 1); auto box2 = make_box(2, 2, 2); std::string iges = export_iges({box1, box2}); // Count MSBO (186) entities — should have at least 2 int count = 0; size_t pos = 0; while ((pos = iges.find(" 186", pos)) != std::string::npos) { count++; pos += 8; } EXPECT_GE(count, 2) << "Expected at least 2 MSBO entities"; } // ═══════════════════════════════════════════════════════════ // Empty model // ═══════════════════════════════════════════════════════════ TEST(IgesExportTest, ExportEmptyModel_ProducesValidOutput) { BrepModel empty; std::string iges = export_iges({empty}); // Should still produce all sections EXPECT_NE(iges.find("S0000001"), std::string::npos); EXPECT_NE(iges.find("G0000001"), std::string::npos); EXPECT_NE(iges.find("T0000001"), std::string::npos); // Terminate section should exist with counts EXPECT_NE(iges.find("T0000001"), std::string::npos); } // ═══════════════════════════════════════════════════════════ // File export // ═══════════════════════════════════════════════════════════ TEST(IgesExportTest, ExportFile_WritesToDisk) { auto box = make_box(1, 1, 1); std::string path = "/tmp/test_vde_iges_export.igs"; export_iges_file(path, {box}); std::ifstream in(path); EXPECT_TRUE(in.good()); std::string content((std::istreambuf_iterator(in)), std::istreambuf_iterator()); EXPECT_NE(content.find("S0000001"), std::string::npos); } // ═══════════════════════════════════════════════════════════ // Line count check (every line is 80 chars + \n) // ═══════════════════════════════════════════════════════════ TEST(IgesExportTest, ExportBox_AllLinesAreEightyColumns) { auto box = make_box(2, 2, 2); std::string iges = export_iges({box}); std::istringstream iss(iges); std::string line; int line_count = 0; while (std::getline(iss, line)) { line_count++; EXPECT_EQ(line.size(), 80u) << "Line " << line_count << " is not 80 columns"; } EXPECT_GT(line_count, 10) << "Should have many lines"; } // ═══════════════════════════════════════════════════════════ // DE section integrity: every DE line ends with Dnnnnnnn // ═══════════════════════════════════════════════════════════ TEST(IgesExportTest, ExportBox_DELinesHaveCorrectSuffix) { auto box = make_box(1, 1, 1); std::string iges = export_iges({box}); int de_count = 0; size_t pos = 0; while ((pos = iges.find('D', pos)) != std::string::npos) { // Check it's a DE line suffix (last 8 chars of a line) // 'D' followed by 7 digits and then newline if (pos >= 72 && iges[pos] == 'D') { // Verify it's at position 72 (0-indexed) in its line size_t line_start = iges.rfind('\n', pos); if (line_start == std::string::npos) line_start = -1; // first line if (pos - line_start == 73) { // 0-indexed → col 73 de_count++; } } pos++; } EXPECT_GT(de_count, 0) << "Should have DE lines with D suffix"; }