how to use CTest with Node js command, for testing JS file compiled from C++ using emscripten, and use Catch2? - cmake

I am try to use Catch2 library for testing and compile it with emscripten and run the test. The directory structure of my project look like this
|- CMakeLists.txt
|- build
|   |- ...
|   |- try-test.js
|   |- try-test.wasm
|   |- try-test.wast
|- test
|   |- main.cpp
|- third_party
|- Catch2
|- ...
when I am move to build directory and run node try-test.js, it success. but when i am run ctest, it fail. Below is the output message.
Test project /Users/janucaria/Projects/junk/em-cpp-unit-test/build
Start 1: trytest
Could not find executable node /Users/janucaria/Projects/junk/em-cpp-unit-test/build/try-test.js
Looked in the following places:
node /Users/janucaria/Projects/junk/em-cpp-unit-test/build/try-test.js
node /Users/janucaria/Projects/junk/em-cpp-unit-test/build/try-test.js
node /Users/janucaria/Projects/junk/em-cpp-unit-test/build/Release/try-test.js
node /Users/janucaria/Projects/junk/em-cpp-unit-test/build/Release/try-test.js
node /Users/janucaria/Projects/junk/em-cpp-unit-test/build/Debug/try-test.js
node /Users/janucaria/Projects/junk/em-cpp-unit-test/build/Debug/try-test.js
node /Users/janucaria/Projects/junk/em-cpp-unit-test/build/MinSizeRel/try-test.js
node /Users/janucaria/Projects/junk/em-cpp-unit-test/build/MinSizeRel/try-test.js
node /Users/janucaria/Projects/junk/em-cpp-unit-test/build/RelWithDebInfo/try-test.js
node /Users/janucaria/Projects/junk/em-cpp-unit-test/build/RelWithDebInfo/try-test.js
node /Users/janucaria/Projects/junk/em-cpp-unit-test/build/Deployment/try-test.js
node /Users/janucaria/Projects/junk/em-cpp-unit-test/build/Deployment/try-test.js
node /Users/janucaria/Projects/junk/em-cpp-unit-test/build/Development/try-test.js
node /Users/janucaria/Projects/junk/em-cpp-unit-test/build/Development/try-test.js
Unable to find executable: node /Users/janucaria/Projects/junk/em-cpp-unit-test/build/try-test.js
1/1 Test #1: trytest ..........................***Not Run 0.00 sec
0% tests passed, 1 tests failed out of 1
Total Test time (real) = 0.01 sec
The following tests FAILED:
1 - trytest (Not Run)
Errors while running CTest
Am I missing something here?
here is my test/main.cpp
#define CATCH_CONFIG_MAIN
#include <catch2/catch.hpp>
TEST_CASE("Try test")
{
int foo = 1;
REQUIRE(foo == 1);
}
and here the CMakeLists.txt
cmake_minimum_required(VERSION 3.11)
project(trytest)
enable_testing()
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
add_executable(try-test "test/main.cpp")
target_include_directories(try-test
PRIVATE
"${PROJECT_SOURCE_DIR}/third_party/Catch2/single_include"
)
target_compile_options(try-test PRIVATE "-Wall" "-Wpedantic" "-stdlib=libc++")
add_test(
NAME trytest
COMMAND "node ${CMAKE_CURRENT_BINARY_DIR}/try-test.js")
I would be grateful for any help you are able to provide.

I figure it out. I am use add_test wrong. It should be
add_test(
NAME trytest
COMMAND node "${CMAKE_CURRENT_BINARY_DIR}/try-test.js")
so the ctest will run command node with arguments ${CMAKE_CURRENT_BINARY_DIR}/try-test.js

Related

CMake EXCLUDE_FROM_ALL argument ignored when running 'make all'

