feat(cmake): Add JUNIT_OUTPUT_DIR option to doctest_discover_tests (#417)

Co-authored-by: Dennis Hezel <dh@3yourmind.com>
diff --git a/scripts/cmake/doctest.cmake b/scripts/cmake/doctest.cmake
index 1376801..8b81c9d 100644
--- a/scripts/cmake/doctest.cmake
+++ b/scripts/cmake/doctest.cmake
@@ -33,6 +33,7 @@
                          [TEST_SUFFIX suffix]
                          [PROPERTIES name1 value1...]
                          [TEST_LIST var]
+                         [JUNIT_OUTPUT_DIR dir]
     )
 
   ``doctest_discover_tests`` sets up a post-build command on the test executable
@@ -90,6 +91,13 @@
     executable is being used in multiple calls to ``doctest_discover_tests()``.
     Note that this variable is only available in CTest.
 
+  ``JUNIT_OUTPUT_DIR dir``
+    If specified, the parameter is passed along with ``--reporters=junit``
+    and ``--out=`` to the test executable. The actual file name is the same
+    as the test target, including prefix and suffix. This should be used
+    instead of EXTRA_ARGS to avoid race conditions writing the XML result
+    output when using parallel test execution.
+
 #]=======================================================================]
 
 #------------------------------------------------------------------------------
@@ -97,7 +105,7 @@
   cmake_parse_arguments(
     ""
     ""
-    "TEST_PREFIX;TEST_SUFFIX;WORKING_DIRECTORY;TEST_LIST"
+    "TEST_PREFIX;TEST_SUFFIX;WORKING_DIRECTORY;TEST_LIST;JUNIT_OUTPUT_DIR"
     "TEST_SPEC;EXTRA_ARGS;PROPERTIES"
     ${ARGN}
   )
@@ -134,6 +142,7 @@
             -D "TEST_PREFIX=${_TEST_PREFIX}"
             -D "TEST_SUFFIX=${_TEST_SUFFIX}"
             -D "TEST_LIST=${_TEST_LIST}"
+            -D "TEST_JUNIT_OUTPUT_DIR=${_JUNIT_OUTPUT_DIR}"
             -D "CTEST_FILE=${ctest_tests_file}"
             -P "${_DOCTEST_DISCOVER_TESTS_SCRIPT}"
     VERBATIM
diff --git a/scripts/cmake/doctestAddTests.cmake b/scripts/cmake/doctestAddTests.cmake
index 98ee4a2..6cba3f1 100644
--- a/scripts/cmake/doctestAddTests.cmake
+++ b/scripts/cmake/doctestAddTests.cmake
@@ -6,6 +6,7 @@
 set(spec ${TEST_SPEC})
 set(extra_args ${TEST_EXTRA_ARGS})
 set(properties ${TEST_PROPERTIES})
+set(junit_output_dir "${TEST_JUNIT_OUTPUT_DIR}")
 set(script)
 set(suite)
 set(tests)
@@ -54,6 +55,13 @@
     continue()
   endif()
   set(test ${line})
+  if(NOT "${junit_output_dir}" STREQUAL "")
+    # turn testname into a valid filename by replacing all special characters with "-"
+    string(REGEX REPLACE "[/\\:\"|<>]" "-" test_filename "${test}")
+    set(TEST_JUNIT_OUTPUT_PARAM "--reporters=junit" "--out=${junit_output_dir}/${prefix}${test_filename}${suffix}.xml")
+  else()
+    unset(TEST_JUNIT_OUTPUT_PARAM)
+  endif()
   # use escape commas to handle properly test cases with commas inside the name
   string(REPLACE "," "\\," test_name ${test})
   # ...and add to script
@@ -62,6 +70,7 @@
     ${TEST_EXECUTOR}
     "${TEST_EXECUTABLE}"
     "--test-case=${test_name}"
+    "${TEST_JUNIT_OUTPUT_PARAM}"
     ${extra_args}
   )
   add_command(set_tests_properties