diff --git a/CMakeLists.txt b/CMakeLists.txt index d2a22048..528a6b78 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -279,6 +279,10 @@ set(CMAKE_INSTALL_RPATH "${rpath}") #--- propagate to the sub-directories ----------------------------------------- add_subdirectory(src) +#--- testing ------------------------------------------------------------------ +enable_testing() +add_subdirectory(tests) + #--- write summary of the installation cmake_host_system_information(RESULT PROCESSOR QUERY PROCESSOR_DESCRIPTION) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 00000000..7bb96858 --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,2 @@ +#--- musrfit integration tests ------------------------------------------------ +add_subdirectory(maxLH_check) diff --git a/tests/maxLH_check/CMakeLists.txt b/tests/maxLH_check/CMakeLists.txt new file mode 100644 index 00000000..95e6371b --- /dev/null +++ b/tests/maxLH_check/CMakeLists.txt @@ -0,0 +1,36 @@ +#--- maxLH_check test (Python) ------------------------------------------------ + +find_package(Python3 REQUIRED COMPONENTS Interpreter) + +#--- helper macro ------------------------------------------------------------- +macro(add_maxLH_test test_name msr_file expected_value) + add_test( + NAME ${test_name} + COMMAND Python3::Interpreter + ${CMAKE_CURRENT_SOURCE_DIR}/maxLH_check.py + $ + ${CMAKE_SOURCE_DIR}/doc/examples/${msr_file} + ${expected_value} + 1e-4 + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/doc/examples + ) +endmacro() + +#--- register ctest(s) ------------------------------------------------------- + +# single histogram fits (maxLH) +add_maxLH_test(test-histo-MusrRoot test-histo-MusrRoot.msr 3971.7) +add_maxLH_test(test-histo-PSI-BIN test-histo-PSI-BIN.msr 663.89) +add_maxLH_test(test-histo-ROOT-NPP test-histo-ROOT-NPP.msr 249.12) +add_maxLH_test(test-histo-HAL9500 test-histo-HAL9500.msr 1286509.8) +add_maxLH_test(test-histo-HAL9500-RRF test-histo-HAL9500-RRF.msr 22187.4) +add_maxLH_test(test-histo-muMinus test-histo-muMinus.msr 238962.6) +add_maxLH_test(test-histo-NeXus test-histo-NeXus.msr 3273.57) +add_maxLH_test(test-histo-NeXus2 test-histo-NeXus2.msr 2582.50) + +# asymmetry fits (chisq) +add_maxLH_test(test-asy-PSI-BIN test-asy-PSI-BIN.msr 566.76) +add_maxLH_test(test-asy-MUD test-asy-MUD.msr 133.96) +add_maxLH_test(test-asy-NeXus2 test-asy-NeXus2.msr 796.72) +add_maxLH_test(test-asy-HAL9500-RRF test-asy-HAL9500-RRF.msr 7402.28) +add_maxLH_test(test-asy-LF-BaB6 test-asy-LF-BaB6.msr 1911.88) \ No newline at end of file diff --git a/tests/maxLH_check/maxLH_check.py b/tests/maxLH_check/maxLH_check.py new file mode 100644 index 00000000..516e6567 --- /dev/null +++ b/tests/maxLH_check/maxLH_check.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 +""" +Runs musrfit -c on a given msr-file, extracts the maxLH (or chisq) +value from stdout, and compares it against an expected reference value. +Returns exit code 1 if the relative deviation exceeds the tolerance. + +Usage: + maxLH_check.py [tolerance] +""" + +import subprocess +import sys +import re + +def main(): + if len(sys.argv) < 4 or len(sys.argv) > 5: + print(f"usage: {sys.argv[0]} [tolerance]") + return 1 + + musrfit = sys.argv[1] + msr_file = sys.argv[2] + expected = float(sys.argv[3]) + tol = float(sys.argv[4]) if len(sys.argv) == 5 else 1e-4 + + # run musrfit -c + result = subprocess.run([musrfit, "-c", msr_file], + capture_output=True, text=True) + if result.returncode != 0: + print(f"**ERROR** musrfit returned exit code {result.returncode}") + print(result.stdout + result.stderr) + return 1 + + # extract maxLH or chisq from stdout + match = re.search(r">>\s+(maxLH|chisq)\s*=\s*([0-9.eE+-]+)", result.stdout) + if not match: + print("**ERROR** could not extract maxLH or chisq from output:") + print(result.stdout) + return 1 + + label = match.group(1) + value = float(match.group(2)) + rel_dev = abs((value - expected) / expected) + + if rel_dev > tol: + print(f"FAIL: {label} = {value}, expected = {expected}, " + f"rel. deviation = {rel_dev:.6e} > {tol:.6e}") + return 1 + + print(f"PASS: {label} = {value}, expected = {expected}, " + f"rel. deviation = {rel_dev:.6e} <= {tol:.6e}") + return 0 + +if __name__ == "__main__": + sys.exit(main())