/*************************************************************************** * GTestSuite.cpp - Test Suite class for GammaLib * * ----------------------------------------------------------------------- * * copyright (C) 2012 by Jean-Baptiste Cayrou * * ----------------------------------------------------------------------- * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * ***************************************************************************/ /** * @file GTestSuite.cpp * @brief Test Suite class implementation * @author Jean-Baptiste Cayrou */ /* __ Includes ___________________________________________________________ */ #ifdef HAVE_CONFIG_H #include #endif #include "GTestSuite.hpp" #include "GLog.hpp" /* __ Method name definitions ____________________________________________ */ #define G_OP_ACCESS "GTestSuite::operator[](int&)" #define G_TRY_SUCCESS "GTestSuite::test_try_success()" #define G_TRY_FAILURE "GTestSuite::test_try_failure(std::string&,std::string&)" /* __ Macros _____________________________________________________________ */ /* __ Coding definitions _________________________________________________ */ /* __ Debug definitions __________________________________________________ */ /*========================================================================== = = = Constructors/destructors = = = ==========================================================================*/ /***********************************************************************//** * @brief Void constructor ***************************************************************************/ GTestSuite::GTestSuite(void) { // Initialise members init_members(); //Return return; } /***********************************************************************//** * @brief Copy constructor * * @param[in] testsuite Test Suite. ***************************************************************************/ GTestSuite::GTestSuite(const GTestSuite& testsuite) { // Initialise members init_members(); // Copy members copy_members(testsuite); //Return return; } /***********************************************************************//** * @brief Name constructor * * @param[in] name Name of the Test Suite ***************************************************************************/ GTestSuite::GTestSuite(const std::string& name) { // Initialise members init_members(); //Set name m_name=name; //Return return; } /***********************************************************************//** * @brief Destructor * Exit(1) if they are failures or errors for compatibility with make check ***************************************************************************/ GTestSuite::~GTestSuite(void) { //For make check if(m_errors+m_failures>0){ exit(1); } //Free members free_members(); //Return return; } /*========================================================================== = = = Operators = = = ==========================================================================*/ /***********************************************************************//** * @brief Assignment operator * * @param[in] testsuite Test Suite. ***************************************************************************/ GTestSuite& GTestSuite::operator= (const GTestSuite& testsuite) { // Execute only if object is not identical if (this != &testsuite) { // Free members free_members(); // Initialise members init_members(); // Copy members copy_members(testsuite); } // endif: object was not identical // Return return *this; } /***********************************************************************//** * @brief Returns reference to test case * * @param[in] index Test case index [0,...,tests()-1]. * * @exception GException::out_of_range * Test case index is out of range. ***************************************************************************/ GTestCase& GTestSuite::operator[](const int& index) { // If index is outside boundary then throw an error if (index < 0 || index >= tests()) { throw GException::out_of_range(G_OP_ACCESS, index, 0, tests()-1); } // Return reference return *(m_tests[index]); } /***********************************************************************//** * @brief Returns reference to test case * * @param[in] index Test case index [0,...,tests()-1]. * * @exception GException::out_of_range * Test case index is out of range. ***************************************************************************/ const GTestCase& GTestSuite::operator[](const int& index) const { // If index is outside boundary then throw an error if (index < 0 || index >= tests()) { throw GException::out_of_range(G_OP_ACCESS, index, 0, tests()-1); } // Return reference return *(m_tests[index]); } /*========================================================================== = = = Public methods = = = ==========================================================================*/ /***********************************************************************//** * @brief Return Test Suite name ***************************************************************************/ std::string GTestSuite::name(void) const { return m_name; } /***********************************************************************//** * @brief Set Test Suite name * @param[in] name Parameter name. ***************************************************************************/ void GTestSuite::name(const std::string& name) { // Set name m_name=name; // Return return; } /***********************************************************************//** * @brief Enables/disables logging into standard output stream * * @param[in] flag Enable/disable logging (true/false). * * Enables or disables logging into the standard output stream. ***************************************************************************/ void GTestSuite::cout(bool cout) { // Enables or disables logging into the standard output stream m_log.cout(cout); //Return return; } /***********************************************************************//** * @brief Test an assert * @param[in] assert Assert (true/false). * @param[in] name Test case name. (defaults to "") * Examples : * GTestSuite testsuite; * testsuite.test_assert(x>3,"Test if x > 3"); * testsuite.test_assert(x>3&&x<10,"Test if 3 < x < 10 "); ***************************************************************************/ void GTestSuite::test_assert(bool assert, const std::string& name,const std::string& message) { // If it is the first test, print test suite name if(tests()==0){ m_log<name()<<": "; } // Create a test case of failure type GTestCase* testcase = new GTestCase(GTestCase::FAIL_TEST,name); // If assert is false if(!assert) { // test case is not ok testcase->m_passed=false; //increment number of failures m_failures++; } //Set message testcase->message(message); // Show the result ( ".","F" or, "E") m_log<print_result(); // Add the test in the container m_tests.push_back(testcase); // Return return; } /***********************************************************************//** * @brief Test an try block * @param[in] name Test case name. (defaults to "") * @see test_try_sucess() * @see test_try_failure(const std::string& message) * @see test_try_failure(const std::exception& e) * Call before testing a try/catch block. * Example: * GTestSuite testsuite; * testsuite.test_try("Test a try block"); * try{ * ... //someting to test testsuite.test_try_success(); * } * catch(...) * { * testsuite.test_try_failure(); * } * ***************************************************************************/ void GTestSuite::test_try(const std::string& name) { // If it is the first test, print test suite name if(tests()==0){ m_log<name()<<": "; } // Create a test case of error type GTestCase* testcase = new GTestCase(GTestCase::ERROR_TEST,name); //Add test case to container m_stack_try.push_back(testcase); // Return return; } /***********************************************************************//** * @brief Notice when a try block successed * @see test_try(const std::string& name) * @see test_try_failure(const std::string& message) * @see test_try_failure(const std::exception& e) * * Call this method at the last line of a try * Example: * GTestSuite testsuite; * testsuite.test_try("Test a try block"); * try{ * ... //someting to test testsuite.test_try_success(); * } * catch(...) * { * testsuite.test_try_failure(); * } * ***************************************************************************/ void GTestSuite::test_try_success(){ // If the stack is empty if(m_stack_try.size()==0) throw GException::test_nested_try_error(G_TRY_SUCCESS, "Error : test_try_success() without test_try()"); // Add the test in the container m_tests.push_back(m_stack_try.back()); // Delete the test case of the stack m_stack_try.pop_back(); // The try block test is ok m_log<print_result(); // Return return; } /***********************************************************************//** * @brief Notice when a try block failed * @param[in] message Message to explain why it failed (defaults to "") * @param[in] type Type of message (defaults to "") * @see test_try_sucess() * @see test_try(const std::string& name) * @see test_try_failure(const std::exception& e) * * Call this method in the catch block. * * Example: * GTestSuite testsuite; * testsuite.test_try("Test a try block"); * try{ * ... //someting to test testsuite.test_try_success(); * } * catch(...) * { * testsuite.test_try_failure("Problem with ..."); * } * ***************************************************************************/ void GTestSuite::test_try_failure(const std::string& message, const std::string& type){ // If the stack is empty if(m_stack_try.size()==0) throw GException::test_nested_try_error(G_TRY_FAILURE,"test_try_success() call without test_try()"); // Test is not ok m_stack_try.back()->m_passed=false; // Increment the number of errors m_errors++; // Set a message m_stack_try.back()->message(message); // Set a type of message m_stack_try.back()->message_type(type); // Add the test in the container m_tests.push_back(m_stack_try.back()); // Delete the test case of the stack m_stack_try.pop_back(); // Show the result ( ".","F" or, "E") m_log<print_result(); //Return return; } /***********************************************************************//** * @brief Notice when a try block failed * @param[in] exception Exception caught * @see test_try_sucess() * @see test_try(const std::string& name) * @see test_try_failure(const std::string& message) * * Call this method in a catch block. * * Example: * GTestSuite testsuite; * testsuite.test_try("Test a try block"); * try{ * ... //someting to test testsuite.test_try_success(); * } * catch(exception& e) * { * testsuite.test_try_failure(e); * } * ***************************************************************************/ void GTestSuite::test_try_failure(const std::exception& e){ // Extract message of exception and class name test_try_failure(e.what(),typeid(e).name()); //Return return; } /***********************************************************************//** * @brief Test a function * @param[in] function Pointer to the function to test ( (void)(*)(void) ) * @param[in] name Test case name. (defaults to "") * * The function to test should have only one throw instruction else the different tests could not be separate. * * Example : * * void foo() * { * if (...) * throw GException::bad_alloc("Test"); * } * * in main : * GTestSuite testsuite; * testsuite.test_function(&foo,"Test function foo"); * * * ***************************************************************************/ void GTestSuite::test_function(const pfunction function,const std::string& name) { // If it is the first test, print test suite name if(tests()==0){ m_log<name()<<": "; } // Create a test case of error type (by default with GTestCase) GTestCase* testcase = new GTestCase(function,name); // Add test case to container m_tests.push_back(testcase); // Call the function. testcase->run(); // Imcrement number of errors if the test is not passed if(!testcase->is_passed()){ m_errors++; } // Show the result ( ".","F" or, "E") m_log<print_result(); // Return return; } /***********************************************************************//** * @brief Notice they are not other test to do. ***************************************************************************/ void GTestSuite::end_test() { if((m_errors+m_failures)==0){ m_log<<" ok"; } else{ m_log<<" NOK\n"; } } /***********************************************************************//** * @brief Return the number of tests ***************************************************************************/ int GTestSuite::tests() const { return m_tests.size(); } /***********************************************************************//** * @brief Return the number of errors ***************************************************************************/ int GTestSuite::errors() const { return m_errors; } /***********************************************************************//** * @brief Return the number of failures ***************************************************************************/ int GTestSuite::failures() const { return m_failures; } /***********************************************************************//** * @brief Return the number of success ***************************************************************************/ int GTestSuite::success() const { return tests()-(m_errors+m_failures); } /***********************************************************************//** * @brief Return the timestamp. Set at the creation of the object ***************************************************************************/ std::time_t GTestSuite::timestamp() const { return m_timestamp; } /*========================================================================== = = = Private methods = = = ==========================================================================*/ /***********************************************************************//** * @brief Initialise class members ***************************************************************************/ void GTestSuite::init_members(void) { m_name="Unamed Test Suite";; m_log.clear(); cout(true); m_log.max_size(1); m_tests.clear(); m_errors=0; m_failures=0; m_timestamp=time(NULL); // Return return; } /***********************************************************************//** * @brief Copy class members * * @param[in] testsuite Test suite. * * This method just clone the container not the test case. ***************************************************************************/ void GTestSuite::copy_members(const GTestSuite& testsuite) { m_name=testsuite.m_name; m_tests=testsuite.m_tests; m_log=testsuite.m_log; m_errors=testsuite.m_errors; m_failures=testsuite.m_failures; // Return return; } /***********************************************************************//** * @brief Delete class members ***************************************************************************/ void GTestSuite::free_members(void) { //Add a new line m_log<<"\n"; // Delete test cases for(int i=0;i