From: Jesse F. Williamson Date: Fri, 31 Jul 2026 14:43:32 +0000 (-0700) Subject: Fix Windows CI build X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=63e5ef2b6ea93c091f48c6ba3a5428e32387855a;p=ceph.git Fix Windows CI build 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 --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 2ade2bf75d85..8cddac58c519 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/cmake/modules/AddCephTest.cmake b/cmake/modules/AddCephTest.cmake index a96ea2231af4..98ae096306b9 100644 --- a/cmake/modules/AddCephTest.cmake +++ b/cmake/modules/AddCephTest.cmake @@ -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 index 000000000000..db3b9afa1c93 --- /dev/null +++ b/src/test/catch2_compat.h @@ -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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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, ""; + } + + if (contains(line, ""; + } + + if (contains(line, ""; + } + + return {}; +} + +constexpr bool skipped_junit_child_line(const std::string_view line) noexcept +{ + return contains(line, "") || + contains(line, "") || + contains(line, ""); +} + +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(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(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 args; + std::vector argv_out; + std::optional 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 index 000000000000..8afdf6c47056 --- /dev/null +++ b/src/test/catch2_compat_main.cc @@ -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 +#include + +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; +} diff --git a/src/test/rgw/test_fdb.cc b/src/test/rgw/test_fdb.cc index 6c71552a48af..a8a7b3882a3a 100644 --- a/src/test/rgw/test_fdb.cc +++ b/src/test/rgw/test_fdb.cc @@ -1123,12 +1123,11 @@ TEST_CASE("block_generator should correctly handle value types") { } -// Adapted from Catch2 documentation: -#include +#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(); diff --git a/src/test/rgw/test_fdb_ceph.cc b/src/test/rgw/test_fdb_ceph.cc index 91f97e29988f..3890dc83e231 100644 --- a/src/test/rgw/test_fdb_ceph.cc +++ b/src/test/rgw/test_fdb_ceph.cc @@ -755,11 +755,11 @@ BENCHMARK_ADVANCED("write simple records-- parallel, one transaction per block") } -#include +#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(); diff --git a/src/test/test_concepts.cc b/src/test/test_concepts.cc index 20ae19fa4173..c601fa240609 100644 --- a/src/test/test_concepts.cc +++ b/src/test/test_concepts.cc @@ -14,6 +14,7 @@ #include #include "common/container_concepts.h" +#include "test/catch2_compat.h" #include #include @@ -24,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -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 { + "\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\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("