diff --git a/src/utils/checkpointing/Checkpoint.cpp b/src/utils/checkpointing/Checkpoint.cpp
index aeeb8688c89fb2e1475895d31a7d62c2e976e2d8..dccd47085cd4a79fc3e719dc9881daa798215fed 100644
--- a/src/utils/checkpointing/Checkpoint.cpp
+++ b/src/utils/checkpointing/Checkpoint.cpp
@@ -32,6 +32,7 @@ void
 checkpoint()
 {
   try {
+    HighFive::SilenceHDF5 m_silence_hdf5{true};
     auto create_props = HighFive::FileCreateProps{};
     create_props.add(HighFive::FileSpaceStrategy(H5F_FSPACE_STRATEGY_FSM_AGGR, true, 0));
 
diff --git a/src/utils/checkpointing/PrintCheckpointInfo.cpp b/src/utils/checkpointing/PrintCheckpointInfo.cpp
index 43dbcdc55ab07a59e7747eeb3f5540f82e592cc8..bc7cdcfdd1730921d950318b727cb14f4825c0e0 100644
--- a/src/utils/checkpointing/PrintCheckpointInfo.cpp
+++ b/src/utils/checkpointing/PrintCheckpointInfo.cpp
@@ -14,7 +14,6 @@
 #include <algebra/TinyVector.hpp>
 
 #include <iomanip>
-#include <iostream>
 #include <regex>
 
 #endif   // PUGS_HAS_HDF5
@@ -23,7 +22,7 @@
 
 template <typename T>
 void
-printAttributeValue(const HighFive::Attribute& attribute)
+printAttributeValue(const HighFive::Attribute& attribute, std::ostream& os)
 {
   std::string delim = "";
 
@@ -33,24 +32,25 @@ printAttributeValue(const HighFive::Attribute& attribute)
 
   HighFive::DataSpace data_space = attribute.getSpace();
   if (data_space.getNumberDimensions() == 0) {
-    std::cout << std::boolalpha << delim << attribute.read<T>() << delim;
+    os << std::boolalpha << delim << attribute.read<T>() << delim;
   } else if (data_space.getNumberDimensions() == 1) {
     std::vector value = attribute.read<std::vector<T>>();
     if (value.size() > 0) {
-      std::cout << '(' << std::boolalpha << delim << value[0] << delim;
+      os << '(' << std::boolalpha << delim << value[0] << delim;
       for (size_t i = 1; i < value.size(); ++i) {
-        std::cout << ", " << std::boolalpha << delim << value[i] << delim;
+        os << ", " << std::boolalpha << delim << value[i] << delim;
       }
-      std::cout << ')';
+      os << ')';
     }
   }
 }
 
 void
-printCheckpointInfo(const std::string& filename)
+printCheckpointInfo(const std::string& filename, std::ostream& os)
 {
   if (parallel::rank() == 0) {
     try {
+      HighFive::SilenceHDF5 m_silence_hdf5{true};
       HighFive::File file(filename, HighFive::File::ReadOnly);
 
       std::map<size_t, std::string> checkpoint_name_list;
@@ -59,11 +59,11 @@ printCheckpointInfo(const std::string& filename)
         std::smatch number_string;
         const std::regex checkpoint_regex("checkpoint_([0-9]+)");
         if (std::regex_match(name, number_string, checkpoint_regex)) {
-          std::stringstream os;
-          os << number_string[1].str();
+          std::stringstream ss;
+          ss << number_string[1].str();
 
           size_t id = 0;
-          os >> id;
+          ss >> id;
 
           checkpoint_name_list[id] = name;
         }
@@ -73,8 +73,8 @@ printCheckpointInfo(const std::string& filename)
         HighFive::Group checkpoint      = file.getGroup(checkpoint_name);
         const std::string creation_date = checkpoint.getAttribute("creation_date").read<std::string>();
 
-        std::cout << rang::fgB::yellow << " * " << rang::fg::reset << rang::fgB::magenta << checkpoint_name
-                  << rang::fg::reset << " [" << rang::fg::green << creation_date << rang::fg::reset << "]\n";
+        os << rang::fgB::yellow << " * " << rang::fg::reset << rang::fgB::magenta << checkpoint_name << rang::fg::reset
+           << " [" << rang::fg::green << creation_date << rang::fg::reset << "]\n";
 
         HighFive::Group saved_symbol_table = checkpoint.getGroup("symbol table");
 
@@ -86,21 +86,20 @@ printCheckpointInfo(const std::string& filename)
             HighFive::Attribute attribute = saved_symbol_table.getAttribute(symbol_name);
             HighFive::DataType data_type  = attribute.getDataType();
 
-            std::cout << "   ";
-            std::cout << std::setw(25) << std::setfill('.')   // << rang::style::bold;
-                      << std::left << symbol_name + ' ' << std::setfill(' ');
-            std::cout << ' ';
+            os << "   ";
+            os << std::setw(25) << std::setfill('.') << std::left << symbol_name + ' ' << std::setfill(' ');
+            os << ' ';
 
             switch (data_type.getClass()) {
             case HighFive::DataTypeClass::Float: {
-              printAttributeValue<double>(attribute);
+              printAttributeValue<double>(attribute, os);
               break;
             }
             case HighFive::DataTypeClass::Integer: {
               if (data_type == HighFive::AtomicType<uint64_t>()) {
-                printAttributeValue<uint64_t>(attribute);
+                printAttributeValue<uint64_t>(attribute, os);
               } else if (data_type == HighFive::AtomicType<int64_t>()) {
-                printAttributeValue<int64_t>(attribute);
+                printAttributeValue<int64_t>(attribute, os);
               }
               break;
             }
@@ -108,51 +107,52 @@ printCheckpointInfo(const std::string& filename)
               HighFive::DataSpace data_space = attribute.getSpace();
 
               if (data_type == HighFive::AtomicType<TinyVector<1>>()) {
-                printAttributeValue<TinyVector<1>>(attribute);
+                printAttributeValue<TinyVector<1>>(attribute, os);
               } else if (data_type == HighFive::AtomicType<TinyVector<2>>()) {
-                printAttributeValue<TinyVector<2>>(attribute);
+                printAttributeValue<TinyVector<2>>(attribute, os);
               } else if (data_type == HighFive::AtomicType<TinyVector<3>>()) {
-                printAttributeValue<TinyVector<3>>(attribute);
+                printAttributeValue<TinyVector<3>>(attribute, os);
               } else if (data_type == HighFive::AtomicType<TinyMatrix<1>>()) {
-                printAttributeValue<TinyMatrix<1>>(attribute);
+                printAttributeValue<TinyMatrix<1>>(attribute, os);
               } else if (data_type == HighFive::AtomicType<TinyMatrix<2>>()) {
-                printAttributeValue<TinyMatrix<2>>(attribute);
+                printAttributeValue<TinyMatrix<2>>(attribute, os);
               } else if (data_type == HighFive::AtomicType<TinyMatrix<3>>()) {
-                printAttributeValue<TinyMatrix<3>>(attribute);
+                printAttributeValue<TinyMatrix<3>>(attribute, os);
               }
               break;
             }
             case HighFive::DataTypeClass::Enum: {
               if (data_type == HighFive::create_datatype<bool>()) {
-                printAttributeValue<bool>(attribute);
+                printAttributeValue<bool>(attribute, os);
               } else {
-                std::cout << "????";
+                os << "????";   // LCOV_EXCL_LINE
               }
               break;
             }
             case HighFive::DataTypeClass::String: {
-              printAttributeValue<std::string>(attribute);
+              printAttributeValue<std::string>(attribute, os);
               break;
             }
+              // LCOV_EXCL_START
             default: {
               std::ostringstream error_msg;
               error_msg << "invalid data type class '" << rang::fgB::yellow << data_type.string() << rang::fg::reset
                         << "' for symbol " << rang::fgB::cyan << symbol_name << rang::fg::reset;
               throw UnexpectedError(error_msg.str());
             }
+              // LCOV_EXCL_STOP
             }
 
-            std::cout << rang::style::reset << '\n';
+            os << rang::style::reset << '\n';
           }
 
           if (saved_symbol_table.exist("embedded")) {
             HighFive::Group embedded_data_list = saved_symbol_table.getGroup("embedded");
             for (auto name : embedded_data_list.listObjectNames()) {
-              std::cout << "   ";
-              std::cout << std::setw(25) << std::setfill('.')   // << rang::style::bold;
-                        << std::left << name + ' ' << std::setfill(' ');
-              std::cout << ' ';
-              std::cout << embedded_data_list.getGroup(name).getAttribute("type").read<std::string>() << '\n';
+              os << "   ";
+              os << std::setw(25) << std::setfill('.') << std::left << name + ' ' << std::setfill(' ');
+              os << ' ';
+              os << embedded_data_list.getGroup(name).getAttribute("type").read<std::string>() << '\n';
             }
           }
 
@@ -166,24 +166,26 @@ printCheckpointInfo(const std::string& filename)
 
         } while (not finished);
       }
-      std::cout << "-------------------------------------------------------\n";
+      os << "-------------------------------------------------------\n";
       for (auto path : std::array{"resuming_checkpoint", "last_checkpoint"}) {
-        std::cout << rang::fgB::yellow << " * " << rang::fg::reset << rang::style::bold << path << rang::style::reset
-                  << " -> " << rang::fgB::green << file.getGroup(path).getAttribute("name").read<std::string>()
-                  << rang::style::reset << '\n';
+        os << rang::fgB::yellow << " * " << rang::fg::reset << rang::style::bold << path << rang::style::reset << " -> "
+           << rang::fgB::green << file.getGroup(path).getAttribute("name").read<std::string>() << rang::style::reset
+           << '\n';
       }
     }
