Skip to content

Commit

Permalink
[SofaKernel] Add BaseTest & NumericTest in helper.
Browse files Browse the repository at this point in the history
The idea is to have simple and basic testing in core then create variant of these
when we want to do InSimulation tests.

The old SofaTestMessageHandler is now forwarding to the base class.
  • Loading branch information
damienmarchal committed Oct 12, 2017
1 parent 81e12e0 commit fcbb885
Show file tree
Hide file tree
Showing 7 changed files with 616 additions and 502 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
#include <gtest/gtest-spi.h>

#include <sofa/helper/testing/BaseTest.h>
using sofa::helper::testing::BaseTest ;


////////////// IMPLEMENTS A TEST PREDICATE TO VALIDE THAT A THERE IS AT LEAST ONE MESSAGE
/// THE IS EMITTED TO VALDIATE THE BEHAVIOR OF THE FRAMEWORK.
namespace testing {
namespace internal{
// This predicate-formatter checks that 'results' contains a test part
// failure of the given type and that the failure message contains the
// given substring.
AssertionResult AtLeastOneFailure(const char* /* results_expr */,
const char* /* type_expr */,
const char* /* substr_expr */,
const TestPartResultArray& results,
TestPartResult::Type type,
const string& substr) {
const std::string expected(type == TestPartResult::kFatalFailure ?
"at least 1 fatal failure" :
"at least 1 non-fatal failure");
Message msg;
if (results.size() == 0) {
msg << "Expected: " << expected << "\n"
<< " Actual: " << results.size() << " failures";
for (int i = 0; i < results.size(); i++) {
msg << "\n" << results.GetTestPartResult(i);
}
return AssertionFailure() << msg;
}

const TestPartResult& r = results.GetTestPartResult(0);
if (r.type() != type) {
return AssertionFailure() << "Expected: " << expected << "\n"
<< " Actual:\n"
<< r;
}

if (strstr(r.message(), substr.c_str()) == NULL) {
return AssertionFailure() << "Expected: " << expected << " containing \""
<< substr << "\"\n"
<< " Actual:\n"
<< r;
}

return AssertionSuccess();
}

// A helper class for implementing EXPECT_FATAL_FAILURE() and
// EXPECT_NONFATAL_FAILURE(). Its destructor verifies that the given
// TestPartResultArray contains exactly one failure that has the given
// type and contains the given substring. If that's not the case, a
// non-fatal failure will be generated.
class GTEST_API_ AnyFailureChecker {
public:
// The constructor remembers the arguments.
AnyFailureChecker(const TestPartResultArray* results,
TestPartResult::Type type,
const string& substr);
~AnyFailureChecker();
private:
const TestPartResultArray* const results_;
const TestPartResult::Type type_;
const string substr_;

GTEST_DISALLOW_COPY_AND_ASSIGN_(AnyFailureChecker);
};


// The constructor of SingleFailureChecker remembers where to look up
// test part results, what type of failure we expect, and what
// substring the failure message should contain.
AnyFailureChecker:: AnyFailureChecker(
const TestPartResultArray* results,
TestPartResult::Type type,
const string& substr)
: results_(results),
type_(type),
substr_(substr) {}

// The destructor of SingleFailureChecker verifies that the given
// TestPartResultArray contains exactly one failure that has the given
// type and contains the given substring. If that's not the case, a
// non-fatal failure will be generated.
AnyFailureChecker::~AnyFailureChecker() {
EXPECT_PRED_FORMAT3(AtLeastOneFailure, *results_, type_, substr_);
}
} // internal
} // testing

#define EXPECT_ATLEASE_ONE_NONFATAL_FAILURE(statement, substr) \
do {\
::testing::TestPartResultArray gtest_failures;\
::testing::internal::AnyFailureChecker gtest_checker(\
&gtest_failures, ::testing::TestPartResult::kNonFatalFailure, \
(substr));\
{\
::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
::testing::ScopedFakeTestPartResultReporter:: \
INTERCEPT_ONLY_CURRENT_THREAD, &gtest_failures);\
if (::testing::internal::AlwaysTrue()) { statement; }\
}\
} while (::testing::internal::AlwaysFalse())


class TestMessageHandler_test : public BaseTest
{
public:
void defaultTestBehavior()
{
msg_deprecated("HERE") << "This should generate a failure" ;
msg_warning("HERE") << "This should generate a failure" ;
msg_error("HERE") << "This should generate a failure" ;
}


void catchingTestBehavior()
{
EXPECT_MSG_EMIT(Warning) ;
EXPECT_MSG_EMIT(Error) ;

msg_warning("HERE") << "This should not generate a failure" ;
msg_error("HERE") << "This should not generate a test falure" ;
}

/// THIS TEST SHOULD FAIL.
void expectAMessageissingBehavior()
{
EXPECT_MSG_EMIT(Warning) ;
EXPECT_MSG_EMIT(Error) ;

//msg_warning("HERE") << "This should not generate a failure" ;
//msg_error("HERE") << "This should not generate a test falure" ;
}

void noEmitTestBehavior()
{
EXPECT_MSG_NOEMIT(Warning) ;
EXPECT_MSG_NOEMIT(Error) ;

msg_warning("HERE") << "This should generate a failure but with line number close to " << __LINE__ ;
msg_error("HERE") << "This should generate a test falure with line number close to " << __LINE__ ;
}

void noEmitIgnoredTestBehavior()
{
EXPECT_MSG_NOEMIT(Error) ;
EXPECT_MSG_NOEMIT(Warning) ;

IGNORE_MSG(Warning) ;
msg_warning("HERE") << "This shouldn't generate a failure " ;

{
IGNORE_MSG(Error) ;
msg_error("HERE") << "This shouldn't generate a failure " ;
}
}

void complexTestBehavior()
{
{
EXPECT_MSG_EMIT(Warning) ;
EXPECT_MSG_EMIT(Error) ;

//msg_warning("HERE") << "This should generate a failure" ;
//msg_error("HERE") << "This should generate a test failure" ;
{
EXPECT_MSG_NOEMIT(Error) ;
msg_error("HERE") << "This should generate a test failure" ;
}
}

{
EXPECT_MSG_NOEMIT(Warning) ;
EXPECT_MSG_NOEMIT(Error) ;

msg_warning("HERE") << "This should generate a failure" ;
msg_error("HERE") << "This should generate a test falure" ;
}

}
};


