diff --git a/CMakeLists.txt b/CMakeLists.txt
index f3f5c8478558efc0a3116f3dfc8fddbb1e0d176a..3f62e1b88ed577fa73bbfddc6ff2263c8925ec0e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -447,7 +447,7 @@ if("${CMAKE_BUILD_TYPE}" STREQUAL "Coverage")
 
       COMMAND ${FASTCOV} -q --gcov "${GCOV_BIN}"
       --include "${PUGS_SOURCE_DIR}/src"
-      --exclude "${PUGS_SOURCE_DIR}/src/main.cpp" "${PUGS_SOURCE_DIR}/src/utils/BacktraceManager.*"
+      --exclude "${PUGS_SOURCE_DIR}/src/main.cpp" "${PUGS_SOURCE_DIR}/src/utils/BacktraceManager.*" "${PUGS_SOURCE_DIR}/src/utils/FPEManager.*" "${PUGS_SOURCE_DIR}/src/utils/SignalManager.*"
       --lcov -o coverage.info -n
 
       COMMAND ${LCOV} --gcov "${GCOV_BIN}" --list coverage.info
diff --git a/src/algebra/TinyMatrix.hpp b/src/algebra/TinyMatrix.hpp
index a4499baa4677f09bc7edd3c1e3c59d41c9b3557d..0635f1b32b12d29bbbaa85273d6c49d92aba12ca 100644
--- a/src/algebra/TinyMatrix.hpp
+++ b/src/algebra/TinyMatrix.hpp
@@ -11,7 +11,7 @@
 #include <iostream>
 
 template <size_t N, typename T = double>
-class TinyMatrix
+class [[nodiscard]] TinyMatrix
 {
  public:
   using data_type = T;
@@ -21,15 +21,13 @@ class TinyMatrix
   static_assert((N > 0), "TinyMatrix size must be strictly positive");
 
   PUGS_FORCEINLINE
-  constexpr size_t
-  _index(size_t i, size_t j) const noexcept   // LCOV_EXCL_LINE (due to forced inline)
+  constexpr size_t _index(size_t i, size_t j) const noexcept   // LCOV_EXCL_LINE (due to forced inline)
   {
     return i * N + j;
   }
 
   template <typename... Args>
-  PUGS_FORCEINLINE constexpr void
-  _unpackVariadicInput(const T& t, Args&&... args) noexcept
+  PUGS_FORCEINLINE constexpr void _unpackVariadicInput(const T& t, Args&&... args) noexcept
   {
     m_values[N * N - 1 - sizeof...(args)] = t;
     if constexpr (sizeof...(args) > 0) {
@@ -39,8 +37,7 @@ class TinyMatrix
 
  public:
   PUGS_INLINE
-  constexpr TinyMatrix
-  operator-() const
+  constexpr TinyMatrix operator-() const
   {
     TinyMatrix opposed;
     for (size_t i = 0; i < N * N; ++i) {
@@ -50,23 +47,20 @@ class TinyMatrix
   }
 
   PUGS_INLINE
-  constexpr friend TinyMatrix
-  operator*(const T& t, const TinyMatrix& A)
+  constexpr friend TinyMatrix operator*(const T& t, const TinyMatrix& A)
   {
     TinyMatrix B = A;
     return B *= t;
   }
 
   PUGS_INLINE
-  constexpr friend TinyMatrix
-  operator*(const T& t, TinyMatrix&& A)
+  constexpr friend TinyMatrix operator*(const T& t, TinyMatrix&& A)
   {
     return std::move(A *= t);
   }
 
   PUGS_INLINE
-  constexpr TinyMatrix&
-  operator*=(const T& t)
+  constexpr TinyMatrix& operator*=(const T& t)
   {
     for (size_t i = 0; i < N * N; ++i) {
       m_values[i] *= t;
@@ -75,8 +69,7 @@ class TinyMatrix
   }
 
   PUGS_INLINE
-  constexpr TinyMatrix
-  operator*(const TinyMatrix& B) const
+  constexpr TinyMatrix operator*(const TinyMatrix& B) const
   {
     const TinyMatrix& A = *this;
     TinyMatrix AB;
@@ -93,8 +86,7 @@ class TinyMatrix
   }
 
   PUGS_INLINE
-  constexpr TinyVector<N, T>
-  operator*(const TinyVector<N, T>& x) const
+  constexpr TinyVector<N, T> operator*(const TinyVector<N, T>& x) const
   {
     const TinyMatrix& A = *this;
     TinyVector<N, T> Ax;
@@ -109,8 +101,7 @@ class TinyMatrix
   }
 
   PUGS_INLINE
-  constexpr friend std::ostream&
-  operator<<(std::ostream& os, const TinyMatrix& A)
+  constexpr friend std::ostream& operator<<(std::ostream& os, const TinyMatrix& A)
   {
     if constexpr (N == 1) {
       os << A(0, 0);
@@ -129,8 +120,7 @@ class TinyMatrix
   }
 
   PUGS_INLINE
-  constexpr bool
-  operator==(const TinyMatrix& A) const
+  constexpr bool operator==(const TinyMatrix& A) const
   {
     for (size_t i = 0; i < N * N; ++i) {
       if (m_values[i] != A.m_values[i])
@@ -140,15 +130,13 @@ class TinyMatrix
   }
 
   PUGS_INLINE
-  constexpr bool
-  operator!=(const TinyMatrix& A) const
+  constexpr bool operator!=(const TinyMatrix& A) const
   {
     return not this->operator==(A);
   }
 
   PUGS_INLINE
-  constexpr TinyMatrix
-  operator+(const TinyMatrix& A) const
+  constexpr TinyMatrix operator+(const TinyMatrix& A) const
   {
     TinyMatrix sum;
     for (size_t i = 0; i < N * N; ++i) {
@@ -158,8 +146,7 @@ class TinyMatrix
   }
 
   PUGS_INLINE
-  constexpr TinyMatrix
-  operator+(TinyMatrix&& A) const
+  constexpr TinyMatrix operator+(TinyMatrix&& A) const
   {
     for (size_t i = 0; i < N * N; ++i) {
       A.m_values[i] += m_values[i];
@@ -168,8 +155,7 @@ class TinyMatrix
   }
 
   PUGS_INLINE
-  constexpr TinyMatrix
-  operator-(const TinyMatrix& A) const
+  constexpr TinyMatrix operator-(const TinyMatrix& A) const
   {
     TinyMatrix difference;
     for (size_t i = 0; i < N * N; ++i) {
@@ -179,8 +165,7 @@ class TinyMatrix
   }
 
   PUGS_INLINE
-  constexpr TinyMatrix
-  operator-(TinyMatrix&& A) const
+  constexpr TinyMatrix operator-(TinyMatrix&& A) const
   {
     for (size_t i = 0; i < N * N; ++i) {
       A.m_values[i] = m_values[i] - A.m_values[i];
@@ -189,8 +174,7 @@ class TinyMatrix
   }
 
   PUGS_INLINE
-  constexpr TinyMatrix&
-  operator+=(const TinyMatrix& A)
+  constexpr TinyMatrix& operator+=(const TinyMatrix& A)
   {
     for (size_t i = 0; i < N * N; ++i) {
       m_values[i] += A.m_values[i];
@@ -199,8 +183,7 @@ class TinyMatrix
   }
 
   PUGS_INLINE
-  constexpr void
-  operator+=(const volatile TinyMatrix& A) volatile
+  constexpr void operator+=(const volatile TinyMatrix& A) volatile
   {
     for (size_t i = 0; i < N * N; ++i) {
       m_values[i] += A.m_values[i];
@@ -208,8 +191,7 @@ class TinyMatrix
   }
 
   PUGS_INLINE
-  constexpr TinyMatrix&
-  operator-=(const TinyMatrix& A)
+  constexpr TinyMatrix& operator-=(const TinyMatrix& A)
   {
     for (size_t i = 0; i < N * N; ++i) {
       m_values[i] -= A.m_values[i];
@@ -218,16 +200,14 @@ class TinyMatrix
   }
 
   PUGS_INLINE
-  constexpr T&
-  operator()(size_t i, size_t j) noexcept(NO_ASSERT)
+  constexpr T& operator()(size_t i, size_t j) noexcept(NO_ASSERT)
   {
     Assert((i < N) and (j < N));
     return m_values[_index(i, j)];
   }
 
   PUGS_INLINE
-  constexpr const T&
-  operator()(size_t i, size_t j) const noexcept(NO_ASSERT)
+  constexpr const T& operator()(size_t i, size_t j) const noexcept(NO_ASSERT)
   {
     Assert((i < N) and (j < N));
     return m_values[_index(i, j)];
@@ -299,7 +279,7 @@ class TinyMatrix
   constexpr TinyMatrix(const TinyMatrix&) noexcept = default;
 
   PUGS_INLINE
-  TinyMatrix(TinyMatrix&& A) noexcept = default;
+  TinyMatrix(TinyMatrix && A) noexcept = default;
 
   PUGS_INLINE
   ~TinyMatrix() = default;
diff --git a/src/algebra/TinyVector.hpp b/src/algebra/TinyVector.hpp
index 07690a826ef13040e42baca75daac425fa199333..3f3c10920f5ae75c6b37a0761393cad19a77786b 100644
--- a/src/algebra/TinyVector.hpp
+++ b/src/algebra/TinyVector.hpp
@@ -11,7 +11,7 @@
 #include <cmath>
 
 template <size_t N, typename T = double>
-class TinyVector
+class [[nodiscard]] TinyVector
 {
  public:
   inline static constexpr size_t Dimension = N;
@@ -22,8 +22,7 @@ class TinyVector
   static_assert((N > 0), "TinyVector size must be strictly positive");
 
   template <typename... Args>
-  PUGS_FORCEINLINE constexpr void
-  _unpackVariadicInput(const T& t, Args&&... args) noexcept
+  PUGS_FORCEINLINE constexpr void _unpackVariadicInput(const T& t, Args&&... args) noexcept
   {
     m_values[N - 1 - sizeof...(args)] = t;
     if constexpr (sizeof...(args) > 0) {
@@ -33,8 +32,7 @@ class TinyVector
 
  public:
   PUGS_INLINE
-  constexpr TinyVector
-  operator-() const
+  constexpr TinyVector operator-() const
   {
     TinyVector opposed;
     for (size_t i = 0; i < N; ++i) {
@@ -44,15 +42,13 @@ class TinyVector
   }
 
   PUGS_INLINE
-  constexpr size_t
-  dimension() const
+  constexpr size_t dimension() const
   {
     return N;
   }
 
   PUGS_INLINE
-  constexpr bool
-  operator==(const TinyVector& v) const
+  constexpr bool operator==(const TinyVector& v) const
   {
     for (size_t i = 0; i < N; ++i) {
       if (m_values[i] != v.m_values[i])
@@ -62,8 +58,7 @@ class TinyVector
   }
 
   PUGS_INLINE
-  constexpr bool
-  operator!=(const TinyVector& v) const
+  constexpr bool operator!=(const TinyVector& v) const
   {
     return not this->operator==(v);
   }
@@ -79,8 +74,7 @@ class TinyVector
   }
 
   PUGS_INLINE
-  constexpr TinyVector&
-  operator*=(const T& t)
+  constexpr TinyVector& operator*=(const T& t)
   {
     for (size_t i = 0; i < N; ++i) {
       m_values[i] *= t;
@@ -103,8 +97,7 @@ class TinyVector
   }
 
   PUGS_INLINE
-  constexpr friend std::ostream&
-  operator<<(std::ostream& os, const TinyVector& v)
+  constexpr friend std::ostream& operator<<(std::ostream& os, const TinyVector& v)
   {
     os << '(' << v.m_values[0];
     for (size_t i = 1; i < N; ++i) {
@@ -115,8 +108,7 @@ class TinyVector
   }
 
   PUGS_INLINE
-  constexpr TinyVector
-  operator+(const TinyVector& v) const
+  constexpr TinyVector operator+(const TinyVector& v) const
   {
     TinyVector sum;
     for (size_t i = 0; i < N; ++i) {
@@ -126,8 +118,7 @@ class TinyVector
   }
 
   PUGS_INLINE
-  constexpr TinyVector
-  operator+(TinyVector&& v) const
+  constexpr TinyVector operator+(TinyVector&& v) const
   {
     for (size_t i = 0; i < N; ++i) {
       v.m_values[i] += m_values[i];
@@ -136,8 +127,7 @@ class TinyVector
   }
 
   PUGS_INLINE
-  constexpr TinyVector
-  operator-(const TinyVector& v) const
+  constexpr TinyVector operator-(const TinyVector& v) const
   {
     TinyVector difference;
     for (size_t i = 0; i < N; ++i) {
@@ -147,8 +137,7 @@ class TinyVector
   }
 
   PUGS_INLINE
-  constexpr TinyVector
-  operator-(TinyVector&& v) const
+  constexpr TinyVector operator-(TinyVector&& v) const
   {
     for (size_t i = 0; i < N; ++i) {
       v.m_values[i] = m_values[i] - v.m_values[i];
@@ -157,8 +146,7 @@ class TinyVector
   }
 
   PUGS_INLINE
-  constexpr TinyVector&
-  operator+=(const TinyVector& v)
+  constexpr TinyVector& operator+=(const TinyVector& v)
   {
     for (size_t i = 0; i < N; ++i) {
       m_values[i] += v.m_values[i];
@@ -167,8 +155,7 @@ class TinyVector
   }
 
   PUGS_INLINE
-  constexpr void
-  operator+=(const volatile TinyVector& v) volatile
+  constexpr void operator+=(const volatile TinyVector& v) volatile
   {
     for (size_t i = 0; i < N; ++i) {
       m_values[i] += v.m_values[i];
@@ -176,8 +163,7 @@ class TinyVector
   }
 
   PUGS_INLINE
-  constexpr TinyVector&
-  operator-=(const TinyVector& v)
+  constexpr TinyVector& operator-=(const TinyVector& v)
   {
     for (size_t i = 0; i < N; ++i) {
       m_values[i] -= v.m_values[i];
@@ -241,7 +227,7 @@ class TinyVector
   constexpr TinyVector(const TinyVector&) noexcept = default;
 
   PUGS_INLINE
-  constexpr TinyVector(TinyVector&& v) noexcept = default;
+  constexpr TinyVector(TinyVector && v) noexcept = default;
 
   PUGS_INLINE
   ~TinyVector() noexcept = default;
diff --git a/src/language/PEGGrammar.hpp b/src/language/PEGGrammar.hpp
index fb3b1d74abf6ba0d33113ec95996c6a270edb77d..553a2797c8cf227ab88d4b977f9f727b671a4c7a 100644
--- a/src/language/PEGGrammar.hpp
+++ b/src/language/PEGGrammar.hpp
@@ -55,11 +55,13 @@ struct character : if_must_else< one< '\\' >, escaped_c, ascii::any> {};
 struct open_parent : seq< one< '(' >, ignored > {};
 struct close_parent : seq< one< ')' >, ignored > {};
 
-struct literal : if_must< one< '"' >, until< one< '"' >, character > > {};
+struct literal : star< minus<character, one < '"' > > >{};
+
+struct quoted_literal : if_must< one< '"' >, seq< literal,  one< '"'  > > >{};
 
 struct import_kw :  TAO_PEGTL_KEYWORD("import") {};
 
-struct LITERAL : seq< literal, ignored >{};
+struct LITERAL : seq< quoted_literal, ignored >{};
 
 struct REAL : seq< real, ignored >{};
 
diff --git a/src/language/utils/ASTPrinter.cpp b/src/language/utils/ASTPrinter.cpp
index 9bf18bdcf88f6399283750dac9ab0b38d8bf0400..8cc88b530997eb3cc9cccb176c3812c41dceea1f 100644
--- a/src/language/utils/ASTPrinter.cpp
+++ b/src/language/utils/ASTPrinter.cpp
@@ -14,9 +14,10 @@ ASTPrinter::_print(std::ostream& os, const ASTNode& node) const
   }
   os << rang::fg::reset;
 
-  if (node.is_type<language::name>() or node.is_type<language::literal>() or node.is_type<language::integer>() or
-      node.is_type<language::real>()) {
+  if (node.is_type<language::name>() or node.is_type<language::integer>() or node.is_type<language::real>()) {
     os << ':' << rang::fgB::green << node.string() << rang::fg::reset;
+  } else if (node.is_type<language::literal>()) {
+    os << ":\"" << rang::fgB::green << node.string() << rang::fg::reset << '"';
   }
 
   if (m_info & static_cast<InfoBaseType>(Info::data_type)) {
diff --git a/src/mesh/Connectivity.hpp b/src/mesh/Connectivity.hpp
index 3bf5cd4201c574749e5b6a67a2b6c4d667bd88f1..f8e4dafdb7a46473434645c26e46ee1c00f86117 100644
--- a/src/mesh/Connectivity.hpp
+++ b/src/mesh/Connectivity.hpp
@@ -12,7 +12,7 @@
 #include <mesh/RefId.hpp>
 #include <mesh/RefItemList.hpp>
 #include <mesh/SubItemValuePerItem.hpp>
-#include <utils/CSRGraph.hpp>
+#include <utils/CRSGraph.hpp>
 #include <utils/Exceptions.hpp>
 #include <utils/PugsAssert.hpp>
 #include <utils/PugsMacros.hpp>
@@ -542,36 +542,20 @@ class Connectivity final : public IConnectivity
   }
 
   PUGS_INLINE
-  CSRGraph
+  CRSGraph
   cellToCellGraph() const
   {
     std::vector<std::set<int>> cell_cells(this->numberOfCells());
-    if constexpr (true) {
-      const auto& face_to_cell_matrix = this->faceToCellMatrix();
+    const auto& face_to_cell_matrix = this->faceToCellMatrix();
 
-      for (FaceId l = 0; l < this->numberOfFaces(); ++l) {
-        const auto& face_to_cell = face_to_cell_matrix[l];
-        if (face_to_cell.size() > 1) {
-          const CellId cell_0 = face_to_cell[0];
-          const CellId cell_1 = face_to_cell[1];
+    for (FaceId l = 0; l < this->numberOfFaces(); ++l) {
+      const auto& face_to_cell = face_to_cell_matrix[l];
+      if (face_to_cell.size() > 1) {
+        const CellId cell_0 = face_to_cell[0];
+        const CellId cell_1 = face_to_cell[1];
 
-          cell_cells[cell_0].insert(cell_1);
-          cell_cells[cell_1].insert(cell_0);
-        }
-      }
-    } else {
-      const auto& node_to_cell_matrix = this->nodeToCellMatrix();
-
-      for (NodeId l = 0; l < this->numberOfNodes(); ++l) {
-        const auto& node_to_cell = node_to_cell_matrix[l];
-        for (size_t i_cell = 0; i_cell < node_to_cell.size(); ++i_cell) {
-          const CellId cell_0 = node_to_cell[i_cell];
-          for (size_t j_cell = 0; j_cell < i_cell; ++j_cell) {
-            const CellId cell_1 = node_to_cell[j_cell];
-            cell_cells[cell_0].insert(cell_1);
-            cell_cells[cell_1].insert(cell_0);
-          }
-        }
+        cell_cells[cell_0].insert(cell_1);
+        cell_cells[cell_1].insert(cell_0);
       }
     }
 
@@ -590,7 +574,7 @@ class Connectivity final : public IConnectivity
         }
       }
     }
-    return CSRGraph(entries, neighbors);
+    return CRSGraph(entries, neighbors);
   }
 
   PUGS_INLINE
diff --git a/src/mesh/ConnectivityDispatcher.cpp b/src/mesh/ConnectivityDispatcher.cpp
index 82bf2a2e006a13d0806b2d88b1dc54715a0cc116..6b73d967d4d4fcb37e1376bf1d9306826d25fb1f 100644
--- a/src/mesh/ConnectivityDispatcher.cpp
+++ b/src/mesh/ConnectivityDispatcher.cpp
@@ -1,6 +1,7 @@
 #include <mesh/ConnectivityDispatcher.hpp>
-#include <mesh/ItemOfItemType.hpp>
 
+#include <mesh/ItemOfItemType.hpp>
+#include <utils/CRSGraph.hpp>
 #include <utils/Partitioner.hpp>
 
 #include <iostream>
@@ -12,7 +13,7 @@ void
 ConnectivityDispatcher<Dimension>::_buildNewOwner()
 {
   if constexpr (item_type == ItemType::cell) {
-    CSRGraph connectivity_graph = m_connectivity.cellToCellGraph();
+    CRSGraph connectivity_graph = m_connectivity.cellToCellGraph();
     Partitioner P;
 
     CellValue<int> cell_new_owner(m_connectivity);
diff --git a/src/mesh/Mesh.hpp b/src/mesh/Mesh.hpp
index d04807650cd08c0b96a7259cbe5756596d54aad1..e78383978469292d6529eb931b432406612f7220 100644
--- a/src/mesh/Mesh.hpp
+++ b/src/mesh/Mesh.hpp
@@ -4,7 +4,6 @@
 #include <algebra/TinyVector.hpp>
 #include <mesh/IMesh.hpp>
 #include <mesh/ItemValue.hpp>
-#include <utils/CSRGraph.hpp>
 
 #include <memory>
 
diff --git a/src/utils/Array.hpp b/src/utils/Array.hpp
index 42ae7f61c375a9cb544020063f827c43dcf5e143..560f60ce7015c06fa68c80121b43f86179a05e83 100644
--- a/src/utils/Array.hpp
+++ b/src/utils/Array.hpp
@@ -10,7 +10,7 @@
 #include <algorithm>
 
 template <typename DataType>
-class Array
+class [[nodiscard]] Array
 {
  public:
   using data_type  = DataType;
@@ -23,15 +23,12 @@ class Array
   friend Array<std::add_const_t<DataType>>;
 
  public:
-  PUGS_INLINE
-  size_t
-  size() const noexcept
+  PUGS_INLINE size_t size() const noexcept
   {
     return m_values.extent(0);
   }
 
-  friend PUGS_INLINE Array<std::remove_const_t<DataType>>
-  copy(const Array<DataType>& source)
+  friend PUGS_INLINE Array<std::remove_const_t<DataType>> copy(const Array<DataType>& source)
   {
     Array<std::remove_const_t<DataType>> image(source.size());
     Kokkos::deep_copy(image.m_values, source.m_values);
@@ -42,16 +39,14 @@ class Array
   template <typename DataType2, typename... RT>
   friend PUGS_INLINE Array<DataType2> encapsulate(const Kokkos::View<DataType2*, RT...>& values);
 
-  PUGS_INLINE
-  DataType& operator[](index_type i) const noexcept(NO_ASSERT)
+  PUGS_INLINE DataType& operator[](index_type i) const noexcept(NO_ASSERT)
   {
     Assert(i < m_values.extent(0));
     return m_values[i];
   }
 
   PUGS_INLINE
-  void
-  fill(const DataType& data) const
+  void fill(const DataType& data) const
   {
     static_assert(not std::is_const<DataType>(), "Cannot modify Array of const");
 
@@ -61,8 +56,7 @@ class Array
   }
 
   template <typename DataType2>
-  PUGS_INLINE Array&
-  operator=(const Array<DataType2>& array) noexcept
+  PUGS_INLINE Array& operator=(const Array<DataType2>& array) noexcept
   {
     // ensures that DataType is the same as source DataType2
     static_assert(std::is_same<std::remove_const_t<DataType>, std::remove_const_t<DataType2>>(),
@@ -81,7 +75,7 @@ class Array
   Array& operator=(Array&&) = default;
 
   PUGS_INLINE
-  Array(size_t size) : m_values("anonymous", size)
+  explicit Array(size_t size) : m_values("anonymous", size)
   {
     static_assert(not std::is_const<DataType>(), "Cannot allocate Array of const data: only view is "
                                                  "supported");
@@ -94,14 +88,13 @@ class Array
   Array(const Array&) = default;
 
   template <typename DataType2>
-  PUGS_INLINE
-  Array(const Array<DataType2>& array) noexcept
+  PUGS_INLINE Array(const Array<DataType2>& array) noexcept
   {
     this->operator=(array);
   }
 
   PUGS_INLINE
-  Array(Array&&) = default;
+  Array(Array &&) = default;
 
   PUGS_INLINE
   ~Array() = default;
diff --git a/src/utils/CRSGraph.hpp b/src/utils/CRSGraph.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..59b74ab57b16db757e95d1b74e72b4e296bfc026
--- /dev/null
+++ b/src/utils/CRSGraph.hpp
@@ -0,0 +1,47 @@
+#ifndef CRS_GRAPH_HPP
+#define CRS_GRAPH_HPP
+
+#include <utils/Array.hpp>
+
+class CRSGraph
+{
+ private:
+  Array<const int> m_entries;
+  Array<const int> m_neighbors;
+
+ public:
+  size_t
+  numberOfNodes() const
+  {
+    Assert(m_entries.size() > 0);
+    return m_entries.size() - 1;
+  }
+
+  const Array<const int>&
+  entries() const
+  {
+    return m_entries;
+  }
+
+  const Array<const int>&
+  neighbors() const
+  {
+    return m_neighbors;
+  }
+
+  CRSGraph& operator=(CRSGraph&&) = delete;
+  CRSGraph& operator=(const CRSGraph&) = delete;
+
+  CRSGraph(const Array<int>& entries, const Array<int>& neighbors) : m_entries(entries), m_neighbors(neighbors)
+  {
+    Assert(m_entries.size() > 0);
+    Assert(static_cast<size_t>(m_entries[m_entries.size() - 1]) == m_neighbors.size());
+  }
+
+  CRSGraph()                = delete;
+  CRSGraph(CRSGraph&&)      = delete;
+  CRSGraph(const CRSGraph&) = delete;
+  ~CRSGraph()               = default;
+};
+
+#endif   // CRS_GRAPH_HPP
diff --git a/src/utils/CSRGraph.hpp b/src/utils/CSRGraph.hpp
deleted file mode 100644
index a3ae85dcced1897fc54901903c919f0009761d74..0000000000000000000000000000000000000000
--- a/src/utils/CSRGraph.hpp
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef CSR_GRAPH_HPP
-#define CSR_GRAPH_HPP
-
-#include <utils/Array.hpp>
-
-class CSRGraph
-{
- private:
-  Array<int> m_entries;
-  Array<int> m_neighbors;
-
- public:
-  size_t
-  numberOfNodes() const
-  {
-    Assert(m_entries.size() > 0);
-    return m_entries.size() - 1;
-  }
-
-  const Array<int>&
-  entries() const
-  {
-    return m_entries;
-  }
-
-  const Array<int>&
-  neighbors() const
-  {
-    return m_neighbors;
-  }
-
-  CSRGraph& operator=(CSRGraph&&) = default;
-  CSRGraph& operator=(const CSRGraph&) = default;
-
-  CSRGraph(const Array<int>& entries, const Array<int>& neighbors) : m_entries(entries), m_neighbors(neighbors)
-  {
-    Assert(m_entries.size() > 0);
-  }
-
-  CSRGraph()                = default;
-  CSRGraph(CSRGraph&&)      = default;
-  CSRGraph(const CSRGraph&) = default;
-  ~CSRGraph()               = default;
-};
-
-#endif   // CSR_GRAPH_HPP
diff --git a/src/utils/CastArray.hpp b/src/utils/CastArray.hpp
index 120bcc25c1f5dd9da75a387016bad8d2b5175688..d329b4ef35f70f3a612ca430c45d0ec23bb7ed9d 100644
--- a/src/utils/CastArray.hpp
+++ b/src/utils/CastArray.hpp
@@ -8,7 +8,7 @@
 #include <iostream>
 
 template <typename DataType, typename CastDataType>
-class CastArray
+class [[nodiscard]] CastArray
 {
  public:
   using data_type = CastDataType;
@@ -20,8 +20,7 @@ class CastArray
 
  public:
   PUGS_INLINE
-  const size_t&
-  size() const
+  const size_t& size() const
   {
     return m_size;
   }
@@ -39,17 +38,10 @@ class CastArray
   PUGS_INLINE
   CastArray& operator=(CastArray&&) = default;
 
-  PUGS_INLINE
-  CastArray() : m_size(0), m_values(nullptr)
-  {
-    ;
-  }
-
-  PUGS_INLINE
-  CastArray(const Array<DataType>& array)
+  explicit CastArray(const Array<DataType>& array)
     : m_array(array),
       m_size(sizeof(DataType) * array.size() / sizeof(CastDataType)),
-      m_values((array.size() == 0) ? nullptr : reinterpret_cast<CastDataType*>(&(array[0])))
+      m_values((array.size() == 0) ? nullptr : reinterpret_cast<CastDataType*>(&(static_cast<DataType&>(array[0]))))
   {
     static_assert((std::is_const_v<CastDataType> and std::is_const_v<DataType>) or (not std::is_const_v<DataType>),
                   "CastArray cannot remove const attribute");
@@ -59,9 +51,8 @@ class CastArray
     }
   }
 
-  PUGS_INLINE
-  CastArray(DataType& value)
-    : m_size(sizeof(DataType) / sizeof(CastDataType)), m_values(reinterpret_cast<CastDataType*>(&(value)))
+  explicit CastArray(DataType & value)
+    : m_size(sizeof(DataType) / sizeof(CastDataType)), m_values(reinterpret_cast<CastDataType*>(&value))
   {
     static_assert((std::is_const_v<CastDataType> and std::is_const_v<DataType>) or (not std::is_const_v<DataType>),
                   "CastArray cannot remove const attribute");
@@ -70,13 +61,13 @@ class CastArray
   }
 
   PUGS_INLINE
-  CastArray(DataType&& value) = delete;
+  CastArray(DataType && value) = delete;
 
   PUGS_INLINE
   CastArray(const CastArray&) = default;
 
   PUGS_INLINE
-  CastArray(CastArray&&) = default;
+  CastArray(CastArray &&) = default;
 
   PUGS_INLINE
   ~CastArray() = default;
diff --git a/src/utils/EscapedString.hpp b/src/utils/EscapedString.hpp
index ed525abd0368614fb756fd8c7795bb1c7ea178c6..cf0f0c676ebd2998673c62870b07e52bf04e0269 100644
--- a/src/utils/EscapedString.hpp
+++ b/src/utils/EscapedString.hpp
@@ -1,6 +1,7 @@
 #ifndef ESCAPED_STRING_HPP
 #define ESCAPED_STRING_HPP
 
+#include <utils/Exceptions.hpp>
 #include <utils/PugsMacros.hpp>
 
 #include <sstream>
@@ -11,7 +12,7 @@ PUGS_INLINE std::string
 unescapeString(std::string_view input_string)
 {
   std::stringstream ss;
-  for (size_t i = 1; i < input_string.size() - 1; ++i) {
+  for (size_t i = 0; i < input_string.size(); ++i) {
     char c = input_string[i];
     if (c == '\\') {
       ++i;
@@ -81,11 +82,15 @@ escapeString(std::string_view input_string)
       ss << R"(\\)";
       break;
     }
+    case '\'': {
+      ss << R"(\')";
+      break;
+    }
     case '\"': {
       ss << R"(\")";
       break;
     }
-    case '?': {
+    case '\?': {
       ss << R"(\?)";
       break;
     }
diff --git a/src/utils/Messenger.hpp b/src/utils/Messenger.hpp
index 437ea62a0d734274900c8af1b474749813e1aeaa..cfe312a0884ae0718ee76c41855ce8b063fecffd 100644
--- a/src/utils/Messenger.hpp
+++ b/src/utils/Messenger.hpp
@@ -168,7 +168,7 @@ class Messenger
             typename RecvArrayType,
             typename... SendT,
             typename... RecvT>
-  RecvArrayType<RecvT...>
+  void
   _allToAll(const SendArrayType<SendT...>& sent_array, RecvArrayType<RecvT...>& recv_array) const
   {
 #ifdef PUGS_HAS_MPI
@@ -189,7 +189,6 @@ class Messenger
 #else    // PUGS_HAS_MPI
     value_copy(sent_array, recv_array);
 #endif   // PUGS_HAS_MPI
-    return recv_array;
   }
 
   template <template <typename... SendT> typename SendArrayType,
diff --git a/src/utils/Partitioner.cpp b/src/utils/Partitioner.cpp
index 43ee64851b8d63e80afaf4d6960fe8015c1fa675..347b07da6bffdf62d0218ca5231ed9e03a9c698f 100644
--- a/src/utils/Partitioner.cpp
+++ b/src/utils/Partitioner.cpp
@@ -15,7 +15,7 @@
 #include <utils/Exceptions.hpp>
 
 Array<int>
-Partitioner::partition(const CSRGraph& graph)
+Partitioner::partition(const CRSGraph& graph)
 {
   std::cout << "Partitioning graph into " << rang::style::bold << parallel::size() << rang::style::reset << " parts\n";
 
@@ -26,7 +26,7 @@ Partitioner::partition(const CSRGraph& graph)
   std::vector<float> tpwgts(npart, 1. / npart);
 
   std::vector<float> ubvec{1.05};
-  std::vector<int> options{1, 1, 0};
+  std::vector<int> options{1, 0, 0};
   int edgecut = 0;
   Array<int> part(0);
 
@@ -57,15 +57,20 @@ Partitioner::partition(const CSRGraph& graph)
     part = Array<int>(local_number_of_nodes);
     std::vector<int> vtxdist{0, local_number_of_nodes};
 
-    const Array<int>& entries   = graph.entries();
-    const Array<int>& neighbors = graph.neighbors();
+    const Array<const int>& entries   = graph.entries();
+    const Array<const int>& neighbors = graph.neighbors();
+
+    int* entries_ptr   = const_cast<int*>(&(entries[0]));
+    int* neighbors_ptr = const_cast<int*>(&(neighbors[0]));
 
     int result =
-      ParMETIS_V3_PartKway(&(vtxdist[0]), &(entries[0]), &(neighbors[0]), NULL, NULL, &wgtflag, &numflag, &ncon, &npart,
+      ParMETIS_V3_PartKway(&(vtxdist[0]), entries_ptr, neighbors_ptr, NULL, NULL, &wgtflag, &numflag, &ncon, &npart,
                            &(tpwgts[0]), &(ubvec[0]), &(options[0]), &edgecut, &(part[0]), &parmetis_comm);
+    // LCOV_EXCL_START
     if (result == METIS_ERROR) {
       throw UnexpectedError("Metis Error");
     }
+    // LCOV_EXCL_STOP
 
     MPI_Comm_free(&parmetis_comm);
   }
@@ -78,9 +83,11 @@ Partitioner::partition(const CSRGraph& graph)
 #else   // PUGS_HAS_MPI
 
 Array<int>
-Partitioner::partition(const CSRGraph&)
+Partitioner::partition(const CRSGraph& graph)
 {
-  return Array<int>(0);
+  Array<int> partition{graph.entries().size() - 1};
+  partition.fill(0);
+  return partition;
 }
 
 #endif   // PUGS_HAS_MPI
diff --git a/src/utils/Partitioner.hpp b/src/utils/Partitioner.hpp
index 30f50723acff089cd1a21fa4f289030f5bbdf7a3..2c720bfd87e7853e12cd0736a46c5eda246f085f 100644
--- a/src/utils/Partitioner.hpp
+++ b/src/utils/Partitioner.hpp
@@ -1,7 +1,7 @@
 #ifndef PARTITIONER_HPP
 #define PARTITIONER_HPP
 
-#include <utils/CSRGraph.hpp>
+#include <utils/CRSGraph.hpp>
 
 class Partitioner
 {
@@ -10,7 +10,7 @@ class Partitioner
   Partitioner(const Partitioner&) = default;
   ~Partitioner()                  = default;
 
-  Array<int> partition(const CSRGraph& graph);
+  Array<int> partition(const CRSGraph& graph);
 };
 
 #endif   // PARTITIONER_HPP
diff --git a/src/utils/PugsUtils.cpp b/src/utils/PugsUtils.cpp
index 8f388c5b492dcd8065ed77740d322556bdc76db3..d54bd333f93107a1e093038764ebe7f088ace9df 100644
--- a/src/utils/PugsUtils.cpp
+++ b/src/utils/PugsUtils.cpp
@@ -19,6 +19,10 @@
 
 #include <iostream>
 
+// LCOV_EXCL_START
+
+// This function cannot be unit-tested: run once when pugs starts
+
 std::string
 initialize(int& argc, char* argv[])
 {
@@ -98,6 +102,12 @@ initialize(int& argc, char* argv[])
   return filename;
 }
 
+// LCOV_EXCL_STOP
+
+// LCOV_EXCL_START
+
+// This function cannot be unit-tested: run once when pugs stops
+
 void
 finalize()
 {
@@ -105,3 +115,5 @@ finalize()
   PETScWrapper::finalize();
   parallel::Messenger::destroy();
 }
+
+// LCOV_EXCL_STOP
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 11680e00f08cc7aa5ed80d9ed022fd3705bc8078..a08e1a689cf3041dd62b90c81630381581b83f38 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -45,16 +45,23 @@ add_executable (unit_tests
   test_BinaryExpressionProcessor_equality.cpp
   test_BinaryExpressionProcessor_logic.cpp
   test_BiCGStab.cpp
+  test_BuildInfo.cpp
   test_BuiltinFunctionEmbedder.cpp
   test_BuiltinFunctionEmbedderTable.cpp
   test_BuiltinFunctionProcessor.cpp
+  test_CastArray.cpp
+  test_ConsoleManager.cpp
   test_CG.cpp
   test_ContinueProcessor.cpp
   test_ConcatExpressionProcessor.cpp
+  test_CRSGraph.cpp
   test_CRSMatrix.cpp
   test_DataVariant.cpp
+  test_Demangle.cpp
   test_DoWhileProcessor.cpp
   test_EmbeddedData.cpp
+  test_EscapedString.cpp
+  test_Exceptions.cpp
   test_ExecutionPolicy.cpp
   test_FakeProcessor.cpp
   test_ForProcessor.cpp
@@ -86,7 +93,8 @@ add_executable (unit_tests
 
 add_executable (mpi_unit_tests
   mpi_test_main.cpp
-  mpi_test_Messenger.cpp
+  test_Messenger.cpp
+  test_Partitioner.cpp
   )
 
 add_library(test_Pugs_MeshDataBase
diff --git a/tests/test_Array.cpp b/tests/test_Array.cpp
index 3b8dd45878d07747cae3b4e761266c8d9bf14293..0071da34de3f6c5ae3173cb282a5a995462b47c5 100644
--- a/tests/test_Array.cpp
+++ b/tests/test_Array.cpp
@@ -197,6 +197,23 @@ TEST_CASE("Array", "[utils]")
     }
   }
 
+  SECTION("checking for Kokkos::View encaspulation")
+  {
+    {
+      Kokkos::View<double*> kokkos_view("anonymous", 10);
+      for (size_t i = 0; i < kokkos_view.size(); ++i) {
+        kokkos_view[i] = i;
+      }
+
+      Array array = encapsulate(kokkos_view);
+
+      REQUIRE(array.size() == kokkos_view.size());
+      for (size_t i = 0; i < array.size(); ++i) {
+        REQUIRE(&array[i] == &kokkos_view[i]);
+      }
+    }
+  }
+
 #ifndef NDEBUG
   SECTION("checking for bounds violation")
   {
diff --git a/tests/test_BuildInfo.cpp b/tests/test_BuildInfo.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..335cc74e420122f61a59067c0df89e416e55c2ba
--- /dev/null
+++ b/tests/test_BuildInfo.cpp
@@ -0,0 +1,65 @@
+#include <catch2/catch.hpp>
+
+#include <utils/BuildInfo.hpp>
+#include <utils/pugs_build_info.hpp>
+#include <utils/pugs_config.hpp>
+
+#include <sstream>
+
+#ifdef PUGS_HAS_MPI
+#include <mpi.h>
+#endif   //  PUGS_HAS_MPI
+
+#ifdef PUGS_HAS_PETSC
+#include <petsc.h>
+#endif   // PUGS_HAS_PETSC
+
+// clazy:excludeall=non-pod-global-static
+
+TEST_CASE("BuildInfo", "[utils]")
+{
+  SECTION("type")
+  {
+    REQUIRE(BuildInfo::type() == PUGS_BUILD_TYPE);
+  }
+
+  SECTION("compiler")
+  {
+    std::stringstream compiler_info;
+    compiler_info << PUGS_BUILD_COMPILER << " (" << PUGS_BUILD_COMPILER_VERSION << ")" << std::ends;
+    REQUIRE(BuildInfo::compiler() == compiler_info.str());
+  }
+
+  SECTION("kokkos")
+  {
+    REQUIRE(BuildInfo::kokkosDevices() == PUGS_BUILD_KOKKOS_DEVICES);
+  }
+
+  SECTION("mpi")
+  {
+#ifdef PUGS_HAS_MPI
+    const std::string mpi_library = []() {
+      int length;
+      char mpi_version[MPI_MAX_LIBRARY_VERSION_STRING];
+      MPI_Get_library_version(mpi_version, &length);
+      return std::string(mpi_version);
+    }();
+
+    REQUIRE(BuildInfo::mpiLibrary() == mpi_library);
+#else
+    REQUIRE(BuildInfo::mpiLibrary() == "none");
+#endif   // PUGS_HAS_MPI
+  }
+
+  SECTION("petsc")
+  {
+#ifdef PUGS_HAS_PETSC
+    const std::string petsc_library = std::to_string(PETSC_VERSION_MAJOR) + "." + std::to_string(PETSC_VERSION_MINOR) +
+                                      "." + std::to_string(PETSC_VERSION_SUBMINOR);
+
+    REQUIRE(BuildInfo::petscLibrary() == petsc_library);
+#else
+    REQUIRE(BuildInfo::petscLibrary() == "none");
+#endif   // PUGS_HAS_PETSC
+  }
+}
diff --git a/tests/test_CRSGraph.cpp b/tests/test_CRSGraph.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5c2fc7f287249468886f557d30bbb5740216f114
--- /dev/null
+++ b/tests/test_CRSGraph.cpp
@@ -0,0 +1,39 @@
+#include <catch2/catch.hpp>
+
+#include <utils/CRSGraph.hpp>
+
+// clazy:excludeall=non-pod-global-static
+
+TEST_CASE("CRSGraph", "[utils]")
+{
+  Array<int> entries{5};
+  Array<int> neighbors{9};
+
+  entries[0]   = 0;
+  neighbors[0] = 0;
+  neighbors[1] = 1;
+
+  entries[1]   = 2;
+  neighbors[2] = 1;
+  neighbors[3] = 3;
+
+  entries[2]   = 4;
+  neighbors[4] = 2;
+  neighbors[5] = 1;
+  neighbors[6] = 3;
+
+  entries[3]   = 7;
+  neighbors[7] = 0;
+  neighbors[8] = 1;
+
+  entries[4] = 9;
+
+  CRSGraph graph(entries, neighbors);
+
+  REQUIRE(graph.numberOfNodes() == 4);
+
+  REQUIRE(entries.size() == graph.entries().size());
+  REQUIRE(&entries[0] == &graph.entries()[0]);
+  REQUIRE(neighbors.size() == graph.neighbors().size());
+  REQUIRE(&neighbors[0] == &graph.neighbors()[0]);
+}
diff --git a/tests/test_CastArray.cpp b/tests/test_CastArray.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6a014045cfaf19a039dcaf0be97edaa81bea8522
--- /dev/null
+++ b/tests/test_CastArray.cpp
@@ -0,0 +1,88 @@
+#include <catch2/catch.hpp>
+
+#include <utils/ArrayUtils.hpp>
+#include <utils/CastArray.hpp>
+
+// clazy:excludeall=non-pod-global-static
+
+TEST_CASE("CastArray", "[utils]")
+{
+  SECTION("explicit cast Array -> CastArray")
+  {
+    Array<double> x_double{5};
+    x_double[0] = 1;
+    x_double[1] = 2;
+    x_double[2] = 3;
+    x_double[3] = 4;
+    x_double[4] = 5;
+
+    CastArray<double, char> x_char{x_double};
+
+    REQUIRE(x_char.size() * sizeof(char) == x_double.size() * sizeof(double));
+
+    Array<char> y_char{x_char.size()};
+    for (size_t i = 0; i < x_char.size(); ++i) {
+      y_char[i] = x_char[i];
+    }
+
+    CastArray<char, double> y_double{y_char};
+    REQUIRE(y_char.size() * sizeof(char) == y_double.size() * sizeof(double));
+
+    REQUIRE(&(y_double[0]) != &(x_double[0]));
+
+    for (size_t i = 0; i < y_double.size(); ++i) {
+      REQUIRE(y_double[i] == x_double[i]);
+    }
+  }
+
+  SECTION("explicit cast value -> CastArray")
+  {
+    double x = 3;
+
+    CastArray<double, char> x_char(x);
+
+    REQUIRE(x_char.size() * sizeof(char) == sizeof(double));
+  }
+
+  SECTION("invalid cast array")
+  {
+    Array<char> x_char{13};
+
+    REQUIRE_THROWS_WITH((CastArray<char, double>{x_char}),
+                        "unexpected error: cannot cast array to the chosen data type");
+  }
+
+  SECTION("cast array utilities")
+  {
+    SECTION("Array -> CastArray")
+    {
+      Array<double> x_double{5};
+      x_double[0] = 1.3;
+      x_double[1] = 3.2;
+      x_double[2] = -4;
+      x_double[3] = 6.2;
+      x_double[4] = -1.6;
+
+      CastArray<double, short> x_short{x_double};
+      auto x_short_from = cast_array_to<short>::from(x_double);
+
+      REQUIRE(x_short_from.size() == x_short.size());
+      for (size_t i = 0; i < x_short_from.size(); ++i) {
+        REQUIRE(x_short_from[i] == x_short[i]);
+      }
+    }
+
+    SECTION("Value -> CastArray")
+    {
+      double x = 3.14;
+
+      CastArray<double, short> x_short{x};
+      auto x_short_from = cast_value_to<short>::from(x);
+
+      REQUIRE(x_short_from.size() == x_short.size());
+      for (size_t i = 0; i < x_short_from.size(); ++i) {
+        REQUIRE(x_short_from[i] == x_short[i]);
+      }
+    }
+  }
+}
diff --git a/tests/test_ConsoleManager.cpp b/tests/test_ConsoleManager.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4387d7042065df80406ba3ba1c06ba44ec3f9e97
--- /dev/null
+++ b/tests/test_ConsoleManager.cpp
@@ -0,0 +1,32 @@
+#include <catch2/catch.hpp>
+
+#include <utils/ConsoleManager.hpp>
+
+#include <rang.hpp>
+
+// clazy:excludeall=non-pod-global-static
+
+TEST_CASE("ConsoleManager", "[utils]")
+{
+  SECTION("is terminal")
+  {
+    const bool is_terminal = rang::rang_implementation::isTerminal(std::cout.rdbuf());
+
+    REQUIRE(is_terminal == ConsoleManager::isTerminal(std::cout));
+  }
+
+  SECTION("control settings")
+  {
+    const rang::control saved_control = rang::rang_implementation::controlMode();
+
+    ConsoleManager::init(true);
+
+    REQUIRE(rang::rang_implementation::controlMode() == rang::control::Force);
+
+    ConsoleManager::init(false);
+
+    REQUIRE(rang::rang_implementation::controlMode() == rang::control::Off);
+
+    rang::setControlMode(saved_control);
+  }
+}
diff --git a/tests/test_Demangle.cpp b/tests/test_Demangle.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a3489fd2d629fe835e3ce247a8ac8008bb06ff9d
--- /dev/null
+++ b/tests/test_Demangle.cpp
@@ -0,0 +1,37 @@
+#include <catch2/catch.hpp>
+
+#include <utils/Demangle.hpp>
+
+#include <cxxabi.h>
+
+// clazy:excludeall=non-pod-global-static
+
+TEST_CASE("Demangle", "[utils]")
+{
+  SECTION("demangle success")
+  {
+    const std::string mangled = typeid(std::string).name();
+
+    int status          = -1;
+    char* cxa_demangled = abi::__cxa_demangle(mangled.data(), NULL, NULL, &status);
+
+    REQUIRE(status == 0);
+
+    std::string demangled{cxa_demangled};
+    free(cxa_demangled);
+
+    REQUIRE(demangled == demangle<std::string>());
+  }
+
+  SECTION("demangle failed")
+  {
+    const std::string mangled = "not_mangled";
+
+    int status = -1;
+    abi::__cxa_demangle(mangled.data(), NULL, NULL, &status);
+
+    REQUIRE(status != 0);
+
+    REQUIRE((std::string{"not_mangled"} == demangle("not_mangled")));
+  }
+}
diff --git a/tests/test_EscapedString.cpp b/tests/test_EscapedString.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3dca01496813ca51e6b52afd1be3c446bc7df54b
--- /dev/null
+++ b/tests/test_EscapedString.cpp
@@ -0,0 +1,22 @@
+#include <catch2/catch.hpp>
+
+#include <utils/EscapedString.hpp>
+
+// clazy:excludeall=non-pod-global-static
+
+TEST_CASE("EscapedString", "[utils]")
+{
+  SECTION("escape string")
+  {
+    const std::string s = "foo\'\\\"\?\a\b\f\n\r\t\vbar";
+
+    REQUIRE(escapeString(s) == R"(foo\'\\\"\?\a\b\f\n\r\t\vbar)");
+  }
+
+  SECTION("unescape string")
+  {
+    const std::string s = R"(foo\'\\\"\?\a\b\f\n\r\t\vbar)";
+
+    REQUIRE(unescapeString(s) == std::string{"foo\'\\\"\?\a\b\f\n\r\t\vbar"});
+  }
+}
diff --git a/tests/test_Exceptions.cpp b/tests/test_Exceptions.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..25b181ae165aef26cd25942cc52741a2606b50ac
--- /dev/null
+++ b/tests/test_Exceptions.cpp
@@ -0,0 +1,20 @@
+#include <catch2/catch.hpp>
+
+#include <utils/Exceptions.hpp>
+
+// clazy:excludeall=non-pod-global-static
+
+TEST_CASE("Exceptions", "[utils]")
+{
+  SECTION("exceptions message")
+  {
+    RawError raw_error{"a raw error"};
+    REQUIRE(std::string{raw_error.what()} == "a raw error");
+
+    UnexpectedError unexpected_error{"an unexpected error"};
+    REQUIRE(std::string{unexpected_error.what()} == "unexpected error: an unexpected error");
+
+    NotImplementedError not_implemented_error{"not implemented error"};
+    REQUIRE(std::string{not_implemented_error.what()} == "not implemented yet: not implemented error");
+  }
+}
diff --git a/tests/mpi_test_Messenger.cpp b/tests/test_Messenger.cpp
similarity index 98%
rename from tests/mpi_test_Messenger.cpp
rename to tests/test_Messenger.cpp
index 19d89851c82020c0f10e4eaeac919595059e8fab..022a5c07e4b16db81dc69ec236a1482d1138d6d1 100644
--- a/tests/mpi_test_Messenger.cpp
+++ b/tests/test_Messenger.cpp
@@ -471,4 +471,11 @@ TEST_CASE("Messenger", "[mpi]")
 
     std::remove("barrier_test");
   }
+
+  SECTION("errors")
+  {
+    int argc    = 0;
+    char** argv = nullptr;
+    REQUIRE_THROWS_WITH((parallel::Messenger::create(argc, argv)), "unexpected error: Messenger already created");
+  }
 }
diff --git a/tests/test_Partitioner.cpp b/tests/test_Partitioner.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9af1fc6c6f24be33aa5363696f36cab5909e6e7d
--- /dev/null
+++ b/tests/test_Partitioner.cpp
@@ -0,0 +1,86 @@
+#include <catch2/catch.hpp>
+
+#include <utils/Messenger.hpp>
+#include <utils/Partitioner.hpp>
+
+#include <set>
+
+// clazy:excludeall=non-pod-global-static
+
+TEST_CASE("Partitioner", "[utils]")
+{
+  SECTION("one graph split to all")
+  {
+    Partitioner partitioner;
+
+    std::vector<int> entries_vector;
+    std::vector<int> neighbors_vector;
+
+    entries_vector.push_back(neighbors_vector.size());
+
+    if (parallel::rank() == 0) {
+      neighbors_vector.push_back(1);
+      neighbors_vector.push_back(2);
+      neighbors_vector.push_back(4);
+      entries_vector.push_back(neighbors_vector.size());
+
+      neighbors_vector.push_back(0);
+      neighbors_vector.push_back(3);
+      neighbors_vector.push_back(5);
+      entries_vector.push_back(neighbors_vector.size());
+
+      neighbors_vector.push_back(0);
+      neighbors_vector.push_back(2);
+      neighbors_vector.push_back(5);
+      entries_vector.push_back(neighbors_vector.size());
+
+      neighbors_vector.push_back(0);
+      neighbors_vector.push_back(2);
+      neighbors_vector.push_back(5);
+      entries_vector.push_back(neighbors_vector.size());
+
+      neighbors_vector.push_back(3);
+      neighbors_vector.push_back(5);
+      neighbors_vector.push_back(7);
+      entries_vector.push_back(neighbors_vector.size());
+
+      neighbors_vector.push_back(3);
+      neighbors_vector.push_back(5);
+      neighbors_vector.push_back(6);
+      entries_vector.push_back(neighbors_vector.size());
+
+      neighbors_vector.push_back(5);
+      neighbors_vector.push_back(6);
+      neighbors_vector.push_back(7);
+      entries_vector.push_back(neighbors_vector.size());
+
+      neighbors_vector.push_back(3);
+      neighbors_vector.push_back(5);
+      neighbors_vector.push_back(7);
+      entries_vector.push_back(neighbors_vector.size());
+
+      neighbors_vector.push_back(4);
+      neighbors_vector.push_back(6);
+      neighbors_vector.push_back(7);
+      entries_vector.push_back(neighbors_vector.size());
+    }
+
+    Array<int> entries   = convert_to_array(entries_vector);
+    Array<int> neighbors = convert_to_array(neighbors_vector);
+
+    CRSGraph graph{entries, neighbors};
+
+    Array<int> partitioned = partitioner.partition(graph);
+
+    REQUIRE((partitioned.size() + 1) == entries.size());
+
+    if (parallel::rank() == 0) {
+      std::set<int> assigned_ranks;
+      for (size_t i = 0; i < partitioned.size(); ++i) {
+        assigned_ranks.insert(partitioned[i]);
+      }
+
+      REQUIRE(assigned_ranks.size() == parallel::size());
+    }
+  }
+}