From 1da6dd433c82ab5619e025afd652b0ea023ae9c7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Del=20Pino?= <stephane.delpino44@gmail.com>
Date: Wed, 31 Mar 2021 15:21:49 +0200
Subject: [PATCH] Add tests for ItemValue (at last)

---
 src/mesh/Connectivity.hpp |  10 ++-
 src/mesh/ItemValue.hpp    |  15 +---
 src/output/VTKWriter.cpp  |   4 +-
 tests/CMakeLists.txt      |   1 +
 tests/test_ItemValue.cpp  | 175 ++++++++++++++++++++++++++++++++++++++
 5 files changed, 190 insertions(+), 15 deletions(-)
 create mode 100644 tests/test_ItemValue.cpp

diff --git a/src/mesh/Connectivity.hpp b/src/mesh/Connectivity.hpp
index 2b25c6e9b..0caec821a 100644
--- a/src/mesh/Connectivity.hpp
+++ b/src/mesh/Connectivity.hpp
@@ -589,8 +589,14 @@ class Connectivity final : public IConnectivity
   size_t
   numberOfEdges() const final
   {
-    const auto& edge_to_node_matrix = this->_getMatrix(ItemType::edge, ItemType::node);
-    return edge_to_node_matrix.numRows();
+    if constexpr (Dimension == 1) {
+      return this->numberOfNodes();
+    } else if constexpr (Dimension == 2) {
+      return this->numberOfFaces();
+    } else {
+      const auto& edge_to_node_matrix = this->_getMatrix(ItemType::edge, ItemType::node);
+      return edge_to_node_matrix.numRows();
+    }
   }
 
   PUGS_INLINE
diff --git a/src/mesh/ItemValue.hpp b/src/mesh/ItemValue.hpp
index a9049a394..32ce896e5 100644
--- a/src/mesh/ItemValue.hpp
+++ b/src/mesh/ItemValue.hpp
@@ -84,26 +84,20 @@ class ItemValue
   // Following Kokkos logic, these classes are view and const view does allow
   // changes in data
   PUGS_FORCEINLINE
-  DataType& operator[](const ItemId& i) const noexcept(NO_ASSERT)
+  DataType&
+  operator[](const ItemId& i) const noexcept(NO_ASSERT)
   {
     Assert(this->isBuilt());
     return m_values[i];
   }
 
   template <typename IndexType>
-  DataType& operator[](const IndexType&) const noexcept(NO_ASSERT)
+  DataType&
+  operator[](const IndexType&) const noexcept(NO_ASSERT)
   {
     static_assert(std::is_same_v<IndexType, ItemId>, "ItemValue must be indexed by ItemId");
   }
 
-  PUGS_INLINE
-  size_t
-  numberOfItems() const noexcept(NO_ASSERT)
-  {
-    Assert(this->isBuilt());
-    return m_values.size();
-  }
-
   template <typename DataType2>
   PUGS_INLINE ItemValue&
   operator=(const Array<DataType2>& values) noexcept(NO_ASSERT)
@@ -162,7 +156,6 @@ class ItemValue
   {
     static_assert(not std::is_const_v<DataType>, "Cannot allocate ItemValue of const data: only view is "
                                                  "supported");
-    ;
   }
 
   PUGS_INLINE
