From 12e703904711f06069ef985237e0376ef098ea37 Mon Sep 17 00:00:00 2001 From: Steffen Albrecht Date: Tue, 9 Jun 2026 15:20:23 +0200 Subject: [PATCH 1/5] [HS3] [RF] Adding test to pull and run external HS3TestSuite --- .../root-ci-config/buildconfig/global.txt | 1 + cmake/modules/RootBuildOptions.cmake | 3 +- roofit/hs3/test/CMakeLists.txt | 13 +++++ roofit/hs3/test/test_hs3_suite.py | 50 +++++++++++++++++++ 4 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 roofit/hs3/test/test_hs3_suite.py diff --git a/.github/workflows/root-ci-config/buildconfig/global.txt b/.github/workflows/root-ci-config/buildconfig/global.txt index 4e598d6afa5ed..464bc6c2261a5 100644 --- a/.github/workflows/root-ci-config/buildconfig/global.txt +++ b/.github/workflows/root-ci-config/buildconfig/global.txt @@ -68,6 +68,7 @@ roofit_multiprocess=OFF root7=ON rootbench=OFF roottest=ON +hs3testsuite=ON runtime_cxxmodules=ON shadowpw=OFF shared=ON diff --git a/cmake/modules/RootBuildOptions.cmake b/cmake/modules/RootBuildOptions.cmake index 0966ae13c3353..b0e6d0152e444 100644 --- a/cmake/modules/RootBuildOptions.cmake +++ b/cmake/modules/RootBuildOptions.cmake @@ -189,6 +189,7 @@ option(gminimal "Enable only required options by default, but include X11/Cocoa" option(minimal "Enable only required options by default" OFF) option(rootbench "Build rootbench if rootbench exists in root or if it is a sibling directory (implies testing=ON)" OFF) option(roottest "Build roottest (implies testing=ON)" OFF) +option(hs3testsuite "Setup and use the HS3 conformance test suite (implies testing=ON)" OFF) option(testing "Enable testing with CTest" OFF) option(asan "Build ROOT with address sanitizer instrumentation" OFF) @@ -329,7 +330,7 @@ endif() ROOT_APPLY_OPTIONS() #---roottest option implies testing -if(roottest OR rootbench) +if(roottest OR rootbench OR hs3testsuite) set(testing ON CACHE BOOL "" FORCE) endif() diff --git a/roofit/hs3/test/CMakeLists.txt b/roofit/hs3/test/CMakeLists.txt index d152337c8a7a8..1f41a041690aa 100644 --- a/roofit/hs3/test/CMakeLists.txt +++ b/roofit/hs3/test/CMakeLists.txt @@ -1,2 +1,15 @@ ROOT_ADD_GTEST(testRooFitHS3 testRooFitHS3.cxx LIBRARIES RooFitCore RooFit RooFitHS3) ROOT_ADD_GTEST(testHS3SimultaneousFit testHS3SimultaneousFit.cxx LIBRARIES RooFitCore RooFit RooFitHS3 RooStats) + +if(pyroot AND hs3testsuite) + set(hs3testsuite_dir ${CMAKE_CURRENT_SOURCE_DIR}/HS3TestSuite) + if(NOT EXISTS ${hs3testsuite_dir}) + find_package(Git QUIET REQUIRED) + execute_process(COMMAND ${GIT_EXECUTABLE} clone https://github.com/Phmonski/HS3TestSuite + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + endif() + + if(EXISTS ${hs3testsuite_dir}) + ROOT_ADD_PYUNITTEST(hs3-suite test_hs3_suite.py PYTHON_DEPS jsonschema ENVIRONMENT HS3TESTSUITE_ROOT=${hs3testsuite_dir}) + endif() +endif() \ No newline at end of file diff --git a/roofit/hs3/test/test_hs3_suite.py b/roofit/hs3/test/test_hs3_suite.py new file mode 100644 index 0000000000000..4c0f653c95668 --- /dev/null +++ b/roofit/hs3/test/test_hs3_suite.py @@ -0,0 +1,50 @@ +import os +from pathlib import Path +import sys +import unittest + + +hs3_root_dir = os.environ.get("HS3TESTSUITE_ROOT") +if hs3_root_dir: + sys.path.insert(0, hs3_root_dir) + +try: + from hs3suite.runner import run_suite + +except ImportError as e: + TestHS3Suite = type( + "TestHS3Suite", + (unittest.TestCase,), + dict(test_dependencies=lambda self, e=e: self.fail(f"Missing dependency: {e}")), + ) +else: + hs3_root_path = Path(hs3_root_dir) + try: + results = run_suite(hs3_root_path, "roofit") + except Exception as e: + + def test(self, e=e): + self.fail(f"HS3TestSuite failed to run: {e}") + + test.__name__ = "test_hs3testsuite_execution" + TestHS3Suite = type("TestHS3Suite", (unittest.TestCase,), {test.__name__: test}) + else: + namespace = dict(__module__=__name__) + for r in results: + + def _make(result): + def test(self): + if result.status == "failed": + self.fail(result.message) + return + + test.__name__ = f"test_{result.test_id}__{result.check_id}" + test.__doc__ = f"{result.test_id}::{result.check_id}" + return test + + func = _make(r) + namespace[func.__name__] = func + TestHS3Suite = type("TestHS3Suite", (unittest.TestCase,), namespace) + +if __name__ == "__main__": + unittest.main() From b02d03b16f1d99bf07e461adb428f4fcc6c18156 Mon Sep 17 00:00:00 2001 From: Steffen Albrecht Date: Thu, 11 Jun 2026 06:19:35 +0200 Subject: [PATCH 2/5] fix linting (import sorting) --- roofit/hs3/test/test_hs3_suite.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/roofit/hs3/test/test_hs3_suite.py b/roofit/hs3/test/test_hs3_suite.py index 4c0f653c95668..983de1be38a8a 100644 --- a/roofit/hs3/test/test_hs3_suite.py +++ b/roofit/hs3/test/test_hs3_suite.py @@ -1,8 +1,7 @@ import os -from pathlib import Path import sys import unittest - +from pathlib import Path hs3_root_dir = os.environ.get("HS3TESTSUITE_ROOT") if hs3_root_dir: From 5b2bdb5a4307c4d7f24679c8f0fd4c1a834f1d32 Mon Sep 17 00:00:00 2001 From: Steffen Albrecht Date: Tue, 16 Jun 2026 14:37:50 +0200 Subject: [PATCH 3/5] [cmake] rename hs3testsuite option to test_roofit_hs3testsuite and document it documents dependecies on network connection and other build options. Now throwing error if `pyroot` or `testing` option is set to OFF instead of implying them with hs3 option. --- .github/workflows/root-ci-config/buildconfig/global.txt | 2 +- cmake/modules/RootBuildOptions.cmake | 8 ++++++-- roofit/hs3/test/CMakeLists.txt | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/workflows/root-ci-config/buildconfig/global.txt b/.github/workflows/root-ci-config/buildconfig/global.txt index 464bc6c2261a5..eafb656ada6f7 100644 --- a/.github/workflows/root-ci-config/buildconfig/global.txt +++ b/.github/workflows/root-ci-config/buildconfig/global.txt @@ -68,7 +68,7 @@ roofit_multiprocess=OFF root7=ON rootbench=OFF roottest=ON -hs3testsuite=ON +test_roofit_hs3testsuite=ON runtime_cxxmodules=ON shadowpw=OFF shared=ON diff --git a/cmake/modules/RootBuildOptions.cmake b/cmake/modules/RootBuildOptions.cmake index b0e6d0152e444..baa50d4ae9d25 100644 --- a/cmake/modules/RootBuildOptions.cmake +++ b/cmake/modules/RootBuildOptions.cmake @@ -189,7 +189,7 @@ option(gminimal "Enable only required options by default, but include X11/Cocoa" option(minimal "Enable only required options by default" OFF) option(rootbench "Build rootbench if rootbench exists in root or if it is a sibling directory (implies testing=ON)" OFF) option(roottest "Build roottest (implies testing=ON)" OFF) -option(hs3testsuite "Setup and use the HS3 conformance test suite (implies testing=ON)" OFF) +option(test_roofit_hs3testsuite "Setup and use the HS3 conformance test suite (requires network)" OFF) option(testing "Enable testing with CTest" OFF) option(asan "Build ROOT with address sanitizer instrumentation" OFF) @@ -330,7 +330,7 @@ endif() ROOT_APPLY_OPTIONS() #---roottest option implies testing -if(roottest OR rootbench OR hs3testsuite) +if(roottest OR rootbench) set(testing ON CACHE BOOL "" FORCE) endif() @@ -339,6 +339,10 @@ if(testing) set(testsupport ON CACHE BOOL "" FORCE) endif() +#---running HS3 test suite requires both testing and pyroot +if(test_roofit_hs3testsuite AND (NOT testing OR NOT pyroot)) + message(FATAL_ERROR "-Dtest_roofit_hs3testsuite=ON requires both -Dtesting=ON and -Dpyroot=ON)") +endif() if(unfold AND NOT xml) message(STATUS "Cannot enable unfold without enabling xml: unfold is disabled.") diff --git a/roofit/hs3/test/CMakeLists.txt b/roofit/hs3/test/CMakeLists.txt index 1f41a041690aa..af22adfca8f86 100644 --- a/roofit/hs3/test/CMakeLists.txt +++ b/roofit/hs3/test/CMakeLists.txt @@ -1,7 +1,7 @@ ROOT_ADD_GTEST(testRooFitHS3 testRooFitHS3.cxx LIBRARIES RooFitCore RooFit RooFitHS3) ROOT_ADD_GTEST(testHS3SimultaneousFit testHS3SimultaneousFit.cxx LIBRARIES RooFitCore RooFit RooFitHS3 RooStats) -if(pyroot AND hs3testsuite) +if(test_roofit_hs3testsuite) set(hs3testsuite_dir ${CMAKE_CURRENT_SOURCE_DIR}/HS3TestSuite) if(NOT EXISTS ${hs3testsuite_dir}) find_package(Git QUIET REQUIRED) From f6a0e5f051a634c3984235c75cb0aec6a006bb04 Mon Sep 17 00:00:00 2001 From: Steffen Albrecht Date: Tue, 16 Jun 2026 15:26:10 +0200 Subject: [PATCH 4/5] [CMake] Update hs3testsuite directory path to use current binary directory and pin to specific commit hash --- roofit/hs3/test/CMakeLists.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/roofit/hs3/test/CMakeLists.txt b/roofit/hs3/test/CMakeLists.txt index af22adfca8f86..92a44e3ee1686 100644 --- a/roofit/hs3/test/CMakeLists.txt +++ b/roofit/hs3/test/CMakeLists.txt @@ -2,11 +2,13 @@ ROOT_ADD_GTEST(testRooFitHS3 testRooFitHS3.cxx LIBRARIES RooFitCore RooFit RooFi ROOT_ADD_GTEST(testHS3SimultaneousFit testHS3SimultaneousFit.cxx LIBRARIES RooFitCore RooFit RooFitHS3 RooStats) if(test_roofit_hs3testsuite) - set(hs3testsuite_dir ${CMAKE_CURRENT_SOURCE_DIR}/HS3TestSuite) + set(hs3testsuite_dir ${CMAKE_CURRENT_BINARY_DIR}/HS3TestSuite) if(NOT EXISTS ${hs3testsuite_dir}) find_package(Git QUIET REQUIRED) execute_process(COMMAND ${GIT_EXECUTABLE} clone https://github.com/Phmonski/HS3TestSuite - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + execute_process(COMMAND ${GIT_EXECUTABLE} reset --hard 9d04e321ae6fddd283a35507f14ecf852eb7df61 + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) endif() if(EXISTS ${hs3testsuite_dir}) From 0d462a0f455a4d2e63f589214cb706a9be7c0ed0 Mon Sep 17 00:00:00 2001 From: Steffen Albrecht Date: Tue, 16 Jun 2026 16:51:29 +0200 Subject: [PATCH 5/5] [CMake] Use FetchContent for more robust HS3TestSuite download --- roofit/hs3/test/CMakeLists.txt | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/roofit/hs3/test/CMakeLists.txt b/roofit/hs3/test/CMakeLists.txt index 92a44e3ee1686..911c70460b6bb 100644 --- a/roofit/hs3/test/CMakeLists.txt +++ b/roofit/hs3/test/CMakeLists.txt @@ -2,16 +2,14 @@ ROOT_ADD_GTEST(testRooFitHS3 testRooFitHS3.cxx LIBRARIES RooFitCore RooFit RooFi ROOT_ADD_GTEST(testHS3SimultaneousFit testHS3SimultaneousFit.cxx LIBRARIES RooFitCore RooFit RooFitHS3 RooStats) if(test_roofit_hs3testsuite) - set(hs3testsuite_dir ${CMAKE_CURRENT_BINARY_DIR}/HS3TestSuite) - if(NOT EXISTS ${hs3testsuite_dir}) - find_package(Git QUIET REQUIRED) - execute_process(COMMAND ${GIT_EXECUTABLE} clone https://github.com/Phmonski/HS3TestSuite - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) - execute_process(COMMAND ${GIT_EXECUTABLE} reset --hard 9d04e321ae6fddd283a35507f14ecf852eb7df61 - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) - endif() - - if(EXISTS ${hs3testsuite_dir}) - ROOT_ADD_PYUNITTEST(hs3-suite test_hs3_suite.py PYTHON_DEPS jsonschema ENVIRONMENT HS3TESTSUITE_ROOT=${hs3testsuite_dir}) + include(FetchContent) + FetchContent_Declare( + hs3testsuite + GIT_REPOSITORY https://github.com/Phmonski/HS3TestSuite.git + GIT_TAG 9d04e321ae6fddd283a35507f14ecf852eb7df61 + ) + FetchContent_MakeAvailable(hs3testsuite) + if(EXISTS ${hs3testsuite_SOURCE_DIR}) + ROOT_ADD_PYUNITTEST(hs3-suite test_hs3_suite.py PYTHON_DEPS jsonschema ENVIRONMENT HS3TESTSUITE_ROOT=${hs3testsuite_SOURCE_DIR}) endif() endif() \ No newline at end of file