Opened 6 years ago
Closed 6 years ago
#12712 closed Patches (fixed)
BOOST_AUTO_TEST_SUITE: Generate unique names by using __COUNTER__
Reported by: | Owned by: | Raffi Enficiaud | |
---|---|---|---|
Milestone: | Boost 1.64.0 | Component: | test |
Version: | Boost Development Trunk | Severity: | Problem |
Keywords: | Cc: | raffi.enficiaud@…, ki.stfu@… |
Description
There is a problem with non-unique names of <test_suite_name>_registrar in BOOST_AUTO_TEST_SUITE when joining multiple source files into one file using #include:
I have a project with huge number of tests in different files and it takes around 10 minutes to compile. The project structure is like:
.../test/data/foo.cpp:
`
#include "stdafx.h"
BOOST_AUTO_TEST_SUITE(data) BOOST_AUTO_TEST_SUITE(foo)
<my test cases>
BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_SUITE_END()
`
.../test/data/bar.cpp:
`
#include "stdafx.h"
BOOST_AUTO_TEST_SUITE(data) BOOST_AUTO_TEST_SUITE(bar)
<my test cases>
BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_SUITE_END()
`
To reduce the compilation time I included all sources into one file and after that I need to compile only that file (so it works much faster):
.../test/_all.cpp:
`
#include "stdafx.h"
#include "data/foo.cpp" #include "data/bar.cpp" and so on...
`
But when I'm compiling this file I get a multiple definitions of "data_registrar3" (3 is a substituted LINE).
I think we can use COUNTER if it's supported (it's not a standard feature but most of compilers support it) so that it will fix the problem.
Here is my patch:
`
$ diff unit_test_suite.hpp.original unit_test_suite.hpp -uar
--- unit_test_suite.hpp.original 2016-12-26 11:01:33.272912600 +0300
+++ unit_test_suite.hpp 2016-12-26 11:00:37.171138300 +0300
@@ -24,6 +24,11 @@
#include <boost/test/detail/pp_variadic.hpp>
+#if defined(COUNTER) +#define BOOST_TEST_UNIQUE_NUMBER COUNTER +#else +#define BOOST_TEST_UNIQUE_NUMBER LINE +#endif
@@ -120,7 +125,7 @@
#define BOOST_AUTO_TEST_SUITE_END() \
-BOOST_AUTO_TU_REGISTRAR( BOOST_JOIN( end_suite, LINE ) )( 1 ); \ +BOOST_AUTO_TU_REGISTRAR( BOOST_JOIN( end_suite, BOOST_TEST_UNIQUE_NUMBER ) )( 1 ); \
} \ //
@@ -298,7 +303,7 @@
#define BOOST_TEST_DECORATOR( D ) \ static boost::unit_test::decorator::collector const& \
-BOOST_JOIN(decorator_collector,LINE) = D; \ +BOOST_JOIN(decorator_collector,BOOST_TEST_UNIQUE_NUMBER) = D; \
//
@@ -322,7 +327,7 @@
#define BOOST_AUTO_TU_REGISTRAR( test_name ) \ static boost::unit_test::ut_detail::auto_test_unit_registrar \
-BOOST_JOIN( BOOST_JOIN( test_name, _registrar ), LINE ) \ +BOOST_JOIN( BOOST_JOIN( test_name, _registrar ), BOOST_TEST_UNIQUE_NUMBER ) \
// #define BOOST_AUTO_TC_INVOKER( test_name ) BOOST_JOIN( test_name, _invoker ) #define BOOST_AUTO_TC_UNIQUE_ID( test_name ) BOOST_JOIN( test_name, _id )
`
Change History (16)
comment:1 by , 6 years ago
comment:4 by , 6 years ago
Version: | Boost 1.62.0 → Boost Development Trunk |
---|
comment:5 by , 6 years ago
Owner: | changed from | to
---|
comment:6 by , 6 years ago
Hi there,
Would you mind checking the current state of boost.test without the #include "stdafx.h"
precompiled header? I looks weird to me that those registrar end-up at the same line.
comment:7 by , 6 years ago
Cc: | added |
---|
stdafx.h
doesn't play any special role in this case because I tested it on Linux with clang. So it can be renamed or even removed, it doesn't matter.
The fact is that __LINE__
is expanded to the current line number and if you have multiple files which define variables on the same line using this naming style then you will get an error.
You can reproduce it by following:
user@u14:~$ ls _all.cpp bar.cpp foo.cpp user@u14:~$ cat foo.cpp #include <boost/test/unit_test.hpp> BOOST_AUTO_TEST_SUITE(data) BOOST_AUTO_TEST_SUITE(foo) BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END() user@u14:~$ cat bar.cpp #include <boost/test/unit_test.hpp> BOOST_AUTO_TEST_SUITE(data) BOOST_AUTO_TEST_SUITE(bar) BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END() user@u14:~$ cat _all.cpp #define BOOST_TEST_MAIN #include <boost/test/unit_test.hpp> #include "foo.cpp" #include "bar.cpp" user@u14:~$ clang++ _all.cpp In file included from _all.cpp:5: ./bar.cpp:3:1: error: redefinition of 'data_registrar3' BOOST_AUTO_TEST_SUITE(data) ^ /usr/include/boost/test/unit_test_suite.hpp:45:73: note: expanded from macro 'BOOST_AUTO_TEST_SUITE' namespace suite_name { \ ^ /usr/include/boost/test/unit_test_suite.hpp:209:62: note: expanded from macro '\ BOOST_AUTO_TU_REGISTRAR' static boost::unit_test::ut_detail::auto_test_unit_registrar BOOST_JOIN( BOOST_JOIN( test_name, _registrar ), __LINE__ ) ^ /usr/include/boost/config/suffix.hpp:608:28: note: expanded from macro 'BOOST_JOIN' #define BOOST_JOIN( X, Y ) BOOST_DO_JOIN( X, Y ) ^ /usr/include/boost/config/suffix.hpp:609:31: note: expanded from macro 'BOOST_DO_JOIN' #define BOOST_DO_JOIN( X, Y ) BOOST_DO_JOIN2(X,Y) ^ /usr/include/boost/config/suffix.hpp:610:32: note: expanded from macro 'BOOST_DO_JOIN2' #define BOOST_DO_JOIN2( X, Y ) X##Y ^ <scratch space>:114:1: note: expanded from here data_registrar3 ^ ./foo.cpp:3:1: note: previous definition is here BOOST_AUTO_TEST_SUITE(data) ^ /usr/include/boost/test/unit_test_suite.hpp:45:73: note: expanded from macro 'BOOST_AUTO_TEST_SUITE' namespace suite_name { \ ^ /usr/include/boost/test/unit_test_suite.hpp:209:62: note: expanded from macro '\ BOOST_AUTO_TU_REGISTRAR' static boost::unit_test::ut_detail::auto_test_unit_registrar BOOST_JOIN( BOOST_JOIN( test_name, _registrar ), __LINE__ ) ^ /usr/include/boost/config/suffix.hpp:608:28: note: expanded from macro 'BOOST_JOIN' #define BOOST_JOIN( X, Y ) BOOST_DO_JOIN( X, Y ) ^ /usr/include/boost/config/suffix.hpp:609:31: note: expanded from macro 'BOOST_DO_JOIN' #define BOOST_DO_JOIN( X, Y ) BOOST_DO_JOIN2(X,Y) ^ /usr/include/boost/config/suffix.hpp:610:32: note: expanded from macro 'BOOST_DO_JOIN2' #define BOOST_DO_JOIN2( X, Y ) X##Y ^ <scratch space>:96:1: note: expanded from here data_registrar3 ^
comment:8 by , 6 years ago
Thanks for the clarification. The problem with __COUNTER__
is that it is not a standard macro, I would rather not include that. Also since those registrar are static, there is no clash in having the exact same declarations (in terms of lines) in 2 different compilation units, if you do not include everything in one place.
That is to me a really specific use case, and also has the following drawbacks:
- each time a .cpp changes, a very big block is recompiled
- you do not benefit from potential accelerations of the build system ( builds)
I am not sure the benefits of doing it the way you do outweigh the problems (maybe you have numbers). I would rather suggest a nasty patch: you can specify a line number with the #line
preprocessor directive, which may be used in conjunction with __COUNTER__
in your case to lower the risks for clashes.
comment:9 by , 6 years ago
I don't think I'm doing anything illegal and in my case the game is worth the candle.
__COUNTER__
is supported by major compilers (MSVC, Clang, GCC) and is already used in Boost library. Moreover, it suits better for generating unique names than __LINE__
.
So why we can't define BOOST_TEST_UNIQUE_NUMBER
macro, which refers to __COUNTER__
or (if it's not available to) __LINE__
?
comment:10 by , 6 years ago
I understand that this is properly handled by major compilers, but not all of them. Maybe there is a way to know if this macro is supported. If so, it would be possible to integrate that, if not then it will be a won't fix.
comment:11 by , 6 years ago
How about the way suggested above?
`
#if defined(COUNTER)
#define BOOST_TEST_UNIQUE_NUMBER COUNTER
#else
#define BOOST_TEST_UNIQUE_NUMBER LINE
#endif
`
comment:12 by , 6 years ago
Ugh... I meant
#if defined(__COUNTER__) #define BOOST_TEST_UNIQUE_NUMBER __COUNTER__ #else #define BOOST_TEST_UNIQUE_NUMBER __LINE__ #endif
comment:14 by , 6 years ago
Milestone: | To Be Determined → Boost 1.64.0 |
---|---|
Status: | new → assigned |
Would you please give a try to the branch topic/12712-several-test-suite-decl-in-same-comp-unit
?
Thanks,
comment:16 by , 6 years ago
Resolution: | → fixed |
---|---|
Status: | assigned → closed |
Merged to master, rev a2b73f5d7568e69162dfac213fab87eea0021ec5
Oops. I fixed its style:
There is a problem with non-unique names of
<test_suite_name>_registrar
inBOOST_AUTO_TEST_SUITE
when joining multiple source files into one file using#include
:I have a project with huge number of tests in different files and it takes around 10 minutes to compile. The project structure is like:
.../test/data/foo.cpp
:.../test/data/bar.cpp
:To reduce the compilation time I included all sources into one file and after that I need to compile only that file (so it works much faster):
.../test/_all.cpp
:But when I'm compiling this file I get a multiple definitions of
data_registrar3
(3
is a substituted__LINE__
).I think we can use
__COUNTER__
if it's supported (it's not a standard feature but most of compilers support it) so that it will fix the problem.Here is my patch: