Catch2 (with CMake) Does Not Compile When Only Test File Discovered Is Empty
Introduction
Catch2 is a popular C++ testing framework that provides a simple and intuitive way to write unit tests. However, when using Catch2 with CMake, a common issue arises when there are no tests in the project, but an empty test file exists. In this article, we will explore this issue, provide a solution, and discuss the implications of this problem.
Describe the bug
When compiling a project with no tests, but an empty test file exists, the compile fails with the following error:
[ 50%] Linking CXX executable test
CMake Error at /usr/lib/cmake/Catch2/CatchAddTests.cmake:150 (string):
string sub-command JSON expected an index less than 0 got '0'.
Call Stack (most recent call first):
/usr/lib/cmake/Catch2/CatchAddTests.cmake:228 (catch_discover_tests_impl)
This error occurs because the catch_discover_tests_impl
function in CatchAddTests.cmake
is trying to parse the JSON output of the catch_discover_tests
function, which is empty since there are no tests in the project. However, the catch_discover_tests_impl
function expects a non-empty JSON output, leading to the error.
Expected behavior
The project should compile correctly, even if there are no tests in the project. The presence of an empty test file should not affect the compilation process.
Reproduction steps
To reproduce this bug, follow these steps:
- Create a base project directory (
base_dir
) - Add a
CMakeLists.txt
file to the base directory (CMakeLists.txt) - Create a
tests
directory inside the base directory (base_dir/tests
) - Create an empty test file inside the
tests
directory (base_dir/tests/tests.cpp
) - Create a
build
directory inside the base directory (base_dir/build
) cd
into thebuild
directory- Run
cmake ..
- Run
make
-> an error occurs
Platform information
- OS: Ubuntu 24.04.1 LTS arm64
- Compiler+version: clang 18.1.3 (1ubuntu1)
- Catch version: v3.8.0
Additional context
We're using Catch2 as part of an autograder for a university Data Structures course. The container we use is here: https://github.com/cs225-illinois/docker/blob/main/container-sp25/Dockerfile
Solution
To fix this issue, we need to modify the CMakeLists.txt
file to exclude the empty test file from the compilation process. We can do this by adding a catch_discover_tests
function with an empty test file:
catch_discover_tests(tests)
However, this will still cause the compilation to fail because the catch_discover_tests_impl
function is trying to parse the JSON output of the catch_discover_tests
function, which is empty. To fix this, we need to modify the CatchAddTests.cmake
file to handle the case where the catch_discover_tests
function returns an empty JSON output.
Modifying CatchAddTests.cmake
To modify the CatchAddTests.cmake
file, we need to add a check to see if the catch_discover_tests
function returns an empty JSON output. If it does, we can skip the compilation process. Here's an updated version of the CatchAddTests.cmake
file:
function(catch_discover_tests_impl)
# ...
if (NOT ${CMAKE_CURRENT_LIST_DIR}/catch_discover_tests.json)
return()
endif()
# ...
endfunction()
With this modification, the compilation process will skip the empty test file and continue without errors.
Conclusion
In conclusion, the issue of Catch2 (with CMake) not compiling when only a test file discovered is empty is a common problem that arises when there are no tests in the project, but an empty test file exists. To fix this issue, we need to modify the CMakeLists.txt
file to exclude the empty test file from the compilation process and modify the CatchAddTests.cmake
file to handle the case where the catch_discover_tests
function returns an empty JSON output. With these modifications, the compilation process will continue without errors.
Best practices
To avoid this issue in the future, it's a good practice to:
- Always include a
catch_discover_tests
function in theCMakeLists.txt
file, even if there are no tests in the project. - Modify the
CatchAddTests.cmake
file to handle the case where thecatch_discover_tests
function returns an empty JSON output. - Use a consistent naming convention for test files and directories to avoid confusion.
Q&A
Q: What is the issue with Catch2 (with CMake) not compiling when only a test file discovered is empty?
A: The issue arises when there are no tests in the project, but an empty test file exists. In this case, the catch_discover_tests_impl
function in CatchAddTests.cmake
tries to parse the JSON output of the catch_discover_tests
function, which is empty. This leads to a compilation error.
Q: What is the expected behavior? A: The project should compile correctly, even if there are no tests in the project. The presence of an empty test file should not affect the compilation process.
Q: How can I reproduce this bug? A: To reproduce this bug, follow these steps:
- Create a base project directory (
base_dir
) - Add a
CMakeLists.txt
file to the base directory (CMakeLists.txt) - Create a
tests
directory inside the base directory (base_dir/tests
) - Create an empty test file inside the
tests
directory (base_dir/tests/tests.cpp
) - Create a
build
directory inside the base directory (base_dir/build
) cd
into thebuild
directory- Run
cmake ..
- Run
make
-> an error occurs
Q: What are the platform information? A: The platform information is:
- OS: Ubuntu 24.04.1 LTS arm64
- Compiler+version: clang 18.1.3 (1ubuntu1)
- Catch version: v3.8.0
Q: What is the additional context? A: We're using Catch2 as part of an autograder for a university Data Structures course. The container we use is here: https://github.com/cs225-illinois/docker/blob/main/container-sp25/Dockerfile
Q: How can I fix this issue?
A: To fix this issue, you need to modify the CMakeLists.txt
file to exclude the empty test file from the compilation process. You can do this by adding a catch_discover_tests
function with an empty test file:
catch_discover_tests(tests)
However, this will still cause the compilation to fail because the catch_discover_tests_impl
function is trying to parse the JSON output of the catch_discover_tests
function, which is empty. To fix this, you need to modify the CatchAddTests.cmake
file to handle the case where the catch_discover_tests
function returns an empty JSON output.
Q: How can I modify the CatchAddTests.cmake file?
A: To modify the CatchAddTests.cmake
file, you need to add a check to see if the catch_discover_tests
function returns an empty JSON output. If it does, you can skip the compilation process. Here's an updated version of the CatchAddTests.cmake
file:
function(catch_discover_tests_impl)
# ...
if (NOT ${CMAKE_CURRENT_LIST_DIR}/catch_discover_tests.json)
return()
endif()
# ...
endfunction()
With this modification, the compilation process will skip the empty test file and continue without errors.
Q: What are the best practices to avoid this issue in the future? A: To avoid this issue in the future, it's a good practice to:
- Always include a
catch_discover_tests
function in theCMakeLists.txt
file, even if there are no tests in the project. - Modify the
CatchAddTests.cmake
file to handle the case where thecatch_discover_tests
function returns an empty JSON output. - Use a consistent naming convention for test files and directories to avoid confusion.
By following these best practices, you can ensure that your project compiles correctly, even if there are no tests in the project.