diff --git a/PhysicsAnalysis/AnalysisCommon/HDF5Utils/CMakeLists.txt b/PhysicsAnalysis/AnalysisCommon/HDF5Utils/CMakeLists.txt
index a8019336ab5683abda7ea4dc71341cad493aed98..ac0d2814ea2001e4100d663f36a27a097cd71ba4 100644
--- a/PhysicsAnalysis/AnalysisCommon/HDF5Utils/CMakeLists.txt
+++ b/PhysicsAnalysis/AnalysisCommon/HDF5Utils/CMakeLists.txt
@@ -64,3 +64,15 @@ if (NOT XAOD_STANDALONE)
     LINK_LIBRARIES IH5GroupSvc ${HDF5_LIBRARIES}
   )
 endif()
+
+# unit tests
+
+atlas_add_executable( test-hdf5-writer
+  util/test-hdf5-writer.cxx
+  LINK_LIBRARIES HDF5Utils )
+atlas_install_scripts( test/test-h5-output )
+
+atlas_add_test( test_hdf5_writer
+  SCRIPT test-hdf5-writer
+  LINK_LIBRARIES HDF5Utils
+  POST_EXEC_SCRIPT test-h5-output)
diff --git a/PhysicsAnalysis/AnalysisCommon/HDF5Utils/HDF5Utils/H5Traits.h b/PhysicsAnalysis/AnalysisCommon/HDF5Utils/HDF5Utils/H5Traits.h
index d0eb38f85287045111a29d8b114f7d42007292b3..6982a65df4129bb5ac7f73b96c3cef3d88ce114b 100644
--- a/PhysicsAnalysis/AnalysisCommon/HDF5Utils/HDF5Utils/H5Traits.h
+++ b/PhysicsAnalysis/AnalysisCommon/HDF5Utils/HDF5Utils/H5Traits.h
@@ -33,7 +33,9 @@ namespace H5Utils {
     union data_buffer_t
     {
       int u_int;
+      long u_long;
       long long u_llong;
+      unsigned long u_ulong;
       unsigned long long u_ullong;
       unsigned int u_uint;
       unsigned char u_uchar;
@@ -54,10 +56,18 @@ namespace H5Utils {
       static const H5::DataType type;
       static int& ref(data_buffer_t& buf) { return buf.u_int; }
     };
+    template <> struct H5Traits<long> {
+      static const H5::DataType type;
+      static long& ref(data_buffer_t& buf) { return buf.u_long; }
+    };
     template <> struct H5Traits<long long> {
       static const H5::DataType type;
       static long long& ref(data_buffer_t& buf) { return buf.u_llong; }
     };
+    template <> struct H5Traits<unsigned long> {
+      static const H5::DataType type;
+      static unsigned long& ref(data_buffer_t& buf) { return buf.u_ulong; }
+    };
     template <> struct H5Traits<unsigned long long> {
       static const H5::DataType type;
       static unsigned long long& ref(data_buffer_t& buf) { return buf.u_ullong; }
diff --git a/PhysicsAnalysis/AnalysisCommon/HDF5Utils/HDF5Utils/Writer.h b/PhysicsAnalysis/AnalysisCommon/HDF5Utils/HDF5Utils/Writer.h
index 86555879520345bd6b5f0d4a267071c0e3668ce1..a84822dae2e28613d482e7cac08a05f78aec2610 100644
--- a/PhysicsAnalysis/AnalysisCommon/HDF5Utils/HDF5Utils/Writer.h
+++ b/PhysicsAnalysis/AnalysisCommon/HDF5Utils/HDF5Utils/Writer.h
@@ -136,10 +136,14 @@ namespace H5Utils {
              Compression = Compression::STANDARD);
 
     /// overload to cast lambdas into functions
-    template <typename T, typename F>
+    template <
+      typename T,
+      typename F,
+      typename R=decltype(std::declval<F>()(std::declval<I>()))
+      >
     void add(const std::string& name, const F func, const T& def = T(),
              Compression comp = Compression::STANDARD) {
-      add(name, std::function<T(I)>(func), def, comp);
+      add<R>(name, std::function<R(I)>(func), R(def), comp);
     }
 
 
diff --git a/PhysicsAnalysis/AnalysisCommon/HDF5Utils/Root/H5Traits.cxx b/PhysicsAnalysis/AnalysisCommon/HDF5Utils/Root/H5Traits.cxx
index 6190f7f426ba8afbacb35fd4ee873f8352d45b03..81066c5cc81c124eb7c31a0d8b8655c642d58d88 100644
--- a/PhysicsAnalysis/AnalysisCommon/HDF5Utils/Root/H5Traits.cxx
+++ b/PhysicsAnalysis/AnalysisCommon/HDF5Utils/Root/H5Traits.cxx
@@ -14,7 +14,9 @@ namespace H5Utils {
 
     typedef H5::PredType PT;
     const H5::DataType H5Traits<int>::type = PT::NATIVE_INT;
+    const H5::DataType H5Traits<long>::type = PT::NATIVE_LONG;
     const H5::DataType H5Traits<long long>::type = PT::NATIVE_LLONG;
+    const H5::DataType H5Traits<unsigned long>::type = PT::NATIVE_ULONG;
     const H5::DataType H5Traits<unsigned long long>::type = PT::NATIVE_ULLONG;
     const H5::DataType H5Traits<unsigned int>::type = PT::NATIVE_UINT;
     const H5::DataType H5Traits<unsigned char>::type = PT::NATIVE_UCHAR;
diff --git a/PhysicsAnalysis/AnalysisCommon/HDF5Utils/test/test-h5-output b/PhysicsAnalysis/AnalysisCommon/HDF5Utils/test/test-h5-output
new file mode 100755
index 0000000000000000000000000000000000000000..3d1678e3ed41aa97e8ffad22aecae0b97b61df90
--- /dev/null
+++ b/PhysicsAnalysis/AnalysisCommon/HDF5Utils/test/test-h5-output
@@ -0,0 +1,4 @@
+#!/usr/bin/env bash
+set -eu
+noerror.sh
+h5ls output.h5
diff --git a/PhysicsAnalysis/AnalysisCommon/HDF5Utils/util/test-hdf5-writer.cxx b/PhysicsAnalysis/AnalysisCommon/HDF5Utils/util/test-hdf5-writer.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..4f8c249f23810e860ef77f33382a974e32cea805
--- /dev/null
+++ b/PhysicsAnalysis/AnalysisCommon/HDF5Utils/util/test-hdf5-writer.cxx
@@ -0,0 +1,123 @@
+/*
+  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "HDF5Utils/Writer.h"
+
+//-------------------------------------------------------------------------
+// output data structure
+struct out_t
+{
+  double dtype;
+  float ftype;
+  char ctype;
+  int itype;
+  long ltype;
+  long long lltype;
+  unsigned char uctype;
+  unsigned int uitype;
+  unsigned long ultype;
+  unsigned long long ulltype;
+  bool btype;
+};
+using consumer_t = H5Utils::Consumers<const out_t&>;
+
+consumer_t getConsumers() {
+  consumer_t consumers;
+  consumers.add(
+    "half",
+    [](const out_t& o) -> float { return o.ftype; },
+    0,
+    H5Utils::Compression::HALF_PRECISION);
+#define ADD(NAME) consumers.add(#NAME, [](const out_t& o){ return o.NAME;}, 0)
+  ADD(ftype);
+  ADD(dtype);
+  ADD(btype);
+  ADD(ctype);
+  ADD(itype);
+  ADD(ltype);
+  ADD(lltype);
+  ADD(uctype);
+  ADD(uitype);
+  ADD(ultype);
+  ADD(ulltype);
+#undef ADD
+  return consumers;
+}
+
+//-------------------------------------------------------------------------
+// outputs
+
+std::vector<out_t> getOutputs(int offset, size_t length, float factor) {
+  std::vector<out_t> outvec;
+  for (size_t n = 0; n < length; n++) {
+    out_t out;
+    long long int shifted = n + offset;
+    double factored = shifted*factor;
+    out.dtype = factored;
+    out.ftype = factored;
+    out.ctype = shifted;
+    out.itype = shifted;
+    out.ltype = shifted;
+    out.lltype = shifted;
+    out.uctype = shifted;
+    out.uitype = shifted;
+    out.ultype = shifted;
+    out.ulltype = shifted;
+    out.btype = n % 2;
+    outvec.push_back(out);
+  }
+  return outvec;
+}
+
+template <size_t N>
+auto nestOutputs(int offset, size_t length) {
+  using ret_t = decltype(
+    nestOutputs<N-1>(std::declval<int>(),std::declval<size_t>()));
+  std::vector<ret_t> ret;
+  for (size_t n = 0; n < length; n++) {
+    ret.push_back(nestOutputs<N-1>(n + offset, length));
+  }
+  return ret;
+}
+template<>
+auto nestOutputs<1>(int offset, size_t length) {
+  return getOutputs(offset, length, 0.5);
+}
+
+//-------------------------------------------------------------------------
+// main routine
+
+int main(int, char*[]) {
+  // make the output file
+  H5::H5File out_file("output.h5", H5F_ACC_TRUNC);
+
+  // scalar output
+  using scalar_writer_t = H5Utils::Writer<0, consumer_t::input_type>;
+  scalar_writer_t::configuration_type scalar_config;
+  scalar_config.name = "scalar";
+  consumer_t consumers = getConsumers();
+  scalar_writer_t scalar(out_file, consumers, scalar_config);
+  scalar.fill(getOutputs(1, 1, 0.5).at(0));
+
+  // 1d output
+  using d1_t = H5Utils::Writer<1, consumer_t::input_type>;
+  d1_t::configuration_type d1_config;
+  d1_config.name = "1d";
+  d1_config.extent = {10};
+  d1_config.chunks = {5};
+  d1_t d1(out_file, consumers, d1_config);
+  d1.fill(getOutputs(0, 10, 0.5));
+
+  // 4d output
+  using d4_t = H5Utils::Writer<4, consumer_t::input_type>;
+  d4_t::configuration_type d4_config;
+  d4_config.name = "4d";
+  d4_config.extent = {2,3,4,5};
+  d4_config.chunks = {1,2,1,2};
+  d4_t d4(out_file, consumers, d4_config);
+  d4.fill(nestOutputs<4>(0,3));
+
+  return 0;
+}
+