Skip to content

Instantly share code, notes, and snippets.

@martinmoene
Last active January 8, 2016 10:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save martinmoene/6683fc0945eaad00c622 to your computer and use it in GitHub Desktop.
Save martinmoene/6683fc0945eaad00c622 to your computer and use it in GitHub Desktop.
EXPECT_ABORTS for lest test framework (C++11) - substitute ::abort(), throw
// 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