diff --git a/Test/CMakeLists.txt b/Test/CMakeLists.txt
index fa9d180af00456b476960f2555d843be3637b05d..11f42ad642b408f2810a03bb7bc921f46c70c635 100644
--- a/Test/CMakeLists.txt
+++ b/Test/CMakeLists.txt
@@ -16,7 +16,6 @@ set(my_headers
    ${CMAKE_CURRENT_SOURCE_DIR}/TestPaths.hh
    ${CMAKE_CURRENT_SOURCE_DIR}/TestReport.hh
    ${CMAKE_CURRENT_SOURCE_DIR}/TestResult.hh
-   ${CMAKE_CURRENT_SOURCE_DIR}/TestResultAnalysis.hh
    PARENT_SCOPE
 )
 
@@ -24,6 +23,7 @@ set(my_headers
 set(my_sources
    ${CMAKE_CURRENT_SOURCE_DIR}/TestArgs.cc
    ${CMAKE_CURRENT_SOURCE_DIR}/TestChecksum.cc
+   ${CMAKE_CURRENT_SOURCE_DIR}/TestChecksumCompare.cc
    ${CMAKE_CURRENT_SOURCE_DIR}/TestChecksumCompletion.cc
    ${CMAKE_CURRENT_SOURCE_DIR}/TestChecksumCondition.cc
    ${CMAKE_CURRENT_SOURCE_DIR}/TestChecksumDebugEvent.cc
@@ -33,6 +33,5 @@ set(my_sources
    ${CMAKE_CURRENT_SOURCE_DIR}/TestOutcome.cc
    ${CMAKE_CURRENT_SOURCE_DIR}/TestPaths.cc
    ${CMAKE_CURRENT_SOURCE_DIR}/TestReport.cc
-   ${CMAKE_CURRENT_SOURCE_DIR}/TestResultAnalysis.cc
    PARENT_SCOPE
 )
diff --git a/Test/TestCase.hh b/Test/TestCase.hh
index 6a1dea61d1fc27f674f4f2c56516aff1f5cc514d..473caaad3bb657a4d92c092e8eff2ffe87c2393a 100755
--- a/Test/TestCase.hh
+++ b/Test/TestCase.hh
@@ -5,26 +5,21 @@
 
 #ifdef TEST_ON
 
+#include <Base/Test/TestChecksumCompare.hh>
+
 /*
 The BASE_TEST() macro wraps around an existing test declaration macro (e.g.
 TEST_CASE() for Catch2), augmenting it with a checksum comparison. For now, the
 existing test declaration macro must define a void function.
 
-In order to use BASE_TEST(), the following macros *must* be defined (before this
+In order to use BASE_TEST(), the following macro *must* be defined (before this
 file is included):
 
-- TEST_DECLARATION: a placeholder for the existing test declaration macro;
-
-- TEST_COMPARE_CHECKSUMS: a placeholder for a function that compares checksums
-  output by the currently-running test against the corresponding baseline.
+  TEST_DECLARATION: a placeholder for the existing test declaration macro;
 
 As an example, to use this with Catch2, one would write:
 
-    #define TEST_DECLARATION TEST_CASE
-
-And to compare the checksums using Test::compare_checksums(), one would write:
-
-    #define TEST_COMPARE_CHECKSUMS Test::compare_checksums()
+  #define TEST_DECLARATION TEST_CASE
 
 It is not required to use BASE_TEST(), and it is straightforward to define a
 custom macro with a similar function. The following macros are available for
@@ -51,30 +46,29 @@ use:
 
 // Both TEST_DECLARATION and TEST_COMPARE_CHECKSUMS must be defined in order to
 // use the BASE_TEST() macro.
-#if defined(TEST_DECLARATION) && defined(TEST_COMPARE_CHECKSUMS)
+#ifdef TEST_DECLARATION
 
 #define INTERNAL_BASE_TEST_VOID(TEST_FUNCTION, ...) \
   static void TEST_FUNCTION(); \
   TEST_DECLARATION(__VA_ARGS__) \
   { \
     TEST_FUNCTION(); \
-    TEST_COMPARE_CHECKSUMS; \
+    ::Test::Checksum::compare.check_equal(); \
   } \
   void TEST_FUNCTION()
 
 #define BASE_TEST(...) \
   INTERNAL_BASE_TEST_VOID(INTERNAL_UNIQUE_BASE_TEST_FUNCTION_NAME, __VA_ARGS__)
 
-#else // defined(TEST_DECLARATION) && defined(TEST_COMPARE_CHECKSUMS)
+#else // TEST_DECLARATION
 
 #define BASE_TEST(...) \
   static_assert(false, \
-      "Both TEST_DECLARATION and TEST_COMPARE_CHECKSUMS must be " \
-      "defined in order to use the BASE_TEST() macro. Please ensure " \
-      "they are defined before TestCase.hh is included."); \
+      "TEST_DECLARATION must be defined in order to use the BASE_TEST() " \
+      "macro. Please ensure it is defined before TestCase.hh is included."); \
   static void INTERNAL_UNIQUE_BASE_TEST_FUNCTION_NAME()
 
-#endif // defined(TEST_DECLARATION) && defined(TEST_COMPARE_CHECKSUMS)
+#endif // TEST_DECLARATION
 
 #endif // TEST_ON
 #endif // BASE_TESTCASE_HH_INCLUDED
diff --git a/Test/TestResultAnalysis.cc b/Test/TestChecksumCompare.cc
old mode 100644
new mode 100755
similarity index 51%
rename from Test/TestResultAnalysis.cc
rename to Test/TestChecksumCompare.cc
index bb3abebdf788e2fbeecf572629c61b05150b71c9..732cd8d57cb313c3844acacbcfe2258a6534d429
--- a/Test/TestResultAnalysis.cc
+++ b/Test/TestChecksumCompare.cc
@@ -3,22 +3,28 @@
 #ifdef TEST_ON
 
 #include <Base/Security/Mandatory.hh>
-#include <Base/Paths/Filesystem.hh>
 
-#include "TestResultAnalysis.hh"
-#include "LongestCommonSubsequenceT.hh"
-#include "TestChecksum.hh"
+#include "TestChecksumCompare.hh"
 #include "TestChecksumCompletion.hh"
-#include "TestChecksumFile.hh"
 
-#include <algorithm>
-#include <cctype>
+#include "LongestCommonSubsequenceT.hh"
+
+#include <Base/Paths/Filesystem.hh>
+#include <Base/Utils/NullOutputStream.hh>
+#include <Base/Paths/PathLink.hh>
+
+#include <exception>
 #include <fstream>
 #include <iostream>
 #include <sstream>
+#include <string>
 
 namespace Test
 {
+using PathLink = Base::PathLink;
+
+namespace Checksum
+{
 
 namespace
 {
@@ -33,8 +39,8 @@ void erase_code_links(std::string& _str)
   const char* const CODE_LINK_END = "]";
 
   for (auto bgn_pstn = _str.find(CODE_LINK_BEGIN);
-        bgn_pstn != std::string::npos && !_str.empty();
-        bgn_pstn = _str.find(CODE_LINK_BEGIN, bgn_pstn))
+       bgn_pstn != std::string::npos && !_str.empty();
+       bgn_pstn = _str.find(CODE_LINK_BEGIN, bgn_pstn))
   {
     const auto end_pstn = _str.find(CODE_LINK_END, bgn_pstn);
     if (end_pstn == std::string::npos)
@@ -52,7 +58,8 @@ inline void rtrim(std::string& s)
       s.end());
 }
 
-// Read and parse lines of a report to get the checksum Result, name and content.
+// Read and parse lines of a report to get the checksum Result, name and
+// content.
 class Report
 {
 public:
@@ -61,8 +68,7 @@ public:
   {
   public:
     Entry() {}
-    explicit Entry(const std::string& _line)
-      : line_(_line)
+    explicit Entry(const std::string& _line) : line_(_line)
     {
       // Ignore lines that represent (debug) callstack groups
       if (group())
@@ -106,8 +112,8 @@ public:
     const Checksum::Record& record() const { return rcrd_; }
 
   private:
-    std::string line_; // Current line
-    std::string name_; // Extracted checksum name
+    std::string line_;      // Current line
+    std::string name_;      // Extracted checksum name
     Checksum::Record rcrd_; // Extracted checksum record
 
   private:
@@ -156,7 +162,7 @@ public:
 
   size_t size() const { return entrs_.size(); }
 
-  const Entry& operator[] (const size_t _i) const { return entrs_[_i]; }
+  const Entry& operator[](const size_t _i) const { return entrs_[_i]; }
 
 private:
   Checksum::Level lvl_;
@@ -165,9 +171,49 @@ private:
 
 } // namespace
 
-DifferenceDistribution compare_reports(const fs::path& _rprt_path0,
-    const fs::path& _rprt_path1, Base::IOutputStream& _log,
-    const Checksum::Compare& _chks_cmpr, const bool _shrt_frmt)
+// "Hidden" import of this function from TestChecksum.cc
+Difference compare_from_registry(
+    const String& _name, const Record& _old_rcrd, const Record& _new_rcrd);
+
+class Compare::Impl
+{
+public:
+  //! Set the report pair to compare
+  void set_reports(const fs::path& _left_path, const fs::path& _right_path);
+
+  //! Set the short format, i.e., remove identical checksums, true by default.
+  void set_short_format(const bool _short_format = true);
+
+  /*!
+  Run the comparison and generate a difference report. Throws a std error if the
+  report paths are not set.
+  */
+  DifferenceDistribution run(Base::IOutputStream& _log_os) const;
+
+  /*!
+  Run the comparison and throw a std error if both reports exist but the
+  checksums are not equal.
+  */
+  void check_equal() const;
+
+private:
+  fs::path left_path_;
+  fs::path right_path_;
+  bool short_format_ = true;
+};
+
+void Compare::Impl::set_reports(const fs::path& _left_path, const fs::path& _right_path)
+{
+  left_path_ = _left_path;
+  right_path_ = _right_path;
+}
+
+void Compare::Impl::set_short_format(const bool _short_format)
+{
+  short_format_ = _short_format;
+}
+
+DifferenceDistribution Compare::Impl::run(Base::IOutputStream& _log_os) const
 {
   using Base::ENDL;
 
@@ -182,7 +228,15 @@ DifferenceDistribution compare_reports(const fs::path& _rprt_path0,
   const char* const DIFF_TAG    = "!   ";
   const char* const RESULT_TAG  = "  ";
 
-  const Report rprts[2] = {Report(_rprt_path0), Report(_rprt_path1)};
+  // Throw an error if the report paths have not been set
+  if (left_path_.empty() || right_path_.empty())
+  {
+    throw std::runtime_error(
+        "Unable to compare checksum reports: Report paths have not been set. "
+        "This should be done using Test::Checksum::Compare::set_reports().");
+  }
+
+  const Report rprts[2] = {Report(left_path_), Report(right_path_)};
 
   LongestCommonSubsequenceT<Report> rprt_lcs(rprts[0], rprts[1]);
   rprt_lcs.trace();
@@ -200,32 +254,32 @@ DifferenceDistribution compare_reports(const fs::path& _rprt_path0,
 
       if (old_entr.group()) // this match entry is a group?
       {
-        if (!_shrt_frmt)
-          _log << GROUP_TAG << old_entr.line() << ENDL; // just print it
+        if (!short_format_)
+          _log_os << GROUP_TAG << old_entr.line() << ENDL; // just print it
       }
       else // checksum case
       {
-        const auto diff =
-            _chks_cmpr(old_entr.name(), old_entr.record(), new_entr.record());
+        const auto diff = compare_from_registry(
+            old_entr.name(), old_entr.record(), new_entr.record());
         if (diff.equal()) // no difference?
         {
-          if (!_shrt_frmt)
-            _log << SAME_TAG << old_entr.line() << ENDL; // just print it
+          if (!short_format_)
+            _log_os << SAME_TAG << old_entr.line() << ENDL; // just print it
         }
         else
         { // print difference
-          _log << NAME_TAG << old_entr.name() << ": " << diff.type_text()
-               << ENDL;
-          _log << OLD_TAG << old_entr.record().rslt << RESULT_TAG
-               << old_entr.record().data << ENDL;
-          _log << NEW_TAG << new_entr.record().rslt << RESULT_TAG
-               << new_entr.record().data << ENDL;
+          _log_os << NAME_TAG << old_entr.name() << ": " << diff.type_text()
+                  << ENDL;
+          _log_os << OLD_TAG << old_entr.record().rslt << RESULT_TAG
+                  << old_entr.record().data << ENDL;
+          _log_os << NEW_TAG << new_entr.record().rslt << RESULT_TAG
+                  << new_entr.record().data << ENDL;
           const char rslt_mark =
               old_entr.record().rslt.type() == new_entr.record().rslt.type()
                   ? ' '
                   : '!';
-          _log << DIFF_TAG << rslt_mark << RESULT_TAG << diff.description()
-               << ENDL;
+          _log_os << DIFF_TAG << rslt_mark << RESULT_TAG << diff.description()
+                  << ENDL;
         }
         ++test_diff[diff];
       }
@@ -233,7 +287,7 @@ DifferenceDistribution compare_reports(const fs::path& _rprt_path0,
     else if (ij.i_valid() && rprts[0].level() <= rprts[1].level())
     { // old entry removed and the old checksum level is equal or stricter
       const auto& old_entr = rprts[0][ij.i];
-      _log << REMOVED_TAG << old_entr.line() << ENDL; // just print it
+      _log_os << REMOVED_TAG << old_entr.line() << ENDL; // just print it
       if (!old_entr.group()) // if it is a group change, just ignore it
       {
         if (Checksum::completion.end(old_entr.line()))
@@ -245,7 +299,7 @@ DifferenceDistribution compare_reports(const fs::path& _rprt_path0,
     else if (ij.j_valid() && rprts[0].level() >= rprts[1].level())
     { // new entry added and the new checksum level is stricter or equal
       const auto& new_entr = rprts[1][ij.j];
-      _log << ADDED_TAG << new_entr.line() << ENDL; // just print it
+      _log_os << ADDED_TAG << new_entr.line() << ENDL; // just print it
       if (!new_entr.group()) // if it is a group change, just ignore it
       {
         if (Checksum::completion.end(new_entr.line()))
@@ -259,6 +313,127 @@ DifferenceDistribution compare_reports(const fs::path& _rprt_path0,
   return test_diff;
 }
 
+void Compare::Impl::check_equal() const
+{
+  std::cout << "Info: Comparing checksums...";
+
+  // Throw an error if the report paths have not been set
+  if (left_path_.empty() || right_path_.empty())
+  {
+    throw std::runtime_error(
+        "Unable to compare checksum reports: Report paths have not been set. "
+        "This should be done using Test::Checksum::Compare::set_reports().");
+  }
+
+  // Skip the comparison if one of these files doesn't exist
+  if (!fs::exists(left_path_))
+  {
+    std::cout << "no baseline report found (expected at "
+              << left_path_.generic_string() << ")." << std::endl;
+    return;
+  }
+
+  if (!fs::exists(right_path_))
+  {
+    std::cout << "no checksum report found for the current test (expected at "
+              << right_path_.generic_string() << ")." << std::endl;
+    return;
+  }
+
+  // Compare the test report against the baseline report file
+  Base::OStringStream log_os;
+  auto diffs = run(log_os);
+
+  std::cout << "complete. ";
+
+  if (diffs.empty())
+  {
+    // No differences found
+    std::cout << "No differences found." << std::endl;
+  }
+  else
+  {
+    // Differences found: display short diff and throw error
+    std::cout << "Differences found!" << std::endl << std::endl;
+    std::cout << log_os.str << std::endl;
+
+    std::cout << "Compare " << PathLink(left_path_) << " with "
+              << PathLink(right_path_) << "." << std::endl;
+    throw std::runtime_error("Checksum comparison failed--differences found!");
+  }
+}
+
+Compare::Impl* Compare::impl_ = nullptr;
+bool Compare::owned_ = false;
+
+void Compare::make()
+{
+  if (impl_ != nullptr)
+    return;
+  impl_ = new Impl;
+  owned_ = true;
+}
+
+void Compare::set(Compare& _othr)
+{
+  if (_othr.impl_ != nullptr)
+  {
+    throw std::runtime_error(
+        "Unable to set implementation: incoming implementation is null.");
+  }
+
+  if (impl_ != nullptr)
+  {
+    throw std::runtime_error(
+        "Unable to set implementation: implementation has already been set.");
+  }
+
+  impl_ = _othr.impl_;
+}
+
+Compare::~Compare()
+{
+  if (owned_)
+    delete impl_;
+}
+
+void Compare::set_reports(
+    const fs::path& _left_path, const fs::path& _right_path)
+{
+  check_implementation();
+  impl_->set_reports(_left_path, _right_path);
+}
+
+void Compare::set_short_format(const bool _short_format)
+{
+  check_implementation();
+  impl_->set_short_format(_short_format);
+}
+
+DifferenceDistribution Compare::run(Base::IOutputStream& _log_os) const
+{
+  check_implementation();
+  return impl_->run(_log_os);
+}
+
+void Compare::check_equal() const
+{
+  check_implementation();
+  impl_->check_equal();
+}
+
+void Compare::check_implementation() const
+{
+  if (impl_ == nullptr)
+  {
+    throw std::runtime_error("Implementation is null: Implementation should be "
+                             "set using Test::Checksum::Compare::make() or "
+                             "Test::Checksum::Compare::set().");
+  }
+}
+
+Compare compare;
+} // namespace Checksum
 } // namespace Test
 
 #endif // TEST_ON
diff --git a/Test/TestChecksumCompare.hh b/Test/TestChecksumCompare.hh
index bc0c2f0e0e65598a1257fb13cc4cc8fa0c2da340..9c627df7c3ecaab66530037efa6a4203b9a6251d 100644
--- a/Test/TestChecksumCompare.hh
+++ b/Test/TestChecksumCompare.hh
@@ -6,31 +6,84 @@
 #ifdef TEST_ON
 
 #include <Base/Test/TestChecksum.hh>
+#include <Base/Paths/Filesystem.hh>
+#include <Base/Utils/NullOutputStream.hh>
 
-#include <functional>
+#include <map>
 
 namespace Test
 {
+namespace fs = Base::filesystem;
+
 namespace Checksum
 {
+
+typedef std::map<Difference, size_t> DifferenceDistribution;
+
 /*!
-Function type to compare two records of the same checksum identified by name.
-The compare function should return \ref Difference value to describe the
-difference of the old vs the new value.
-*/
-typedef std::function<Difference(const String& /*!<[in] checksum name */,
-    const Record& /*!<[in] checksum old value */,
-    const Record& /*!<[in] checksum new value */)>
-    Compare;
-
-/*! 
-Compare function that uses the compare method of registered checksums.
-\note Make sure to wrap this appropriately for shared object export when using
-in shared binary components in order to use the registry in the shared binary!
+Compare two test checksum reports.
+
+This class should be instantiated uniquely in a specific way to ensure it is
+shared across different instances of Base in separate binary modules in the same
+process.
+
+As the checksums reside in the binary that implements the tested algorithms, the
+class instance should be created there with \ref make(). The instance is owned
+by that binary and must be deleted by it, as it's stored on its heap.
+
+Once created, the instance should be \ref set() in the test binary (usually an
+executable). \ref set() will not take ownership of the pointer. With this
+approach all class methods will return the same instance throughout the process.
+
+\note These considerations are irrelevant if the tested and test executable are
+linked statically, i.e., they share the same binary.
 */
-Difference compare_from_registry(
-    const String& _name, const Record& _old_rcrd, const Record& _new_rcrd);
+class Compare
+{
+public:
+  //! Make and store the unique instance
+  static void make();
+
+  //! Set an instance made in another binary
+  static void set(Compare&);
 
+public:
+  //! Destroy the owned instance
+  ~Compare();
+
+  //! Set the report pair to compare
+  void set_reports(const fs::path& _left_path, const fs::path& _right_path);
+
+  //! Set the short format, i.e., remove identical checksums, true by default.
+  void set_short_format(const bool _short_format = true);
+
+  /*!
+  Run the comparison and generate a difference report. Throws a std error if the
+  report paths are not set.
+  */
+  DifferenceDistribution run(
+      Base::IOutputStream& _log_os = Base::null_os) const;
+
+  /*!
+  Run the comparison and throw a std error if both reports exist but the
+  checksums are not equal.
+  */
+  void check_equal() const;
+
+private:
+  //! Throw std error if impl_ is nullptr
+  void check_implementation() const;
+
+private:
+  class Impl;
+  static Impl* impl_; // shared implementation pointer
+  static bool owned_; // own implementation or not
+};
+
+/*!
+Shared instance per binary, make sure to call make() and set() as appropriate.
+*/
+extern Compare compare;
 } // namespace Checksum
 } // namespace Test
 
diff --git a/Test/TestReport.cc b/Test/TestReport.cc
index 74738d02acfcdd5cf049e28e72fc3ae14449cf7d..df9cb04454a78f180bb954f9ab904af5afd0084b 100644
--- a/Test/TestReport.cc
+++ b/Test/TestReport.cc
@@ -6,10 +6,10 @@
 #include <Base/Paths/Filesystem.hh>
 #include <Base/Paths/PathLink.hh>
 #include "TestChecksum.hh"
+#include "TestChecksumCompare.hh"
 #include "TestChecksumCompletion.hh"
 #include "TestReport.hh"
 #include "TestResult.hh"
-#include "TestResultAnalysis.hh"
 
 #include <cstring>
 #include <fstream>
@@ -236,7 +236,8 @@ typedef std::stringstream TestStream;
 struct TestDiffSummary
 {
   TestDiffSummary(const fs::path& _test_path,
-      const Test::DifferenceDistribution& _diff, const TestStream& _descr)
+      const Test::Checksum::DifferenceDistribution& _diff,
+      const TestStream& _descr)
       : path_(_test_path), diffs_(_diff), descr_(std::move(_descr.str()))
   {
   }
@@ -274,7 +275,7 @@ struct TestDiffSummary
   bool equivalent() const { return diffs_.empty(); }
 
   fs::path path_;
-  Test::DifferenceDistribution diffs_;
+  Test::Checksum::DifferenceDistribution diffs_;
   std::string descr_; // Test report of test differences description.
 };
 
@@ -457,7 +458,7 @@ void replace(const fs::path& _root_source, const fs::path& _root_target,
 // right.
 ExitStatus make_comparison(const char* const _dir_left,
     const char* const _dir_right, const CompareOutputType _cot,
-    const Checksum::Compare& _chks_cmpr, const bool _show_progress)
+    const bool _show_progress)
 {
   // Find the executed tests in the two test suites.
   TestTree test_trees[2]{TestTree(_dir_left), TestTree(_dir_right)};
@@ -488,15 +489,15 @@ ExitStatus make_comparison(const char* const _dir_left,
     // Create stream to store the differences for the current test
     Base::OutputStreamAdaptT<TestStream> test_diff_log;
 
-    // Get the paths to the reports for both suites
-    const auto report_path_left =
-        test_trees[0].root_dir() / test_path / Test::REPORT_FILENAME;
-    const auto report_path_right =
-        test_trees[1].root_dir() / test_path / Test::REPORT_FILENAME;
+    // Set comparison parameters
+    Test::Checksum::compare.set_reports(
+        test_trees[0].root_dir() / test_path / Test::REPORT_FILENAME,
+        test_trees[1].root_dir() / test_path / Test::REPORT_FILENAME);
+
+    Test::Checksum::compare.set_short_format(_cot == COT_SHORT_DIFF);
 
     // Compare the checksums for the test between the two suites
-    const auto diff_stats = compare_reports(report_path_left, report_path_right,
-        test_diff_log, _chks_cmpr, _cot == COT_SHORT_DIFF);
+    const auto diff_stats = Test::Checksum::compare.run(test_diff_log);
 
     if (!diff_stats.empty())
     { // Differences were found
@@ -648,8 +649,7 @@ ExitStatus make_comparison(const char* const _dir_left,
     continue; \
   }
 
-int report(const int _argc, const char* const _argv[],
-    const Checksum::Compare& _chks_cmpr)
+int report(const int _argc, const char* const _argv[])
 {
   // Set usage text
   const auto usage =
@@ -712,7 +712,7 @@ int report(const int _argc, const char* const _argv[],
   // Perform the appropriate comparison and catch any errors
   try
   {
-    rslt = make_comparison(dir_left, dir_right, cot, _chks_cmpr, show_progress);
+    rslt = make_comparison(dir_left, dir_right, cot, show_progress);
   }
   catch (const std::exception& excpt)
   {
diff --git a/Test/TestReport.hh b/Test/TestReport.hh
index 7b660b0541b00647e5ef82e59b5b5a652f2b4a5d..39e411f209582bebcf0e5172b987529af24443e6 100644
--- a/Test/TestReport.hh
+++ b/Test/TestReport.hh
@@ -54,7 +54,7 @@ of progress-related output from the function.
 */
 ExitStatus make_comparison(const char* const _dir_left,
     const char* const _dir_right, const CompareOutputType _cot,
-    const Checksum::Compare& _chks_cmpr, const bool _show_progress = true);
+    const bool _show_progress = true);
 
 /*!
 This is a wrapper to make_comparison() that parses command-line arguments. The
@@ -66,8 +66,7 @@ following command-line format is expected:
 * --no-progress will set _show_progress = false.
 
 */
-int report(const int _argc, const char* const _argv[],
-    const Checksum::Compare& _chks_cmpr);
+int report(const int _argc, const char* const _argv[]);
 
 } // namespace Test
 
diff --git a/Test/TestResultAnalysis.hh b/Test/TestResultAnalysis.hh
deleted file mode 100644
index 65ceec1935ad48f58e1045cc3c8f82c67cab8dc0..0000000000000000000000000000000000000000
--- a/Test/TestResultAnalysis.hh
+++ /dev/null
@@ -1,42 +0,0 @@
-// (C) Copyright 2021 by Autodesk, Inc.
-
-#ifndef BASE_TESTRESULTANALYSIS_HH_INCLUDE
-#define BASE_TESTRESULTANALYSIS_HH_INCLUDE
-
-#ifdef TEST_ON
-
-#include <Base/Test/TestChecksumCompare.hh>
-#include <Base/Paths/Filesystem.hh>
-
-#include <map>
-#include <string>
-
-namespace Test
-{
-namespace fs = Base::filesystem;
-
-typedef Checksum::Difference Difference;
-typedef std::map<Difference, size_t> DifferenceDistribution;
-
-/*!
-Compares the checksums listed in two test reports. Returns a map with the
-difference statistics (counts for each type of difference). Equal checksums are
-ignored if _short_frmt = true.
-
-Arguments:
-
-* [in] _rprt_path0: Path to the left-suite report file.
-* [in] _rprt_path1: Path to the right-suite report file.
-* [out] _log: Description of the differences.
-* [in] _chks_cmpr: Checksum compare function.
-* [in] _short_frmt: Remove identical checksums (short format) [default = false].
-
-*/
-DifferenceDistribution compare_reports(const fs::path& _rprt_path0,
-    const fs::path& _rprt_path1, Base::IOutputStream& _log,
-    const Checksum::Compare& _chks_cmpr, const bool _short_frmt = false);
-
-} // namespace Test
-
-#endif // TEST_ON
-#endif // BASE_TESTRESULTANALYSIS_HH_INCLUDE
diff --git a/Utils/CMakeLists.txt b/Utils/CMakeLists.txt
index cf4fb2d068e741d23c28324a1dc80b8908e5189c..331c336486ce22dfa254d159a6a8ecc300ac37be 100644
--- a/Utils/CMakeLists.txt
+++ b/Utils/CMakeLists.txt
@@ -4,6 +4,7 @@ set(my_headers
    ${CMAKE_CURRENT_SOURCE_DIR}/Environment.hh
    ${CMAKE_CURRENT_SOURCE_DIR}/FileOutput.hh
    ${CMAKE_CURRENT_SOURCE_DIR}/IOutputStream.hh
+   ${CMAKE_CURRENT_SOURCE_DIR}/NullOutputStream.hh
    ${CMAKE_CURRENT_SOURCE_DIR}/OStringStream.hh
    ${CMAKE_CURRENT_SOURCE_DIR}/RedirectStream.hh
    ${CMAKE_CURRENT_SOURCE_DIR}/StopWatch.hh
@@ -17,6 +18,7 @@ set(my_sources
    ${CMAKE_CURRENT_SOURCE_DIR}/Environment.cc
    ${CMAKE_CURRENT_SOURCE_DIR}/FileOutput.cc
    ${CMAKE_CURRENT_SOURCE_DIR}/IOutputStream.cc
+   ${CMAKE_CURRENT_SOURCE_DIR}/NullOutputStream.cc
    ${CMAKE_CURRENT_SOURCE_DIR}/OStringStream.cc
    ${CMAKE_CURRENT_SOURCE_DIR}/RedirectStream.cc
    ${CMAKE_CURRENT_SOURCE_DIR}/StopWatch.cc
diff --git a/Utils/NullOutputStream.cc b/Utils/NullOutputStream.cc
new file mode 100755
index 0000000000000000000000000000000000000000..2f522ef995e052a6a66390e15f919f93ebfac566
--- /dev/null
+++ b/Utils/NullOutputStream.cc
@@ -0,0 +1,11 @@
+// (C) Copyright 2021 by Autodesk, Inc.
+
+#include "Base/Security/Mandatory.hh"
+#include "NullOutputStream.hh"
+
+namespace Base
+{
+
+NullOutputStream null_os;
+
+} // namespace Base
diff --git a/Utils/NullOutputStream.hh b/Utils/NullOutputStream.hh
new file mode 100755
index 0000000000000000000000000000000000000000..3f9dce6128b792896d9424f971dae8f6233693fe
--- /dev/null
+++ b/Utils/NullOutputStream.hh
@@ -0,0 +1,27 @@
+// (C) Copyright 2021 by Autodesk, Inc.
+
+#ifndef BASE_NULLOUTPUTSTREAM_HH_INCLUDED
+#define BASE_NULLOUTPUTSTREAM_HH_INCLUDED
+
+#include <Base/Utils/IOutputStream.hh>
+
+namespace Base
+{
+
+// An output stream that ignores data streamed to it
+class BASEDLLEXPORT NullOutputStream : public IOutputStream
+{
+public:
+  IOutputStream& print(const char) override { return *this; }
+  IOutputStream& print(const int) override { return *this; }
+  IOutputStream& print(const size_t) override { return *this; }
+  IOutputStream& print(const float) override { return *this; }
+  IOutputStream& print(const double) override { return *this; }
+  IOutputStream& print(const char* const) override { return *this; }
+};
+
+extern NullOutputStream null_os;
+
+} // namespace Base
+
+#endif // BASE_NULLOUTPUTSTREAM_HH_INCLUDED