Introduction
Using CMake, I am trying to build a library using a special make target. To this end, I use the EXCLUDE_FROM_ALL argument to ensure that the library is not built by running make (which defaults to make all). Unfortunately, the EXCLUDE_FROM_ALL option seems to be ignored by cmake.
Consider the following file tree:
.
├── CMakeLists.txt
├── foo
│   ├── CMakeLists.txt
│   ├── headers
│   │   └── foo.h
│   └── src
│   └── foo.cpp
└── src
└── main.cpp
4 directories, 5 files
In this file tree, you can see that I basically have two parts:
The foo library, for which all files are located in ./foo/.
The main executable, for which the source code is located in ./src/main.cpp.
Below, I will further explain these two parts and the behaviour I am observing.
The foo library
First of all, the header code located in ./foo/headers/foo.h is:
#ifndef _FOO_H_
#define _FOO_H_
#include <iostream>
void foo(void);
#endif // _FOO_H_
The corresponding source code, located in ./foo/src/foo.cpp, is:
#include "foo.h"
void foo(void) {
std::printf("Hello foo!\n");
}
As you can see, the foo library only contains the function foo(). This function simply prints Hello, foo! to the terminal. To build the foo library, I have the following CMakeLists.txt file defined (in ./foo/CMakeLists.txt):
cmake_minimum_required(VERSION 3.10)
project(foo
LANGUAGES CXX
)
# Create a foo library target
add_library(foo EXCLUDE_FROM_ALL
"src/foo.cpp"
)
target_include_directories(foo
PUBLIC "headers"
)
Note that I use the EXCLUDE_FROM_ALL argument in the add_library() function.
To test the behaviour of the EXCLUDE_FROM_ALL argument, I will now build the foo library as a stand-alone (using the previously shown CMakeLists.txt). Starting from the top directory (.), I use the following workflow:
$ cd foo
$ mkdir build
$ cd build
$ cmake ..
After this is finished, I run the make command:
$ make
(nothing happens)
As expected, nothing happens (since the foo library is excluded from the all target). Now, when I use make foo, I get the following output:
$ make foo
Scanning dependencies of target foo
[ 50%] Building CXX object CMakeFiles/foo.dir/src/foo.cpp.o
[100%] Linking CXX static library libfoo.a
[100%] Built target foo
So far, so good. Before moving on to building the main executable, I completely remove the ./foo/build directory and go back to the top-level directory:
$ cd ..
$ rm -rf build
$ cd ..
The main executable
The source code for the main executable is located in ./src/main.cpp:
#include "foo.h"
int main() {
foo();
return 0;
}
The top-level CMakeLists.txt contains:
cmake_minimum_required(VERSION 3.10)
project(TestProject
LANGUAGES CXX
)
# Include the foo library
add_subdirectory("foo" EXCLUDE_FROM_ALL)
# Create the main executable
add_executable(TestProject
"src/main.cpp"
)
target_link_libraries(TestProject
PRIVATE foo
)
Note that I again use the EXCLUDE_FROM_ALL argument, but now for the add_subdirectory() function.
To generate a makefile for the main executable, I use the following workflow:
$ mkdir build
$ cd build
$ cmake ..
When I now run make, I get the following output:
$ make
Scanning dependencies of target foo
[ 25%] Building CXX object foo/CMakeFiles/foo.dir/src/foo.cpp.o
[ 50%] Linking CXX static library libfoo.a
[ 50%] Built target foo
Scanning dependencies of target TestProject
[ 75%] Building CXX object CMakeFiles/TestProject.dir/src/main.cpp.o
[100%] Linking CXX executable TestProject
[100%] Built target TestProject
As you can see, it first builds the foo library. However, this is not what I expected! I explicitly stated to exclude the foo library from the all target. Hence, I would expect the need to first run make foo before running make.
This brings me to my main question(s): does someone know why it ignores the EXCLUDE_FROM_ALL option in the add_subdirectory() function in the top-level CMakeLists.txt? It did work when I built the foo library as a stand-alone. Is this a bug in cmake? If not, how do I achieve my expected behaviour (i.e. the need to run make foo before running make)?
This is not a bug. CMake does not include the foo lib in the all target directly. It does however add the foo target as dependency to TestProject and since TestProject is included in the all target, foo gets built too, if you build all.
This needs to be done this way. How else would you be able to link the foo function into TestProject?
If you want to use a lib that is not built as part of all, you need to use a imported lib. Doing this is and including the lib in the project seems a bit nonsensical though, but here you go.
add_library(foo STATIC EXCLUDE_FROM_ALL
"src/foo.cpp"
)
cmake_minimum_required(VERSION 3.10)
project(TestProject
LANGUAGES CXX
)
# Include the foo library
add_subdirectory("foo" EXCLUDE_FROM_ALL)
# Create the main executable
add_executable(TestProject
"src/main.cpp"
)
# add copy of foo as imported lib
add_library(foo_imported STATIC IMPORTED)
target_include_directories(foo_imported INTERFACE $<TARGET_PROPERTY:foo,INTERFACE_INCLUDE_DIRECTORIES>)
set_target_properties(foo_imported PROPERTIES IMPORTED_LOCATION $<TARGET_FILE:foo>)
target_link_libraries(TestProject
PRIVATE foo_imported
)

