From 2dba22b9412872fbd3891a30a9dc4b939630e1d2 Mon Sep 17 00:00:00 2001
From: Stephane Del Pino <stephane.delpino44@gmail.com>
Date: Fri, 25 Oct 2024 01:02:28 +0200
Subject: [PATCH] Add tests for Checkpoint

---
 src/language/utils/ASTCheckpointsInfo.hpp     |   3 +
 src/utils/PugsUtils.cpp                       |   6 +-
 src/utils/checkpointing/Checkpoint.cpp        |   8 +-
 tests/CMakeLists.txt                          |   7 +
 tests/test_checkpointing_Checkpoint.cpp       | 192 +++++++++++++++
 ...st_checkpointing_Checkpoint_sequential.cpp | 230 ++++++++++++++++++
 6 files changed, 444 insertions(+), 2 deletions(-)
 create mode 100644 tests/test_checkpointing_Checkpoint.cpp
 create mode 100644 tests/test_checkpointing_Checkpoint_sequential.cpp

diff --git a/src/language/utils/ASTCheckpointsInfo.hpp b/src/language/utils/ASTCheckpointsInfo.hpp
index ca10d3a58..d033f0ff0 100644
--- a/src/language/utils/ASTCheckpointsInfo.hpp
+++ b/src/language/utils/ASTCheckpointsInfo.hpp
@@ -22,6 +22,9 @@ class ASTCheckpointsInfo
   // The only place where the ASTCheckpointsInfo can be built
   friend void parser(const std::string& filename);
 
+  // to allow special manipulations in tests
+  friend class ASTCheckpointsInfoTester;
+
   ASTCheckpointsInfo(const ASTNode& root_node);
 
  public:
diff --git a/src/utils/PugsUtils.cpp b/src/utils/PugsUtils.cpp
index e04e8eeee..1d2d6d57d 100644
--- a/src/utils/PugsUtils.cpp
+++ b/src/utils/PugsUtils.cpp
@@ -171,7 +171,11 @@ initialize(int& argc, char* argv[])
     }
 
     ResumingManager::getInstance().setIsResuming(is_resuming);
-    ResumingManager::getInstance().setFilename(filename);
+    if (is_resuming) {
+      ResumingManager::getInstance().setFilename(filename);
+    } else {
+      ResumingManager::getInstance().setFilename("checkpoint.h5");
+    }
 
     ExecutionStatManager::getInstance().setPrint(print_exec_stat);
     BacktraceManager::setShow(show_backtrace);
diff --git a/src/utils/checkpointing/Checkpoint.cpp b/src/utils/checkpointing/Checkpoint.cpp
index dccd47085..5976cb2fb 100644
--- a/src/utils/checkpointing/Checkpoint.cpp
+++ b/src/utils/checkpointing/Checkpoint.cpp
@@ -44,7 +44,7 @@ checkpoint()
 
     const auto file_openmode = (checkpoint_number == 0) ? HighFive::File::Truncate : HighFive::File::ReadWrite;
 
-    HighFive::File file("checkpoint.h5", file_openmode, create_props, fapl);
+    HighFive::File file(ResumingManager::getInstance().filename(), file_openmode, create_props, fapl);
 
     std::string checkpoint_name = "checkpoint_" + std::to_string(checkpoint_number);
 
@@ -202,10 +202,14 @@ checkpoint()
                                                                         data[i], file, checkpoint, symbol_table_group);
                     }
                   } else {
+                    // LCOV_EXCL_START
                     throw UnexpectedError("unexpected data type");
+                    // LCOV_EXCL_STOP
                   }
                 } else {
+                  // LCOV_EXCL_START
                   throw UnexpectedError("unexpected data type");
+                  // LCOV_EXCL_STOP
                 }
               },
               symbol.attributes().value());
@@ -228,9 +232,11 @@ checkpoint()
     }
     file.createHardLink("resuming_checkpoint", checkpoint);
   }
+  // LCOV_EXCL_START
   catch (HighFive::Exception& e) {
     throw NormalError(e.what());
   }
+  // LCOV_EXCL_STOP
 }
 
 #else   // PUGS_HAS_HDF5
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index b043734c9..57b3d1be1 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -4,6 +4,11 @@ include_directories(${PUGS_SOURCE_DIR}/src)
 include_directories(${PUGS_BINARY_DIR}/src)
 include_directories(${PUGS_SOURCE_DIR}/tests)
 
+# These should enventually integrate parallel tests
+set(checkpointing_sequential_TESTS
+  test_checkpointing_Checkpoint_sequential.cpp
+)
+
 add_executable (unit_tests
   test_main.cpp
   test_AffectationProcessor.cpp
@@ -155,9 +160,11 @@ add_executable (unit_tests
   test_UnaryOperatorMangler.cpp
   test_Vector.cpp
   test_WhileProcessor.cpp
+  ${checkpointing_sequential_TESTS}
   )
 
   set(checkpointing_TESTS
+    test_checkpointing_Checkpoint.cpp
     test_checkpointing_PrintCheckpointInfo.cpp
     test_checkpointing_PrintScriptFrom.cpp
     test_checkpointing_ResumingManager.cpp
diff --git a/tests/test_checkpointing_Checkpoint.cpp b/tests/test_checkpointing_Checkpoint.cpp
new file mode 100644
index 000000000..63107f702
--- /dev/null
+++ b/tests/test_checkpointing_Checkpoint.cpp
@@ -0,0 +1,192 @@
+#include <catch2/catch_approx.hpp>
+#include <catch2/catch_test_macros.hpp>
+#include <catch2/matchers/catch_matchers_predicate.hpp>
+
+#include <utils/pugs_config.hpp>
+
+#ifdef PUGS_HAS_HDF5
+
+#include <dev/ParallelChecker.hpp>
+#include <language/ast/ASTBuilder.hpp>
+#include <language/ast/ASTExecutionStack.hpp>
+#include <language/ast/ASTModulesImporter.hpp>
+#include <language/ast/ASTNodeDataTypeBuilder.hpp>
+#include <language/ast/ASTNodeDeclarationToAffectationConverter.hpp>
+#include <language/ast/ASTNodeExpressionBuilder.hpp>
+#include <language/ast/ASTNodeTypeCleaner.hpp>
+#include <language/ast/ASTSymbolTableBuilder.hpp>
+#include <language/modules/MathModule.hpp>
+#include <language/utils/ASTCheckpointsInfo.hpp>
+#include <language/utils/CheckpointResumeRepository.hpp>
+#include <utils/ExecutionStatManager.hpp>
+
+class ASTCheckpointsInfoTester
+{
+ private:
+  ASTCheckpointsInfo m_ast_checkpoint_info;
+
+ public:
+  ASTCheckpointsInfoTester(const ASTNode& root_node) : m_ast_checkpoint_info(root_node) {}
+  ~ASTCheckpointsInfoTester() = default;
+};
+
+#define RUN_AST(data)                                          \
+  {                                                            \
+    ExecutionStatManager::create();                            \
+    ParallelChecker::create();                                 \
+    CheckpointResumeRepository::create();                      \
+                                                               \
+    TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"}; \
+    auto ast = ASTBuilder::build(input);                       \
+                                                               \
+    ASTModulesImporter{*ast};                                  \
+    ASTNodeTypeCleaner<language::import_instruction>{*ast};    \
+                                                               \
+    ASTSymbolTableBuilder{*ast};                               \
+    ASTNodeDataTypeBuilder{*ast};                              \
+                                                               \
+    ASTNodeDeclarationToAffectationConverter{*ast};            \
+    ASTNodeTypeCleaner<language::var_declaration>{*ast};       \
+    ASTNodeTypeCleaner<language::fct_declaration>{*ast};       \
+                                                               \
+    ASTNodeExpressionBuilder{*ast};                            \
+    ExecutionPolicy exec_policy;                               \
+    ASTExecutionStack::create();                               \
+    ASTCheckpointsInfoTester ast_cp_info_tester{*ast};         \
+    ast->execute(exec_policy);                                 \
+    ASTExecutionStack::destroy();                              \
+    ast->m_symbol_table->clearValues();                        \
+                                                               \
+    CheckpointResumeRepository::destroy();                     \
+    ParallelChecker::destroy();                                \
+    ExecutionStatManager::destroy();                           \
+  }
+
+#else   // PUGS_HAS_HDF5
+
+#include <utils/checkpointing/Checkpoint.hpp>
+
+#endif   // PUGS_HAS_HDF5
+
+// clazy:excludeall=non-pod-global-static
+
+TEST_CASE("checkpointing_Checkpoint", "[utils/checkpointing]")
+{
+#ifdef PUGS_HAS_HDF5
+
+  std::string tmp_dirname;
+  {
+    {
+      if (parallel::rank() == 0) {
+        tmp_dirname = [&]() -> std::string {
+          std::string temp_filename = std::filesystem::temp_directory_path() / "pugs_checkpointing_XXXXXX";
+          return std::string{mkdtemp(&temp_filename[0])};
+        }();
+      }
+      parallel::broadcast(tmp_dirname, 0);
+    }
+    std::filesystem::path path = tmp_dirname;
+    const std::string filename = path / "checkpoint.h5";
+
+    ResumingManager::getInstance().setFilename(filename);
+  }
+
+  std::string data = R"(
+import math;
+import mesh;
+import scheme;
+
+let f:R*R^3 -> R^3, (a, v) -> a * v;
+
+let alpha:R, alpha = 3.2;
+let u:R^3, u = [1,2,3];
+
+let m:mesh, m = cartesianMesh(0, [1,1], (10,10));
+
+let n:(N), n = (1,2,3,4);
+
+for(let i:N, i=0; i<3; ++i) {
+  checkpoint();
+
+  let g:R -> R^3, x -> [x, 1.2*x, 3];
+  u = f(alpha,u);
+
+  checkpoint();
+}
+)";
+
+  const size_t initial_mesh_id         = GlobalVariableManager::instance().getMeshId();
+  const size_t initial_connectivity_id = GlobalVariableManager::instance().getConnectivityId();
+
+  RUN_AST(data);
+
+  GlobalVariableManager::instance().setMeshId(initial_mesh_id);
+  GlobalVariableManager::instance().setConnectivityId(initial_connectivity_id);
+
+  {   // Check checkpoint file
+    std::filesystem::path path = tmp_dirname;
+    const std::string filename = path / "checkpoint.h5";
+
+    HighFive::File file(filename, HighFive::File::ReadOnly);
+
+    HighFive::Group checkpoint = file.getGroup("/resuming_checkpoint");
+
+    REQUIRE(checkpoint.getAttribute("id").read<uint64_t>() == 1);
+    REQUIRE(checkpoint.getAttribute("checkpoint_number").read<uint64_t>() == 5);
+    REQUIRE(checkpoint.getAttribute("name").read<std::string>() == "checkpoint_5");
+
+    HighFive::Group symbol_table0 = checkpoint.getGroup("symbol table");
+    REQUIRE(symbol_table0.getAttribute("i").read<uint64_t>() == 2);
+
+    HighFive::Group symbol_table1 = symbol_table0.getGroup("symbol table");
+    REQUIRE(symbol_table1.getAttribute("alpha").read<double>() == 3.2);
+    REQUIRE(symbol_table1.getAttribute("n").read<std::vector<uint64_t>>() == std::vector<uint64_t>{1, 2, 3, 4});
+    REQUIRE(l2Norm(symbol_table1.getAttribute("u").read<TinyVector<3>>() - TinyVector<3>{32.768, 65.536, 98.304}) ==
+            Catch::Approx(0).margin(1E-12));
+
+    HighFive::Group embedded1 = symbol_table1.getGroup("embedded");
+
+    HighFive::Group m = embedded1.getGroup("m");
+    REQUIRE(m.getAttribute("type").read<std::string>() == "mesh");
+    REQUIRE(m.getAttribute("id").read<uint64_t>() == initial_mesh_id + (parallel::size() > 1));
+
+    HighFive::Group singleton        = checkpoint.getGroup("singleton");
+    HighFive::Group global_variables = singleton.getGroup("global_variables");
+    REQUIRE(global_variables.getAttribute("connectivity_id").read<uint64_t>() ==
+            initial_connectivity_id + 1 + (parallel::size() > 1));
+    REQUIRE(global_variables.getAttribute("mesh_id").read<uint64_t>() == initial_mesh_id + 1 + (parallel::size() > 1));
+    HighFive::Group execution_info = singleton.getGroup("execution_info");
+    REQUIRE(execution_info.getAttribute("run_number").read<uint64_t>() == 1);
+
+    HighFive::Group connectivity = checkpoint.getGroup("connectivity");
+    HighFive::Group connectivity0 =
+      connectivity.getGroup(std::to_string(initial_connectivity_id + (parallel::size() > 1)));
+    REQUIRE(connectivity0.getAttribute("dimension").read<uint64_t>() == 2);
+    REQUIRE(connectivity0.getAttribute("id").read<uint64_t>() == initial_connectivity_id + (parallel::size() > 1));
+    REQUIRE(connectivity0.getAttribute("type").read<std::string>() == "unstructured");
+
+    HighFive::Group mesh  = checkpoint.getGroup("mesh");
+    HighFive::Group mesh0 = mesh.getGroup(std::to_string(initial_mesh_id + (parallel::size() > 1)));
+    REQUIRE(mesh0.getAttribute("connectivity").read<uint64_t>() == initial_connectivity_id + (parallel::size() > 1));
+    REQUIRE(mesh0.getAttribute("dimension").read<uint64_t>() == 2);
+    REQUIRE(mesh0.getAttribute("id").read<uint64_t>() == initial_mesh_id + (parallel::size() > 1));
+    REQUIRE(mesh0.getAttribute("type").read<std::string>() == "polygonal");
+
+    HighFive::Group functions = checkpoint.getGroup("functions");
+    HighFive::Group f         = functions.getGroup("f");
+    REQUIRE(f.getAttribute("id").read<uint64_t>() == 0);
+    REQUIRE(f.getAttribute("symbol_table_id").read<uint64_t>() == 1);
+    HighFive::Group g = functions.getGroup("g");
+    REQUIRE(g.getAttribute("id").read<uint64_t>() == 1);
+    REQUIRE(g.getAttribute("symbol_table_id").read<uint64_t>() == 0);
+  }
+
+  parallel::barrier();
+  if (parallel::rank() == 0) {
+    std::filesystem::remove_all(std::filesystem::path{tmp_dirname});
+  }
+
+#else    // PUGS_HAS_HDF5
+  REQUIRE_THROWS_WITH(checkpoint(), "error: checkpoint/resume mechanism requires HDF5");
+#endif   // PUGS_HAS_HDF5
+}
diff --git a/tests/test_checkpointing_Checkpoint_sequential.cpp b/tests/test_checkpointing_Checkpoint_sequential.cpp
new file mode 100644
index 000000000..d22e7ccb6
--- /dev/null
+++ b/tests/test_checkpointing_Checkpoint_sequential.cpp
@@ -0,0 +1,230 @@
+#include <catch2/catch_approx.hpp>
+#include <catch2/catch_test_macros.hpp>
+#include <catch2/matchers/catch_matchers_predicate.hpp>
+
+#include <utils/pugs_config.hpp>
+
+#ifdef PUGS_HAS_HDF5
+
+#include <dev/ParallelChecker.hpp>
+#include <language/ast/ASTBuilder.hpp>
+#include <language/ast/ASTExecutionStack.hpp>
+#include <language/ast/ASTModulesImporter.hpp>
+#include <language/ast/ASTNodeDataTypeBuilder.hpp>
+#include <language/ast/ASTNodeDeclarationToAffectationConverter.hpp>
+#include <language/ast/ASTNodeExpressionBuilder.hpp>
+#include <language/ast/ASTNodeTypeCleaner.hpp>
+#include <language/ast/ASTSymbolTableBuilder.hpp>
+#include <language/modules/MathModule.hpp>
+#include <language/utils/ASTCheckpointsInfo.hpp>
+#include <language/utils/CheckpointResumeRepository.hpp>
+#include <mesh/DualMeshType.hpp>
+#include <utils/ExecutionStatManager.hpp>
+#include <utils/checkpointing/DualMeshTypeHFType.hpp>
+
+class ASTCheckpointsInfoTester
+{
+ private:
+  ASTCheckpointsInfo m_ast_checkpoint_info;
+
+ public:
+  ASTCheckpointsInfoTester(const ASTNode& root_node) : m_ast_checkpoint_info(root_node) {}
+  ~ASTCheckpointsInfoTester() = default;
+};
+
+#define RUN_AST(data)                                          \
+  {                                                            \
+    ExecutionStatManager::create();                            \
+    ParallelChecker::create();                                 \
+    CheckpointResumeRepository::create();                      \
+                                                               \
+    TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"}; \
+    auto ast = ASTBuilder::build(input);                       \
+                                                               \
+    ASTModulesImporter{*ast};                                  \
+    ASTNodeTypeCleaner<language::import_instruction>{*ast};    \
+                                                               \
+    ASTSymbolTableBuilder{*ast};                               \
+    ASTNodeDataTypeBuilder{*ast};                              \
+                                                               \
+    ASTNodeDeclarationToAffectationConverter{*ast};            \
+    ASTNodeTypeCleaner<language::var_declaration>{*ast};       \
+    ASTNodeTypeCleaner<language::fct_declaration>{*ast};       \
+                                                               \
+    ASTNodeExpressionBuilder{*ast};                            \
+    ExecutionPolicy exec_policy;                               \
+    ASTExecutionStack::create();                               \
+    ASTCheckpointsInfoTester ast_cp_info_tester{*ast};         \
+    ast->execute(exec_policy);                                 \
+    ASTExecutionStack::destroy();                              \
+    ast->m_symbol_table->clearValues();                        \
+                                                               \
+    CheckpointResumeRepository::destroy();                     \
+    ParallelChecker::destroy();                                \
+    ExecutionStatManager::destroy();                           \
+  }
+
+#else   // PUGS_HAS_HDF5
+
+#include <utils/checkpointing/Checkpoint.hpp>
+
+#endif   // PUGS_HAS_HDF5
+
+// clazy:excludeall=non-pod-global-static
+
+TEST_CASE("checkpointing_Checkpoint_sequential", "[utils/checkpointing]")
+{
+#ifdef PUGS_HAS_HDF5
+
+  std::string tmp_dirname;
+  {
+    {
+      if (parallel::rank() == 0) {
+        tmp_dirname = [&]() -> std::string {
+          std::string temp_filename = std::filesystem::temp_directory_path() / "pugs_checkpointing_XXXXXX";
+          return std::string{mkdtemp(&temp_filename[0])};
+        }();
+      }
+      parallel::broadcast(tmp_dirname, 0);
+    }
+    std::filesystem::path path = tmp_dirname;
+    const std::string filename = path / "checkpoint.h5";
+
+    ResumingManager::getInstance().setFilename(filename);
+  }
+
+  std::string data = R"(
+import math;
+import mesh;
+import scheme;
+
+let f:R*R^3 -> R^3, (a, v) -> a * v;
+
+let alpha:R, alpha = 3.2;
+let u:R^3, u = [1,2,3];
+
+let m:mesh, m = cartesianMesh(0, [1,1], (10,10));
+
+let n:(N), n = (1,2,3,4);
+
+let duals:(mesh), duals = (diamondDual(m), medianDual(m));
+
+for(let i:N, i=0; i<3; ++i) {
+  checkpoint();
+
+  let g:R -> R^3, x -> [x, 1.2*x, 3];
+  u = f(alpha,u);
+
+  checkpoint();
+}
+)";
+
+  const size_t initial_mesh_id         = GlobalVariableManager::instance().getMeshId();
+  const size_t initial_connectivity_id = GlobalVariableManager::instance().getConnectivityId();
+
+  RUN_AST(data);
+
+  GlobalVariableManager::instance().setMeshId(initial_mesh_id);
+  GlobalVariableManager::instance().setConnectivityId(initial_connectivity_id);
+
+  {   // Check checkpoint file
+    std::filesystem::path path = tmp_dirname;
+    const std::string filename = path / "checkpoint.h5";
+
+    HighFive::File file(filename, HighFive::File::ReadOnly);
+
+    HighFive::Group checkpoint = file.getGroup("/resuming_checkpoint");
+
+    REQUIRE(checkpoint.getAttribute("id").read<uint64_t>() == 1);
+    REQUIRE(checkpoint.getAttribute("checkpoint_number").read<uint64_t>() == 5);
+    REQUIRE(checkpoint.getAttribute("name").read<std::string>() == "checkpoint_5");
+
+    HighFive::Group symbol_table0 = checkpoint.getGroup("symbol table");
+    REQUIRE(symbol_table0.getAttribute("i").read<uint64_t>() == 2);
+
+    HighFive::Group symbol_table1 = symbol_table0.getGroup("symbol table");
+    REQUIRE(symbol_table1.getAttribute("alpha").read<double>() == 3.2);
+    REQUIRE(symbol_table1.getAttribute("n").read<std::vector<uint64_t>>() == std::vector<uint64_t>{1, 2, 3, 4});
+    REQUIRE(l2Norm(symbol_table1.getAttribute("u").read<TinyVector<3>>() - TinyVector<3>{32.768, 65.536, 98.304}) ==
+            Catch::Approx(0).margin(1E-12));
+
+    HighFive::Group embedded1 = symbol_table1.getGroup("embedded");
+
+    HighFive::Group duals = embedded1.getGroup("duals");
+    REQUIRE(duals.getAttribute("type").read<std::string>() == "(mesh)");
+    HighFive::Group duals_0 = duals.getGroup("0");
+    REQUIRE(duals_0.getAttribute("type").read<std::string>() == "mesh");
+    REQUIRE(duals_0.getAttribute("id").read<uint64_t>() == initial_mesh_id + 1);
+    HighFive::Group duals_1 = duals.getGroup("1");
+    REQUIRE(duals_1.getAttribute("type").read<std::string>() == "mesh");
+    REQUIRE(duals_1.getAttribute("id").read<uint64_t>() == initial_mesh_id + 2);
+
+    HighFive::Group m = embedded1.getGroup("m");
+    REQUIRE(m.getAttribute("type").read<std::string>() == "mesh");
+    REQUIRE(m.getAttribute("id").read<uint64_t>() == initial_mesh_id);
+
+    HighFive::Group singleton        = checkpoint.getGroup("singleton");
+    HighFive::Group global_variables = singleton.getGroup("global_variables");
+    REQUIRE(global_variables.getAttribute("connectivity_id").read<uint64_t>() == initial_connectivity_id + 3);
+    REQUIRE(global_variables.getAttribute("mesh_id").read<uint64_t>() == initial_mesh_id + 3);
+    HighFive::Group execution_info = singleton.getGroup("execution_info");
+    REQUIRE(execution_info.getAttribute("run_number").read<uint64_t>() == 1);
+
+    HighFive::Group connectivity  = checkpoint.getGroup("connectivity");
+    HighFive::Group connectivity0 = connectivity.getGroup(std::to_string(initial_connectivity_id));
+    REQUIRE(connectivity0.getAttribute("dimension").read<uint64_t>() == 2);
+    REQUIRE(connectivity0.getAttribute("id").read<uint64_t>() == initial_connectivity_id);
+    REQUIRE(connectivity0.getAttribute("type").read<std::string>() == "unstructured");
+
+    HighFive::Group connectivity1 = connectivity.getGroup(std::to_string(initial_connectivity_id + 1));
+    REQUIRE(connectivity1.getAttribute("id").read<uint64_t>() == initial_connectivity_id + 1);
+    REQUIRE(connectivity1.getAttribute("primal_connectivity_id").read<uint64_t>() == initial_connectivity_id);
+    REQUIRE(connectivity1.getAttribute("type").read<std::string>() == "dual_connectivity");
+    REQUIRE(connectivity1.getAttribute("type_of_dual").read<DualMeshType>() == DualMeshType::Diamond);
+
+    HighFive::Group connectivity2 = connectivity.getGroup(std::to_string(initial_connectivity_id + 2));
+    REQUIRE(connectivity2.getAttribute("id").read<uint64_t>() == initial_connectivity_id + 2);
+    REQUIRE(connectivity2.getAttribute("primal_connectivity_id").read<uint64_t>() == initial_connectivity_id);
+    REQUIRE(connectivity2.getAttribute("type").read<std::string>() == "dual_connectivity");
+    REQUIRE(connectivity2.getAttribute("type_of_dual").read<DualMeshType>() == DualMeshType::Median);
+
+    HighFive::Group mesh  = checkpoint.getGroup("mesh");
+    HighFive::Group mesh0 = mesh.getGroup(std::to_string(initial_mesh_id));
+    REQUIRE(mesh0.getAttribute("connectivity").read<uint64_t>() == initial_connectivity_id);
+    REQUIRE(mesh0.getAttribute("dimension").read<uint64_t>() == 2);
+    REQUIRE(mesh0.getAttribute("id").read<uint64_t>() == initial_mesh_id);
+    REQUIRE(mesh0.getAttribute("type").read<std::string>() == "polygonal");
+
+    HighFive::Group mesh1 = mesh.getGroup(std::to_string(initial_mesh_id + 1));
+    REQUIRE(mesh1.getAttribute("id").read<uint64_t>() == initial_mesh_id + 1);
+    REQUIRE(mesh1.getAttribute("primal_mesh_id").read<uint64_t>() == initial_mesh_id);
+    REQUIRE(mesh1.getAttribute("type").read<std::string>() == "dual_mesh");
+    REQUIRE(mesh1.getAttribute("type_of_dual").read<DualMeshType>() == DualMeshType::Diamond);
+
+    HighFive::Group mesh2 = mesh.getGroup(std::to_string(initial_mesh_id + 2));
+    REQUIRE(mesh2.getAttribute("id").read<uint64_t>() == initial_mesh_id + 2);
+    REQUIRE(mesh2.getAttribute("primal_mesh_id").read<uint64_t>() == initial_mesh_id);
+    REQUIRE(mesh2.getAttribute("type").read<std::string>() == "dual_mesh");
+    REQUIRE(mesh2.getAttribute("type_of_dual").read<DualMeshType>() == DualMeshType::Median);
+
+    HighFive::Group functions = checkpoint.getGroup("functions");
+    HighFive::Group f         = functions.getGroup("f");
+    REQUIRE(f.getAttribute("id").read<uint64_t>() == 0);
+    REQUIRE(f.getAttribute("symbol_table_id").read<uint64_t>() == 1);
+    HighFive::Group g = functions.getGroup("g");
+    REQUIRE(g.getAttribute("id").read<uint64_t>() == 1);
+    REQUIRE(g.getAttribute("symbol_table_id").read<uint64_t>() == 0);
+  }
+
+  parallel::barrier();
+  if (parallel::rank() == 0) {
+    std::filesystem::remove_all(std::filesystem::path{tmp_dirname});
+  }
+
+  // Revert to default value
+  ResumingManager::getInstance().setFilename("checkpoint.h5");
+
+#else    // PUGS_HAS_HDF5
+  REQUIRE_THROWS_WITH(checkpoint(), "error: checkpoint/resume mechanism requires HDF5");
+#endif   // PUGS_HAS_HDF5
+}
-- 
GitLab