+    // LCOV_EXCL_START
     catch (HighFive::Exception& e) {
       std::cerr << rang::fgB::red << "error: " << rang::fg::reset << rang::style::bold << e.what() << rang::style::reset
                 << '\n';
     }
+    // LCOV_EXCL_STOP
   }
 }
 
 #else   // PUGS_HAS_HDF5
 
 void
-printCheckpointInfo(const std::string&)
+printCheckpointInfo(const std::string&, std::ostream&)
 {
   std::cerr << rang::fgB::red << "error: " << rang::fg::reset << "checkpoint info requires HDF5\n";
 }
diff --git a/src/utils/checkpointing/PrintCheckpointInfo.hpp b/src/utils/checkpointing/PrintCheckpointInfo.hpp
index bbe5b4860b18e50df524b26671704e852ccce7c0..fcfb800622fcc2b03ab2770c3abc6c3a23bf8fc8 100644
--- a/src/utils/checkpointing/PrintCheckpointInfo.hpp
+++ b/src/utils/checkpointing/PrintCheckpointInfo.hpp
@@ -1,8 +1,9 @@
 #ifndef PRINT_CHECKPOINT_INFO_HPP
 #define PRINT_CHECKPOINT_INFO_HPP
 
+#include <iostream>
 #include <string>
 
