@ -46,27 +46,19 @@ extern std::string TmpDir(Env* env = Env::Default());
// runs may be able to vary the seed.
// runs may be able to vary the seed.
extern int RandomSeed ( ) ;
extern int RandomSeed ( ) ;
class TesterHelper ;
// An instance of Tester is allocated to hold temporary state during
// An instance of Tester is allocated to hold temporary state during
// the execution of an assertion.
// the execution of an assertion.
class Tester {
class Tester {
friend class TesterHelper ;
private :
private :
bool ok_ ;
bool ok_ ;
const char * fname_ ;
int line_ ;
std : : stringstream ss_ ;
std : : stringstream ss_ ;
public :
public :
Tester ( const char * f , int l )
Tester ( ) : ok_ ( true ) { }
: ok_ ( true ) , fname_ ( f ) , line_ ( l ) {
}
~ Tester ( ) {
if ( ! ok_ ) {
fprintf ( stderr , " %s:%d:%s \n " , fname_ , line_ , ss_ . str ( ) . c_str ( ) ) ;
port : : PrintStack ( 2 ) ;
exit ( 1 ) ;
}
}
Tester & Is ( bool b , const char * msg ) {
Tester & Is ( bool b , const char * msg ) {
if ( ! b ) {
if ( ! b ) {
@ -118,38 +110,85 @@ class Tester {
}
}
return * this ;
return * this ;
}
}
operator bool ( ) const { return ok_ ; }
} ;
class TesterHelper {
private :
const char * fname_ ;
int line_ ;
public :
TesterHelper ( const char * f , int l ) : fname_ ( f ) , line_ ( l ) { }
void operator = ( const Tester & tester ) {
fprintf ( stderr , " %s:%d:%s \n " , fname_ , line_ , tester . ss_ . str ( ) . c_str ( ) ) ;
port : : PrintStack ( 2 ) ;
exit ( 1 ) ;
}
} ;
} ;
# define ASSERT_TRUE(c) ::rocksdb::test::Tester(__FILE__, __LINE__).Is((c), #c)
// This is trying to solve:
# define ASSERT_OK(s) ::rocksdb::test::Tester(__FILE__, __LINE__).IsOk((s))
// * Evaluate expression
# define ASSERT_NOK(s) ::rocksdb::test::Tester(__FILE__, __LINE__).IsNotOk((s))
// * Abort the test if the evaluation is not successful with the evaluation
# define ASSERT_EQ(a,b) ::rocksdb::test::Tester(__FILE__, __LINE__).IsEq((a),(b))
// details.
# define ASSERT_NE(a,b) ::rocksdb::test::Tester(__FILE__, __LINE__).IsNe((a),(b))
// * Support operator << with ASSERT* for extra messages provided by the user
# define ASSERT_GE(a,b) ::rocksdb::test::Tester(__FILE__, __LINE__).IsGe((a),(b))
// code of ASSERT*
# define ASSERT_GT(a,b) ::rocksdb::test::Tester(__FILE__, __LINE__).IsGt((a),(b))
//
# define ASSERT_LE(a,b) ::rocksdb::test::Tester(__FILE__, __LINE__).IsLe((a),(b))
// For the third, we need to make sure that an expression at the end of macro
# define ASSERT_LT(a,b) ::rocksdb::test::Tester(__FILE__, __LINE__).IsLt((a),(b))
// supports << operator. But since we can have multiple of << we cannot abort
// inside implementation of operator <<, as we may miss some extra message. That
# define TCONCAT(a,b) TCONCAT1(a,b)
// is why there is TesterHelper with operator = which has lower precedence then
# define TCONCAT1(a,b) a##b
// operator <<, and it will be called after all messages from use code are
// accounted by <<.
# define TEST(base,name) \
//
class TCONCAT ( _Test_ , name ) : public base { \
// operator bool is added to Tester to make possible its declaration inside if
public : \
// statement and do not pollute its outer scope with the name tester. But in C++
void _Run ( ) ; \
// we cannot do any other operations inside if statement besides declaration.
static void _RunIt ( ) { \
// Then in order to get inside if body there are two options: make operator
TCONCAT ( _Test_ , name ) t ; \
// Tester::bool return true if ok_ == false or put the body into else part.
t . _Run ( ) ; \
# define TEST_EXPRESSION_(expression) \
} \
if ( : : rocksdb : : test : : Tester & tester = ( expression ) ) \
} ; \
; \
bool TCONCAT ( _Test_ignored_ , name ) = \
else \
: : rocksdb : : test : : RegisterTest ( # base , # name , & TCONCAT ( _Test_ , name ) : : _RunIt ) ; \
: : rocksdb : : test : : TesterHelper ( __FILE__ , __LINE__ ) = tester
void TCONCAT ( _Test_ , name ) : : _Run ( )
# define ASSERT_TRUE(c) TEST_EXPRESSION_(::rocksdb::test::Tester().Is((c), #c))
# define ASSERT_OK(s) TEST_EXPRESSION_(::rocksdb::test::Tester().IsOk((s)))
# define ASSERT_NOK(s) TEST_EXPRESSION_(::rocksdb::test::Tester().IsNotOk((s)))
# define ASSERT_EQ(a, b) \
TEST_EXPRESSION_ ( : : rocksdb : : test : : Tester ( ) . IsEq ( ( a ) , ( b ) ) )
# define ASSERT_NE(a, b) \
TEST_EXPRESSION_ ( : : rocksdb : : test : : Tester ( ) . IsNe ( ( a ) , ( b ) ) )
# define ASSERT_GE(a, b) \
TEST_EXPRESSION_ ( : : rocksdb : : test : : Tester ( ) . IsGe ( ( a ) , ( b ) ) )
# define ASSERT_GT(a, b) \
TEST_EXPRESSION_ ( : : rocksdb : : test : : Tester ( ) . IsGt ( ( a ) , ( b ) ) )
# define ASSERT_LE(a, b) \
TEST_EXPRESSION_ ( : : rocksdb : : test : : Tester ( ) . IsLe ( ( a ) , ( b ) ) )
# define ASSERT_LT(a, b) \
TEST_EXPRESSION_ ( : : rocksdb : : test : : Tester ( ) . IsLt ( ( a ) , ( b ) ) )
# define TCONCAT(a, b) TCONCAT1(a, b)
# define TCONCAT1(a, b) a##b
# define TEST(base, name) \
class TCONCAT ( _Test_ , name ) : public base { \
public : \
void _Run ( ) ; \
static void _RunIt ( ) { \
TCONCAT ( _Test_ , name ) t ; \
t . _Run ( ) ; \
} \
} ; \
bool TCONCAT ( _Test_ignored_ , name ) = : : rocksdb : : test : : RegisterTest ( \
# base, #name, &TCONCAT(_Test_, name)::_RunIt); \
void TCONCAT ( _Test_ , name ) : : _Run ( )
// Register the specified test. Typically not used directly, but
// Register the specified test. Typically not used directly, but
// invoked via the macro expansion of TEST.
// invoked via the macro expansion of TEST.
extern bool RegisterTest ( const char * base , const char * name , void ( * func ) ( ) ) ;
extern bool RegisterTest ( const char * base , const char * name , void ( * func ) ( ) ) ;
} // namespace test
} // namespace test
} // namespace rocksdb
} // namespace rocksdb