]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
Fix Windows CI build jfw-libfdb-sequence-concepts 70596/head
authorJesse F. Williamson <jfw@ibm.com>
Fri, 31 Jul 2026 14:43:32 +0000 (07:43 -0700)
committerJesse F. Williamson <jfw@ibm.com>
Sun, 2 Aug 2026 04:43:12 +0000 (21:43 -0700)
After Boost is configured, Windows builds now add ${Boost_INCLUDE_DIRS} to the real Catch2
source targets.

This is basically a temporary hack until either the CI system runs
Catch2 different or I can hack something into the build system that
changes things on Windows.

Assisted-by: Codex:GPT-5
Signed-off-by: Jesse F. Williamson <jfw@ibm.com>
CMakeLists.txt
cmake/modules/AddCephTest.cmake
src/test/catch2_compat.h [new file with mode: 0644]
src/test/catch2_compat_main.cc [new file with mode: 0644]
src/test/rgw/test_fdb.cc
src/test/rgw/test_fdb_ceph.cc
src/test/test_concepts.cc

index 2ade2bf75d850c8b87e11e1f05b937ff9c173cd2..8cddac58c519ae9c145bf4f2ba55a791e8fa60ab 100644 (file)
@@ -861,6 +861,15 @@ else()
   endif()
 endif()
 include_directories(BEFORE SYSTEM ${Boost_INCLUDE_DIRS})
+if(WIN32 AND WITH_CATCH2)
+  foreach(catch2_target Catch2 Catch2WithMain)
+    if(TARGET ${catch2_target})
+      target_include_directories(${catch2_target} SYSTEM PRIVATE
+        ${PROJECT_BINARY_DIR}/include
+        ${Boost_INCLUDE_DIRS})
+    endif()
+  endforeach()
+endif()
 add_library(Boost::asio INTERFACE IMPORTED)
 if(WITH_LIBURING AND CMAKE_SYSTEM_VERSION VERSION_GREATER_EQUAL "5.10")
   # enable uring in boost::asio
index a96ea2231af4d9f18881fb87f56d05cf7744a848..98ae096306b91a48fda3057e7dec94c7e342e9c5 100644 (file)
@@ -188,7 +188,10 @@ endif()
 if(${catch2_opt_NO_CATCH2_MAIN})
   LIST(APPEND tl_libs Catch2::Catch2)
 else()