-void printCheckpointInfo(const std::string& filename);
+void printCheckpointInfo(const std::string& filename, std::ostream& os = std::cout);
 
 #endif   // PRINT_CHECKPOINT_INFO_HPP
diff --git a/src/utils/checkpointing/PrintScriptFrom.cpp b/src/utils/checkpointing/PrintScriptFrom.cpp
index 9e324d1132cbe25989d89b61325df28b1bad2735..41c80c1b767945db0ade360d84bce4fbee8d62bf 100644
--- a/src/utils/checkpointing/PrintScriptFrom.cpp
+++ b/src/utils/checkpointing/PrintScriptFrom.cpp
@@ -11,9 +11,10 @@
 #include <utils/HighFivePugsUtils.hpp>
 
 void
-printScriptFrom(const std::string& filename, const uint64_t& checkpoint_number)
+printScriptFrom(const std::string& filename, const uint64_t& checkpoint_number, std::ostream& os)
 {
   try {
+    HighFive::SilenceHDF5 m_silence_hdf5{true};
     HighFive::File file(filename, HighFive::File::ReadWrite);
     const std::string checkpoint_name = "checkpoint_" + std::to_string(checkpoint_number);
 
@@ -25,7 +26,7 @@ printScriptFrom(const std::string& filename, const uint64_t& checkpoint_number)
     }
 
     HighFive::Group checkpoint = file.getGroup(checkpoint_name);
-    std::cout << checkpoint.getAttribute("data.pgs").read<std::string>();
+    os << checkpoint.getAttribute("data.pgs").read<std::string>();
   }
   catch (HighFive::Exception& e) {
     throw NormalError(e.what());
@@ -35,7 +36,7 @@ printScriptFrom(const std::string& filename, const uint64_t& checkpoint_number)
 #else   // PUGS_HAS_HDF5
 
 void
-printScriptFrom(const std::string&, const uint64_t&)
+printScriptFrom(const std::string&, const uint64_t&, std::ostream&)
 {
   std::cerr << rang::fgB::red << "error: " << rang::fg::reset << "printing  checkpoint's script requires HDF5\n";
 }
diff --git a/src/utils/checkpointing/PrintScriptFrom.hpp b/src/utils/checkpointing/PrintScriptFrom.hpp
index c3807c7af000280698406050ffa3320effb05eb6..416a0c76dc5126e19699d22bba5926050f9bbb33 100644
--- a/src/utils/checkpointing/PrintScriptFrom.hpp
+++ b/src/utils/checkpointing/PrintScriptFrom.hpp
@@ -2,8 +2,9 @@
 #define PRINT_SCRIPT_FROM_HPP
 
 #include <cstdint>
+#include <iostream>
 #include <string>
 
-void printScriptFrom(const std::string& filename, const uint64_t& checkpoint_number);
+void printScriptFrom(const std::string& filename, const uint64_t& checkpoint_number, std::ostream& os = std::cout);
 
 #endif   // PRINT_SCRIPT_FROM_HPP
diff --git a/src/utils/checkpointing/ReadItemArrayVariant.cpp b/src/utils/checkpointing/ReadItemArrayVariant.cpp
index 6420d9331becba07271b12d646aa810aeecc15eb..d14087366ac79b7e47acb14b4b8310cf46e4786d 100644
--- a/src/utils/checkpointing/ReadItemArrayVariant.cpp
+++ b/src/utils/checkpointing/ReadItemArrayVariant.cpp
@@ -54,7 +54,9 @@ readItemArrayVariant(const HighFive::Group& item_array_variant_group)
     p_item_array = std::make_shared<ItemArrayVariant>(
       readItemArray<TinyMatrix<3>, item_type>(item_array_variant_group, "arrays", connectivity));
   } else {
+    // LCOV_EXCL_START
     throw UnexpectedError("unexpected discrete function data type: " + data_type);
+    // LCOV_EXCL_STOP
   }
   return p_item_array;
 }
