From cc37bd6d968d352a7188a77206dc86a15735bbe3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Del=20Pino?= <stephane.delpino44@gmail.com>
Date: Tue, 31 Aug 2021 19:01:50 +0200
Subject: [PATCH] Add tests for DiscreteFunctionUtils

---
 src/scheme/DiscreteFunctionUtils.cpp |  20 +-
 tests/CMakeLists.txt                 |   1 +
 tests/test_DiscreteFunctionUtils.cpp | 477 +++++++++++++++++++++++++++
 3 files changed, 496 insertions(+), 2 deletions(-)
 create mode 100644 tests/test_DiscreteFunctionUtils.cpp

diff --git a/src/scheme/DiscreteFunctionUtils.cpp b/src/scheme/DiscreteFunctionUtils.cpp
index 6d2e62da4..f7057c4ab 100644
--- a/src/scheme/DiscreteFunctionUtils.cpp
+++ b/src/scheme/DiscreteFunctionUtils.cpp
@@ -10,6 +10,10 @@ std::shared_ptr<const IDiscreteFunction>
 shallowCopy(const std::shared_ptr<const Mesh<Connectivity<Dimension>>>& mesh,
             const std::shared_ptr<const DiscreteFunctionP0<Dimension, DataType>>& discrete_function)
 {
+  Assert(mesh->shared_connectivity() ==
+           dynamic_cast<const Mesh<Connectivity<Dimension>>&>(*discrete_function->mesh()).shared_connectivity(),
+         "connectivities should be the same");
+
   return std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh, discrete_function->cellValues());
 }
 
@@ -22,7 +26,7 @@ shallowCopy(const std::shared_ptr<const Mesh<Connectivity<Dimension>>>& mesh,
     std::dynamic_pointer_cast<const Mesh<Connectivity<Dimension>>>(discrete_function->mesh());
 
   if (mesh->shared_connectivity() != function_mesh->shared_connectivity()) {
-    throw NormalError("incompatible connectivities");
+    throw NormalError("cannot shallow copy when connectivity changes");
   }
 
   switch (discrete_function->descriptor().type()) {
@@ -46,17 +50,21 @@ shallowCopy(const std::shared_ptr<const Mesh<Connectivity<Dimension>>>& mesh,
         return shallowCopy(mesh, std::dynamic_pointer_cast<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(
                                    discrete_function));
       }
+        // LCOV_EXCL_START
       default: {
         throw UnexpectedError("invalid data vector dimension: " +
                               std::to_string(discrete_function->dataType().dimension()));
       }
+        // LCOV_EXCL_STOP
       }
     }
     case ASTNodeDataType::matrix_t: {
       if (discrete_function->dataType().numberOfRows() != discrete_function->dataType().numberOfColumns()) {
+        // LCOV_EXCL_START
         throw UnexpectedError(
           "invalid data matrix dimensions: " + std::to_string(discrete_function->dataType().numberOfRows()) + "x" +
           std::to_string(discrete_function->dataType().numberOfColumns()));
+        // LCOV_EXCL_STOP
       }
       switch (discrete_function->dataType().numberOfRows()) {
       case 1: {
@@ -71,21 +79,27 @@ shallowCopy(const std::shared_ptr<const Mesh<Connectivity<Dimension>>>& mesh,
         return shallowCopy(mesh, std::dynamic_pointer_cast<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>>(
                                    discrete_function));
       }
+        // LCOV_EXCL_START
       default: {
         throw UnexpectedError(
           "invalid data matrix dimensions: " + std::to_string(discrete_function->dataType().numberOfRows()) + "x" +
           std::to_string(discrete_function->dataType().numberOfColumns()));
       }
+        // LCOV_EXCL_STOP
       }
     }
+      // LCOV_EXCL_START
     default: {
       throw UnexpectedError("invalid kind of P0 function: invalid data type");
     }
+      // LCOV_EXCL_STOP
     }
   }
