find external test file for unit test by relative path c++ cmake guest
Asked Answered
F

5

15

What would be the proper way to access an external test file for the unit test of a c++ project? I am using CMake and Gtest.

This is a sample of the directory structure.

Project
   -src
       -test (unit tests here)
   -test-data (data file here)

Thanks!

Fruition answered 8/8, 2014 at 19:42 Comment(0)
P
7

Pass the file name to gtest arguments:

add_executable(foo ...)
enable_testing()
add_test(FooTest foo "${CMAKE_CURRENT_LIST_DIR}/data/input.file")

get the parameter after gtest parse input:

int main(int argc, char** argv) {
  ::testing::InitGoogleTest(&argc, argv);
  assert(argc == 2); // gtest leaved unparsed arguments for you

and save it to some global *:

  file_name = argv[1];
  return RUN_ALL_TESTS();

* Usually it's not a very good idea to pollute the global namespace but I think it's fine for testing app

Related

Philae answered 9/8, 2014 at 15:3 Comment(3)
This looks great! When I try to implement it argv does not have the argument. Any suggestions?Fruition
the argc/argv are the same before and after the InitGoogleTest each time they only include the executable path and not any argumentsFruition
I am running the test in Xcode as a part of the project. I think that it runs the executable directly. When I run Ctest from the command line it says no tests were found. I may be missing something with a proper Ctest setup, but if you could direct me to a good example of a project that is doing what I am trying to do(with c++, Gtest, CMake, and external test files) I should be able to figure it out. I just can't find a good example. Thanks!Fruition
T
12

I prefer to find my test data relative to my executable test. To do so, I usually define a helper method in some TestHelpers.h and then pass the relative path of the file I'm looking to resolve.

inline std::string resolvePath(const std::string &relPath)
{
    namespace fs = std::tr2::sys;
    // or namespace fs = boost::filesystem;
    auto baseDir = fs::current_path();
    while (baseDir.has_parent_path())
    {
        auto combinePath = baseDir / relPath;
        if (fs::exists(combinePath))
        {
            return combinePath.string();
        }
        baseDir = baseDir.parent_path();
    }
    throw std::runtime_error("File not found!");
}

To use it, I go:

std::string foofullPath = resolvePath("test/data/foo.txt");

and that gives me a full path of the test file as long as my executing directory runs from on a descendant of the project's root directory.

Trachytic answered 13/3, 2017 at 20:26 Comment(0)
G
9

In your CMakefile, add your tests and set some an environment variable with the path to you data.

add_test(mytests ${PROJECT_BINARY_DIR}/unittests)
set_tests_properties(mytests PROPERTIES 
                     ENVIRONMENT
                     DATADIR=${CMAKE_CURRENT_SOURCE_DIR}/tests/testvectors)

You can later retrieve the DATADIR from the environment in any test.

You other option is to define a different working directory

set_tests_properties(mytests PROPERTIES
        WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/tests)

In my opinion, this is the less intrusive and simpler way.

Gottlieb answered 6/8, 2019 at 8:54 Comment(1)
I'm not having luck with set_tests_properties() cmake command with either the ENVIRONMENT or the WORKING_DIRECTORY directives. Neither one seem to work in Visual Studio 2019. I've dumped all environment variables from within the runner and dumped the current working directory from within the runner, and they both remain unchanged. I suspect it is an issue with Visual Studio and not cmake however.Toilet
P
7

Pass the file name to gtest arguments:

add_executable(foo ...)
enable_testing()
add_test(FooTest foo "${CMAKE_CURRENT_LIST_DIR}/data/input.file")

get the parameter after gtest parse input:

int main(int argc, char** argv) {
  ::testing::InitGoogleTest(&argc, argv);
  assert(argc == 2); // gtest leaved unparsed arguments for you

and save it to some global *:

  file_name = argv[1];
  return RUN_ALL_TESTS();

* Usually it's not a very good idea to pollute the global namespace but I think it's fine for testing app

Related

Philae answered 9/8, 2014 at 15:3 Comment(3)
This looks great! When I try to implement it argv does not have the argument. Any suggestions?Fruition
the argc/argv are the same before and after the InitGoogleTest each time they only include the executable path and not any argumentsFruition
I am running the test in Xcode as a part of the project. I think that it runs the executable directly. When I run Ctest from the command line it says no tests were found. I may be missing something with a proper Ctest setup, but if you could direct me to a good example of a project that is doing what I am trying to do(with c++, Gtest, CMake, and external test files) I should be able to figure it out. I just can't find a good example. Thanks!Fruition
L
2

You could use the CMAKE_SOURCE_DIR (gives absolute path of the top level cmake directory) variable to define the path and pass it to the test script.

Logbook answered 8/8, 2014 at 19:54 Comment(4)
How would I access this from the c++ code? Could you help me with a simple example?Fruition
You can't access that from the c++ code directly, you would need to somehow feed to the binary that runs the test. I've never used Gtest so I don't how that might be possible in that context. If the data is you need is not very large you also could copy there via CMake (see file(COPY ...)). There are a lot ways you can achieve this, but depends very heavily on your CMake/build/Project/Test structure how to make it good .Logbook
I am trying to access the file by the relative path in the c++ code so I do not need to hard code the file path based on my system. open(test-data/dataFile.txt)Fruition
Based on the sample structure you posted, you can just do something like open(../../test-data/dataFile.txt). But I assumed you are looking for something more flexible.Logbook
B
0

Just specify a WORKING_DIRECTORY in the add_test function. Any path specification in the test cases will then be relative to the specified WORKING_DIRECTORY.

For example: In your root CMakeLists.txt

# ...
add_executable(<name of your test executable> src/test/test.cpp)

# ...

add_test(NAME <arbitrary name> COMMAND <name of your test executable> WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}/src/test/")

And then in your google tests use paths like "../test-data/expected_values.csv"

Butyraceous answered 18/12, 2022 at 7:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.