From 46c0865766c5144bf8068929b9378c1a6c7bc337 Mon Sep 17 00:00:00 2001 From: Joey Kleingers Date: Tue, 31 Dec 2024 15:53:26 -0500 Subject: [PATCH] Add unit test. Signed-off-by: Joey Kleingers --- src/Plugins/SimplnxCore/test/CMakeLists.txt | 1 + .../test/WriteNodesAndElementsFileTest.cpp | 247 ++++++++++++++++++ 2 files changed, 248 insertions(+) create mode 100644 src/Plugins/SimplnxCore/test/WriteNodesAndElementsFileTest.cpp diff --git a/src/Plugins/SimplnxCore/test/CMakeLists.txt b/src/Plugins/SimplnxCore/test/CMakeLists.txt index 5ae4af0332..7e59448934 100644 --- a/src/Plugins/SimplnxCore/test/CMakeLists.txt +++ b/src/Plugins/SimplnxCore/test/CMakeLists.txt @@ -137,6 +137,7 @@ set(${PLUGIN_NAME}UnitTest_SRCS WriteBinaryDataTest.cpp WriteFeatureDataCSVTest.cpp WriteLosAlamosFFTTest.cpp + WriteNodesAndElementsFileTest.cpp WriteStlFileTest.cpp WriteVtkRectilinearGridTest.cpp ) diff --git a/src/Plugins/SimplnxCore/test/WriteNodesAndElementsFileTest.cpp b/src/Plugins/SimplnxCore/test/WriteNodesAndElementsFileTest.cpp new file mode 100644 index 0000000000..69e2fd62e1 --- /dev/null +++ b/src/Plugins/SimplnxCore/test/WriteNodesAndElementsFileTest.cpp @@ -0,0 +1,247 @@ +#include + +#include "SimplnxCore/Filters/Algorithms/WriteNodesAndElementsFile.hpp" +#include "SimplnxCore/Filters/WriteNodesAndElementsFileFilter.hpp" +#include "SimplnxCore/SimplnxCore_test_dirs.hpp" + +#include "simplnx/DataStructure/Geometry/EdgeGeom.hpp" +#include "simplnx/UnitTest/UnitTestCommon.hpp" +#include "simplnx/Utilities/StringUtilities.hpp" + +#include +namespace fs = std::filesystem; + +using namespace nx::core; +using namespace nx::core::Constants; +namespace +{ +const std::string k_GeometryName = "Geometry"; +const DataPath k_GeometryPath = DataPath({k_GeometryName}); +const fs::path k_OutputNodeFilePath = fs::temp_directory_path() / "nodes.node"; +const fs::path k_OutputElementFilePath = fs::temp_directory_path() / "elements.ele"; + +void Cleanup() +{ + if(fs::exists(k_OutputNodeFilePath)) + { + REQUIRE(fs::remove(k_OutputNodeFilePath)); + } + if(fs::exists(k_OutputElementFilePath)) + { + REQUIRE(fs::remove(k_OutputElementFilePath)); + } +} + +void CreateVertexGeometry(DataStructure& ds) +{ + VertexGeom* geom = VertexGeom::Create(ds, k_GeometryName); + auto vertexAttrMatrix = AttributeMatrix::Create(ds, "Vertex Data", {2}, geom->getId()); + geom->setVertexAttributeMatrix(*vertexAttrMatrix); + Float32Array* vertices = UnitTest::CreateTestDataArray(ds, "Vertices Store", {2}, {3}, geom->getId()); + std::vector verticesVec = {1, 1.5, 1.75, 2, 3, 4}; + std::copy(verticesVec.begin(), verticesVec.end(), vertices->begin()); + geom->setVertices(*vertices); +} + +void CreateEdgeGeometry(DataStructure& ds) +{ + EdgeGeom* geom = EdgeGeom::Create(ds, k_GeometryName); + auto edgeAttrMatrix = AttributeMatrix::Create(ds, "Edge Data", {1}, geom->getId()); + geom->setEdgeAttributeMatrix(*edgeAttrMatrix); + auto vertexAttrMatrix = AttributeMatrix::Create(ds, "Vertex Data", {2}, geom->getId()); + geom->setVertexAttributeMatrix(*vertexAttrMatrix); + Float32Array* vertices = UnitTest::CreateTestDataArray(ds, "Vertices Store", {2}, {3}, geom->getId()); + std::vector verticesVec = {1, 1.5, 1.75, 2, 3, 4}; + std::copy(verticesVec.begin(), verticesVec.end(), vertices->begin()); + geom->setVertices(*vertices); + DataArray* cells = UnitTest::CreateTestDataArray(ds, "Cells Store", {1}, {2}, geom->getId()); + std::vector cellsVec = {0, 1}; + std::copy(cellsVec.begin(), cellsVec.end(), cells->begin()); + geom->setEdgeList(*cells); +} + +void ValidateFile(const fs::path& filePath, const std::vector& expectedHeader, const std::vector>& expectedContent) +{ + std::ifstream file(filePath.string()); + REQUIRE(file.is_open()); + + auto validateTokens = [&](const std::string& line, const std::vector& expectedTokens) { + auto tokens = StringUtilities::split(line, ' '); + REQUIRE(tokens == expectedTokens); + }; + + std::string line; + + // Skip the comment line + std::getline(file, line); + + // Validate header if provided + if(!expectedHeader.empty()) + { + std::getline(file, line); + validateTokens(line, expectedHeader); + } + + // Validate content lines + for(const auto& expectedTokens : expectedContent) + { + std::getline(file, line); + validateTokens(line, expectedTokens); + } + + file.close(); +} +} // namespace + +TEST_CASE("SimplnxCore::WriteNodesAndElementsFileFilter: Valid Execution", "[SimplnxCore][WriteNodesAndElementsFileFilter]") +{ + // Instantiate the filter, a DataStructure object and an Arguments Object + WriteNodesAndElementsFileFilter filter; + + DataStructure dataStructure; + Arguments args; + + CreateEdgeGeometry(dataStructure); + + bool writeNodeFile = false; + bool numberNodes = false; + bool includeNodeFileHeader = false; + bool writeElementFile = false; + bool numberElements = false; + bool includeElementFileHeader = false; + + SECTION("Node File") + { + writeNodeFile = true; + + SECTION("Number Nodes") + { + numberNodes = true; + } + SECTION("Include File Header") + { + includeNodeFileHeader = true; + } + SECTION("Both Number Nodes & Include File Header") + { + numberNodes = true; + includeNodeFileHeader = true; + } + } + SECTION("Element File") + { + writeElementFile = true; + + SECTION("Number Elements") + { + numberElements = true; + } + SECTION("Include File Header") + { + includeElementFileHeader = true; + } + SECTION("Both Number Elements & Include File Header") + { + numberElements = true; + includeElementFileHeader = true; + } + } + + // Create default Parameters for the filter. + args.insertOrAssign(WriteNodesAndElementsFileFilter::k_SelectedGeometry, std::make_any(k_GeometryPath)); + args.insertOrAssign(WriteNodesAndElementsFileFilter::k_WriteNodeFile, std::make_any(writeNodeFile)); + args.insertOrAssign(WriteNodesAndElementsFileFilter::k_NumberNodes, std::make_any(numberNodes)); + args.insertOrAssign(WriteNodesAndElementsFileFilter::k_IncludeNodeFileHeader, std::make_any(includeNodeFileHeader)); + args.insertOrAssign(WriteNodesAndElementsFileFilter::k_NodeFilePath, std::make_any(k_OutputNodeFilePath)); + args.insertOrAssign(WriteNodesAndElementsFileFilter::k_WriteElementFile, std::make_any(writeElementFile)); + args.insertOrAssign(WriteNodesAndElementsFileFilter::k_NumberElements, std::make_any(numberElements)); + args.insertOrAssign(WriteNodesAndElementsFileFilter::k_IncludeElementFileHeader, std::make_any(includeElementFileHeader)); + args.insertOrAssign(WriteNodesAndElementsFileFilter::k_ElementFilePath, std::make_any(k_OutputElementFilePath)); + + // Preflight the filter and check result + auto preflightResult = filter.preflight(dataStructure, args); + SIMPLNX_RESULT_REQUIRE_VALID(preflightResult.outputActions); + + // Execute the filter and check the result + auto executeResult = filter.execute(dataStructure, args); + SIMPLNX_RESULT_REQUIRE_VALID(executeResult.result); + + if(writeNodeFile) + { + std::vector expectedHeader = includeNodeFileHeader ? std::vector{"X", "Y", "Z"} : std::vector{}; + std::vector> expectedContent = {{"1.0000", "1.5000", "1.7500"}, {"2.0000", "3.0000", "4.0000"}}; + if(numberNodes) + { + if(includeNodeFileHeader) + { + expectedHeader.insert(expectedHeader.begin(), "NODE_NUM"); + } + expectedContent[0].insert(expectedContent[0].begin(), "0"); + expectedContent[1].insert(expectedContent[1].begin(), "1"); + } + ValidateFile(k_OutputNodeFilePath, expectedHeader, expectedContent); + } + + if(writeElementFile) + { + std::vector expectedHeader = includeElementFileHeader ? std::vector{"NUM_VERTS_IN_ELEMENT", "V0_Index", "V1_Index"} : std::vector{}; + std::vector> expectedContent = {{"2", "0", "1"}}; + if(numberElements) + { + if(includeElementFileHeader) + { + expectedHeader.insert(expectedHeader.begin(), "ELEMENT_NUM"); + } + expectedContent[0].insert(expectedContent[0].begin(), "0"); + } + ValidateFile(k_OutputElementFilePath, expectedHeader, expectedContent); + } + + // Clean up the files + Cleanup(); +} + +TEST_CASE("SimplnxCore::WriteNodesAndElementsFileFilter: Invalid Execution", "[SimplnxCore][WriteNodesAndElementsFileFilter]") +{ + // Instantiate the filter, a DataStructure object and an Arguments Object + WriteNodesAndElementsFileFilter filter; + + DataStructure dataStructure; + Arguments args; + + int32 code = -1; + SECTION("No File Writer Chosen") + { + CreateEdgeGeometry(dataStructure); + code = to_underlying(WriteNodesAndElementsFile::ErrorCodes::NoFileWriterChosen); + + args.insertOrAssign(WriteNodesAndElementsFileFilter::k_WriteNodeFile, std::make_any(false)); + args.insertOrAssign(WriteNodesAndElementsFileFilter::k_NumberNodes, std::make_any(true)); + args.insertOrAssign(WriteNodesAndElementsFileFilter::k_IncludeNodeFileHeader, std::make_any(true)); + args.insertOrAssign(WriteNodesAndElementsFileFilter::k_WriteElementFile, std::make_any(false)); + args.insertOrAssign(WriteNodesAndElementsFileFilter::k_NumberElements, std::make_any(true)); + args.insertOrAssign(WriteNodesAndElementsFileFilter::k_IncludeElementFileHeader, std::make_any(true)); + } + SECTION("Writing A Node File Using A Vertex Geometry") + { + CreateVertexGeometry(dataStructure); + code = to_underlying(WriteNodesAndElementsFile::ErrorCodes::VertexGeomHasNoElements); + + args.insertOrAssign(WriteNodesAndElementsFileFilter::k_WriteNodeFile, std::make_any(false)); + args.insertOrAssign(WriteNodesAndElementsFileFilter::k_NumberNodes, std::make_any(true)); + args.insertOrAssign(WriteNodesAndElementsFileFilter::k_IncludeNodeFileHeader, std::make_any(true)); + args.insertOrAssign(WriteNodesAndElementsFileFilter::k_WriteElementFile, std::make_any(true)); + args.insertOrAssign(WriteNodesAndElementsFileFilter::k_NumberElements, std::make_any(true)); + args.insertOrAssign(WriteNodesAndElementsFileFilter::k_IncludeElementFileHeader, std::make_any(true)); + } + + args.insertOrAssign(WriteNodesAndElementsFileFilter::k_SelectedGeometry, std::make_any(k_GeometryPath)); + args.insertOrAssign(WriteNodesAndElementsFileFilter::k_NodeFilePath, std::make_any(k_OutputNodeFilePath)); + args.insertOrAssign(WriteNodesAndElementsFileFilter::k_ElementFilePath, std::make_any(k_OutputElementFilePath)); + + // Preflight the filter and check result + auto preflightResult = filter.preflight(dataStructure, args); + SIMPLNX_RESULT_REQUIRE_INVALID(preflightResult.outputActions); + REQUIRE(preflightResult.outputActions.errors().size() == 1); + REQUIRE(preflightResult.outputActions.errors()[0].code == code); +}