Last active
January 8, 2016 10:33
-
-
Save martinmoene/6683fc0945eaad00c622 to your computer and use it in GitHub Desktop.
EXPECT_ABORTS for lest test framework (C++11) - substitute ::abort(), throw
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Death test for abort/assert - substitute ::abort() | |
// | |
// Expect_aborts succeeds for std::abort() [pass] | |
// Expect_aborts succeeds for assert(false) [pass] | |
// Expect_aborts reports assert(true) [fail] | |
// Expect_aborts reports an unexpected standard exception [fail] | |
// Expect_aborts reports an unexpected non-standard exception [fail] | |
// Expect_no_abort succeeds for assert(true) [pass] | |
// Expect_no_abort reports std::abort() [fail] | |
// Expect_no_abort reports assert(false) [fail] | |
// Expect_no_abort reports an unexpected standard exception [fail] | |
// Expect_no_abort reports an unexpected non-standard exception [fail] | |
#include <lest.hpp> | |
// ----------------------------------------------------------------------- | |
// Additions to lest.hpp: | |
#include <io.h> | |
#include <fcntl.h> | |
#if ! defined( lest_NO_SHORT_MACRO_NAMES ) | |
# define EXPECT_NO_ABORT lest_EXPECT_NO_ABORT | |
# define EXPECT_ABORTS lest_EXPECT_ABORTS | |
#endif | |
#define lest_EXPECT_NO_ABORT( expr ) \ | |
do \ | |
{ \ | |
try \ | |
{ \ | |
lest::scoped_abort_substitute lest_UNIQUE( id ); \ | |
try \ | |
{ \ | |
expr; \ | |
} \ | |
catch( lest::death const & ) \ | |
{ \ | |
throw lest::aborted{ "failed", lest_LOCATION, #expr }; \ | |
} \ | |
} \ | |
catch (...) \ | |
{ \ | |
lest::inform( lest_LOCATION, #expr ); \ | |
} \ | |
if ( lest_env.pass ) \ | |
lest::report( lest_env.os, lest::not_aborted{ "passed", lest_LOCATION, #expr }, lest_env.testing ); \ | |
} while ( lest::is_false() ) | |
#define lest_EXPECT_ABORTS( expr ) \ | |
do \ | |
{ \ | |
try \ | |
{ \ | |
lest::scoped_abort_substitute lest_UNIQUE( id ); \ | |
try \ | |
{ \ | |
expr; \ | |
} \ | |
catch( lest::death const & ) \ | |
{ \ | |
if ( lest_env.pass ) \ | |
lest::report( lest_env.os, lest::aborted{ "passed", lest_LOCATION, #expr }, lest_env.testing ); \ | |
break; \ | |
} \ | |
} \ | |
catch (...) \ | |
{ \ | |
lest::inform( lest_LOCATION, #expr ); \ | |
} \ | |
throw lest::not_aborted{ "failed", lest_LOCATION, #expr }; \ | |
} \ | |
while ( lest::is_false() ) | |
#ifndef lest_ABORT_SIGNATURE | |
# if _MSC_VER | |
# define lest_NORETURN __declspec(noreturn) | |
# define lest_ABORT_SIGNATURE() _ACRTIMP lest_NORETURN void __cdecl abort(void) | |
# else | |
# define lest_NORETURN [[noreturn]] | |
# define lest_ABORT_SIGNATURE() lest_NORETURN void __cdecl abort() | |
# endif | |
#else | |
# ifndef lest_NORETURN | |
# define lest_NORETURN | |
# endif | |
#endif | |
#if _WIN32 | |
# define lest_DEV_NULL "nul" | |
# else | |
# define lest_DEV_NULL "/dev/null" | |
#endif | |
namespace lest { | |
struct death {}; | |
struct aborted : message | |
{ | |
aborted( text kind, location where, text expr ) | |
: message{ kind + ": aborted", where, expr } {} | |
}; | |
struct not_aborted : message | |
{ | |
not_aborted( text kind, location where, text expr ) | |
: message{ kind + ": didn't abort", where, expr } {} | |
}; | |
// substitute for ::abort(), | |
// inhibit/restore output to stderr to suppress output of assert(). | |
// non-thread-safe | |
class scoped_abort_substitute | |
{ | |
public: | |
scoped_abort_substitute() | |
{ | |
inhibit_stderr(); | |
} | |
~scoped_abort_substitute() | |
{ | |
restore_stderr(); | |
} | |
lest_NORETURN static void abort() | |
{ | |
throw death{}; | |
} | |
private: | |
void inhibit_stderr() | |
{ | |
fflush( stderr ); | |
stderr_org = dup( 2 ); | |
stderr_new = open( lest_DEV_NULL, O_WRONLY ); | |
dup2 ( stderr_new, 2 ); | |
close( stderr_new ); | |
} | |
void restore_stderr() | |
{ | |
fflush( stdout ); | |
dup2 ( stderr_org, 2 ); | |
close ( stderr_org ); | |
} | |
int stderr_org = 0; | |
int stderr_new = 0; | |
}; | |
} // namespace lest | |
// substitute ::abort(): | |
lest_ABORT_SIGNATURE() | |
{ | |
lest::scoped_abort_substitute::abort(); | |
} | |
// ----------------------------------------------------------------------- | |
// Usage: | |
#include <cassert> | |
#define CASE( name ) lest_CASE( specification, name ) | |
static lest::tests specification; | |
struct user_type{}; | |
// report value of __cplusplus: | |
CASE( "__cplusplus" ) | |
{ | |
EXPECT( __cplusplus == 0 ); | |
} | |
// test for abort: | |
CASE( "Expect_aborts succeeds for std::abort() " "[pass]" ) | |
{ | |
EXPECT_ABORTS( std::abort() ); | |
} | |
CASE( "Expect_aborts succeeds for assert(false) " "[pass]" ) | |
{ | |
EXPECT_ABORTS( assert( false ) ); | |
} | |
CASE( "Expect_aborts reports assert(true) " "[fail]" ) | |
{ | |
EXPECT_ABORTS( assert( true ) ); | |
} | |
CASE( "Expect_aborts reports an unexpected standard exception " "[fail]" ) | |
{ | |
EXPECT_ABORTS( throw std::runtime_error("augh") ); | |
} | |
CASE( "Expect_aborts reports an unexpected non-standard exception " "[fail]" ) | |
{ | |
EXPECT_ABORTS( throw user_type{} ); | |
} | |
// test for no abort: | |
CASE( "Expect_no_abort succeeds for assert(true) " "[pass]" ) | |
{ | |
EXPECT_NO_ABORT( assert( true ) ); | |
} | |
CASE( "Expect_no_abort reports std::abort() " "[fail]" ) | |
{ | |
EXPECT_NO_ABORT( std::abort() ); | |
} | |
CASE( "Expect_no_abort reports assert(false) " "[fail]" ) | |
{ | |
EXPECT_NO_ABORT( assert( false ) ); | |
} | |
CASE( "Expect_no_abort reports an unexpected standard exception " "[fail]" ) | |
{ | |
EXPECT_NO_ABORT( throw std::runtime_error("augh") ); | |
} | |
CASE( "Expect_no_abort reports an unexpected non-standard exception " "[fail]" ) | |
{ | |
EXPECT_NO_ABORT( throw user_type{} ); | |
} | |
// run tests: | |
int main( int argc, char * argv[] ) | |
{ | |
return lest::run( specification, argc, argv /*, std::cout */ ); | |
} | |
// ----------------------------------------------------------------------- | |
// Compilation: | |
#if 0 | |
cl -EHsc -Dlest_FEATURE_AUTO_REGISTER=1 -I../../../lest/ main-own-abort.cpp && main-own-abort.exe | |
g++ -Wall -std=c++11 -Dlest_FEATURE_AUTO_REGISTER=1 -I../../../lest/ -o main-own-abort.exe main-own-abort.cpp && main-own-abort.exe --pass | |
// -Dlest_ABORT_SIGNATURE()="void __cdecl abort()" | |
#endif | |
// Output: | |
// main-own-abort.cpp:177: failed: __cplusplus: __cplusplus == 0 for 201103 == 0 | |
// main-own-abort.cpp:184: passed: aborted: Expect_aborts succeeds for std::abort() [pass]: std::abort() | |
// main-own-abort.cpp:189: passed: aborted: Expect_aborts succeeds for assert(false) [pass]: assert( false ) | |
// main-own-abort.cpp:194: failed: didn't abort: Expect_aborts reports assert(true) [fail]: assert( true ) | |
// main-own-abort.cpp:199: failed: got unexpected exception with message "augh": Expect_aborts reports an unexpected standard exception [fail]: throw std::runtime_error("augh") | |
// main-own-abort.cpp:204: failed: got unexpected exception of unknown type: Expect_aborts reports an unexpected non-standard exception [fail]: throw user_type{} | |
// main-own-abort.cpp:211: passed: didn't abort: Expect_no_abort succeeds for assert(true) [pass]: assert( true ) | |
// main-own-abort.cpp:216: failed: aborted: Expect_no_abort reports std::abort() [fail]: std::abort() | |
// main-own-abort.cpp:221: failed: aborted: Expect_no_abort reports assert(false) [fail]: assert( false ) | |
// main-own-abort.cpp:226: failed: got unexpected exception with message "augh": Expect_no_abort reports an unexpected standard exception [fail]: throw std::runtime_error("augh") | |
//main-own-abort.cpp:231: failed: got unexpected exception of unknown type: Expect_no_abort reports an unexpected non-standard exception [fail]: throw user_type{} | |
// 8 out of 11 selected tests failed. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment