diff --git a/src/cell_group.hpp b/src/cell_group.hpp
index 14ea3946ef4cb05a2b644ba6257563bcb328181f..f667ebdbeabb7ed93f0941bfba076eda45f94296 100644
--- a/src/cell_group.hpp
+++ b/src/cell_group.hpp
@@ -171,7 +171,7 @@ private:
 
     /// the global id of the first target (e.g. a synapse) in this group
     index_type first_target_gid_;
- 
+
     /// the global id of the first probe in this group
     index_type first_probe_gid_;
 
diff --git a/src/util/ioutil.hpp b/src/util/ioutil.hpp
index ff000a47bbdf64138c5446d748a42295ea4606ff..2feab394df71d730bde904d041ebbeeb85bf9a44 100644
--- a/src/util/ioutil.hpp
+++ b/src/util/ioutil.hpp
@@ -24,10 +24,10 @@ private:
 };
 
 
-template <typename charT,typename traitsT=std::char_traits<charT> >
-struct basic_null_streambuf: std::basic_streambuf<charT,traitsT> {
+template <typename charT, typename traitsT = std::char_traits<charT> >
+class basic_null_streambuf: public std::basic_streambuf<charT, traitsT> {
 private:
-    typedef typename std::basic_streambuf<charT,traitsT> streambuf_type;
+    typedef typename std::basic_streambuf<charT, traitsT> streambuf_type;
 
 public:
     typedef typename streambuf_type::char_type char_type;
@@ -39,7 +39,7 @@ public:
     virtual ~basic_null_streambuf() {}
 
 protected:
-    std::streamsize xsputn(const char_type *s,std::streamsize count) override {
+    std::streamsize xsputn(const char_type* s, std::streamsize count) override {
         return count;
     }
 
@@ -48,28 +48,29 @@ protected:
     }
 };
 
-struct mask_stream {
-    explicit mask_stream(bool mask_): mask(mask_) {}
+class mask_stream {
+public:
+    explicit mask_stream(bool mask): mask_(mask) {}
 
-    operator bool() const { return mask; }
+    operator bool() const { return mask_; }
 
-    template <typename charT,typename traitsT>
-    friend std::basic_ostream<charT,traitsT> &
-    operator<<(std::basic_ostream<charT,traitsT> &O,const mask_stream &F) {
-        int xindex=get_xindex();
+    template <typename charT, typename traitsT>
+    friend std::basic_ostream<charT, traitsT>&
+    operator<<(std::basic_ostream<charT, traitsT>& O, const mask_stream& F) {
+        int xindex = get_xindex();
 
-        std::basic_streambuf<charT,traitsT> *saved_streambuf=
-            static_cast<std::basic_streambuf<charT,traitsT> *>(O.pword(xindex));
+        std::basic_streambuf<charT, traitsT>* saved_streambuf =
+            static_cast<std::basic_streambuf<charT, traitsT>*>(O.pword(xindex));
 
-        if (F.mask && saved_streambuf) {
+        if (F.mask_ && saved_streambuf) {
             // re-enable by restoring saved streambuf
-            O.pword(xindex)=0;
+            O.pword(xindex) = 0;
             O.rdbuf(saved_streambuf);
         }
-        else if (!F.mask && !saved_streambuf) {
+        else if (!F.mask_ && !saved_streambuf) {
             // disable stream but save old streambuf
-            O.pword(xindex)=O.rdbuf();
-            O.rdbuf(get_null_streambuf<charT,traitsT>());
+            O.pword(xindex) = O.rdbuf();
+            O.rdbuf(get_null_streambuf<charT, traitsT>());
         }
 
         return O;
@@ -78,18 +79,18 @@ struct mask_stream {
 private:
     // our key for retrieve saved streambufs.
     static int get_xindex() {
-        static int xindex=std::ios_base::xalloc();
+        static int xindex = std::ios_base::xalloc();
         return xindex;
     }
 
-    template <typename charT,typename traitsT>
-    static std::basic_streambuf<charT,traitsT> *get_null_streambuf() {
-        static basic_null_streambuf<charT,traitsT> the_null_streambuf;
+    template <typename charT, typename traitsT>
+    static std::basic_streambuf<charT, traitsT>* get_null_streambuf() {
+        static basic_null_streambuf<charT, traitsT> the_null_streambuf;
         return &the_null_streambuf;
     }
 
     // true => do not filter
-    bool mask;
+    bool mask_;
 };
 
 } // namespace util
diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt
index 61d713bc831e7ec63dfaf370f7931e204c7d9e45..4ba5bb8b0be6764e84fb24ea1c16ee803f6bc516 100644
--- a/tests/unit/CMakeLists.txt
+++ b/tests/unit/CMakeLists.txt
@@ -17,6 +17,7 @@ set(TEST_SOURCES
     test_fvm.cpp
     test_cell_group.cpp
     test_lexcmp.cpp
+    test_mask_stream.cpp
     test_matrix.cpp
     test_mechanisms.cpp
     test_optional.cpp
diff --git a/tests/unit/test_mask_stream.cpp b/tests/unit/test_mask_stream.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8ca8089eab1f7486204ce0df70fb953000b301a0
--- /dev/null
+++ b/tests/unit/test_mask_stream.cpp
@@ -0,0 +1,68 @@
+#include "gtest.h"
+
+#include <sstream>
+
+#include <util/ioutil.hpp>
+
+using namespace nest::mc::util;
+
+TEST(mask_stream,nomask) {
+    // expect mask_stream(true) on a new stream not to change rdbuf.
+    std::ostringstream s;
+    auto sbuf = s.rdbuf();
+    s << mask_stream(true);
+    EXPECT_EQ(sbuf, s.rdbuf());
+}
+
+TEST(mask_stream,mask) {
+    // masked stream should produce no ouptut
+    std::ostringstream s;
+    s << "one";
+    s << mask_stream(false);
+
+    s << "two";
+    EXPECT_EQ(s.str(), "one");
+
+    s << mask_stream(true);
+    s << "three";
+    EXPECT_EQ(s.str(), "onethree");
+}
+
+TEST(mask_stream,mask_multi) {
+    // mark_stream(false) should be idempotent
+
+    std::ostringstream s;
+    auto sbuf1 = s.rdbuf();
+
+    s << "foo";
+    s << mask_stream(false);
+    auto sbuf2 = s.rdbuf();
+
+    s << "bar";
+    s << mask_stream(false);
+    auto sbuf3 = s.rdbuf();
+    EXPECT_EQ(sbuf2, sbuf3);
+
+    s << "baz";
+    s << mask_stream(true);
+    auto sbuf4 = s.rdbuf();
+    EXPECT_EQ(sbuf1, sbuf4);
+
+    s << "xyzzy";
+    EXPECT_EQ(s.str(), "fooxyzzy");
+}
+
+TEST(mask_stream,fmt) {
+    // expect formatting to be preserved across masks.
+
+    std::ostringstream s;
+    s.precision(1);
+
+    s << mask_stream(false);
+    EXPECT_EQ(s.precision(), 1);
+    s.precision(2);
+
+    s << mask_stream(true);
+    EXPECT_EQ(s.precision(), 2);
+}
+