How does project(...) affect variables?

I stumbled upon the following nice cmake feature recently:
https://cmake.org/cmake/help/latest/variable/CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT.html
Save the following snippet as CMakeLists.txt, run mkdir build; cd build:
cmake_minimum_required(VERSION 3.12)
message(STATUS "CMID: ${CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT}")
project( test )
Executing that snippet does not output a true variable:
➜ build /usr/bin/rm -rf *; cmake ../ | grep CMID
-- CMID:
Now if you change that snippet:
cmake_minimum_required(VERSION 3.12)
project( test )
message(STATUS "CMID: ${CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT}")
Execution yields the result, I expect from the documentation:
➜ build /usr/bin/rm -rf *; cmake ../ | grep CMID
-- CMID: 1
So I wonder, how does the relative position of the project( ... ) command change that variable?
project() call sets many CMake variables, and CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT is one of such variables.
So, for many CMake commands and variables' accesses placing them before or after the project() call is crusial.
In most cases, project() call should be before the using of the other commands and variables.
If you are looking for a way of changing default install prefix from the CMakeLists.txt, see that my answer: https://stackoverflow.com/a/39485990/3440745.

Using google tests with CMake/Ctest with the new command gtest_discover_tests

I am trying to use googletest with CMake/Ctest. I have several sources files for my tests (each one containing many TEST/TEST_F/... commands) which are located in several directories. I want that the tests related to a given source are executed in the same directory as their source file. Also, I prefer that the build process of a test source file is a test by itself. So I made something like:
file(GLOB_RECURSE test_srcs
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
"tests/*.cpp")
foreach(test_src ${test_srcs})
get_filename_component(test_dir ${test_src} DIRECTORY)
get_filename_component(test_exe ${test_src} )NAME_WE)
add_executable(${test_exe} EXCLUDE_FROM_ALL tests/gtest_main.cpp ${test_src})
set_target_properties(${test_exe}
PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${test_dir}
)
target_link_libraries(${test_exe} gtest)
add_test(NAME build_${test_exe} COMMAND "${CMAKE_COMMAND}" --build ${CMAKE_BINARY_DIR} --target ${test_exe})
set_tests_properties(build_${test_exe} PROPERTIES FIXTURES_SETUP ${test_exe})
gtest_discover_tests(${test_exe}
TEST_LIST list
WORKING_DIRECTORY ${test_dir}
PROPERTIES DEPENDS build_${test_exe}
PROPERTIES FIXTURES_REQUIRED ${test_exe}
)
endforeach()
But it seems that the dependencies I am trying to declare between the tests are not taken into account: the build of the tests does not necessarily occurs before the execution of the underlying tests...
If I use the old gtest_add_tests as in the following instead of gtest_discover_tests, it works:
gtest_add_tests(
TARGET ${test_exe}
SOURCES ${test_src}
WORKING_DIRECTORY ${test_dir}
TEST_LIST tlist
)
set_tests_properties(${tlist} PROPERTIES FIXTURES_REQUIRED ${test_exe})
Am I missing something with gtest_discover_tests?
After having started the bounty, I re-started the research on my own. I found out, the simplest method out there is to have googletest installed system-wide.
So, first install the package. On Ubuntu 18.04, that was supt apt install googletest.
For some reason, I had to build the library (perhaps not necessary somehow though?):
cd /usr/src/googletest
mkdir bin && cd bin
cmake ..
make && make install
After that I have been able to compile and run a test case. My CMakeLists.txt testing section looks like this:
enable_testing()
find_package(GTest REQUIRED)
include(GoogleTest)
add_executable(tests tests/foo_test.cpp tests/bar_test.cpp)
target_link_libraries(tests GTest::GTest GTest::Main)
gtest_discover_tests(tests)
A minimal test case file looks like this in my project:
// tests/foo_test.cpp
#include "gtest/gtest.h"
TEST(Foo, Sum)
{
EXPECT_EQ(2, 1 + 1);
}
Compiling is as easy as:
mkdir bin && cd bin
cmake ..
./tests