diff --git a/src/output/VTKWriter.cpp b/src/output/VTKWriter.cpp
index f65a4acfa..5da7dd6fb 100644
--- a/src/output/VTKWriter.cpp
+++ b/src/output/VTKWriter.cpp
@@ -88,9 +88,9 @@ class VTKWriter::SerializedDataList
   void
   add(const ItemValue<DataT, item_type, ConnectivityT>& item_value)
   {
-    Array<std::remove_const_t<DataT>> array(item_value.numberOfItems());
+    Array<std::remove_const_t<DataT>> array(item_value.size());
     parallel_for(
-      item_value.numberOfItems(), PUGS_LAMBDA(ItemIdT<item_type> item_id) { array[item_id] = item_value[item_id]; });
+      item_value.size(), PUGS_LAMBDA(ItemIdT<item_type> item_id) { array[item_id] = item_value[item_id]; });
 
     this->add(array);
   }
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index c8df103aa..8cd540c76 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -100,6 +100,7 @@ add_executable (mpi_unit_tests
   mpi_test_main.cpp
   test_Messenger.cpp
   test_Partitioner.cpp
+  test_ItemValue.cpp
   )
 
 add_library(test_Pugs_MeshDataBase
diff --git a/tests/test_ItemValue.cpp b/tests/test_ItemValue.cpp
new file mode 100644
index 000000000..ef1451264
--- /dev/null
+++ b/tests/test_ItemValue.cpp
@@ -0,0 +1,175 @@
+#include <catch2/catch_test_macros.hpp>
+#include <catch2/matchers/catch_matchers_all.hpp>
+
+#include <MeshDataBaseForTests.hpp>
+#include <mesh/Connectivity.hpp>
+#include <mesh/ItemValue.hpp>
+#include <mesh/Mesh.hpp>
+#include <utils/Messenger.hpp>
+
+// Instantiate to ensure full coverage is performed
+template class ItemValue<int, ItemType::cell>;
+
+// clazy:excludeall=non-pod-global-static
+
+TEST_CASE("ItemValue", "[mesh]")
+{
+  SECTION("default constructors")
+  {
+    REQUIRE_NOTHROW(NodeValue<int>{});
+    REQUIRE_NOTHROW(EdgeValue<int>{});
+    REQUIRE_NOTHROW(FaceValue<int>{});
+    REQUIRE_NOTHROW(CellValue<int>{});
+
+    REQUIRE(not NodeValue<int>{}.isBuilt());
+    REQUIRE(not EdgeValue<int>{}.isBuilt());
+    REQUIRE(not FaceValue<int>{}.isBuilt());
+    REQUIRE(not CellValue<int>{}.isBuilt());
+  }
+
+  SECTION("1D")
+  {
+    const Mesh<Connectivity<1>>& mesh_1d = MeshDataBaseForTests::get().cartesianMesh<1>();
+    const Connectivity<1>& connectivity  = mesh_1d.connectivity();
+
+    EdgeValue<int>{connectivity};
+
+    REQUIRE_NOTHROW(NodeValue<int>{connectivity});
+    REQUIRE_NOTHROW(EdgeValue<int>{connectivity});
+    REQUIRE_NOTHROW(FaceValue<int>{connectivity});
+    REQUIRE_NOTHROW(CellValue<int>{connectivity});
+
+    REQUIRE(NodeValue<int>{connectivity}.isBuilt());
+    REQUIRE(EdgeValue<int>{connectivity}.isBuilt());
+    REQUIRE(FaceValue<int>{connectivity}.isBuilt());
+    REQUIRE(CellValue<int>{connectivity}.isBuilt());
+
+    NodeValue<int> node_value{connectivity};
+    EdgeValue<int> edge_value{connectivity};
+    FaceValue<int> face_value{connectivity};
+    CellValue<int> cell_value{connectivity};
+
+    REQUIRE(edge_value.size() == node_value.size());
+    REQUIRE(face_value.size() == node_value.size());
+    REQUIRE(cell_value.size() + 1 == node_value.size());
+  }
+
+  SECTION("2D")
+  {
+    const Mesh<Connectivity<2>>& mesh_2d = MeshDataBaseForTests::get().cartesianMesh<2>();
+    const Connectivity<2>& connectivity  = mesh_2d.connectivity();
+
+    EdgeValue<int>{connectivity};
+
+    REQUIRE_NOTHROW(NodeValue<int>{connectivity});
+    REQUIRE_NOTHROW(EdgeValue<int>{connectivity});
+    REQUIRE_NOTHROW(FaceValue<int>{connectivity});
+    REQUIRE_NOTHROW(CellValue<int>{connectivity});
+
+    REQUIRE(NodeValue<int>{connectivity}.isBuilt());
+    REQUIRE(EdgeValue<int>{connectivity}.isBuilt());
+    REQUIRE(FaceValue<int>{connectivity}.isBuilt());
+    REQUIRE(CellValue<int>{connectivity}.isBuilt());
+
+    EdgeValue<int> edge_value{connectivity};
+    FaceValue<int> face_value{connectivity};
+
+    REQUIRE(edge_value.size() == face_value.size());
+  }
+
+  SECTION("3D")
+  {
+    const Mesh<Connectivity<3>>& mesh_3d = MeshDataBaseForTests::get().cartesianMesh<3>();
+    const Connectivity<3>& connectivity  = mesh_3d.connectivity();
+
+    EdgeValue<int>{connectivity};
+
+    REQUIRE_NOTHROW(NodeValue<int>{connectivity});
+    REQUIRE_NOTHROW(EdgeValue<int>{connectivity});
+    REQUIRE_NOTHROW(FaceValue<int>{connectivity});
+    REQUIRE_NOTHROW(CellValue<int>{connectivity});
+
+    REQUIRE(NodeValue<int>{connectivity}.isBuilt());
+    REQUIRE(EdgeValue<int>{connectivity}.isBuilt());
+    REQUIRE(FaceValue<int>{connectivity}.isBuilt());
+    REQUIRE(CellValue<int>{connectivity}.isBuilt());
+  }
+
+  SECTION("copy")
+  {
+    const Mesh<Connectivity<3>>& mesh_3d = MeshDataBaseForTests::get().cartesianMesh<3>();
+    const Connectivity<3>& connectivity  = mesh_3d.connectivity();
+
+    CellValue<int> cell_value{connectivity};
+    cell_value.fill(parallel::rank());
+
+    CellValue<const int> const_cell_value;
+    const_cell_value = copy(cell_value);
+
+    cell_value.fill(0);
+
+    for (CellId i_cell = 0; i_cell < mesh_3d.numberOfCells(); ++i_cell) {
+      REQUIRE(cell_value[i_cell] == 0);
+    }
+
+    for (CellId i_cell = 0; i_cell < mesh_3d.numberOfCells(); ++i_cell) {
+      REQUIRE(const_cell_value[i_cell] == static_cast<std::int64_t>(parallel::rank()));
+    }
+  }
+
+  SECTION("WeakItemValue")
+  {
+    const Mesh<Connectivity<2>>& mesh_2d = MeshDataBaseForTests::get().cartesianMesh<2>();
+    const Connectivity<2>& connectivity  = mesh_2d.connectivity();
+
+    WeakFaceValue<int> weak_face_value{connectivity};
+
+    weak_face_value.fill(parallel::rank());
+
+    FaceValue<const int> face_value{weak_face_value};
+
+    REQUIRE(face_value.connectivity_ptr() == weak_face_value.connectivity_ptr());
+  }
+
+#ifndef NDEBUG
+  SECTION("error")
+  {
+    SECTION("checking for build ItemValue")
+    {
+      CellValue<int> cell_value;
+      REQUIRE_THROWS_AS(cell_value[CellId{0}], AssertError);
+
+      FaceValue<int> face_value;
+      REQUIRE_THROWS_AS(face_value[FaceId{0}], AssertError);
+
+      EdgeValue<int> edge_value;
+      REQUIRE_THROWS_AS(edge_value[EdgeId{0}], AssertError);
+
+      NodeValue<int> node_value;
+      REQUIRE_THROWS_AS(node_value[NodeId{0}], AssertError);
+    }
+
+    SECTION("checking for bounds violation")
+    {
+      const Mesh<Connectivity<3>>& mesh_3d = MeshDataBaseForTests::get().cartesianMesh<3>();
+      const Connectivity<3>& connectivity  = mesh_3d.connectivity();
+
+      CellValue<int> cell_value{connectivity};
+      CellId invalid_cell_id = connectivity.numberOfCells();
+      REQUIRE_THROWS_AS(cell_value[invalid_cell_id], AssertError);
+
+      FaceValue<int> face_value{connectivity};
+      FaceId invalid_face_id = connectivity.numberOfFaces();
+      REQUIRE_THROWS_AS(face_value[invalid_face_id], AssertError);
+
+      EdgeValue<int> edge_value{connectivity};
+      EdgeId invalid_edge_id = connectivity.numberOfEdges();
+      REQUIRE_THROWS_AS(edge_value[invalid_edge_id], AssertError);
+
+      NodeValue<int> node_value{connectivity};
+      NodeId invalid_node_id = connectivity.numberOfNodes();
+      REQUIRE_THROWS_AS(node_value[invalid_node_id], AssertError);
+    }
+  }
+#endif   // NDEBUG
+}
-- 
GitLab