diff --git a/Modules/GoogleTest.cmake b/Modules/GoogleTest.cmake index b62f8393af..e187804c5b 100644 --- a/Modules/GoogleTest.cmake +++ b/Modules/GoogleTest.cmake @@ -347,16 +347,51 @@ function(gtest_add_tests) unset(testList) - set(gtest_case_name_regex ".*\\( *([A-Za-z_0-9]+) *, *([A-Za-z_0-9]+) *\\).*") + set(gtest_case_name_regex ".*\\([ \r\n\t]*([A-Za-z_0-9]+)[ \r\n\t]*,[ \r\n\t]*([A-Za-z_0-9]+)[ \r\n\t]*\\).*") set(gtest_test_type_regex "(TYPED_TEST|TEST)_?[FP]?") + set(each_line_regex "([^\r\n]*[\r\n])") foreach(source IN LISTS ARGS_SOURCES) if(NOT ARGS_SKIP_DEPENDENCY) set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${source}) endif() file(READ "${source}" contents) - string(REGEX MATCHALL "${gtest_test_type_regex} *\\(([A-Za-z_0-9 ,]+)\\)" found_tests "${contents}") - foreach(hit ${found_tests}) + # Replace characters in file content that are special to CMake + string(REPLACE "[" "" contents "${contents}") + string(REPLACE "]" "" contents "${contents}") + string(REPLACE ";" "\\;" contents "${contents}") + # Split into lines + string(REGEX MATCHALL "${each_line_regex}" content_lines "${contents}") + set(line "0") + # Stores the line number of the start of a test definition + set(accumulate_line "0") + # Stores accumulated lines to match multi-line test definitions + set(accumulated "") + # Iterate over each line in the file so that we know the line number of a test definition + foreach(line_str IN LISTS content_lines) + MATH(EXPR line "${line}+1") + # Check if the current line is the start of a test definition + string(REGEX MATCH "[ \t]*${gtest_test_type_regex}[ \t]*[\\(]*" accumlate_start_hit "${line_str}") + if(accumlate_start_hit) + set(accumulate_line "${line}") + endif() + # Append the current line to the accumulated string + set(accumulated "${accumulated}${line_str}") + # Attempt to match a complete test definition in the accumulated string + string(REGEX MATCH "${gtest_test_type_regex}[ \r\n\t]*\\(([A-Za-z_0-9 ,\r\n\t]+)\\)" hit "${accumulated}") + if(hit) + # Reset accumulated for the next match + set(accumulated "") + else() + # Continue accumulating lines + continue() + endif() + # At this point, the start line of the test definition is known + # Hence, we can set the test's DEF_SOURCE_LINE property with + # ${source}:${accumulate_line} below. + # VS Code CMake Tools extension looks for DEF_SOURCE_LINE + # to locate the test definition for its "Go to test" feature. + string(REGEX MATCH "${gtest_test_type_regex}" test_type ${hit}) # Parameterized tests have a different signature for the filter @@ -394,7 +429,8 @@ function(gtest_add_tests) --gtest_filter=${gtest_test_name} ${ARGS_EXTRA_ARGS} ) - set_tests_properties(${ctest_test_name} PROPERTIES DISABLED TRUE) + set_tests_properties(${ctest_test_name} PROPERTIES DISABLED TRUE + DEF_SOURCE_LINE "${source}:${accumulate_line}") list(APPEND testList ${ctest_test_name}) endif() else() @@ -410,6 +446,7 @@ function(gtest_add_tests) ${ctest_test_name} PROPERTIES SKIP_REGULAR_EXPRESSION "\\[ SKIPPED \\]" + DEF_SOURCE_LINE "${source}:${accumulate_line}" ) list(APPEND testList ${ctest_test_name}) endif() diff --git a/Tests/GoogleTest/Test/CMakeLists.txt b/Tests/GoogleTest/Test/CMakeLists.txt index baf00d53fd..201c39e15c 100644 --- a/Tests/GoogleTest/Test/CMakeLists.txt +++ b/Tests/GoogleTest/Test/CMakeLists.txt @@ -81,10 +81,30 @@ gtest_add_tests(test_gtest3 "" AUTO) if(NOT TEST GoogleTest.Foo) message(FATAL_ERROR "Test case GoogleTest.Foo not defined") endif() +# Check if test has property DEF_SOURCE_LINE +get_test_property(GoogleTest.Foo DEF_SOURCE_LINE testSourceLineFoo) +if(NOT testSourceLineFoo) + message(FATAL_ERROR "Test GoogleTest.Foo should have DEF_SOURCE_LINE property") +endif() +# If check property ends with correct value +string(FIND "${testSourceLineFoo}" "main3.cxx:3" testSourceLineFooFound) +if(${testSourceLineFooFound} EQUAL -1) + message(FATAL_ERROR "Test GoogleTest.Foo should have DEF_SOURCE_LINE property with value main3.cxx:3") +endif() + if(NOT TEST GoogleTest.Bar) message(FATAL_ERROR "Test case GoogleTest.Bar not defined") endif() - +# Check if test has property DEF_SOURCE_LINE +get_test_property(GoogleTest.Bar DEF_SOURCE_LINE testSourceLineBar) +if(NOT testSourceLineBar) + message(FATAL_ERROR "Test GoogleTest.Bar should have DEF_SOURCE_LINE property") +endif() +# If check property ends with correct value +string(FIND "${testSourceLineBar}" "main3.cxx:8" testSourceLineBarFound) +if(${testSourceLineBarFound} EQUAL -1) + message(FATAL_ERROR "Test GoogleTest.Bar should have DEF_SOURCE_LINE property with value main3.cxx:8") +endif() # Non-keyword form, explicitly specified sources. Allows a non-target to be # given for the executable.