I run this piece of code
#define BOOST_TEST_MAIN
#define BOOST_TEST_DYN_LINK
#include <boost/test/unit_test.hpp>
#include <boost/test/unit_test_log.hpp>
#include <boost/filesystem/fstream.hpp>
#include <iostream>
using namespace boost::unit_test;
using namespace std;
void TestFoo()
{
BOOST_CHECK(0==0);
}
test_suite* init_unit_test_suite( int argc, char* argv[] )
{
std::cout << "Enter init_unit_test_suite" << endl;
boost::unit_test::test_suite* master_test_suite =
BOOST_TEST_SUITE( "MasterTestSuite" );
master_test_suite->add(BOOST_TEST_CASE(&TestFoo));
return master_test_suite;
}
But at runtime it says
Test setup error: test tree is empty
Why does it not run the init_unit_test_suite function?
Did you actually dynamically link against the boost_unit_test framework library? Furthermore, the combination of manual test registration and the definition of BOOST_TEST_MAIN does not work. The dynamic library requires slightly different initialization routines.
The easiest way to avoid this hurdle is to use automatic test registration
#define BOOST_TEST_MAIN
#define BOOST_TEST_DYN_LINK
#include <boost/test/unit_test.hpp>
#include <boost/test/unit_test_log.hpp>
#include <boost/filesystem/fstream.hpp>
#include <iostream>
using namespace boost::unit_test;
using namespace std;
BOOST_AUTO_TEST_SUITE(MasterSuite)
BOOST_AUTO_TEST_CASE(TestFoo)
{
BOOST_CHECK(0==0);
}
BOOST_AUTO_TEST_SUITE_END()
This is more robust and scales much better when you add more and more tests.
I had exactly the same issue. Besides switching to automatic test registration, as suggested previously, you can also use static linking, i.e. by replacing
#define BOOST_TEST_DYN_LINK
with
#define BOOST_TEST_STATIC_LINK
This was suggested at the boost mailing list:
The easiest way to fix this is to [...] link with static library.
Dynamic library init API is slightly different since 1.34.1 and this is the
cause of the error you see. init_unit_test_suite function is not called in this
case.
Related
I have a small snipped of code, which just produces a function to get the current directory for either Windows or Linux platform:
#include <stdio.h> /* defines FILENAME_MAX */
#include <string>
#ifdef WINDOWS
#include <direct.h>
#define GetCurrentDir _getcwd
#else
#include <unistd.h>
#define GetCurrentDir getcwd
#endif
std::string getcwd(){
char mCurrentPath[FILENAME_MAX];
GetCurrentDir(mCurrentPath, sizeof(mCurrentPath));
return *(new std::string (mCurrentPath));
}
This is all great and working; however, I'd like to make the getcwd() function inside the namespace, fUtils, hence I did this:
#include <stdio.h> /* defines FILENAME_MAX */
#include <string>
#ifdef WINDOWS
#include <direct.h>
#define GetCurrentDir _getcwd
#else
#include <unistd.h>
#define GetCurrentDir getcwd
#endif
namespace fUtils{
std::string getcwd(){
char mCurrentPath[FILENAME_MAX];
GetCurrentDir(mCurrentPath, sizeof(mCurrentPath));
return *(new std::string (mCurrentPath));
}
}
But this gives an error in VSCode which says:
no matching function for call to 'getcwd'
What mistake am I making in this? If this isn't how I put the function to the namespace fUtils, then how should I put it into the namespace?
Your fUtils::getcwd() function is attempting to call itself when the GetCurrentDir macro is evaluated (to getcwd), and this results in a function that expects no argument but is being given two arguments.
To resolve this, add the global namespace operator (::) in the definitions for GetCurrentDir, as follows:
#ifdef WINDOWS
#include <direct.h>
#define GetCurrentDir ::_getcwd
#else
#include <unistd.h>
#define GetCurrentDir ::getcwd
#endif
Then, in your function body, it is clear to the compiler that your aren't looking for a 'recursive' (and invalid) call.
Use of macros in such context is invitation to problems in future.
Just wrap those functions with own API and all problems will be resolved.
Header file:
#include <string>
namepsace fUtils {
std::string getcwd();
}
Then you can have platform specific cpp files, Windows:
namepsace fUtils {
std::string getcwd() {
char mCurrentPath[FILENAME_MAX];
::_getcwd(mCurrentPath, sizeof(mCurrentPath));
return {mCurrentPath};
}
}
Mac version is obvious.
You also can use this macros inside single cpp file and this way contain them there if you do not what to do larger clean up.
Side notes:
there is boost::filesystem which has such api also use of boost::filesystem::path is quite handy
C++17 introduces std::filesystem, but it is not well supported yet (for example MacOS)
if you wrap this functionality in classes you will open your way for better testing (mocks).
I'm testing a huge piece of software and would like to use Catch for this task.
I'm using the "single include" version 1.9, integrating it in Visual Studio 2012 update 4 and using C++04 standard.
As you will see below, I use three ".cpp" files. Each of them reference:
a include file providing "abstraction" macros (eg. #define Assert(x) REQUIRE(x));
a utility file providing... utilities for the test;
the specific test target include files;
some "using namespace" statement, all cpp files "using" the same namespace;
the actual tests, written with the macros (eg. Assert(2 == getNumber())).
More details on the files content below.
This configuration works, but one of the test file is growing bigger by the day and I would like to split it in 3, or more. Now, say that I do the following:
take part of the content of a test test.cpp and move it in a new file test2.cpp;
add the same includes and defines to make it compile;
include the new file in my main
this error pops up when I run the tests:
=============================
No tests ran
error: TEST_CASE( "test 2" ) already defined.
First seen at c:\tests\catchtest2\catchtest2\test2.cpp(3)
Redefined at c:\tests\catchtest2\catchtest2\test2.cpp(3)
where test2.cpp is the new file.
If I move the content back to test.cpp it all works, but working with tests thousands of lines long is almost harder than working on the project itself, and the dimension could grow 3, 4 times bigger still.
Is there a way to split the tests in multiple files?
-- NOTES --
I reckon including Catch in a header and using the including header instead of catch.cpp directly is not a good idea, but I successfully used this configuration with 3 (exactly 3) included .cpp test files, and am unable to use this with 4 files.
I remember reading that it was somehow related to the line at which the components were defined, but I can also move the code so that the test cases are defined at different lines and the behaviour doesn't change.
I also tried to "clean and rebuild", because it may well be that dirty data is kept in the compiler / linker's caches, but to no avail.
I couldn't create an actual MWE right now, so I gave you a sketch of the test setup as accurate as I thought it could be needed. I'm more than willing to provide additional details or try and build an actual MWE and share it.
Any idea is appreciated!
My "working" code looks like this:
main.cpp
#define CATCH_CONFIG_RUNNER
#include "catch.hpp"
#include "test1.cpp"
#include "test2.cpp"
#include "test3.cpp"
int main( int argc, char* argv[] )
{
cleanDir("c:\\temp");
init (argv);
int result = Catch::Session().run( argc, argv );
return ( result < 0xff ? result : 0xff );
}
test1.cpp
#include "unitTestSuite.h"
#include "utils.h"
#include "systemundertest.h"
using namespace system::under::test;
my_test_case("test 1") {
my_section("does X") {
// tests...
}
}
my_test_case("test 2") {
my_section("does Y") {
// tests...
}
}
unitTestSuite.h
#ifndef UNIT_TEST_SUITE
#define UNIT_TEST_SUITE 1
#include "catch.hpp"
#define my_test_case(x) TEST_CASE("Testing: " x)
... // here is also a namespace with some unit test specific utils
#endif
utils.h
#ifndef _UTILS_
#define _UTILS_
// some global variables declared here and defined in utils.cpp
// template functions defined in the header
// non-template functions defined in utils.cpp
// a test generation namespace with some template functions and some non-template functions defined in utils.cpp
#endif
After the "split":
test1.cpp
#include "unitTestSuite.h"
#include "utils.h"
#include "systemundertest.h"
using namespace system::under::test;
my_test_case("test 1") {
my_section("does X") {
// tests...
}
}
test1.2.cpp
#include "unitTestSuite.h"
#include "utils.h"
#include "systemundertest.h"
using namespace system::under::test;
my_test_case("test 2") {
my_section("does Y") {
// tests...
}
}
main.cpp
#define CATCH_CONFIG_RUNNER
#include "catch.hpp"
#include "test1.cpp"
#include "test1.2.cpp"
#include "test2.cpp"
#include "test3.cpp"
int main( int argc, char* argv[] )
{
cleanDir("c:\\temp");
init (argv);
int result = Catch::Session().run( argc, argv );
return ( result < 0xff ? result : 0xff );
}
program output:
=============================
No tests ran
error: TEST_CASE( "test 2" ) already defined.
First seen at c:\tests\catchtest2\catchtest2\test1.2.cpp(3)
Redefined at c:\tests\catchtest2\catchtest2\test1.2.cpp(3)
Don’t include the cpp files, just add them to the project.
Your main.cpp file only needs the first two lines (a define and an include).
Trying to run some tests through the use of the boost test library by using the following code:
int main(int arg, char *argv[])
{
string help = "help";
#ifdef TESTING_CONSTANT
TestingPeerClass testingClass;
testingClass.test_method();
#else
//rest of the codre
#endif
}
Which calls the following test function found in another class called testing.h :
#define BOOST_TEST_MODULE mytest
#include <algorithm>
#include <boost/test/unit_test.hpp>
BOOST_AUTO_TEST_CASE(TestingPeerClass)
{
BOOST_CHECK(1 == 1);
}
when running the test a strange runtime error raises when it hits the BOOST_CHECK function.
I cant figure out why, any ideas? since when i built a new project it worked perfectly fine.
The documentation for pool in 1.53.0 claims that it is 'header-only'. However, a minimal program:
#include <boost/pool/pool_alloc.hpp>
int main() {
return 0;
}
ends up with undefined symbols from boost_system, and bcp thinks that boost_system is required. Is there #define or something to cure this?
This is a known bug. https://svn.boost.org/trac/boost/ticket/7085.
If you don't need multi-threading, we could
modify pool/detail/mutex.hpp to not to include <boost/thread/mutex.hpp> as described in the URL,
...
#if defined(BOOST_HAS_THREADS) && !defined(BOOST_NO_MT) && !defined(BOOST_POOL_NO_MT)
#include <boost/thread/mutex.hpp>
#endif
...
or, if you can't modify the files, fake the compiler that <boost/thread/mutex.hpp> has been defined:
#define BOOST_POOL_NO_MT // disable multi-threading
#define BOOST_THREAD_MUTEX_HPP // define the #include-guard to disable the header
#include <boost/pool/pool_alloc.hpp>
int main () {}
or, if you do need multi-threading, but C++11 is allowed, we could use std::mutex to substitute boost::mutex:
#define BOOST_THREAD_MUTEX_HPP
#include <mutex>
namespace boost {
using std::mutex;
}
#include <boost/pool/pool_alloc.hpp>
int main () {}
I'm trying to test a library that I've done (Calculus), in QTCreator for Windows.
I've created a main file, and a class in a separate file for the testing. If I compile the example found in http://www.boost.org/doc/libs/1_47_0/libs/test/doc/html/utf/user-guide/test-organization/manual-test-suite.html it works, and so the example found in http://www.boost.org/doc/libs/1_47_0/libs/test/doc/html/utf/user-guide/test-organization/manual-nullary-test-case.html also works.
But when I try to compile my project I've a lot (over 500) errors of multiple definitions. Below you can find my files. As you can see I've also tried to put some guard around boost headers, but it does not work. What am I doing wrong?
main.cpp
#include "testcalculus.h"
#ifndef USE_BOOST_HEADERS
#define USE_BOOST_HEADERS
#include <boost/test/included/unit_test.hpp>
#include <boost/bind.hpp>
#endif
using namespace boost::unit_test;
test_suite*
init_unit_test_suite( int argc, char* argv[] )
{
WRayTesting::TestCalculus xTestCalculus;
test_suite* pxTestSuiteCalculus = BOOST_TEST_SUITE("Test Calculus");
pxTestSuiteCalculus->add(BOOST_TEST_CASE( boost::bind(&WRayTesting::TestCalculus::testCartesianPoint2D, &xTestCalculus)));
framework::master_test_suite().add(pxTestSuiteCalculus);
return 0;
}
testcalculus.h
#ifndef TESTCALCULUS_H
#define TESTCALCULUS_H
#ifndef USE_BOOST_HEADERS
#define USE_BOOST_HEADERS
#include <boost/test/included/unit_test.hpp>
#include <boost/bind.hpp>
#endif
#include "cartesianpoint2d.h"
#include "cartesianvector2d.h"
namespace WRayTesting
{
/** Class for testing the Calculus project */
class TestCalculus
{
public:
//! Constructor
TestCalculus();
//! Testing class point
void testCartesianPoint2D();
private:
};
} // namespace WRayTesting
#endif // TESTCALCULUS_H
testcalculus.cpp
#include "testcalculus.h"
#ifndef USE_BOOST_HEADERS
#define USE_BOOST_HEADERS
#include <boost/test/included/unit_test.hpp>
#include <boost/bind.hpp>
#endif
namespace WRayTesting
{
using ::Calculus::CartesianPoint2D;
using namespace boost::unit_test;
/**
* Constructor
*/
TestCalculus::TestCalculus()
{
}
/**
* Test the CartesianPoint2D class.
*/
void TestCalculus::testCartesianPoint2D()
{
// Default constructor
CartesianPoint2D xTestingPoint;
BOOST_CHECK(0.0 == xTestingPoint.getX());
BOOST_CHECK(0.0 == xTestingPoint.getY());
}
} // namespace WRayTesting
Compile output
debug/testcalculus.o:c:/lib/boost/boost/test/impl/compiler_log_formatter.ipp:62: multiple definition of `boost::unit_test::output::compiler_log_formatter::log_start(std::ostream&, unsigned long)'
debug/main.o:c:/lib/boost/boost/test/impl/compiler_log_formatter.ipp:62: first defined here
debug/testcalculus.o:c:/lib/boost/boost/test/impl/compiler_log_formatter.ipp:72: multiple definition of `boost::unit_test::output::compiler_log_formatter::log_finish(std::ostream&)'
debug/main.o:c:/lib/boost/boost/test/impl/compiler_log_formatter.ipp:72: first defined here
debug/testcalculus.o:c:/lib/boost/boost/test/impl/compiler_log_formatter.ipp:80: multiple definition of `boost::unit_test::output::compiler_log_formatter::log_build_info(std::ostream&)'
debug/main.o:c:/lib/boost/boost/test/impl/compiler_log_formatter.ipp:80: first defined here
debug/testcalculus.o:c:/lib/boost/boost/test/impl/compiler_log_formatter.ipp:93: multiple definition of `boost::unit_test::output::compiler_log_formatter::test_unit_start(std::ostream&, boost::unit_test::test_unit const&)'
debug/main.o:c:/lib/boost/boost/test/impl/compiler_log_formatter.ipp:93: first defined here
debug/testcalculus.o:c:/lib/boost/boost/test/impl/compiler_log_formatter.ipp:103: multiple definition of `boost::unit_test::output::compiler_log_formatter::test_unit_finish(std::ostream&, boost::unit_test::test_unit const&, unsigned long)'
debug/main.o:c:/lib/boost/boost/test/impl/compiler_log_formatter.ipp:103: first defined here
...........
You cannot include #include in multiple files within the same test module. You either need to switch to library or put everything inside single file