/// performing the regression test on every plugins/projects
TEST_F(TestMessageHandler_test, defaultTestBehavior)
{
EXPECT_ATLEASE_ONE_NONFATAL_FAILURE(this->defaultTestBehavior(), "Message") ;
}

/// performing the regression test on every plugins/projects
TEST_F(TestMessageHandler_test, catchingTestBehavior)
{
this->catchingTestBehavior();
}

/// performing the regression test on every plugins/projects
TEST_F(TestMessageHandler_test, noEmitTestBehavior)
{
EXPECT_ATLEASE_ONE_NONFATAL_FAILURE(this->noEmitTestBehavior(), "Message") ;
}

/// performing the regression test on every plugins/projects
TEST_F(TestMessageHandler_test, noEmitIgnoredTestBehavior)
{
this->noEmitIgnoredTestBehavior();
}

/// performing the regression test on every plugins/projects
TEST_F(TestMessageHandler_test, complexTestBehavior)
{
EXPECT_ATLEASE_ONE_NONFATAL_FAILURE(this->complexTestBehavior(), "Message") ;
}

18 changes: 18 additions & 0 deletions SofaKernel/framework/sofa/helper/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,17 @@ if(CMAKE_SYSTEM_NAME STREQUAL Windows)
list(APPEND SOURCE_FILES system/FileMonitor_windows.cpp)
endif()

if(SOFA_BUILD_TESTS)

list(APPEND HEADER_FILES testing/BaseTest.h
testing/NumericTest.h
testing/TestMessageHandler.h
)
list(APPEND SOURCE_FILES testing/BaseTest.cpp
testing/NumericTest.cpp
testing/TestMessageHandler.cpp
)
endif()

if(SOFA_HAVE_PNG)
list(APPEND HEADER_FILES io/ImagePNG.h)
Expand Down Expand Up @@ -365,6 +376,13 @@ if(APPLE)
endif()
target_link_libraries(${PROJECT_NAME} PUBLIC ${SOFAFRAMEWORK_DEPENDENCY_LINK} ${Boost_LIBRARIES})

if(SOFA_BUILD_TESTS)
target_link_libraries(${PROJECT_NAME} PUBLIC ${SOFAFRAMEWORK_DEPENDENCY_LINK} ${Boost_LIBRARIES} gtest)
else()
target_link_libraries(${PROJECT_NAME} PUBLIC ${SOFAFRAMEWORK_DEPENDENCY_LINK} ${Boost_LIBRARIES})
endif()


target_include_directories(${PROJECT_NAME} PUBLIC "$<INSTALL_INTERFACE:include>")
target_include_directories(${PROJECT_NAME} PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../..>")
target_include_directories(${PROJECT_NAME} SYSTEM PUBLIC "$<BUILD_INTERFACE:${SOFAFRAMEWORK_DEPENDENCY_INCLUDE_DIRECTORIES}>")
Expand Down
33 changes: 20 additions & 13 deletions SofaKernel/framework/sofa/helper/testing/BaseTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ using sofa::helper::Console ;
using sofa::helper::logging::MessageDispatcher ;
using sofa::helper::logging::MainGtestMessageHandler ;

#include <sofa/helper/random.h>

#include "BaseTest.h"

namespace sofa {
Expand All @@ -60,19 +62,18 @@ void initializeOnce()
BackTrace::autodump() ;


const std::string pluginDir = Utils::getPluginDirectory() ;
PluginRepository.addFirstPath(pluginDir);

PluginManager::getInstance().loadPlugin("SceneCreator") ;
//const std::string pluginDir = Utils::getPluginDirectory() ;
//PluginRepository.addFirstPath(pluginDir);
//PluginManager::getInstance().loadPlugin("SceneCreator") ;
initialized=true ;
}
}

int BaseTest::seed = (unsigned int)time(NULL);

BaseTest::BaseTest() :
m_fatal(sofa::helper::logging::Message::Fatal, __FILE__, __LINE__ ),
m_error(sofa::helper::logging::Message::Error, __FILE__, __LINE__ )
m_fatal(sofa::helper::logging::Message::Fatal, __FILE__, __LINE__ ),
m_error(sofa::helper::logging::Message::Error, __FILE__, __LINE__ )
{
initializeOnce() ;

Expand All @@ -94,13 +95,19 @@ BaseTest::BaseTest() :

BaseTest::~BaseTest() {}

void BaseTest::SetUp()
{
onSetUp();
}

void BaseTest::TearDown()
{
onTearDown();
}
}

#ifdef SOFA_WITH_FLOAT
template struct SOFA_HELPER_API sofa::helper::testing::NumericTest<float>;
#endif
#ifdef SOFA_WITH_DOUBLE
template struct SOFA_HELPER_API sofa::helper::testing::NumericTest<double>;
#endif

} /// testing
} /// helper
} /// sofa


Loading

0 comments on commit fcbb885

Please sign in to comment.