-  LIST(APPEND tl_libs Catch2::Catch2WithMain)
+  # Accept the gtest XML flag used by the Windows test runner.
+  target_sources(unittest_${test_name}
+    PRIVATE ${CMAKE_SOURCE_DIR}/src/test/catch2_compat_main.cc)
+  LIST(APPEND tl_libs Catch2::Catch2)
 endif()
 
 target_link_libraries(unittest_${test_name} 
diff --git a/src/test/catch2_compat.h b/src/test/catch2_compat.h
new file mode 100644 (file)
index 0000000..db3b9af
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2026 International Business Machines Corp. (IBM)
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation.  See file COPYING.
+ *
+ */
+
+#ifndef CEPH_TEST_CATCH2_COMPAT_H
+#define CEPH_TEST_CATCH2_COMPAT_H
+
+#include <catch2/catch_session.hpp>
+
+#include <cstdio>
+#include <fstream>
+#include <istream>
+#include <iterator>
+#include <optional>
+#include <ostream>
+#include <string>
+#include <string_view>
+#include <vector>
+
+namespace ceph::test {
+
+namespace detail {
+
+constexpr bool contains(const std::string_view line,
+                        const std::string_view text) noexcept
+{
+  return std::string_view::npos != line.find(text);
+}
+
+constexpr std::string_view skipped_junit_child_end(const std::string_view line) noexcept
+{
+  if (contains(line, "<properties")) {
+    return "</properties>";
+  }
+
+  if (contains(line, "<system-out")) {
+    return "</system-out>";
+  }
+
+  if (contains(line, "<system-err")) {
+    return "</system-err>";
+  }
+
+  return {};
+}
+
+constexpr bool skipped_junit_child_line(const std::string_view line) noexcept
+{
+  return contains(line, "<property ") ||
+         contains(line, "</properties>") ||
+         contains(line, "</system-out>") ||
+         contains(line, "</system-err>");
+}
+
+inline void sanitize_catch2_junit_for_gtest2subunit(std::istream& in,
+                                                   std::ostream& out)
+{
+  std::string_view skipped_child_end;
+  std::string line;
+
+  while (std::getline(in, line)) {
+    const std::string_view view { line };
+
+    if (!skipped_child_end.empty()) {
+      if (contains(view, skipped_child_end)) {
+        skipped_child_end = {};
+      }
+
+      continue;
+    }
+
+    if (skipped_junit_child_line(view)) {
+      continue;
+    }
+
+    const auto child_end = skipped_junit_child_end(view);
+
+    if (!child_end.empty()) {
+      if (!contains(view, "/>") &&
+          !contains(view, child_end)) {
+        skipped_child_end = child_end;
+      }
+
+      continue;
+    }
+
+    out << line << '\n';
+  }
+}
+
+inline bool sanitize_catch2_junit_for_gtest2subunit(const std::string& input_path,
+                                                   const std::string& output_path)
+{
+  std::ifstream in { input_path };
+  std::ofstream out { output_path, std::ios::trunc };
+
+  if (!in || !out) {
+    return false;
+  }
+
+  sanitize_catch2_junit_for_gtest2subunit(in, out);
+
+  return out.good();
+}
+
+} // namespace detail
+
+class catch2_args final
+{
+ public:
+  catch2_args(const int argc, char *argv[])
+  {
+    args.reserve(static_cast<std::size_t>(argc) + 3);
+    args.emplace_back(argv[0]);
+
+    translate_args(argc, argv);
+
+    argv_out.reserve(std::size(args));
+
+    for (auto& arg : args) {
+      argv_out.push_back(arg.data());
+    }
+  }
+
+  int argc() const
+  {
+    return static_cast<int>(std::size(argv_out));
+  }
+
+  char **argv()
+  {
+    return argv_out.data();
+  }
+
+  bool write_gtest2subunit_xml() const
+  {
+    if (!gtest_xml_output_path) {
+      return true;
+    }
+
+    if (!detail::sanitize_catch2_junit_for_gtest2subunit(
+          catch2_xml_output_path, *gtest_xml_output_path)) {
+      std::fprintf(stderr,
+                   "failed to write gtest-compatible Catch2 XML: %s\n",
+                   gtest_xml_output_path->c_str());
+      return false;
+    }
+
+    std::remove(catch2_xml_output_path.c_str());
+
+    return true;
+  }
+
+ private:
+  static constexpr std::string_view gtest_xml_output = "--gtest_output=xml:";
+
+  void translate_args(const int argc, char *argv[])
+  {
+    for (int i = 1; i < argc; ++i) {
+      const std::string_view arg{ argv[i] };
+
+      if (arg.starts_with(gtest_xml_output)) {
+        gtest_xml_output_path = arg.substr(std::size(gtest_xml_output));
+        catch2_xml_output_path = *gtest_xml_output_path + ".catch2.xml";
+
+        args.emplace_back("-r");
+        args.emplace_back("JUnit");
+        args.emplace_back("-o");
+        args.emplace_back(catch2_xml_output_path);
+        continue;
+      }
+
+      args.emplace_back(arg);
+    }
+  }
+
+  std::vector<std::string> args;
+  std::vector<char *> argv_out;
+  std::optional<std::string> gtest_xml_output_path;
+  std::string catch2_xml_output_path;
+};
+
+inline int run_catch2(const int argc, char *argv[])
+{
+  catch2_args args(argc, argv);
+  const auto result = Catch::Session().run(args.argc(), args.argv());
+
+  if (!args.write_gtest2subunit_xml()) {
+    return 1;
+  }
+
+  return result;
+}
+
+} // namespace ceph::test
+
+#endif
diff --git a/src/test/catch2_compat_main.cc b/src/test/catch2_compat_main.cc
new file mode 100644 (file)
index 0000000..8afdf6c
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2026 International Business Machines Corp. (IBM)
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation.  See file COPYING.
+ *
+ */
+
+#include "test/catch2_compat.h"
+
+#include <cstdio>
+#include <exception>
+
+int main(int argc, char *argv[])
+try
+{
+  return ceph::test::run_catch2(argc, argv);
+} catch (const std::exception& e) {
+  std::fprintf(stderr, "Catch2 test runner failed: %s\n", e.what());
+  return 1;
+}
index 6c71552a48af79bd86d6466152b5c33d4a706962..a8a7b3882a3a8f25ccaf5c890c51f882bf23e9b1 100644 (file)
@@ -1123,12 +1123,11 @@ TEST_CASE("block_generator should correctly handle value types") {
 }
 
 
-// Adapted from Catch2 documentation:
-#include <catch2/catch_session.hpp>
+#include "test/catch2_compat.h"
 
 int main(int argc, char **argv) 
 {
-  int result = Catch::Session().run(argc, argv);
+  const auto result = ceph::test::run_catch2(argc, argv);
 
   // Make sure that FoundationDB is shut down once and only once:
   ceph::libfdb::shutdown_libfdb(); 
index 91f97e29988f7587ecb01b9b008574157270c628..3890dc83e2310980451f059a0dfd97317def816c 100644 (file)
@@ -755,11 +755,11 @@ BENCHMARK_ADVANCED("write simple records-- parallel, one transaction per block")
 
 }
 
-#include <catch2/catch_session.hpp>
+#include "test/catch2_compat.h"
 
 int main(int argc, char **argv) 
 {
-  int result = Catch::Session().run(argc, argv);
+  const auto result = ceph::test::run_catch2(argc, argv);
 
   // Make sure that FoundationDB is shut down once and only once:
   ceph::libfdb::shutdown_libfdb(); 
index 20ae19fa41734feb8aeee28bbc861b680dd70bc8..c601fa2406094c348dd30be803c0621697e97829 100644 (file)
@@ -14,6 +14,7 @@
 #include <catch2/catch_template_test_macros.hpp>
 
 #include "common/container_concepts.h"
+#include "test/catch2_compat.h"
 
 #include <algorithm>
 #include <array>
@@ -24,6 +25,7 @@
 #include <map>
 #include <ranges>
 #include <set>
+#include <sstream>
 #include <string>
 #include <string_view>
 #include <unordered_map>
@@ -585,3 +587,33 @@ TEST_CASE("has_* member capability predicates match member availability",
 // Put the X-macro machinery back into the original packaging:
 #undef CEPH_CHECK_HAS_MEMBER_CAPABILITY
 #undef CEPH_HAS_MEMBER_CAPABILITY_CASES
+
+TEST_CASE("Catch2 gtest compatibility XML keeps only testcase children",
+          "[concepts]")
+{
+  std::istringstream in {
+    "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+    "<testsuites>\n"
+    "  <testsuite name=\"unittest_concepts.exe\" tests=\"1\">\n"
+    "    <properties>\n"
+    "      <property name=\"random-seed\" value=\"1\"/>\n"
+    "    </properties>\n"
+    "    <testcase classname=\"unittest_concepts.exe.global\" "
+    "name=\"concepts pass\" time=\"0.000\" status=\"run\"/>\n"
+    "    <system-out/>\n"
+    "    <system-err/>\n"
+    "  </testsuite>\n"
+    "</testsuites>\n"
+  };
+  std::ostringstream out;
+
+  ceph::test::detail::sanitize_catch2_junit_for_gtest2subunit(in, out);
+
+  const auto xml = out.str();
+
+  CHECK(std::string::npos == xml.find("properties"));
+  CHECK(std::string::npos == xml.find("<system-out"));
+  CHECK(std::string::npos == xml.find("<system-err"));
+  CHECK(std::string::npos != xml.find("<testcase"));
+  CHECK(std::string::npos != xml.find("concepts pass"));
+}