+    // LCOV_EXCL_START
   default: {
-    throw NormalError("invalid discretization type");
+    throw UnexpectedError("invalid discretization type");
   }
+    // LCOV_EXCL_STOP
   }
 }
 
@@ -108,8 +122,10 @@ shallowCopy(const std::shared_ptr<const IMesh>& mesh, const std::shared_ptr<cons
   case 3: {
     return shallowCopy(std::dynamic_pointer_cast<const Mesh<Connectivity<3>>>(mesh), discrete_function);
   }
+    // LCOV_EXCL_START
   default: {
     throw UnexpectedError("invalid mesh dimension");
   }
+    // LCOV_EXCL_STOP
   }
 }
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index c70beb399..b107e3e02 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -64,6 +64,7 @@ add_executable (unit_tests
   test_DiscreteFunctionDescriptorP0.cpp
   test_DiscreteFunctionDescriptorP0Vector.cpp
   test_DiscreteFunctionType.cpp
+  test_DiscreteFunctionUtils.cpp
   test_DoWhileProcessor.cpp
   test_EigenvalueSolver.cpp
   test_EmbeddedData.cpp
diff --git a/tests/test_DiscreteFunctionUtils.cpp b/tests/test_DiscreteFunctionUtils.cpp
new file mode 100644
index 000000000..6587fcba0
--- /dev/null
+++ b/tests/test_DiscreteFunctionUtils.cpp
@@ -0,0 +1,477 @@
+#include <catch2/catch_test_macros.hpp>
+#include <catch2/matchers/catch_matchers_all.hpp>
+
+#include <MeshDataBaseForTests.hpp>
+#include <scheme/DiscreteFunctionP0.hpp>
+#include <scheme/DiscreteFunctionP0Vector.hpp>
+#include <scheme/DiscreteFunctionUtils.hpp>
+
+#include <mesh/CartesianMeshBuilder.hpp>
+
+// clazy:excludeall=non-pod-global-static
+
+TEST_CASE("DiscreteFunctionUtils", "[scheme]")
+{
+  SECTION("1D")
+  {
+    constexpr size_t Dimension = 1;
+
+    std::shared_ptr mesh = MeshDataBaseForTests::get().cartesianMesh1D();
+    std::shared_ptr mesh_copy =
+      std::make_shared<std::decay_t<decltype(*mesh)>>(mesh->shared_connectivity(), mesh->xr());
+
+    SECTION("common mesh")
+    {
+      std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh);
+      std::shared_ptr vh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh);
+      std::shared_ptr wh = std::make_shared<DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh);
+
+      std::shared_ptr qh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh_copy);
+
+      REQUIRE(getCommonMesh({uh, vh, wh}).get() == mesh.get());
+      REQUIRE(getCommonMesh({uh, vh, wh, qh}).use_count() == 0);
+    }
+
+    SECTION("check discretization type")
+    {
+      std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh);
+      std::shared_ptr vh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh);
+
+      std::shared_ptr qh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh_copy);
+
+      std::shared_ptr Uh = std::make_shared<DiscreteFunctionP0Vector<Dimension, double>>(mesh, 3);
+      std::shared_ptr Vh = std::make_shared<DiscreteFunctionP0Vector<Dimension, double>>(mesh, 3);
+
+      REQUIRE(checkDiscretizationType({uh}, DiscreteFunctionType::P0));
+      REQUIRE(checkDiscretizationType({uh, vh, qh}, DiscreteFunctionType::P0));
+      REQUIRE(not checkDiscretizationType({uh}, DiscreteFunctionType::P0Vector));
+      REQUIRE(not checkDiscretizationType({uh, vh, qh}, DiscreteFunctionType::P0Vector));
+      REQUIRE(checkDiscretizationType({Uh}, DiscreteFunctionType::P0Vector));
+      REQUIRE(checkDiscretizationType({Uh, Vh}, DiscreteFunctionType::P0Vector));
+      REQUIRE(not checkDiscretizationType({Uh, Vh}, DiscreteFunctionType::P0));
+      REQUIRE(not checkDiscretizationType({Uh}, DiscreteFunctionType::P0));
+    }
+
+    SECTION("scalar function shallow copy")
+    {
+      std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh);
+      std::shared_ptr vh = shallowCopy(mesh, uh);
+
+      REQUIRE(uh == vh);
+
+      std::shared_ptr wh = shallowCopy(mesh_copy, uh);
+
+      REQUIRE(uh != wh);
+      REQUIRE(&(uh->cellValues()[CellId{0}]) ==
+              &(dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*wh).cellValues()[CellId{0}]));
+    }
+
+    SECTION("R^1 function shallow copy")
+    {
+      using DataType     = TinyVector<1>;
+      std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh);
+      std::shared_ptr vh = shallowCopy(mesh, uh);
+
+      REQUIRE(uh == vh);
+
+      std::shared_ptr wh = shallowCopy(mesh_copy, uh);
+
+      REQUIRE(uh != wh);
+      REQUIRE(&(uh->cellValues()[CellId{0}]) ==
+              &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}]));
+    }
+
+    SECTION("R^2 function shallow copy")
+    {
+      using DataType     = TinyVector<2>;
+      std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh);
+      std::shared_ptr vh = shallowCopy(mesh, uh);
+
+      REQUIRE(uh == vh);
+
+      std::shared_ptr wh = shallowCopy(mesh_copy, uh);
+
+      REQUIRE(uh != wh);
+      REQUIRE(&(uh->cellValues()[CellId{0}]) ==
+              &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}]));
+    }
+
+    SECTION("R^3 function shallow copy")
+    {
+      using DataType     = TinyVector<3>;
+      std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh);
+      std::shared_ptr vh = shallowCopy(mesh, uh);
+
+      REQUIRE(uh == vh);
+
+      std::shared_ptr wh = shallowCopy(mesh_copy, uh);
+
+      REQUIRE(uh != wh);
+      REQUIRE(&(uh->cellValues()[CellId{0}]) ==
+              &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}]));
+    }
+
+    SECTION("R^1x1 function shallow copy")
+    {
+      using DataType     = TinyMatrix<1>;
+      std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh);
+      std::shared_ptr vh = shallowCopy(mesh, uh);
+
+      REQUIRE(uh == vh);
+
+      std::shared_ptr wh = shallowCopy(mesh_copy, uh);
+
+      REQUIRE(uh != wh);
+      REQUIRE(&(uh->cellValues()[CellId{0}]) ==
+              &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}]));
+    }
+
+    SECTION("R^2x2 function shallow copy")
+    {
+      using DataType     = TinyMatrix<2>;
+      std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh);
+      std::shared_ptr vh = shallowCopy(mesh, uh);
+
+      REQUIRE(uh == vh);
+
+      std::shared_ptr wh = shallowCopy(mesh_copy, uh);
+
+      REQUIRE(uh != wh);
+      REQUIRE(&(uh->cellValues()[CellId{0}]) ==
+              &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}]));
+    }
+
+    SECTION("R^3x3 function shallow copy")
+    {
+      using DataType     = TinyMatrix<3>;
+      std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh);
+      std::shared_ptr vh = shallowCopy(mesh, uh);
+
+      REQUIRE(uh == vh);
+
+      std::shared_ptr wh = shallowCopy(mesh_copy, uh);
+
+      REQUIRE(uh != wh);
+      REQUIRE(&(uh->cellValues()[CellId{0}]) ==
+              &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}]));
+    }
+  }
+
+  SECTION("2D")
+  {
+    constexpr size_t Dimension = 2;
+
+    std::shared_ptr mesh = MeshDataBaseForTests::get().cartesianMesh2D();
+    std::shared_ptr mesh_copy =
+      std::make_shared<std::decay_t<decltype(*mesh)>>(mesh->shared_connectivity(), mesh->xr());
+
+    SECTION("common mesh")
+    {
+      std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh);
+      std::shared_ptr vh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh);
+      std::shared_ptr wh = std::make_shared<DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh);
+
+      std::shared_ptr qh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh_copy);
+
+      REQUIRE(getCommonMesh({uh, vh, wh}).get() == mesh.get());
+      REQUIRE(getCommonMesh({uh, vh, wh, qh}).use_count() == 0);
+    }
+
+    SECTION("check discretization type")
+    {
+      std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh);
+      std::shared_ptr vh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh);
+
+      std::shared_ptr qh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh_copy);
+
+      std::shared_ptr Uh = std::make_shared<DiscreteFunctionP0Vector<Dimension, double>>(mesh, 3);
+      std::shared_ptr Vh = std::make_shared<DiscreteFunctionP0Vector<Dimension, double>>(mesh, 3);
+
+      REQUIRE(checkDiscretizationType({uh}, DiscreteFunctionType::P0));
+      REQUIRE(checkDiscretizationType({uh, vh, qh}, DiscreteFunctionType::P0));
+      REQUIRE(not checkDiscretizationType({uh}, DiscreteFunctionType::P0Vector));
+      REQUIRE(not checkDiscretizationType({uh, vh, qh}, DiscreteFunctionType::P0Vector));
+      REQUIRE(checkDiscretizationType({Uh}, DiscreteFunctionType::P0Vector));
+      REQUIRE(checkDiscretizationType({Uh, Vh}, DiscreteFunctionType::P0Vector));
+      REQUIRE(not checkDiscretizationType({Uh, Vh}, DiscreteFunctionType::P0));
+      REQUIRE(not checkDiscretizationType({Uh}, DiscreteFunctionType::P0));
+    }
+
+    SECTION("scalar function shallow copy")
+    {
+      std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh);
+      std::shared_ptr vh = shallowCopy(mesh, uh);
+
+      REQUIRE(uh == vh);
+
+      std::shared_ptr wh = shallowCopy(mesh_copy, uh);
+
+      REQUIRE(uh != wh);
+      REQUIRE(&(uh->cellValues()[CellId{0}]) ==
+              &(dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*wh).cellValues()[CellId{0}]));
+    }
+
+    SECTION("R^1 function shallow copy")
+    {
+      using DataType     = TinyVector<1>;
+      std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh);
+      std::shared_ptr vh = shallowCopy(mesh, uh);
+
+      REQUIRE(uh == vh);
+
+      std::shared_ptr wh = shallowCopy(mesh_copy, uh);
+
+      REQUIRE(uh != wh);
+      REQUIRE(&(uh->cellValues()[CellId{0}]) ==
+              &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}]));
+    }
+
+    SECTION("R^2 function shallow copy")
+    {
+      using DataType     = TinyVector<2>;
+      std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh);
+      std::shared_ptr vh = shallowCopy(mesh, uh);
+
+      REQUIRE(uh == vh);
+
+      std::shared_ptr wh = shallowCopy(mesh_copy, uh);
+
+      REQUIRE(uh != wh);
+      REQUIRE(&(uh->cellValues()[CellId{0}]) ==
+              &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}]));
+    }
+
+    SECTION("R^3 function shallow copy")
+    {
+      using DataType     = TinyVector<3>;
+      std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh);
+      std::shared_ptr vh = shallowCopy(mesh, uh);
+
+      REQUIRE(uh == vh);
+
+      std::shared_ptr wh = shallowCopy(mesh_copy, uh);
+
+      REQUIRE(uh != wh);
+      REQUIRE(&(uh->cellValues()[CellId{0}]) ==
+              &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}]));
+    }
+
+    SECTION("R^1x1 function shallow copy")
+    {
+      using DataType     = TinyMatrix<1>;
+      std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh);
+      std::shared_ptr vh = shallowCopy(mesh, uh);
+
+      REQUIRE(uh == vh);
+
+      std::shared_ptr wh = shallowCopy(mesh_copy, uh);
+
+      REQUIRE(uh != wh);
+      REQUIRE(&(uh->cellValues()[CellId{0}]) ==
+              &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}]));
+    }
+
+    SECTION("R^2x2 function shallow copy")
+    {
+      using DataType     = TinyMatrix<2>;
+      std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh);
+      std::shared_ptr vh = shallowCopy(mesh, uh);
+
+      REQUIRE(uh == vh);
+
+      std::shared_ptr wh = shallowCopy(mesh_copy, uh);
+
+      REQUIRE(uh != wh);
+      REQUIRE(&(uh->cellValues()[CellId{0}]) ==
+              &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}]));
+    }
+
+    SECTION("R^3x3 function shallow copy")
+    {
+      using DataType     = TinyMatrix<3>;
+      std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh);
+      std::shared_ptr vh = shallowCopy(mesh, uh);
+
+      REQUIRE(uh == vh);
+
+      std::shared_ptr wh = shallowCopy(mesh_copy, uh);
+
+      REQUIRE(uh != wh);
+      REQUIRE(&(uh->cellValues()[CellId{0}]) ==
+              &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}]));
+    }
+  }
+
+  SECTION("3D")
+  {
+    constexpr size_t Dimension = 3;
+
+    std::shared_ptr mesh = MeshDataBaseForTests::get().cartesianMesh3D();
+    std::shared_ptr mesh_copy =
+      std::make_shared<std::decay_t<decltype(*mesh)>>(mesh->shared_connectivity(), mesh->xr());
+
+    SECTION("common mesh")
+    {
+      std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh);
+      std::shared_ptr vh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh);
+      std::shared_ptr wh = std::make_shared<DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh);
+
+      std::shared_ptr qh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh_copy);
+
+      REQUIRE(getCommonMesh({uh, vh, wh}).get() == mesh.get());
+      REQUIRE(getCommonMesh({uh, vh, wh, qh}).use_count() == 0);
+    }
+
+    SECTION("check discretization type")
+    {
+      std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh);
+      std::shared_ptr vh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh);
+
+      std::shared_ptr qh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh_copy);
+
+      std::shared_ptr Uh = std::make_shared<DiscreteFunctionP0Vector<Dimension, double>>(mesh, 3);
+      std::shared_ptr Vh = std::make_shared<DiscreteFunctionP0Vector<Dimension, double>>(mesh, 3);
+
+      REQUIRE(checkDiscretizationType({uh}, DiscreteFunctionType::P0));
+      REQUIRE(checkDiscretizationType({uh, vh, qh}, DiscreteFunctionType::P0));
+      REQUIRE(not checkDiscretizationType({uh}, DiscreteFunctionType::P0Vector));
+      REQUIRE(not checkDiscretizationType({uh, vh, qh}, DiscreteFunctionType::P0Vector));
+      REQUIRE(checkDiscretizationType({Uh}, DiscreteFunctionType::P0Vector));
+      REQUIRE(checkDiscretizationType({Uh, Vh}, DiscreteFunctionType::P0Vector));
+      REQUIRE(not checkDiscretizationType({Uh, Vh}, DiscreteFunctionType::P0));
+      REQUIRE(not checkDiscretizationType({Uh}, DiscreteFunctionType::P0));
+    }
+
+    SECTION("scalar function shallow copy")
+    {
+      std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh);
+      std::shared_ptr vh = shallowCopy(mesh, uh);
+
+      REQUIRE(uh == vh);
+
+      std::shared_ptr wh = shallowCopy(mesh_copy, uh);
+
+      REQUIRE(uh != wh);
+      REQUIRE(&(uh->cellValues()[CellId{0}]) ==
+              &(dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*wh).cellValues()[CellId{0}]));
+    }
+
+    SECTION("R^1 function shallow copy")
+    {
+      using DataType     = TinyVector<1>;
+      std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh);
+      std::shared_ptr vh = shallowCopy(mesh, uh);
+
+      REQUIRE(uh == vh);
+
+      std::shared_ptr wh = shallowCopy(mesh_copy, uh);
+
+      REQUIRE(uh != wh);
+      REQUIRE(&(uh->cellValues()[CellId{0}]) ==
+              &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}]));
+    }
+
+    SECTION("R^2 function shallow copy")
+    {
+      using DataType     = TinyVector<2>;
+      std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh);
+      std::shared_ptr vh = shallowCopy(mesh, uh);
+
+      REQUIRE(uh == vh);
+
+      std::shared_ptr wh = shallowCopy(mesh_copy, uh);
+
+      REQUIRE(uh != wh);
+      REQUIRE(&(uh->cellValues()[CellId{0}]) ==
+              &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}]));
+    }
+
+    SECTION("R^3 function shallow copy")
+    {
+      using DataType     = TinyVector<3>;
+      std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh);
+      std::shared_ptr vh = shallowCopy(mesh, uh);
+
+      REQUIRE(uh == vh);
+
+      std::shared_ptr wh = shallowCopy(mesh_copy, uh);
+
+      REQUIRE(uh != wh);
+      REQUIRE(&(uh->cellValues()[CellId{0}]) ==
+              &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}]));
+    }
+
+    SECTION("R^1x1 function shallow copy")
+    {
+      using DataType     = TinyMatrix<1>;
+      std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh);
+      std::shared_ptr vh = shallowCopy(mesh, uh);
+
+      REQUIRE(uh == vh);
+
+      std::shared_ptr wh = shallowCopy(mesh_copy, uh);
+
+      REQUIRE(uh != wh);
+      REQUIRE(&(uh->cellValues()[CellId{0}]) ==
+              &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}]));
+    }
+
+    SECTION("R^2x2 function shallow copy")
+    {
+      using DataType     = TinyMatrix<2>;
+      std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh);
+      std::shared_ptr vh = shallowCopy(mesh, uh);
+
+      REQUIRE(uh == vh);
+
+      std::shared_ptr wh = shallowCopy(mesh_copy, uh);
+
+      REQUIRE(uh != wh);
+      REQUIRE(&(uh->cellValues()[CellId{0}]) ==
+              &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}]));
+    }
+
+    SECTION("R^3x3 function shallow copy")
+    {
+      using DataType     = TinyMatrix<3>;
+      std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh);
+      std::shared_ptr vh = shallowCopy(mesh, uh);
+
+      REQUIRE(uh == vh);
+
+      std::shared_ptr wh = shallowCopy(mesh_copy, uh);
+
+      REQUIRE(uh != wh);
+      REQUIRE(&(uh->cellValues()[CellId{0}]) ==
+              &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}]));
+    }
+  }
+
+  SECTION("errors")
+  {
+    SECTION("different connectivities")
+    {
+      constexpr size_t Dimension = 1;
+
+      std::shared_ptr mesh = MeshDataBaseForTests::get().cartesianMesh1D();
+      std::shared_ptr other_mesh =
+        CartesianMeshBuilder{TinyVector<1>{-1}, TinyVector<1>{3}, TinyVector<1, size_t>{19}}.mesh();
+
+      std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh);
+
+      REQUIRE_THROWS_WITH(shallowCopy(other_mesh, uh), "error: cannot shallow copy when connectivity changes");
+    }
+
+    SECTION("incompatible mesh dimension")
+    {
+      constexpr size_t Dimension = 1;
+
+      std::shared_ptr mesh_1d = MeshDataBaseForTests::get().cartesianMesh1D();
+      std::shared_ptr mesh_2d = MeshDataBaseForTests::get().cartesianMesh2D();
+
+      std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh_1d);
+
+      REQUIRE_THROWS_WITH(shallowCopy(mesh_2d, uh), "error: incompatible mesh dimensions");
+    }
+  }
+}
-- 
GitLab