How to add a CMake custom target to test all sub-projects?

I have a repository with several projects inside. The resulting directory structure is like this :
Repository
--CMakeLists.txt
--Project A
--CMakeLists.txt
--Project B
--CMakeLists.txt
In projects A and B I have tests that I add using add_test. When inside a project I can do make test.
How can I add a target "test" to the top CMakeLists.txt to be able to call make test from the top directory and get the tests of all projects executed ?
I have just tried to reproduce your setup with the following files:
/tmp/test $ tree
.
├── a
│   └── CMakeLists.txt
├── b
│   └── CMakeLists.txt
└── CMakeLists.txt
/tmp/test $ cat CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
project(Foo)
enable_testing()
add_subdirectory(a)
add_subdirectory(b)
/tmp/test $ cat a/CMakeLists.txt
project(A)
add_test(NAME atest COMMAND echo "hello from a")
/tmp/test $ cat b/CMakeLists.txt
project(B)
add_test(NAME btest COMMAND echo "hello from b")
/tmp/test/build $ mkdir build && cd build
/tmp/test/build $ cmake .. && make test
# Remove some output
Running tests...
Test project /tmp/test/build
Start 1: atest
1/2 Test #1: atest ............................ Passed 0.00 sec
Start 2: btest
2/2 Test #2: btest ............................ Passed 0.00 sec

Calling Unittest++ from cmake created makefile

I recently started learning cmake, and have run into a small issue. I got both my executable and the unit tests to compile from the generated makefile without issue. If I run ./test in the build directory, the tests created in UnitTest++ run and complete as expected, printing the results. Is there any way to get make test to simply run the test executable rather than running it inside ctest framework or should I go about this a different way?
Here is a minimal working example of my code:
src/main/main.c is a simple empty main function
src/test/testMain.cpp:
#include <UnitTest++/UnitTest++.h>
TEST(FailSpect)
{
CHECK(false);
}
int main()
{
UnitTest::RunAllTests();
}
CMakeLists.txt:
cmake_minimum_required( VERSION 2.6 )
project( myProject)
enable_testing()
set( myProjectMain
src/main/main.c
)
set( myProjectSrc
)
set( myProjectTestSrc
src/test/testMain.cpp
)
add_executable( myExecutable ${myProjectMain} ${myProjectSrc} )
add_executable( testSuite ${myProjectTestSrc} ${myProjectSrc} )
target_link_libraries( testSuite UnitTest++ )
add_test( testExe testSuite )
make test output:
Running tests...
Start processing tests
Test project /myProjectDir/build
1/ 1 Testing testExe Passed
100% tests passed, 0 tests failed out of 1
./testSuite output:
/myProjectDir/src/test/testMain.cpp:5: error: Failure in FailSpect: false
FAILURE: 1 out of 1 tests failed (1 failures).
Test time: 0.00 seconds.
I have sorted out how to do this. First remove the lines:
enable_testing()
and
add_test(testExe testSuite)
and replace them by the line:
add_custom_target(test ./testExe
DEPENDS ./testExe)
at the end of the CMakeLists.txt file. Now make (all) builds both the tests and the main program. If everything is built already, then make test will just check that the tests are built and run them, producing:
[100%] Built target testExe
/myProjectDir/src/test/testMain.cpp:5: error: Failure in FailSpect: false
FAILURE: 1 out of 1 tests failed (1 failures).
Test time: 0.00 seconds.
[100%] Built target test
If the tests are out of date (after a make clean for instance), then make test will produce:
[100%] Building CXX object CMakeFiles/testExe.dir/src/test/testMain.cpp.o
Linking CXX executable testExe
[100%] Built target testExe
/myProjectDir/src/test/testMain.cpp:5: error: Failure in FailSpect: false
FAILURE: 1 out of 1 tests failed (1 failures).
Test time: 0.00 seconds.
[100%] Built target test