Support for CTest
Closed this issue · 9 comments
Is your feature request related to a problem? Please describe.
I would like to suggest support for running CTest (unit test driver packaged with CMake by default) using the cmake4vim plugin, and having any test errors be parsed in the quickfix list (file/line #).
Describe the solution you'd like
A set of one or more commands for CTest integration:
-
A new command, possibly named
CTest
that can accept optional arguments. See CTest documentation for common command line options here. Example::CTest --verbose --rerun-failed
. Running this command will output to the quickfix window and highlight the first test failure (file and line #). -
A new command, possibly named
CMakeBuildAndCTest
that will runCMakeBuild
in its current form and, if successful, executeCTest
as described above.
Describe alternatives you've considered
Created custom commands that modify makeprg
to run the commands via make
:
- Created a new command
CTest
:command! CTest let &makeprg = 'cd build && ctest --output-on-failure' <bar> make
- Created a new command
CMakeBuildAndTest
:command! CMakeBuildAndTest let &makeprg = 'cd build && make && ctest --output-on-failure' <bar> make
- If the build fails the test will still run (and pass if the last set of test pass, false positive)
- Did not get the desired quickfix output
Created a custom command that uses cmake4vim's CMakeBuild
with a test
target:
command! -nargs=? -complete=custom,cmake4vim#CompleteTarget CMakeBuildAndTest call cmake4vim#CMakeBuild('--target test')
- Now the target is set to
test
for the next time i want to runCMakeBuild
so it only runs the test. I would need to runCMakeSelectTarget all
to put the target back.
- Now the target is set to
Created a custom function that uses cmake4vim's CMakeBuild
in two ways:
function! Test() abort
call cmake4vim#CMakeBuild('--target all')
" if there are no build errors, run the tests
let s:num_build_errors = len(filter(getqflist(), 'v:val.valid'))
if s:num_build_errors == 0
echo "Build succeeded!"
call cmake4vim#CMakeBuild('--target test')
let s:num_test_errors = len(filter(getqflist(), 'v:val.valid'))
if s:num_test_errors == 0
echo "Tests passed!"
endif
else
echo "Build failed!"
endif
endfunction
command! CMakeBuildAndCTest call Test()
- I couldn't get the test failure to report the correct output. Running
ctest
on the command line produces correct result. (this might be due to the async nature of running both commands in the same function, also i have not defined an errorformat for ctest results) - The targets are hardcoded to "all" and "test"
- Cannot pass arguments to CTest by calling CMake with a target of "test"
Let me know if there are already ways to accomplish this with custom commands and/or <bar>
ing together cmake4vim commands somehow.
Hi @nbn22385 ,
I didn't work with CTest.
But I thought that if I use test
target, it means that CMake should automatically build changed files and run the tests. Am I not right?
Do you know how CTest works with different CMake generators? Is it independent on CMake generator type?
Hi @ilyachur , thanks for the response.
But I thought that if I use test target, it means that CMake should automatically build changed files and run the tests. Am I not right?
Running cmake --build . --target test
(or make test
or even ctest
) does not trigger cmake to rebuild any changed source files, the last built version of the test will be run. You must run cmake --build . [--target all]
(or make
) to rebuild the source, then rerun the preferred test command. The rebuild+test behavior can be achieved with a workaround.
In addition, running tests without going through a call to ctest
provides no way of passing ctest-specific arguments to get more fine-grained control over unit test output.
Do you know how CTest works with different CMake generators? Is it independent on CMake generator type?
Calling include(CTest)
or enable_testing()
in your project's CMakeLists.txt adds another build target, which is test
for Makefile generators, or RUN_TESTS
for integrated development environments (like Visual Studio). I don't know exactly how CTest is impacted by different generators, however I do believe it is independent of the generator that is used except for the Visual Studio example. I tested with Ninja and the ctest
command works as expected.
I hope I was able to address your questions.
Hi @nbn22385 ,
Thank you for clarification. Now it is more clear for me.
In general if you have resources for contributing you can create a PR for this feature.
Or I will investigate this enhancement because I didn't use CTest.
Also "test proj" application should be extended in order to test this feature.
After some more research, you can pass arguments to ctest
via cmake
in the form of:
cmake --build <bld_directory> --target test -- ARGS="<ctest_args>"
Also I found that cmake files can be regenerated when calling ctest
using the --build-and-test
argument if the generator is specified:
ctest --build-and-test <path-to-source> <path-to-build> --build-generator <generator>
I am playing around with the code on a fork and can put up a PR if I get somewhere worth sharing. Seems like there are a handful of ways to get the desired behavior.
This is awesome, thank you!
I have experimented with the update and have a couple observations that I will put below. Feel free to close the issue if you feel they are not worthy of making any changes.
When running the following scenario:
CMake
CMakeBuild
(runs targetall
)CTest
(runs targettest
)
The output is correct. However, if I make a code change and run:
CMakeBuild
(runs targettest
, unless i specifyall
)
Only the tests from the prior build run again because the target is still set to test
. This may be by design, as it might be unexpected behavior to silently change the target back to all
. A way to remedy this would be to manually specify the target, unless you have a better suggestion:
CMakeBuild all
(runs targetall
)CTest
(runs targettest
)- Make a code change
CMakeBuild all
CTest
- repeat
Do you think it's a good idea to add the -bar
attribute to the CMakeBuild
command so that the commands can be chained together? For example (run a build, and if successful, run the tests):
:CMakeBuild | CTest -V
This would only make sense if the CMakeBuild
generating a build error returns a failure status, so that the CTest
command would not be run. I would like to be able to simulate the unix command make && ctest
.
I have merged this PR.