From 095aeee941cbd463107484525ebab7469dc4e161 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Del=20Pino?= <stephane.delpino44@gmail.com>
Date: Tue, 5 Apr 2022 11:11:41 +0200
Subject: [PATCH] Add tests for MeshFaceBoundary and improve error message

---
 src/mesh/MeshFaceBoundary.cpp   |  13 +-
 src/mesh/MeshFaceBoundary.hpp   |   4 +-
 tests/CMakeLists.txt            |   1 +
 tests/test_MeshFaceBoundary.cpp | 220 ++++++++++++++++++++++++++++++++
 4 files changed, 235 insertions(+), 3 deletions(-)
 create mode 100644 tests/test_MeshFaceBoundary.cpp

diff --git a/src/mesh/MeshFaceBoundary.cpp b/src/mesh/MeshFaceBoundary.cpp
index 3690c5c0c..751bcf962 100644
--- a/src/mesh/MeshFaceBoundary.cpp
+++ b/src/mesh/MeshFaceBoundary.cpp
@@ -26,7 +26,18 @@ getMeshFaceBoundary(const Mesh<Connectivity<Dimension>>& mesh, const IBoundaryDe
   }
 
   std::ostringstream ost;
-  ost << "cannot find surface with name " << rang::fgB::red << boundary_descriptor << rang::style::reset;
+  ost << "cannot find surface with name " << rang::fgB::red << boundary_descriptor << rang::style::reset << '\n';
+  ost << "The mesh contains " << mesh.connectivity().template numberOfRefItemList<ItemType::face>()
+      << " face boundaries: ";
+  for (size_t i_ref_face_list = 0; i_ref_face_list < mesh.connectivity().template numberOfRefItemList<ItemType::face>();
+       ++i_ref_face_list) {
+    const auto& ref_face_list = mesh.connectivity().template refItemList<ItemType::face>(i_ref_face_list);
+    const RefId& ref          = ref_face_list.refId();
+    if (i_ref_face_list > 0) {
+      ost << ", ";
+    }
+    ost << rang::fgB::yellow << ref << rang::style::reset;
+  }
 
   throw NormalError(ost.str());
 }
diff --git a/src/mesh/MeshFaceBoundary.hpp b/src/mesh/MeshFaceBoundary.hpp
index a45108aa5..7493e9cd4 100644
--- a/src/mesh/MeshFaceBoundary.hpp
+++ b/src/mesh/MeshFaceBoundary.hpp
@@ -39,8 +39,8 @@ class [[nodiscard]] MeshFaceBoundary   // clazy:exclude=copyable-polymorphic
   MeshFaceBoundary(const Mesh<Connectivity<Dimension>>& mesh, const RefFaceList& ref_face_list);
 
  public:
-  MeshFaceBoundary(const MeshFaceBoundary&) = default;
-  MeshFaceBoundary(MeshFaceBoundary &&)     = default;
+  MeshFaceBoundary(const MeshFaceBoundary&) = default;   // LCOV_EXCL_LINE
+  MeshFaceBoundary(MeshFaceBoundary &&)     = default;   // LCOV_EXCL_LINE
 
   MeshFaceBoundary()          = default;
   virtual ~MeshFaceBoundary() = default;
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 52a41bcb6..ede705d51 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -175,6 +175,7 @@ add_executable (mpi_unit_tests
   test_ItemArrayUtils.cpp
   test_ItemValue.cpp
   test_ItemValueUtils.cpp
+  test_MeshFaceBoundary.cpp
   test_Messenger.cpp
   test_OFStream.cpp
   test_Partitioner.cpp
diff --git a/tests/test_MeshFaceBoundary.cpp b/tests/test_MeshFaceBoundary.cpp
new file mode 100644
index 000000000..5b390e17f
--- /dev/null
+++ b/tests/test_MeshFaceBoundary.cpp
@@ -0,0 +1,220 @@
+#include <catch2/catch_test_macros.hpp>
+#include <catch2/matchers/catch_matchers_all.hpp>
+
+#include <MeshDataBaseForTests.hpp>
+
+#include <mesh/Connectivity.hpp>
+#include <mesh/Mesh.hpp>
+#include <mesh/MeshFaceBoundary.hpp>
+#include <mesh/NamedBoundaryDescriptor.hpp>
+#include <mesh/NumberedBoundaryDescriptor.hpp>
+
+// clazy:excludeall=non-pod-global-static
+
+TEST_CASE("MeshFaceBoundary", "[mesh]")
+{
+  auto is_same = [](const auto& a, const auto& b) -> bool {
+    if (a.size() > 0 and b.size() > 0) {
+      return (a[0] == b[0]);
+    } else {
+      return (a.size() == b.size());
+    }
+  };
+
+  SECTION("1D")
+  {
+    static constexpr size_t Dimension = 1;
+
+    using ConnectivityType = Connectivity<Dimension>;
+    using MeshType         = Mesh<ConnectivityType>;
+
+    SECTION("cartesian 1d")
+    {
+      std::shared_ptr p_mesh = MeshDataBaseForTests::get().cartesian1DMesh();
+      const MeshType& mesh   = *p_mesh;
+
+      const ConnectivityType& connectivity = mesh.connectivity();
+
+      for (size_t i = 0; i < connectivity.numberOfRefItemList<ItemType::face>(); ++i) {
+        const auto& ref_face_list = connectivity.refItemList<ItemType::face>(i);
+        const RefId ref_id        = ref_face_list.refId();
+
+        {
+          NumberedBoundaryDescriptor numbered_boundary_descriptor(ref_id.tagNumber());
+          const auto& face_boundary = getMeshFaceBoundary(mesh, numbered_boundary_descriptor);
+          REQUIRE(is_same(face_boundary.faceList(), ref_face_list.list()));
+        }
+
+        {
+          NamedBoundaryDescriptor named_boundary_descriptor(ref_id.tagName());
+          const auto& face_boundary = getMeshFaceBoundary(mesh, named_boundary_descriptor);
+          REQUIRE(is_same(face_boundary.faceList(), ref_face_list.list()));
+        }
+      }
+    }
+
+    SECTION("unordered 1d")
+    {
+      std::shared_ptr p_mesh = MeshDataBaseForTests::get().unordered1DMesh();
+      const MeshType& mesh   = *p_mesh;
+
+      const ConnectivityType& connectivity = mesh.connectivity();
+
+      for (size_t i = 0; i < connectivity.numberOfRefItemList<ItemType::face>(); ++i) {
+        const auto& ref_face_list = connectivity.refItemList<ItemType::face>(i);
+        const RefId ref_id        = ref_face_list.refId();
+
+        {
+          NumberedBoundaryDescriptor numbered_boundary_descriptor(ref_id.tagNumber());
+          const auto& face_boundary = getMeshFaceBoundary(mesh, numbered_boundary_descriptor);
+          REQUIRE(is_same(face_boundary.faceList(), ref_face_list.list()));
+        }
+
+        {
+          NamedBoundaryDescriptor named_boundary_descriptor(ref_id.tagName());
+          const auto& face_boundary = getMeshFaceBoundary(mesh, named_boundary_descriptor);
+          REQUIRE(is_same(face_boundary.faceList(), ref_face_list.list()));
+        }
+      }
+    }
+  }
+
+  SECTION("2D")
+  {
+    static constexpr size_t Dimension = 2;
+
+    using ConnectivityType = Connectivity<Dimension>;
+    using MeshType         = Mesh<ConnectivityType>;
+
+    SECTION("cartesian 2d")
+    {
+      std::shared_ptr p_mesh = MeshDataBaseForTests::get().cartesian2DMesh();
+      const MeshType& mesh   = *p_mesh;
+
+      const ConnectivityType& connectivity = mesh.connectivity();
+
+      for (size_t i = 0; i < connectivity.numberOfRefItemList<ItemType::face>(); ++i) {
+        const auto& ref_face_list = connectivity.refItemList<ItemType::face>(i);
+        const RefId ref_id        = ref_face_list.refId();
+
+        {
+          NumberedBoundaryDescriptor numbered_boundary_descriptor(ref_id.tagNumber());
+          const auto& face_boundary = getMeshFaceBoundary(mesh, numbered_boundary_descriptor);
+          REQUIRE(is_same(face_boundary.faceList(), ref_face_list.list()));
+        }
+
+        {
+          NamedBoundaryDescriptor named_boundary_descriptor(ref_id.tagName());
+          const auto& face_boundary = getMeshFaceBoundary(mesh, named_boundary_descriptor);
+          REQUIRE(is_same(face_boundary.faceList(), ref_face_list.list()));
+        }
+      }
+    }
+
+    SECTION("hybrid 2d")
+    {
+      std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid2DMesh();
+      const MeshType& mesh   = *p_mesh;
+
+      const ConnectivityType& connectivity = mesh.connectivity();
+
+      for (size_t i = 0; i < connectivity.numberOfRefItemList<ItemType::face>(); ++i) {
+        const auto& ref_face_list = connectivity.refItemList<ItemType::face>(i);
+        const RefId ref_id        = ref_face_list.refId();
+
+        {
+          NumberedBoundaryDescriptor numbered_boundary_descriptor(ref_id.tagNumber());
+          const auto& face_boundary = getMeshFaceBoundary(mesh, numbered_boundary_descriptor);
+          REQUIRE(is_same(face_boundary.faceList(), ref_face_list.list()));
+        }
+
+        {
+          NamedBoundaryDescriptor named_boundary_descriptor(ref_id.tagName());
+          const auto& face_boundary = getMeshFaceBoundary(mesh, named_boundary_descriptor);
+          REQUIRE(is_same(face_boundary.faceList(), ref_face_list.list()));
+        }
+      }
+    }
+  }
+
+  SECTION("3D")
+  {
+    static constexpr size_t Dimension = 3;
+
+    using ConnectivityType = Connectivity<Dimension>;
+    using MeshType         = Mesh<ConnectivityType>;
+
+    SECTION("cartesian 3d")
+    {
+      std::shared_ptr p_mesh = MeshDataBaseForTests::get().cartesian3DMesh();
+      const MeshType& mesh   = *p_mesh;
+
+      const ConnectivityType& connectivity = mesh.connectivity();
+
+      for (size_t i = 0; i < connectivity.numberOfRefItemList<ItemType::face>(); ++i) {
+        const auto& ref_face_list = connectivity.refItemList<ItemType::face>(i);
+        const RefId ref_id        = ref_face_list.refId();
+
+        {
+          NumberedBoundaryDescriptor numbered_boundary_descriptor(ref_id.tagNumber());
+          // force copy for tests
+          auto face_boundary = getMeshFaceBoundary(mesh, numbered_boundary_descriptor);
+          REQUIRE(is_same(face_boundary.faceList(), ref_face_list.list()));
+        }
+
+        {
+          NamedBoundaryDescriptor named_boundary_descriptor(ref_id.tagName());
+          const auto& face_boundary = getMeshFaceBoundary(mesh, named_boundary_descriptor);
+          REQUIRE(is_same(face_boundary.faceList(), ref_face_list.list()));
+        }
+      }
+    }
+
+    SECTION("hybrid 3d")
+    {
+      std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid3DMesh();
+      const MeshType& mesh   = *p_mesh;
+
+      const ConnectivityType& connectivity = mesh.connectivity();
+
+      for (size_t i = 0; i < connectivity.numberOfRefItemList<ItemType::face>(); ++i) {
+        const auto& ref_face_list = connectivity.refItemList<ItemType::face>(i);
+        const RefId ref_id        = ref_face_list.refId();
+
+        {
+          NumberedBoundaryDescriptor numbered_boundary_descriptor(ref_id.tagNumber());
+          // force copy for tests
+          auto face_boundary = getMeshFaceBoundary(mesh, numbered_boundary_descriptor);
+          REQUIRE(is_same(face_boundary.faceList(), ref_face_list.list()));
+        }
+
+        {
+          NamedBoundaryDescriptor named_boundary_descriptor(ref_id.tagName());
+          const auto& face_boundary = getMeshFaceBoundary(mesh, named_boundary_descriptor);
+          REQUIRE(is_same(face_boundary.faceList(), ref_face_list.list()));
+        }
+      }
+    }
+  }
+
+  SECTION("errors")
+  {
+    SECTION("cannot find boundary")
+    {
+      static constexpr size_t Dimension = 3;
+
+      using ConnectivityType = Connectivity<Dimension>;
+      using MeshType         = Mesh<ConnectivityType>;
+
+      std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid3DMesh();
+      const MeshType& mesh   = *p_mesh;
+
+      NamedBoundaryDescriptor named_boundary_descriptor("invalid_boundary");
+
+      REQUIRE_THROWS_WITH(getMeshFaceBoundary(mesh, named_boundary_descriptor),
+                          "error: cannot find surface with name \"invalid_boundary\"\nThe mesh contains 8 face "
+                          "boundaries: XMIN(22), XMAX(23), ZMAX(24), ZMIN(25), YMAX(26), YMIN(27), INTERFACE1(55), "
+                          "INTERFACE2(56)");
+    }
+  }
+}
-- 
GitLab