[Boost.Test] What's the best way to make custom assertions?
[Please do not mail me a copy of your followup] I want to make custom assertion methods that report the failure location as the place where the custom assertion is invoked, not the location where the BOOST_REQUIRE_xxx macros are used in the implementation of the custom assertion. In my own code, when I wanted to do report the point of invocation instead of the point of implementation, I implemented my code along the lines of void report(char const* file, int line) { // ... // output a message using line and file // ... } #define REPORT() report(__FILE__, __LINE__) void code() { REPORT(); // report something interesting here } When I look at how the assertion macros are implemented in Boost.Test, it seems that __FILE__ and __LINE__ are substituted down pretty far in the macro invocation chain. This means that if I want to write my own custom assertion that reports messages at the point of invocation and not at the point of implementation, I have to call these very low-level macro facilities and duplicate a bunch of stuff that's in Boost.Test. One thing I don't want to do is make a gigantic multi-line macro for my custom assertion. I really don't like using macros for things that could be done with functions and a custom assertion, IMO, falls into that category. Is there a clean way of implementing a custom assertion in the manner I've described without replicating a bunch of the intermediate layers of Boost.Test's macros? Gennady, if you're reading this and there isn't a clean way of doing what I'd like, are you willing to accept a refactoring changeset that promotes __FILE__ and __LINE__ arguments higher in the macro call chain? -- "The Direct3D Graphics Pipeline" free book http://tinyurl.com/d3d-pipeline The Computer Graphics Museum http://computergraphicsmuseum.org The Terminals Wiki http://terminals.classiccmp.org Legalize Adulthood! (my blog) http://legalizeadulthood.wordpress.com
Richard
I want to make custom assertion methods that report the failure location as the place where the custom assertion is invoked, not the location where the BOOST_REQUIRE_xxx macros are used in the implementation of the custom assertion.
Hi Richard, Frankly I do not follow what you want exactly. BOOST_REQUIRE reports a location of that statement. What do you want to report? It might be that you want something like this: void check_op1( char const* f, int l ) { BOOST_REQUIRE( expr, f, l ); } BOOST_AUTO_TEST_CASE( t1 ) { check_op1( __FILE_, __LINE__ ); } BOOST_AUTO_TEST_CASE( t2 ) { check_op1( __FILE_, __LINE__ ); } If this is the case, I'd rather you use new BOOST_TEST_CONTEXT facility and implement check_op1 like this: void check_op1( char const* f, int l ) { BOOST_TEST_CONTEXT( "Testing invoked from: " << f << "(" << l << ")" ) { BOOST_REQUIRE( expr1 ); BOOST_REQUIRE( expr2 ); } }
Le 23/10/12 19:11, Gennadiy Rozental a écrit :
Richard
writes: I want to make custom assertion methods that report the failure location as the place where the custom assertion is invoked, not the location where the BOOST_REQUIRE_xxx macros are used in the implementation of the custom assertion. Hi Richard,
Frankly I do not follow what you want exactly. BOOST_REQUIRE reports a location of that statement. What do you want to report?
It might be that you want something like this:
void check_op1( char const* f, int l ) { BOOST_REQUIRE( expr, f, l ); }
BOOST_AUTO_TEST_CASE( t1 ) { check_op1( __FILE_, __LINE__ ); }
BOOST_AUTO_TEST_CASE( t2 ) { check_op1( __FILE_, __LINE__ ); }
If this is the case, I'd rather you use new BOOST_TEST_CONTEXT facility and implement check_op1 like this:
void check_op1( char const* f, int l ) { BOOST_TEST_CONTEXT( "Testing invoked from: " << f << "(" << l << ")" ) { BOOST_REQUIRE( expr1 ); BOOST_REQUIRE( expr2 ); } }
Would this works as well? void check_op1() { BOOST_REQUIRE( expr ); } BOOST_AUTO_TEST_CASE( t1 ) { BOOST_TEST_CONTEXT( "Testing invoked from: " << __FILE__ << "(" << __LINE__ << ")" ); check_op1( ); } Best, Vicente
[Please do not mail me a copy of your followup] boost-users@lists.boost.org spake the secret code <5086D292.3000908@wanadoo.fr> thusly:
BOOST_TEST_CONTEXT( "Testing invoked from: " << __FILE__ << "(" << __LINE__ << ")" );
Writing this is an unnecessary burden on authors of custom assertions and further more doesn't provide me with a message in the output that is double-clickable from the IDE to take me to the point of failure, like the existing failure messages. -- "The Direct3D Graphics Pipeline" free book http://tinyurl.com/d3d-pipeline The Computer Graphics Museum http://computergraphicsmuseum.org The Terminals Wiki http://terminals.classiccmp.org Legalize Adulthood! (my blog) http://legalizeadulthood.wordpress.com
Vicente J. Botet Escriba
Would this works as well? void check_op1() { BOOST_REQUIRE( expr ); } BOOST_AUTO_TEST_CASE( t1 ) { BOOST_TEST_CONTEXT( " Testing invoked from: " << __FILE__ << "(" << __LINE__ << ")" ); check_op1( ); }
Yes. It will, but in my case this statement needs to be written once. Gennadiy
[Please do not mail me a copy of your followup]
boost-users@lists.boost.org spake the secret code
Vicente J. Botet Escriba
writes: Would this works as well? void check_op1() { BOOST_REQUIRE( expr ); } BOOST_AUTO_TEST_CASE( t1 ) { BOOST_TEST_CONTEXT( " Testing invoked from: " << __FILE__ << "(" << __LINE__ << ")" ); check_op1( ); }
Yes. It will, but in my case this statement needs to be written once.
What I'm proposing wouldn't require even this one statement to be written and reuses the existing mechanisms in Boost.Test instead of burdening the author/user of a custom assertion with even more code that they have to write. -- "The Direct3D Graphics Pipeline" free book http://tinyurl.com/d3d-pipeline The Computer Graphics Museum http://computergraphicsmuseum.org The Terminals Wiki http://terminals.classiccmp.org Legalize Adulthood! (my blog) http://legalizeadulthood.wordpress.com
[Please do not mail me a copy of your followup]
boost-users@lists.boost.org spake the secret code
Richard
writes: I want to make custom assertion methods that report the failure location as the place where the custom assertion is invoked, not the location where the BOOST_REQUIRE_xxx macros are used in the implementation of the custom assertion.
Hi Richard,
Frankly I do not follow what you want exactly. BOOST_REQUIRE reports a location of that statement. What do you want to report?
I don't propose to change BOOST_REQUIRE; I want a macro just below BOOST_REQUIRE (and _CHECK, etc.) that allows me to supply the file and line number for the purposes of reporting failures. This is already done several layers below in the existing macros.
If this is the case, I'd rather you use new BOOST_TEST_CONTEXT facility and implement check_op1 like this:
void check_op1( char const* f, int l ) { BOOST_TEST_CONTEXT( "Testing invoked from: " << f << "(" << l << ")" ) { BOOST_REQUIRE( expr1 ); BOOST_REQUIRE( expr2 ); } }
My version of Boost.Test doesn't have BOOST_TEST_CONTEXT, so I can't use that. However, from looking at http://lists.boost.org/boost-commit/2011/09/36947.php it seems way more mechanism than I need and more importantly isn't the mechanism I want from what I can tell. I shouldn't have to decorate my test code with extra messaging context just because I'm invoking a custom assertion. A custom assertion should be just as usable as the built-in assertions to Boost.Test, i.e. it should require nothing more than using BOOST_REQUIRE requires right now. All I need is for __FILE__ and __LINE__ to be substituted in at the first level of macro expansion. BOOST_REQUIRE expands to a call to BOOST_CHECK_IMPL: #define BOOST_REQUIRE( P ) \ BOOST_CHECK_IMPL( (P), BOOST_TEST_STRINGIZE( P ), REQUIRE, CHECK_PRED ) BOOST_CHECK_IMPL expands to a call to BOOST_TEST_TOOL_IMPL: #define BOOST_CHECK_IMPL( P, check_descr, TL, CT ) \ do { \ BOOST_TEST_PASSPOINT(); \ BOOST_TEST_TOOL_IMPL( check_impl, P, check_descr, TL, CT ), 0 );\ } while( ::boost::test_tools::dummy_cond ) \ /**/ BOOST_TEST_TOOL_IMPL is where __FILE__ and __LINE__ finally appear: #define BOOST_TEST_TOOL_IMPL( func, P, check_descr, TL, CT ) \ ::boost::test_tools::tt_detail::func( \ P, \ ::boost::unit_test::lazy_ostream::instance() << check_descr, \ BOOST_TEST_L(__FILE__), \ static_caststd::size_t(__LINE__), \ ::boost::test_tools::tt_detail::TL, \ ::boost::test_tools::tt_detail::CT \ /**/ I propose a refactoring like: #define BOOST_REQUIRE( P ) BOOST_REQUIRE_FL( P, __FILE__, __LINE__ ) #define BOOST_REQUIRE_FL(P, F, L) \ BOOST_CHECK_IMPL( (P), BOOST_TEST_STRINGIZE( P ), REQUIRE, CHECK_PRED, F, L ) #define BOOST_CHECK_IMPL( P, check_descr, TL, CT, F, L ) \ do { \ BOOST_TEST_PASSPOINT(); \ BOOST_TEST_TOOL_IMPL( check_impl, P, check_descr, TL, CT, F, L ), 0 );\ } while( ::boost::test_tools::dummy_cond ) \ /**/ #define BOOST_TEST_TOOL_IMPL( func, P, check_descr, TL, CT, F, L ) \ ::boost::test_tools::tt_detail::func( \ P, \ ::boost::unit_test::lazy_ostream::instance() << check_descr, \ BOOST_TEST_L(F), \ static_caststd::size_t(L), \ ::boost::test_tools::tt_detail::TL, \ ::boost::test_tools::tt_detail::CT \ /**/ There may be other places where F,L need to be passed down; it looks like BOOST_TEST_PASSPOINT uses it as well. -- "The Direct3D Graphics Pipeline" free book http://tinyurl.com/d3d-pipeline The Computer Graphics Museum http://computergraphicsmuseum.org The Terminals Wiki http://terminals.classiccmp.org Legalize Adulthood! (my blog) http://legalizeadulthood.wordpress.com
[Please do not mail me a copy of your followup]
boost-users@lists.boost.org spake the secret code
All I need is for __FILE__ and __LINE__ to be substituted in at the first level of macro expansion. [...]
I propose a refactoring like:
#define BOOST_REQUIRE( P ) BOOST_REQUIRE_FL( P, __FILE__, __LINE__ ) [...]
Gennady, if I make such a patch, will it be accepted? -- "The Direct3D Graphics Pipeline" free book http://tinyurl.com/d3d-pipeline The Computer Graphics Museum http://computergraphicsmuseum.org The Terminals Wiki http://terminals.classiccmp.org Legalize Adulthood! (my blog) http://legalizeadulthood.wordpress.com
participants (3)
-
Gennadiy Rozental
-
legalize+jeeves@mail.xmission.com
-
Vicente J. Botet Escriba