diff --git a/src/utils/checkpointing/Resume.cpp b/src/utils/checkpointing/Resume.cpp
index dbb539771547fc485cbb3642a9a3b24216fd907c..184011049c31febd92f53439bf1389b49fbbd6f2 100644
--- a/src/utils/checkpointing/Resume.cpp
+++ b/src/utils/checkpointing/Resume.cpp
@@ -25,6 +25,7 @@ void
 resume()
 {
   try {
+    HighFive::SilenceHDF5 m_silence_hdf5{true};
     checkpointing::ResumingData::create();
     HighFive::File file(ResumingManager::getInstance().filename(), HighFive::File::ReadOnly);
 
diff --git a/src/utils/checkpointing/SetResumeFrom.cpp b/src/utils/checkpointing/SetResumeFrom.cpp
index 2d1f5e5ca361a0378161024f9f4c367dc6bf1bb7..81502da2f74e9d0e71d812d8692d7318b3135e71 100644
--- a/src/utils/checkpointing/SetResumeFrom.cpp
+++ b/src/utils/checkpointing/SetResumeFrom.cpp
@@ -11,9 +11,10 @@
 #include <utils/HighFivePugsUtils.hpp>
 
 void
-setResumeFrom(const std::string& filename, const uint64_t& checkpoint_number)
+setResumeFrom(const std::string& filename, const uint64_t& checkpoint_number, std::ostream& os)
 {
   try {
+    HighFive::SilenceHDF5 m_silence_hdf5{true};
     HighFive::File file(filename, HighFive::File::ReadWrite);
     const std::string checkpoint_name = "checkpoint_" + std::to_string(checkpoint_number);
 
@@ -29,18 +30,20 @@ setResumeFrom(const std::string& filename, const uint64_t& checkpoint_number)
       file.unlink("resuming_checkpoint");
     }
     file.createHardLink("resuming_checkpoint", checkpoint);
-    std::cout << "Resuming checkpoint " << rang::style::bold << "successfully" << rang::style::reset << " set to "
-              << rang::fgB::yellow << checkpoint_number << rang::fg::reset << '\n';
+    os << "Resuming checkpoint " << rang::style::bold << "successfully" << rang::style::reset << " set to "
+       << rang::fgB::yellow << checkpoint_number << rang::fg::reset << '\n';
   }
+  // LCOV_EXCL_START
   catch (HighFive::Exception& e) {
     throw NormalError(e.what());
   }
+  // LCOV_EXCL_STOP
 }
 
 #else   // PUGS_HAS_HDF5
 
 void
-setResumeFrom(const std::string&, const uint64_t&)
+setResumeFrom(const std::string&, const uint64_t&, std::ostream&)
 {
   std::cerr << rang::fgB::red << "error: " << rang::fg::reset << "setting resuming checkpoint requires HDF5\n";
 }
diff --git a/src/utils/checkpointing/SetResumeFrom.hpp b/src/utils/checkpointing/SetResumeFrom.hpp
index c8e44e6e4319832d9018a1569f003bed509ab5d2..842c638933a7ee3083b44aebc234d8797542185a 100644
--- a/src/utils/checkpointing/SetResumeFrom.hpp
+++ b/src/utils/checkpointing/SetResumeFrom.hpp
@@ -2,8 +2,9 @@
 #define SET_RESUME_FROM_HPP
 
 #include <cstdint>
+#include <iostream>
 #include <string>
 
-void setResumeFrom(const std::string& filename, const uint64_t& checkpoint_number);
+void setResumeFrom(const std::string& filename, const uint64_t& checkpoint_number, std::ostream& os = std::cout);
 
 #endif   // SET_RESUME_FROM_HPP
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index f533f3194b9011212b833ca0489fb05e150a3c74..b043734c94b6202c3bd08410866699d95666d397 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -157,7 +157,13 @@ add_executable (unit_tests
   test_WhileProcessor.cpp
   )
 
-set(checkpointing_TESTS)
+  set(checkpointing_TESTS
+    test_checkpointing_PrintCheckpointInfo.cpp
+    test_checkpointing_PrintScriptFrom.cpp
+    test_checkpointing_ResumingManager.cpp
+    test_checkpointing_ResumingUtils.cpp
+    test_checkpointing_SetResumeFrom.cpp
+  )
 
 if(PUGS_HAS_HDF5)
   list(APPEND checkpointing_TESTS
@@ -165,21 +171,21 @@ if(PUGS_HAS_HDF5)
     test_checkpointing_Connectivity.cpp
     test_checkpointing_DiscreteFunctionVariant.cpp
     test_checkpointing_HFTypes.cpp
-    test_checkpointing_ItemArray.cpp
-    test_checkpointing_ItemArrayVariant.cpp
-    test_checkpointing_ItemValue.cpp
-    test_checkpointing_ItemValueVariant.cpp
-    test_checkpointing_OStream.cpp
     test_checkpointing_IBoundaryDescriptor.cpp
     test_checkpointing_IBoundaryConditionDescriptor.cpp
     test_checkpointing_IQuadratureDescriptor.cpp
     test_checkpointing_IDiscreteFunctionDescriptor.cpp
     test_checkpointing_IInterfaceDescriptor.cpp
     test_checkpointing_INamedDiscreteData.cpp
+    test_checkpointing_ItemArray.cpp
+    test_checkpointing_ItemArrayVariant.cpp
     test_checkpointing_ItemType.cpp
+    test_checkpointing_ItemValue.cpp
+    test_checkpointing_ItemValueVariant.cpp
     test_checkpointing_IWriter.cpp
     test_checkpointing_IZoneDescriptor.cpp
     test_checkpointing_Mesh.cpp
+    test_checkpointing_OStream.cpp
     test_checkpointing_SubItemArrayPerItemVariant.cpp
     test_checkpointing_SubItemValuePerItemVariant.cpp
     test_checkpointing_Table.cpp
diff --git a/tests/test_checkpointing_PrintCheckpointInfo.cpp b/tests/test_checkpointing_PrintCheckpointInfo.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8f3d28ecfddf97ab8162c0ad60e878ea67f5ff3d
--- /dev/null
+++ b/tests/test_checkpointing_PrintCheckpointInfo.cpp
@@ -0,0 +1,162 @@
+#include <catch2/catch_test_macros.hpp>
+#include <catch2/matchers/catch_matchers_all.hpp>
+
+#include <algebra/TinyMatrix.hpp>
+#include <algebra/TinyVector.hpp>
+#include <utils/HighFivePugsUtils.hpp>
+#include <utils/Messenger.hpp>
+#include <utils/checkpointing/PrintCheckpointInfo.hpp>
+
+#include <filesystem>
+
+// clazy:excludeall=non-pod-global-static
+
+TEST_CASE("PrintCheckpointInfo", "[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";
+
+    const std::string data_file0 = R"(Un tiens vaut mieux que deux tu l'auras,
+Un tiens vaut mieux que deux tu l'auras,...)";
+    const std::string data_file1 = R"(All work and no play makes Jack a dull boy,
+All work and no play makes Jack a dull boy,...)";
+    const std::string data_file2 = R"(solo trabajo y nada de juego hacen de Jack un chico aburrido,
+solo trabajo y nada de juego hacen de Jack un chico aburrido,...)";
+
+    std::string info = R"( * checkpoint_0 [Today]
+   X1 ...................... [2.7]
+   X2 ...................... [-2.3,4.1]
+   a ....................... 1.3
+   b ....................... true
+   n ....................... 12
+   z ....................... -3
+   mesh0 ................... mesh
+ * checkpoint_1 [Tomorrow]
+   X3 ...................... [1.2,1.4,-1]
+   m ....................... 8
+   z ....................... -6
+   tv ...................... ([1,2], [-1.2,3])
+ * checkpoint_2 [Yesterday]
+   M1 ...................... [[2.7]]
+   M2 ...................... [[-2.3,4.1],[-1.8,1.5]]
+   M3 ...................... [[-2.3,4.1,3.2],[-1.8,1.5,1.7],[-1.2,0.7,1.2]]
+   s ....................... "foo"
+   ts ...................... ("foo", "bar")
+-------------------------------------------------------
+ * resuming_checkpoint -> checkpoint_1
+ * last_checkpoint -> checkpoint_2
+)";
+
+    {
+      HighFive::FileAccessProps fapl;
+      fapl.add(HighFive::MPIOFileAccess{MPI_COMM_WORLD, MPI_INFO_NULL});
+      fapl.add(HighFive::MPIOCollectiveMetadata{});
+      HighFive::File file = HighFive::File(filename, HighFive::File::Truncate, fapl);
+
+      {
+        HighFive::Group cp = file.createGroup("/checkpoint_0");
+        cp.createAttribute("data.pgs", data_file0);
+        cp.createAttribute("id", 0ul);
+        cp.createAttribute("creation_date", std::string{"Today"});
+        cp.createAttribute("checkpoint_number", 0ul);
+        cp.createAttribute("name", std::string{"checkpoint_0"});
+        HighFive::Group symbol_table = cp.createGroup("symbol table");
+        symbol_table.createAttribute("a", 1.3);
+        symbol_table.createAttribute("n", uint64_t{12});
+        symbol_table.createAttribute("z", int64_t{-3});
+        symbol_table.createAttribute("X1", TinyVector<1>{2.7});
+        symbol_table.createAttribute("X2", TinyVector<2>{-2.3, 4.1});
+        symbol_table.createAttribute("b", true);
+        HighFive::Group embedded = symbol_table.createGroup("embedded");
+        HighFive::Group mesh0    = embedded.createGroup("mesh0");
+        mesh0.createAttribute("type", std::string{"mesh"});
+      }
+
+      {
+        HighFive::Group cp = file.createGroup("/checkpoint_1");
+        cp.createAttribute("data.pgs", data_file1);
+        cp.createAttribute("id", 1ul);
+        cp.createAttribute("creation_date", std::string{"Tomorrow"});
+        cp.createAttribute("checkpoint_number", 1ul);
+        cp.createAttribute("name", std::string{"checkpoint_1"});
+        HighFive::Group symbol_table = cp.createGroup("symbol table");
+        symbol_table.createAttribute("m", uint64_t{8});
+        symbol_table.createAttribute("z", int64_t{-6});
+        symbol_table.createAttribute("X3", TinyVector<3>{1.2, 1.4, -1});
+
+        HighFive::Group sub_symbol_table = symbol_table.createGroup("symbol table");
+
+        sub_symbol_table.createAttribute("tv", std::vector{TinyVector<2>{1, 2}, TinyVector<2>{-1.2, 3}});
+
+        file.createHardLink("resuming_checkpoint", cp);
+      }
+
+      {
+        HighFive::Group cp = file.createGroup("/checkpoint_2");
+        cp.createAttribute("data.pgs", data_file2);
+        cp.createAttribute("id", 2ul);
+        cp.createAttribute("creation_date", std::string{"Yesterday"});
+        cp.createAttribute("checkpoint_number", 2ul);
+        cp.createAttribute("name", std::string{"checkpoint_2"});
+        HighFive::Group symbol_table = cp.createGroup("symbol table");
+        symbol_table.createAttribute("s", std::string{"foo"});
+        symbol_table.createAttribute("M1", TinyMatrix<1>{2.7});
+        symbol_table.createAttribute("M2", TinyMatrix<2>{-2.3, 4.1,   //
+                                                         -1.8, 1.5});
+        symbol_table.createAttribute("M3", TinyMatrix<3>{-2.3, 4.1, 3.2,   //
+                                                         -1.8, 1.5, 1.7,   //
+                                                         -1.2, 0.7, 1.2});
+
+        symbol_table.createAttribute("ts", std::vector<std::string>{"foo", "bar"});
+
+        file.createHardLink("last_checkpoint", cp);
+      }
+    }
+
+    {
+      std::ostringstream os;
+      printCheckpointInfo(filename, os);
+
+      if (parallel::rank() == 0) {
+        REQUIRE(os.str() == info);
+      } else {
+        REQUIRE(os.str() == "");
+      }
+    }
+  }
+
+  parallel::barrier();
+  if (parallel::rank() == 0) {
+    std::filesystem::remove_all(std::filesystem::path{tmp_dirname});
+  }
+
+#else   // PUGS_HAS_HDF5
+
+  if (parallel::rank() == 0) {
+    std::cerr.setstate(std::ios::badbit);
+  }
+
+  std::ostringstream os;
+  REQUIRE_NOTHROW(printCheckpointInfo("foo.h5", os));
+
+  if (parallel::rank() == 0) {
+    std::cerr.clear();
+  }
+
+  REQUIRE(os.str() == "");
+
+#endif   // PUGS_HAS_HDF5
+}
diff --git a/tests/test_checkpointing_PrintScriptFrom.cpp b/tests/test_checkpointing_PrintScriptFrom.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0896124064e6aa2542f9d4f0996b961485845be2
--- /dev/null
+++ b/tests/test_checkpointing_PrintScriptFrom.cpp
@@ -0,0 +1,109 @@
+#include <catch2/catch_test_macros.hpp>
+#include <catch2/matchers/catch_matchers_all.hpp>
+
+#include <utils/HighFivePugsUtils.hpp>
+#include <utils/Messenger.hpp>
+#include <utils/checkpointing/PrintScriptFrom.hpp>
+
+#include <filesystem>
+
+// clazy:excludeall=non-pod-global-static
+
+TEST_CASE("checkpointing_PrintScriptFrom", "[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";
+
+    const std::string data_file0 = R"(Un tiens vaut mieux que deux tu l'auras,
+Un tiens vaut mieux que deux tu l'auras,...)";
+    const std::string data_file1 = R"(All work and no play makes Jack a dull boy,
+All work and no play makes Jack a dull boy,...)";
+    const std::string data_file2 = R"(solo trabajo y nada de juego hacen de Jack un chico aburrido,
+solo trabajo y nada de juego hacen de Jack un chico aburrido,...)";
+
+    {
+      HighFive::FileAccessProps fapl;
+      fapl.add(HighFive::MPIOFileAccess{MPI_COMM_WORLD, MPI_INFO_NULL});
+      fapl.add(HighFive::MPIOCollectiveMetadata{});
+      HighFive::File file = HighFive::File(filename, HighFive::File::Truncate, fapl);
+
+      file.createGroup("/checkpoint_0").createAttribute("data.pgs", data_file0);
+      file.createGroup("/checkpoint_1").createAttribute("data.pgs", data_file1);
+      file.createGroup("/checkpoint_2").createAttribute("data.pgs", data_file2);
+    }
+
+    {
+      std::ostringstream os;
+      printScriptFrom(filename, 0, os);
+      REQUIRE(os.str() == data_file0);
+    }
+
+    {
+      std::ostringstream os;
+      printScriptFrom(filename, 1, os);
+      REQUIRE(os.str() == data_file1);
+    }
+
+    {
+      std::ostringstream os;
+      printScriptFrom(filename, 2, os);
+      REQUIRE(os.str() == data_file2);
+    }
+
+    {
+      std::ostringstream error_msg;
+      error_msg << "error: cannot find checkpoint " << 12 << " in " << filename;
+      REQUIRE_THROWS_WITH(printScriptFrom(filename, 12), error_msg.str());
+    }
+
+    {
+      const std::string malformed_filename = path / "malformed.h5";
+
+      {
+        HighFive::FileAccessProps fapl;
+        fapl.add(HighFive::MPIOFileAccess{MPI_COMM_WORLD, MPI_INFO_NULL});
+        fapl.add(HighFive::MPIOCollectiveMetadata{});
+        HighFive::File file = HighFive::File(malformed_filename, HighFive::File::Truncate, fapl);
+
+        file.createGroup("/checkpoint_0");
+      }
+      REQUIRE_THROWS_WITH(printScriptFrom(malformed_filename, 0),
+                          "error: Unable to open the attribute \"data.pgs\": (Attribute) Object not found");
+    }
+  }
+
+  parallel::barrier();
+  if (parallel::rank() == 0) {
+    std::filesystem::remove_all(std::filesystem::path{tmp_dirname});
+  }
+
+#else   // PUGS_HAS_HDF5
+
+  if (parallel::rank() == 0) {
+    std::cerr.setstate(std::ios::badbit);
+  }
+
+  std::ostringstream os;
+  REQUIRE_NOTHROW(printScriptFrom("foo.h5", 0, os));
+
+  if (parallel::rank() == 0) {
+    std::cerr.clear();
+  }
+
+  REQUIRE(os.str() == "");
+
+#endif   // PUGS_HAS_HDF5
+}
diff --git a/tests/test_checkpointing_ResumingManager.cpp b/tests/test_checkpointing_ResumingManager.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1d5da95081d179894d66fe04306af877e0af676b
--- /dev/null
+++ b/tests/test_checkpointing_ResumingManager.cpp
@@ -0,0 +1,95 @@
+#include <catch2/catch_test_macros.hpp>
+#include <catch2/matchers/catch_matchers_all.hpp>
+
+#include <utils/HighFivePugsUtils.hpp>
+#include <utils/Messenger.hpp>
+#include <utils/checkpointing/ResumingManager.hpp>
+
+#include <filesystem>
+
+// clazy:excludeall=non-pod-global-static
+
+TEST_CASE("checkpointing_ResumingManager", "[utils/checkpointing]")
+{
+  // Need to destroy the instance created in the main for tests
+  REQUIRE_NOTHROW(ResumingManager::destroy());
+
+#ifndef NDEBUG
+  REQUIRE_THROWS_WITH(ResumingManager::destroy(), "Resuming manager was not created");
+  REQUIRE_THROWS_WITH(ResumingManager::getInstance(), "instance was not created");
+#endif   // NDEBUG
+
+  REQUIRE_NOTHROW(ResumingManager::create());
+
+#ifndef NDEBUG
+  REQUIRE_THROWS_WITH(ResumingManager::create(), "Resuming manager was already created");
+#endif   // NDEBUG
+
+#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";
+
+    {
+      HighFive::FileAccessProps fapl;
+      fapl.add(HighFive::MPIOFileAccess{MPI_COMM_WORLD, MPI_INFO_NULL});
+      fapl.add(HighFive::MPIOCollectiveMetadata{});
+      HighFive::File file = HighFive::File(filename, HighFive::File::Truncate, fapl);
+
+      {
+        HighFive::Group cp = file.createGroup("/resuming_checkpoint");
+        cp.createAttribute("id", 13ul);
+      }
+    }
+
+    parallel::barrier();
+    REQUIRE_NOTHROW(ResumingManager::getInstance().setFilename(filename));
+    REQUIRE(ResumingManager::getInstance().filename() == filename);
+
+    REQUIRE(ResumingManager::getInstance().checkpointId() == 13);
+  }
+
+  parallel::barrier();
+  if (parallel::rank() == 0) {
+    std::filesystem::remove_all(std::filesystem::path{tmp_dirname});
+  }
+
+#else   // PUGS_HAS_HDF5
+
+  ResumingManager::getInstance().setFilename("useless");
+  REQUIRE(ResumingManager::getInstance().filename() == "useless");
+  REQUIRE(ResumingManager::getInstance().checkpointId() == 0);
+
+#endif   // PUGS_HAS_HDF5
+
+  ResumingManager::getInstance().currentASTLevel()  = 3;
+  ResumingManager::getInstance().checkpointNumber() = 7;
+  ResumingManager::getInstance().setIsResuming(false);
+
+  REQUIRE(ResumingManager::getInstance().currentASTLevel() == 3);
+  REQUIRE(ResumingManager::getInstance().checkpointNumber() == 7);
+  REQUIRE(not ResumingManager::getInstance().isResuming());
+
+  ResumingManager::getInstance().currentASTLevel()  = 1;
+  ResumingManager::getInstance().checkpointNumber() = 5;
+  ResumingManager::getInstance().setIsResuming(true);
+
+  REQUIRE(ResumingManager::getInstance().currentASTLevel() == 1);
+  REQUIRE(ResumingManager::getInstance().checkpointNumber() == 5);
+  REQUIRE(ResumingManager::getInstance().isResuming());
+
+  REQUIRE_NOTHROW(ResumingManager::destroy());
+
+  // Recreate ResumingManager for remaining tests
+  REQUIRE_NOTHROW(ResumingManager::create());
+}
diff --git a/tests/test_checkpointing_ResumingUtils.cpp b/tests/test_checkpointing_ResumingUtils.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..23c8e7e99d36e009a2f8f6b04d53da4c28183331
--- /dev/null
+++ b/tests/test_checkpointing_ResumingUtils.cpp
@@ -0,0 +1,77 @@
+#include <catch2/catch_test_macros.hpp>
+#include <catch2/matchers/catch_matchers_all.hpp>
+
+#include <utils/HighFivePugsUtils.hpp>
+#include <utils/Messenger.hpp>
+#include <utils/checkpointing/ResumingUtils.hpp>
+
+#include <filesystem>
+
+// clazy:excludeall=non-pod-global-static
+
+TEST_CASE("checkpointing_ResumingUtils", "[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";
+
+    const std::string data_file0 = R"(Un tiens vaut mieux que deux tu l'auras,
+Un tiens vaut mieux que deux tu l'auras,...)";
+    const std::string data_file1 = R"(All work and no play makes Jack a dull boy,
+All work and no play makes Jack a dull boy,...)";
+    const std::string data_file2 = R"(solo trabajo y nada de juego hacen de Jack un chico aburrido,
+solo trabajo y nada de juego hacen de Jack un chico aburrido,...)";
+
+    HighFive::FileAccessProps fapl;
+    fapl.add(HighFive::MPIOFileAccess{MPI_COMM_WORLD, MPI_INFO_NULL});
+    fapl.add(HighFive::MPIOCollectiveMetadata{});
+    HighFive::File file = HighFive::File(filename, HighFive::File::Truncate, fapl);
+
+    file.createGroup("/checkpoint_0").createAttribute("data.pgs", data_file0);
+    file.createGroup("/checkpoint_1").createAttribute("data.pgs", data_file1);
+    file.createGroup("/checkpoint_2").createAttribute("data.pgs", data_file2);
+    file.createHardLink("last_checkpoint", file.getGroup("/checkpoint_2"));
+
+    file.createHardLink("resuming_checkpoint", file.getGroup("/checkpoint_0"));
+    file.flush();
+    parallel::barrier();
+    REQUIRE(resumingDatafile(filename) == data_file0);
+    parallel::barrier();
+
+    file.unlink("resuming_checkpoint");
+    file.createHardLink("resuming_checkpoint", file.getGroup("/checkpoint_1"));
+    file.flush();
+    parallel::barrier();
+    REQUIRE(resumingDatafile(filename) == data_file1);
+    parallel::barrier();
+
+    file.unlink("resuming_checkpoint");
+    file.createHardLink("resuming_checkpoint", file.getGroup("/checkpoint_2"));
+    file.flush();
+    parallel::barrier();
+    REQUIRE(resumingDatafile(filename) == data_file2);
+  }
+
+  parallel::barrier();
+  if (parallel::rank() == 0) {
+    std::filesystem::remove_all(std::filesystem::path{tmp_dirname});
+  }
+
+#else   // PUGS_HAS_HDF5
+
+  REQUIRE_THROWS_WITH(resumingDatafile("foo.h5"), "error: Resuming requires HDF5");
+
+#endif   // PUGS_HAS_HDF5
+}
diff --git a/tests/test_checkpointing_SetResumeFrom.cpp b/tests/test_checkpointing_SetResumeFrom.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..bead609386049914cc3a55edcab77651f67812e4
--- /dev/null
+++ b/tests/test_checkpointing_SetResumeFrom.cpp
@@ -0,0 +1,112 @@
+#include <catch2/catch_test_macros.hpp>
+#include <catch2/matchers/catch_matchers_all.hpp>
+
+#include <utils/HighFivePugsUtils.hpp>
+#include <utils/Messenger.hpp>
+#include <utils/checkpointing/SetResumeFrom.hpp>
+
+#include <filesystem>
+
+// clazy:excludeall=non-pod-global-static
+
+TEST_CASE("checkpointing_SetResumeFrom", "[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";
+
+    const std::string data_file0 = R"(Un tiens vaut mieux que deux tu l'auras,
+Un tiens vaut mieux que deux tu l'auras,...)";
+    const std::string data_file1 = R"(All work and no play makes Jack a dull boy,
+All work and no play makes Jack a dull boy,...)";
+    const std::string data_file2 = R"(solo trabajo y nada de juego hacen de Jack un chico aburrido,
+solo trabajo y nada de juego hacen de Jack un chico aburrido,...)";
+
+    {
+      HighFive::FileAccessProps fapl;
+      fapl.add(HighFive::MPIOFileAccess{MPI_COMM_WORLD, MPI_INFO_NULL});
+      fapl.add(HighFive::MPIOCollectiveMetadata{});
+      HighFive::File file = HighFive::File(filename, HighFive::File::Truncate, fapl);
+
+      file.createGroup("/checkpoint_0").createAttribute("data.pgs", data_file0);
+      file.createGroup("/checkpoint_1").createAttribute("data.pgs", data_file1);
+      file.createGroup("/checkpoint_2").createAttribute("data.pgs", data_file2);
+    }
+
+    {
+      std::ostringstream os;
+      setResumeFrom(filename, 0, os);
+      REQUIRE(os.str() == "Resuming checkpoint successfully set to 0\n");
+
+      HighFive::FileAccessProps fapl;
+      fapl.add(HighFive::MPIOFileAccess{MPI_COMM_WORLD, MPI_INFO_NULL});
+      fapl.add(HighFive::MPIOCollectiveMetadata{});
+      HighFive::File file = HighFive::File(filename, HighFive::File::ReadOnly, fapl);
+      REQUIRE(file.getGroup("/resuming_checkpoint").getAttribute("data.pgs").read<std::string>() == data_file0);
+    }
+
+    {
+      std::ostringstream os;
+      setResumeFrom(filename, 1, os);
+      REQUIRE(os.str() == "Resuming checkpoint successfully set to 1\n");
+
+      HighFive::FileAccessProps fapl;
+      fapl.add(HighFive::MPIOFileAccess{MPI_COMM_WORLD, MPI_INFO_NULL});
+      fapl.add(HighFive::MPIOCollectiveMetadata{});
+      HighFive::File file = HighFive::File(filename, HighFive::File::ReadOnly, fapl);
+      REQUIRE(file.getGroup("/resuming_checkpoint").getAttribute("data.pgs").read<std::string>() == data_file1);
+    }
+
+    {
+      std::ostringstream os;
+      setResumeFrom(filename, 2, os);
+      REQUIRE(os.str() == "Resuming checkpoint successfully set to 2\n");
+
+      HighFive::FileAccessProps fapl;
+      fapl.add(HighFive::MPIOFileAccess{MPI_COMM_WORLD, MPI_INFO_NULL});
+      fapl.add(HighFive::MPIOCollectiveMetadata{});
+      HighFive::File file = HighFive::File(filename, HighFive::File::ReadOnly, fapl);
+      REQUIRE(file.getGroup("/resuming_checkpoint").getAttribute("data.pgs").read<std::string>() == data_file2);
+    }
+
+    {
+      std::ostringstream error_msg;
+      error_msg << "error: cannot find checkpoint " << 12 << " in " << filename;
+      REQUIRE_THROWS_WITH(setResumeFrom(filename, 12), error_msg.str());
+    }
+  }
+
+  parallel::barrier();
+  if (parallel::rank() == 0) {
+    std::filesystem::remove_all(std::filesystem::path{tmp_dirname});
+  }
+
+#else   // PUGS_HAS_HDF5
+
+  if (parallel::rank() == 0) {
+    std::cerr.setstate(std::ios::badbit);
+  }
+
+  std::ostringstream os;
+  REQUIRE_NOTHROW(setResumeFrom("foo.h5", 0, os));
+
+  if (parallel::rank() == 0) {
+    std::cerr.clear();
+  }
+
+  REQUIRE(os.str() == "");
+
+#endif   // PUGS_HAS_HDF5
+}