00001 // BUnit.h (C) 2008 adolfo@di-mare.com 00002 00003 /* 00004 THIS IS FREE SOFWTWARE. 00005 - Use at your own risk; acknowledge authorship, please. 00006 - You can never blame the author for your use of this software. 00007 - Released to the world under LGPLv3: 00008 http://www.gnu.org/licenses/lgpl-3.0.html 00009 ESTE PROGRAMA ES LIBRE. 00010 - Uselo baja su propia responsabilidad; reconozca la autoría, por favor. 00011 - Usted nunca podrá culpar al autor por su propio uso de este software. 00012 - Entregado al mundo bajo LGPLv3: 00013 http://www.gnu.org/licenses/lgpl-3.0.html 00014 */ 00015 /* 00016 Version 0: No TestSuite<> 00017 Version 1: English Doxygen 00018 Version 2: English+Spanish Doxygen 00019 */ 00020 00021 #ifdef English_dox 00022 /** \file BUnit.h 00023 \brief [B]asic module for [unit] program testing. 00024 00025 \author Adolfo Di Mare <adolfo@di-mare.com> 00026 \date 2008 00027 */ 00028 #endif 00029 #ifdef Spanish_dox 00030 /** \file BUnit.h 00031 \brief Módulo [B]ásico para prueba [unit]aria de programas. 00032 00033 \author Adolfo Di Mare <adolfo@di-mare.com> 00034 \date 2008 00035 */ 00036 #endif 00037 00038 #ifdef English_dox 00039 /// Doxygen English documentation. 00040 #define English_dox "Doxygen English documentation" 00041 /// \def English_dox ///< Marks English documentation blocks. 00042 /// \def BUnit_h ///< Avoids multiple inclusion. 00043 #endif 00044 #ifdef Spanish_dox 00045 /// Documentación en español. 00046 #define Spanish_dox "Documentación en español" 00047 /// \def Spanish_dox ///< Macro usado para que Doxygen genere documentación 00048 /// \def BUnit_h ///< Evita la inclusión múltiple. 00049 #endif 00050 00051 #ifndef BUnit_h 00052 #define BUnit_h // avoid multiple inclusion 00053 00054 #include <list> // std::list 00055 #include <string> // class std::string 00056 #include <sstream> // class basic_ostringstream<T,Ch> 00057 #include <cstdio> // memcpy()+strlen() 00058 #include <typeinfo> // class std::type_info ==> char* typeid().name(); 00059 #include <algorithm> // find() 00060 00061 namespace std {} // using namespace std; 00062 00063 /// Escuela de Ciencias de la Computación e Informática. 00064 /// \see http:www.ecci.ucr.ac.cr 00065 namespace ECCI { } 00066 00067 // Private class to hold test cases that didn´t succeed. 00068 class TestCaseFailure { 00069 private: 00070 const char * m_fname; // file where the failure ocurred 00071 int m_lineno; // line for the failure 00072 const char * m_label; // descriptive message for the failure 00073 bool m_destroy_label; // true when "m_label" requires destruction 00074 private: 00075 TestCaseFailure() : // almost never used 00076 m_fname(""), m_lineno(0), m_label(""), m_destroy_label(false) 00077 { } // always sets "m_destroy_label" to "false" 00078 TestCaseFailure(const char * fname, int line, const char * label, bool destroy ) 00079 : m_fname(fname), m_lineno(line), m_label(label), m_destroy_label(destroy) 00080 { } 00081 public: 00082 ~TestCaseFailure() { if (m_destroy_label) { delete [] m_label; } } 00083 TestCaseFailure( const TestCaseFailure& o ) { 00084 m_fname = o.m_fname; m_lineno = o.m_lineno; m_label = o.m_label; 00085 m_destroy_label = o.m_destroy_label; 00086 // avoid double destruction of "m_label" 00087 const_cast<TestCaseFailure*>(&o)->m_destroy_label = false; 00088 // const_cast<bool>(o.m_destroy_label) = false; // won't compile 00089 } 00090 void operator = ( TestCaseFailure& o ) { 00091 m_fname = o.m_fname; m_lineno = o.m_lineno; m_label = o.m_label; 00092 m_destroy_label = o.m_destroy_label; 00093 o.m_destroy_label = false; // evita doble destrucción de "m_label" 00094 } 00095 template <class TestCase> friend void do_toXML( 00096 const TestCase * tc , std::basic_ostringstream<char> & ost ); 00097 template <class TestCase> friend void do_toString( 00098 const TestCase * tc , std::basic_ostringstream<char> & ost ); 00099 #ifdef English_dox 00100 /// Test case. 00101 #endif 00102 #ifdef Spanish_dox 00103 /// Caso de prueba. 00104 #endif 00105 friend class TestCase; 00106 }; // TestCaseFailure 00107 00108 00109 // Abstract base class for every test case ==> 00110 // - It's always mandatory to reimplement \c TestCase::run(). 00111 class TestCase { 00112 protected: 00113 int m_pass; // number successful tests 00114 int m_failure; // number of non successful tests [broken assert_XXX()] 00115 const char * m_name; // name for the test case 00116 bool m_test_suite_destroy; // true means destroy from dynamic memory 00117 std::list<TestCaseFailure> m_failureList; // container for al non successful tests 00118 public: 00119 TestCase(const char * name=0); 00120 virtual ~TestCase() { } 00121 virtual bool run() = 0; // must implement in derived class 00122 void runBare(); 00123 bool Run() { return run(); } // same as run() 00124 bool runTest() { return run(); } 00125 virtual void setUp(); 00126 virtual void tearDown(); 00127 int countTestCases() const { return 1; } // more than 1 for TestSuite<> 00128 // errorCount() == 0 ==> "error" means "wrong exception" 00129 int runCount() const { return successCount()+failureCount()+errorCount(); } 00130 virtual int failureCount() const { return m_failure; } 00131 int errorCount() const { return 0; } 00132 virtual int successCount() const { return m_pass; } 00133 // true when all runs have been a success 00134 bool wasSuccessful() const { return successCount() == runCount(); } 00135 virtual void reset(); // resets al counter back to 0 00136 public: 00137 std::string getName() const; 00138 void setName( const char * name=0 ); 00139 virtual const std::string toString() const; 00140 virtual const std::string summary() const; 00141 virtual const std::string toXML() const; 00142 const std::string report() const { return summary() + '\n' + toString(); } 00143 const std::string failureString() const { return toString(); } 00144 template <class T> static std::string toString( const T & val ); 00145 protected: 00146 void recordSuccess() { ++m_pass; } // record another successful test 00147 void recordFailure( // (char*) version 00148 const char* label, const char* fname, int lineno, 00149 bool must_copy=false ); 00150 void recordFailure( // std::string version 00151 const std::string& label, const char* fname, int lineno ); 00152 void testThis( // (char*) version ==> don't destroy label 00153 bool cond, const char* label, const char* fname, long lineno, 00154 bool must_copy=false ); 00155 void testThis( // string<> version ==> create copy of "label" in dynamic memory 00156 bool cond, const std::string& label, const char* fname, long lineno ); 00157 template <class TestCase> friend 00158 void do_toXML( const TestCase * tc , std::basic_ostringstream<char> & ost ); 00159 template <class TestCase> friend 00160 void do_toString( const TestCase * tc , std::basic_ostringstream<char> & ost ); 00161 template <class TestCase> friend class TestSuite; ///< Colección de pruebas. 00162 int nPass() const { return m_pass; } // Deprecated: it's here for 00163 int nError() const { return m_failure; } // compatibility with Allison's work 00164 private: 00165 virtual bool iAmTestSuite() const { return false; } // I am NOT a TestSuite<> 00166 TestCase(const TestCase&); // trick to prevent copy on init 00167 TestCase& operator=(const TestCase&); // trick to prevent copying 00168 #ifdef English_dox 00169 /// Test case class for \c BUnit.h 00170 #endif 00171 #ifdef Spanish_dox 00172 /// Clase de prueba para \c BUnit.h 00173 #endif 00174 friend class test_BUnit; 00175 }; // TestCase 00176 00177 #ifdef Spanish_dox 00178 /// Sinónimo de \c TestCase. 00179 #endif 00180 #ifdef English_dox 00181 /// Synonym for \c TestCase. 00182 #endif 00183 typedef TestCase TestCase_is_base_for_TestSuite; 00184 00185 // Test collection. 00186 template <class TestCase> 00187 class TestSuite : public TestCase_is_base_for_TestSuite { 00188 public: 00189 typedef std::list<TestCase_is_base_for_TestSuite*> container_type; 00190 typedef container_type::iterator iterator; 00191 typedef const container_type::iterator cons_iterator; 00192 typedef const container_type const_container_type; 00193 private: 00194 container_type m_allTest; // holds [pointers to] failed tests 00195 public: 00196 TestSuite(const char * name=0): TestCase(name), m_allTest() { } 00197 virtual ~TestSuite(); 00198 bool addTest(TestCase& T); 00199 bool addTest(TestCase* T); 00200 void addSuite( TestSuite& SSS ); 00201 bool run(); // implemented: TestSuite<> is not an abstract class 00202 void runBare(); 00203 int countTestCases() const { return int(m_allTest.size()); } 00204 int failureCount() const; 00205 int successCount() const; 00206 void reset(); 00207 const_container_type& allTests() const { return m_allTest; } 00208 const std::string toString() const; 00209 const std::string summary() const; 00210 const std::string toXML() const; 00211 private: 00212 bool iAmTestSuite() const { return true; } 00213 TestSuite(const TestSuite& DONTcopy); 00214 TestSuite& operator=(const TestSuite& DONTcopy); // forbid copying 00215 }; // TestSuite 00216 00217 /************************\ 00218 ************************** 00219 ** ** 00220 ** BUnit.h ** 00221 ** ** 00222 ************************** 00223 \************************/ 00224 00225 #ifdef English_dox 00226 /// Doxygen English documentation. 00227 #define English_dox "Doxygen English documentation" 00228 /// \def English_dox ///< Marks English documentation blocks. 00229 #endif 00230 #ifdef Spanish_dox 00231 /// Documentación en español. 00232 #define Spanish_dox "Documentación en español" 00233 /// \def Spanish_dox ///< Macro usado para que Doxygen genere documentación 00234 #endif 00235 00236 #ifdef English_dox 00237 /** \mainpage 00238 00239 \section sec-01 [B]asic module for [unit] program testing. 00240 00241 Header file \c BUnit.h supports writing modules for unit program testing. 00242 The model used for this implementation is similar to that described in 00243 the article "The Simplest Automated Unit Test Framework That Could 00244 Possibly Work "by Chuck Allison, which you can get here: 00245 - http://www.stickyminds.com/getfile.asp?ot=XML&id=3129&fn=XDD3129filelistfilename1.pdf 00246 - http://www.google.com/search?num=100&as_q=Simplest+Unit+Test+Allison 00247 - http://search.yahoo.com/search?n=100&p=Simplest+Unit+Test+Allison 00248 00249 - To simplify to a minimum the task of writing test cases, the full 00250 implementation of \c BUnit is contained within the single header 00251 file \c BUnit.h, so testing requieres only this directive: 00252 - <strong>\#include "BUnit.h"</strong> 00253 - This framework is similar to JUnit, because it is presumed that 00254 in the future students will use Java as their primary language 00255 to develop programs (as C++ is used only for deep training in 00256 programming techniques). 00257 \see http://search.yahoo.com/search?n=100&p=JUnit+Java 00258 - As C++ does not have a mechanism similar to Java's "reflection", 00259 for each failed test the exact test condition is recorded 00260 using an invocation to macro \c BUnit_TEST() that also records 00261 the filename \c __FILE__ and the line \c __LINE__ for that test. 00262 \see http://search.yahoo.com/search?n=100&p=reflection+Java 00263 - In JUnit class \c TestCase is a subclass of \c Assert; in BUnit no 00264 \c Assert class exist but to maintain compatibility with JUnit similar 00265 functionality is provided with macros whose names begin with "assert". 00266 \see http://search.yahoo.com/search?n=100&p=JUnit+Java+Assert+method 00267 - To simplify this framework no difference is made between a test that 00268 is not successfull and one that didn´t succeed because the correct 00269 exception was not raised. This is a contrast with JUnit where an 00270 "error" is a test case that raised the wrong exception. This 00271 explains why \c TestCase::errorCount() always returns zero \c 0. 00272 \code 00273 // Failure vs Error in JUnit 00274 public void test_Fail () { 00275 try { 00276 new ArrayList(10).get( 11 ); 00277 fail("Error if IndexOutOfBoundsException is not thrown" ); // error 00278 } 00279 catch (IndexOutOfBoundsException success) { } // Ok 00280 } 00281 public void test_Failure() { 00282 assertTrue( 1 == 2 ); // failure 00283 } 00284 \endcode 00285 - In \c BUnit.h no difference is made between "failures" and "errors". 00286 - En \c JUnit an "error" means that the wrong exception was raised. 00287 - En \c JUnit a "failure" means that an assertion was false. 00288 - \see http://osdir.com/ml/java.junit.user/2002-06/msg00114.html 00289 - \see http://search.yahoo.com/search?n=100&p=junit+difference+failure+error 00290 - In JUnit, what's the difference between a failure and an error? 00291 - Assertions are used to check for the possibility of failures, 00292 therefore failures are anticipated with invokations similar to \c assertTrue(). 00293 - Errors are unanticipated problems resulting in uncaught exceptions 00294 being propagated from a JUnit test method. 00295 - \see http://www.cs.waikato.ac.nz/~bernhard/314/junit3.8.1/doc/faq/faq.htm#tests_9 00296 - \see http://www.cs.wm.edu/~noonan/junit/doc/faq/faq.htm#tests_9 00297 00298 \dontinclude test_BUnit.cpp 00299 \skipline test::Allison() 00300 \until }} 00301 \see test_BUnit::test_Allison() 00302 */ 00303 #endif 00304 #ifdef Spanish_dox 00305 /** \mainpage 00306 00307 \section sec-01 Módulo [B]ásico para prueba [unit]aria de programas. 00308 00309 El archivo de encabezado \c BUnit.h apoya la escritura de módulos de prueba de 00310 unitaria programas. El modelo que se usa para esta implementación es 00311 similar al expuesto en este artículo "The Simplest Automated Unit 00312 Test Framework That Could Possibly Work" de Chuck Allison, que se 00313 puede obtener aquí: 00314 - http://www.stickyminds.com/getfile.asp?ot=XML&id=3129&fn=XDD3129filelistfilename1.pdf 00315 - http://www.google.com/search?num=100&as_q=Simplest+Unit+Test+Allison 00316 - http://search.yahoo.com/search?n=100&p=Simplest+Unit+Test+Allison 00317 00318 - Para simplificar al mínimo la tarea de programar los casos de prueba, 00319 la implementación completa de \c BUnit está contenida en el archivo 00320 de encabezado \c BUnit.h, por lo que para hacer pruebas basta poner 00321 esta directiva: 00322 - <strong>\#include "BUnit.h"</strong> 00323 - Este marco de pruebas es similar a JUnit, pues se presume que en 00324 el futuro los estudiantes usarán Java como su lenguaje principal 00325 para desarrollo de programas (pues usan C++ sólo para adiestrarse 00326 profundamente en técnicas de programación). 00327 \see http://search.yahoo.com/search?n=100&p=JUnit+Java 00328 - Como el lenguaje C++ no tiene un mecanismo similar al de "reflexión" 00329 de Java, en cada prueba fallida se registra la condición de prueba 00330 exacta, obtenida a través de una invocación de la macro \c BUnit_TEST() 00331 que registra el nombre del archivo \c __FILE__ y el renglón \c __LINE__ 00332 de la prueba. 00333 \see http://search.yahoo.com/search?n=100&p=reflection+Java 00334 - En JUnit la clase \c TestCase es una subclase de \c Assert; en BUnit no 00335 existe la clase \c Assert pero para mantener compatibilidad con JUnit 00336 sí se provée funcionalidad similar usando macros cuyos nombres comienzan 00337 con "assert". 00338 \see http://search.yahoo.com/search?n=100&p=JUnit+Java+Assert+method 00339 - Para simplificar este marco de pruebas no se usa la clase \c TestResult 00340 que sirve para acumular resultados de las pruebas. En su lugar, se puede 00341 obtener una hilera enorme \c std::string que contiene el registro de 00342 todas las pruebas que no tuvieron éxito invocando el método 00343 \c TestCase::toString() o \c TestCase::toXML(). 00344 - Para simplificar esta plataforma de pruebas no se hace diferencia entre 00345 un caso de prueba de prueba no existoso y uno que no tiene éxito porque no 00346 se ha levantado la excepción adecuada. Esto contrasta con JUnit, que 00347 llama "error" a un caso de prueba que ha levantado la excepción equivocada. 00348 Por eso \c TestCase::errorCount() siempre retorna cero \c 0. 00349 \code 00350 // Falla vs Error en JUnit 00351 public void test_Error() { 00352 try { 00353 new ArrayList(10).get( 11 ); 00354 fail("Error si no tira IndexOutOfBoundsException" ); // error 00355 } 00356 catch (IndexOutOfBoundsException success) { } // Ok 00357 } 00358 public void test_Failure() { 00359 assertTrue( 1 == 2 ); // falla 00360 } 00361 \endcode 00362 - En \c BUnit.h no se hace diferencia entre "fallas" y "errores". 00363 - En \c JUnit un "error" se produce cuando no se levanta la excepción adecuada. 00364 - En \c JUnit una "falla" se produce cuando una aserción resulta falsa. 00365 - \see http://osdir.com/ml/java.junit.user/2002-06/msg00114.html 00366 - \see http://www.cs.waikato.ac.nz/~bernhard/314/junit3.8.1/doc/faq/faq.htm#tests_9 00367 - \see http://search.yahoo.com/search?n=100&p=junit+difference+failure+error 00368 - In JUnit, ¿cuál es la diferencia entre fallas y errores? 00369 - Las aseveraciones son usadas para verificar si existen fallas, y por eso las 00370 fallas son previstas con invocaciones similares a \c assertTrue(). 00371 - Los errores son problemas no previstos que resultan de excepciones no captadas 00372 por los método de prueba JUnit. 00373 - \see http://www.cs.waikato.ac.nz/~bernhard/314/junit3.8.1/doc/faq/faq.htm#tests_9 00374 - \see http://www.cs.wm.edu/~noonan/junit/doc/faq/faq.htm#tests_9 00375 00376 \dontinclude test_BUnit.cpp 00377 \skipline test::Allison() 00378 \until }} 00379 \see test_BUnit::test_Allison() 00380 */ 00381 #endif 00382 00383 #ifdef Spanish_dox 00384 // using namespace std; 00385 /// Definido por la biblioteca C++ estándar. 00386 namespace std {} // It's here for Doxygen to document it 00387 #endif 00388 #ifdef English_dox 00389 // using namespace std; 00390 /// Defined by the C++ estándar library. 00391 namespace std {} // Está acá para que Doxygen lo documente 00392 #endif 00393 00394 /// Escuela de Ciencias de la Computación e Informática. 00395 /// \see http:www.ecci.ucr.ac.cr 00396 namespace ECCI { } 00397 00398 /************************\ 00399 ************************** 00400 ** ** 00401 ** TestCaseFailure ** 00402 ** ** 00403 ************************** 00404 \************************/ 00405 00406 #ifdef English_dox 00407 /** \class TestCaseFailure 00408 \brief Private class to hold test cases that didn´t succeed. 00409 */ 00410 /** \var const char * TestCaseFailure::m_fname; 00411 \brief Name of the file where the failure was produced. 00412 */ 00413 /** \var int TestCaseFailure::m_lineno; 00414 \brief Line number in the file where the failure was produced. 00415 */ 00416 /** \var const char * TestCaseFailure::m_label; 00417 \brief Descriptive message for the failure. 00418 */ 00419 /** \var bool TestCaseFailure::m_destroy_label; 00420 \brief Holds \c "true" if the destructor should return the dynamic memory for \c m_label. 00421 */ 00422 /** \fn TestCaseFailure::TestCaseFailure(); 00423 \brief Default constructor. 00424 */ 00425 /** \fn TestCaseFailure::TestCaseFailure(const char * fname, int line, const char * label, bool destroy ); 00426 \brief Private constructor that can set \c m_label to \c true. 00427 */ 00428 #endif 00429 #ifdef Spanish_dox 00430 /** \class TestCaseFailure 00431 \brief Clase privada que contiene los datos de cada prueba no exitosa. 00432 */ 00433 /** \var const char * TestCaseFailure::m_fname; 00434 \brief Nombre del archivo en donde se produjo el error. 00435 */ 00436 /** \var int TestCaseFailure::m_lineno; 00437 \brief Número de línea del archivo en donde se produjo el error. 00438 */ 00439 /** \var const char * TestCaseFailure::m_label; 00440 \brief Mensaje descriptivo del error. 00441 */ 00442 /** \var bool TestCaseFailure::m_destroy_label; 00443 \brief Contiene \c "true" si el destructor debe retornar la memoria dinámica de \c m_label. 00444 */ 00445 /** \fn TestCaseFailure::TestCaseFailure(); 00446 \brief Constructor por defecto. 00447 */ 00448 /** \fn TestCaseFailure::TestCaseFailure(const char * fname, int line, const char * label, bool destroy ); 00449 \brief Constructor Privado que puede inicializar \c m_label en \c true. 00450 */ 00451 #endif 00452 00453 #ifdef English_dox 00454 /** \fn TestCaseFailure::~TestCaseFailure(); 00455 \brief Destructor. 00456 */ 00457 /** \fn TestCaseFailure::TestCaseFailure( const TestCaseFailure& o ); 00458 \brief Copy constructor. 00459 */ 00460 /** \fn void TestCaseFailure::operator = ( TestCaseFailure& o ); 00461 \brief Copy operator used to insert into contanier. 00462 */ 00463 #endif 00464 00465 #ifdef Spanish_dox 00466 /** \fn TestCaseFailure::~TestCaseFailure() 00467 \brief Destructor. 00468 */ 00469 /** \fn TestCaseFailure::TestCaseFailure( const TestCaseFailure& o ); 00470 \brief Constructor de copia. 00471 */ 00472 /** \fn void TestCaseFailure::operator = ( TestCaseFailure& o ) 00473 \brief Copiador usado al insertar en el contenedor. 00474 */ 00475 #endif 00476 00477 /************************\ 00478 ************************** 00479 ** ** 00480 ** TestCase ** 00481 ** ** 00482 ************************** 00483 \************************/ 00484 00485 #ifdef English_dox 00486 /** \class TestCase 00487 \brief Every test case is an instance derived from this abstract class. 00488 - It's always mandatory to reimplement \c TestCase::run(). 00489 */ 00490 /** \fn int TestCase::m_pass; 00491 \brief Number of successful tests. 00492 */ 00493 /** \fn int TestCase::m_failure; 00494 \brief Number of test that produced failed. 00495 */ 00496 /** \fn const char * TestCase::m_name; 00497 \brief Test case name. 00498 */ 00499 /** \fn bool TestCase::m_test_suite_destroy; 00500 \brief Holds \c "true" if the test case is stored in dynamic memory. 00501 */ 00502 /** \fn std::list<TestCaseFailure> TestCase::m_failureList; 00503 \brief Container where test cases that produced failures are stored. 00504 */ 00505 #endif 00506 00507 #ifdef Spanish_dox 00508 /** \class TestCase 00509 \brief Cada caso de prueba es una instancia derivada de esta clase abstracta. 00510 - Siempre es obligatorio reimplementar \c TestCase::run(). 00511 */ 00512 /** \fn int TestCase::m_pass; 00513 \brief Cantidad de pruebas exitosas. 00514 */ 00515 /** \fn int TestCase::m_failure; 00516 \brief Cantidad de pruebas que han fallado. 00517 */ 00518 /** \fn const char * TestCase::m_name; 00519 \brief Nombre del caso de prueba. 00520 */ 00521 /** \fn bool TestCase::m_test_suite_destroy; 00522 \brief Contiene \c "true" si la prueba está almacenada en memoria dinámica. 00523 */ 00524 /** \fn std::list<TestCaseFailure> TestCase::m_failureList; 00525 \brief Contenedor para almacenar las pruebas que han producido fallas. 00526 */ 00527 #endif 00528 00529 #ifdef English_dox 00530 /** \fn virtual TestCase::~TestCase(); 00531 \brief Destructor. 00532 */ 00533 /** \fn virtual bool TestCase::run() = 0; 00534 \brief <strong>[virtual]</strong> ==> Executes test and returns \c "false" if not successful. 00535 <strong>[***]</strong> It is always mandatory to redefine method \c run(). 00536 \see runBare(). 00537 */ 00538 /** \fn bool TestCase::Run(); 00539 \brief Synonym for \c run(). 00540 */ 00541 /** \fn bool TestCase::runTest(); 00542 \brief Synonym for \c run(). 00543 */ 00544 /** \fn int TestCase::countTestCases() const; 00545 \brief 1 == Number of test cases. 00546 The value returned always is one \c 1 because class \c TestCase 00547 represents a single test case. For the container \c TestSuite<> 00548 the value returned can be bigger than \c 1. 00549 - A "test case" is a class, derived from class \c TestCase. 00550 - A "test run" gets counted when either a specific test succeeds or fails. 00551 - A "test run" gets counted when protected method TestCase::testThis() is 00552 executed, either directly or through any BUnit \c "assert()" macro, as 00553 \c assertTrue(), \c fail_Msg(), \c assertEquals_Delta(), or others like 00554 \c BUnit_SUCCESS() or \c BUnit_TEST(). 00555 - A "test case" ussually has many "test runs". A collection of "test cases" 00556 resided within an instance derived from class \c TestSuite<>. 00557 */ 00558 /** \fn int TestCase::runCount() const; 00559 \brief Number of test runs. 00560 - Synonym for <code>successCount()+failureCount()+errorCount()</code>. 00561 \see reset(). 00562 */ 00563 /** \fn virtual int TestCase::failureCount() const; 00564 \brief Number of test runs that failed. \see reset(). 00565 */ 00566 /** \fn int TestCase::errorCount() const; 00567 \brief Always returns \c 0 (cero): "Number of errors". 00568 - BUnit does not maintain separate counts for "errors" and "failures". 00569 \see http://osdir.com/ml/java.junit.user/2002-06/msg00114.html 00570 */ 00571 /** \fn virtual int TestCase::successCount() const; 00572 \brief Number of successful test runs. \see reset(). 00573 */ 00574 /** \fn bool TestCase::wasSuccessful() const; 00575 \brief Returns \c "true" when all test runs where successful. 00576 - Synonym for <code>(successCount() == runCount())</code> 00577 */ 00578 /** \fn std::string TestCase::getName() const; 00579 \brief Gets the test case name. \see setName(). 00580 */ 00581 /** \fn const std::string TestCase::report() const; 00582 \brief Returns string \c summary() followed by \c toString(). 00583 */ 00584 /** \fn const std::string TestCase::failureString() const; 00585 \brief Synonym for \c toString(). 00586 */ 00587 /** \fn void TestCase::recordSuccess(); 00588 \brief Records the test run as a success. 00589 */ 00590 /** \fn int TestCase::nPass() const; 00591 \brief Synonym for \c successCount() [OBSOLETE]. \deprecated 00592 */ 00593 /** \fn int TestCase::nError() const; 00594 \brief Synonym for \c failureCount() [OBSOLETE]. \deprecated 00595 */ 00596 /** \fn virtual bool TestCase::iAmTestSuite() const; 00597 \brief Returns \c false for \c TestCase. 00598 */ 00599 /** \fn TestCase::TestCase(const TestCase&); 00600 \brief This \c "private" declaration forbids test case copying. 00601 */ 00602 /** \fn TestCase& TestCase::operator=(const TestCase&); 00603 \brief This \c "private" declaration forbids test case copying. 00604 */ 00605 #endif 00606 #ifdef Spanish_dox 00607 /** \fn virtual TestCase::~TestCase(); 00608 \brief Destructor. 00609 */ 00610 /** \fn virtual bool TestCase::run() = 0; 00611 \brief <strong>[virtual]</strong> ==> Ejecuta la prueba y retorna \c "false" si produce error. 00612 <strong>[***]</strong> Siempre es necesario redefinir el método \c run(). 00613 \see runBare(). 00614 */ 00615 /** \fn bool TestCase::Run(); 00616 \brief Sinónimo de \c run(). 00617 */ 00618 /** \fn bool TestCase::runTest(); 00619 \brief Sinónimo de \c run(). 00620 */ 00621 /** \fn int TestCase::countTestCases() const; 00622 \brief 1 == Cantidad de casos de prueba. 00623 El valor retornado siempre es uno \c 1 porque la clase \c TestCase 00624 representa un único caso de pruebas. Para el contenedor 00625 \c TestSuite<> el valor retornado puede ser mayor a \c 1. 00626 - Un "caso de prueba" es una clase derivada de la clase \c TestCase. 00627 - Una "prueba" se cuenta cuando tiene éxito o fracasa. 00628 - Una "prueba" se cuenta cuando el método protegido TestCase::testThis() es 00629 ejecutado, ya sea directamente o a través de cualquiera de los macros 00630 \c "assert()" de BUnit, como lo son \c assertTrue(), \c fail_Msg(), 00631 \c assertEquals_Delta(), u otros como \c BUnit_SUCCESS() or \c BUnit_TEST(). 00632 - Un "caso de prueba" generalmente incluye muchas "pruebas". Una colección de 00633 "casos de prueba" reside en una instancia derivada de la clase \c TestSuite<>. 00634 */ 00635 /** \fn int TestCase::runCount() const; 00636 \brief Cantidad total de pruebas realizadas. 00637 - Sinónimo de <code>successCount()+failureCount()+errorCount()</code>. 00638 \see reset(). 00639 */ 00640 /** \fn virtual int TestCase::failureCount() const; 00641 \brief Cantidad de pruebas que fallaron. \see reset(). 00642 */ 00643 /** \fn int TestCase::errorCount() const; 00644 \brief Siempre retorna \c 0 (cero): "Cantidad de errores". 00645 - BUnit no se contabilizan aparte los "errores" de las "fallas". 00646 \see http://osdir.com/ml/java.junit.user/2002-06/msg00114.html 00647 */ 00648 /** \fn virtual int TestCase::successCount() const; 00649 \brief Cantidad de pruebas exitosas. \see reset(). 00650 */ 00651 /** \fn bool TestCase::wasSuccessful() const; 00652 \brief Retorna \c "true" si todas las pruebas han sido exitosas. 00653 - Sinónimo de <code>(successCount() == runCount())</code> 00654 */ 00655 /** \fn std::string TestCase::getName() const; 00656 \brief Obtiene el nombre de la prueba. \see setName(). 00657 */ 00658 /** \fn const std::string TestCase::report() const; 00659 \brief Retorna la hilera encabezado \c summary() seguido \c toString(). 00660 */ 00661 /** \fn const std::string TestCase::failureString() const; 00662 \brief Sinónimo de \c toString(). 00663 */ 00664 /** \fn void TestCase::recordSuccess(); 00665 \brief Registra como exitoso el resultado de una prueba. 00666 */ 00667 /** \fn int TestCase::nPass() const; 00668 \brief Sinónimo de \c successCount() [OBSOLETO]. \deprecated 00669 */ 00670 /** \fn int TestCase::nError() const; 00671 \brief Sinónimo de \c failureCount() [OBSOLETO]. \deprecated 00672 */ 00673 /** \fn virtual bool TestCase::iAmTestSuite() const; 00674 \brief Retorna \c false para \c TestCase. 00675 */ 00676 /** \fn TestCase::TestCase(const TestCase&); 00677 \brief Esta declaración \c "private" prohibe la copia de casos de prueba. 00678 */ 00679 /** \fn TestCase& TestCase::operator=(const TestCase&); 00680 \brief Esta declaración \c "private" prohibe la copia de casos de prueba. 00681 */ 00682 #endif 00683 00684 #ifdef Spanish_dox 00685 /** Constructor. 00686 Si no se indica el nombre en \c "name", después el nombre se obtiene 00687 invocando <code>typeid(*this).name()</code>. 00688 */ 00689 #endif 00690 #ifdef English_dox 00691 /** Constructor. 00692 If no name is given to this constructor in \c "name", later the 00693 name will be obtained invoking <code>typeid(*this).name()</code>. 00694 */ 00695 #endif 00696 /** \dontinclude test_BUnit.cpp 00697 \skipline test::constructor() 00698 \until }} 00699 \see test_BUnit::test_constructor() 00700 */ 00701 inline TestCase::TestCase(const char * name) : 00702 m_pass(0), m_failure(0), m_name(name), 00703 m_test_suite_destroy(false), m_failureList() { } 00704 00705 #ifdef Spanish_dox 00706 /** Elimina todas las pruebas realizadas. 00707 - Anula los contadores de pruebas porque deja la clase en el estado 00708 inicial que tuvo al ser construida. 00709 - Borra el registro de pruebas no exitosas. 00710 - No borra el nombre de la prueba. 00711 */ 00712 #endif 00713 #ifdef English_dox 00714 /** Discards all test runs. 00715 - Resets to cero al counters because the test case is left in 00716 the state it had when initially contructed. 00717 - Deletes the record for not successful tests. 00718 - Does not change the test case name. 00719 */ 00720 #endif 00721 /** \dontinclude test_BUnit.cpp 00722 \skipline test::reset() 00723 \until }} 00724 \see test_BUnit::test_reset() 00725 */ 00726 inline void TestCase::reset() { 00727 m_pass = m_failure = 0; 00728 m_failureList.clear(); 00729 } 00730 00731 inline std::string TestCase::getName() const { 00732 return ( m_name != 0 ? m_name : typeid(*this).name() ); 00733 } 00734 00735 #ifdef Spanish_dox 00736 /** Le cambia el nombre a la prueba por \c "name". 00737 - Si \c "name" es una hilera o puntero nulo, después 00738 usa <code>typeid(*this).name()</code> para obtener 00739 el nombre de la prueba. 00740 */ 00741 #endif 00742 #ifdef English_dox 00743 /** Sets the test case name to \c "name". 00744 - When \c "name" is a null string or pointer, later 00745 <code>typeid(*this).name()</code> will be invoked 00746 to get the test´s name. 00747 */ 00748 #endif 00749 /** \dontinclude test_BUnit.cpp 00750 \skipline test::setName() 00751 \until }} 00752 \see test_BUnit::test_setName() 00753 */ 00754 inline void TestCase::setName( const char * name ) { 00755 m_name = name; 00756 } 00757 00758 #ifdef Spanish_dox 00759 /** Ejecuta la prueba <code>setUp(); run(); tearDown();</code>. 00760 - A diferencia de \c run(), este método sí establece el ambiente 00761 de prueba invocando \c setUp() y \c tearDown() antes y después 00762 de hacer la prueba. 00763 */ 00764 #endif 00765 #ifdef English_dox 00766 /** Excecutes the test run <code>setUp(); run(); tearDown();</code>. 00767 - In contrast to \c run(), this method will setup the environment 00768 for the test run invoking \c setUp() and \c tearDown() before and 00769 after the test. 00770 */ 00771 #endif 00772 /** \dontinclude test_BUnit.cpp 00773 \skipline test::run() 00774 \until }} 00775 \see test_BUnit::test_run() 00776 */ 00777 inline void TestCase::runBare( ) { setUp(); run(); tearDown(); } 00778 00779 #ifdef Spanish_dox 00780 /** Establece el ambiente para la ejecución de la prueba. 00781 Esta clase existe para mejorar la compatibilidad con JUnit. 00782 \see TestCase::setUp() 00783 */ 00784 #endif 00785 #ifdef English_dox 00786 /** Sets the environment for the test run. 00787 This clase exists to improve compatibility with JUnit. 00788 \see TestCase::setUp() 00789 */ 00790 #endif 00791 typedef TestCase TestFixture; 00792 00793 #ifdef Spanish_dox 00794 /** Establece el ambiente en que se realizará la prueba. 00795 - Como \c TestCase::run() es un método abstracto, para facilitar la 00796 programación lo usual es que el programador no incluya invocaciones 00797 a \c TestCase::setUp() y \c TestCase::tearDown() pues es más fácil 00798 dejar que lo haga \c TestSuite<TestCase>::runBare(). 00799 - A diferencia de \c TestCase::runBare(), el método \c TestCase::run() 00800 no establece el ambiente de prueba porque no invoca ni a 00801 \c TestCase::setUp() antes de la prueba ni a \c TestCase::tearDown() 00802 después de la prueba. 00803 - \c TestSuite<TestCase>::runBare() invoca los métodos 00804 \c TestCase::setUp() y \c TestCase::tearDown() cuando ejecuta cada 00805 prueba. 00806 - Si el programador cliente quiere que cada prueba se ejecute luego de 00807 establecer el ambiente de la prueba, lo más práctico es que agregue 00808 sus pruebas a una colección de pruebas \c TestSuite para ejecutarlas 00809 con \c TestSuite<TestCase>::runBare(). 00810 */ 00811 #endif 00812 #ifdef English_dox 00813 /** Sets the environment for the test run. 00814 - As \c TestCase::run() is an abstract method, to facilitate 00815 programming it is usual for the programmer not to invoke 00816 \c TestCase::setUp() and \c TestCase::tearDown() because it is 00817 easier to have \c TestSuite<TestCase>::runBare() do it. 00818 - In contrast with \c TestCase::runBare(), method \c TestCase::run() 00819 will not establish the test environment because it does not 00820 invoke neither \c TestCase::setUp() before the test run nor 00821 \c TestCase::tearDown() after the test run. 00822 - \c TestSuite<TestCase>::runBare() invokes methods 00823 \c TestCase::setUp() and \c TestCase::tearDown() when the test run 00824 is executed. 00825 - If the client programmer wants each test run to stablish it test 00826 environment, it is easier to put all test cases into a test collection 00827 \c TestSuite and execute all of them invoking 00828 \c TestSuite<TestCase>::runBare(). 00829 */ 00830 #endif 00831 inline void TestCase::setUp() { } 00832 00833 #ifdef Spanish_dox 00834 /// Destruye el ambiente de prueba. 00835 #endif 00836 #ifdef English_dox 00837 /// Destroys the test environment. 00838 #endif 00839 inline void TestCase::tearDown() {} 00840 00841 #ifdef Spanish_dox 00842 /** Efectúa la prueba y registra su resultado. 00843 - Si la prueba fue exitosa sólo incrementa la cantidad de éxitos 00844 \c successCount(). 00845 - Si la prueba no tuvo éxito reporta en \c toString() ese hecho. 00846 - El resultado de la prueba es \c "cond". 00847 - Los valores \c "fname" y \c "lineno" indican el archivo y el renglón 00848 en donde se ejecuta la prueba. 00849 - Usualmente los valores de \c "fname" y \c "lineno" se obtienen con 00850 las macros globales \c "__FILE__" y \c "__LINE__". 00851 - El valor \c "must_copy" indica que es necesario hacer una copia de la 00852 hilera \c "label", copia que será destruida cuando el registro de 00853 pruebas no exitosas sea borrado. 00854 - En la mayor parte de los casos, la hilera \c "label" es una constante 00855 generada por el preprocesador al usar la macro \c \#cond y por eso su 00856 memoria no debe ser retornada. 00857 Este método es invocado usando la macro \c BUnit_TEST(). 00858 */ 00859 #endif 00860 #ifdef English_dox 00861 /** Executes the test and records its result. 00862 - If the test is successful only increases the numbero of success 00863 \c successCount(). 00864 - If the test is not successful reports in \c toString() this fact. 00865 - The result of the test is \c "cond". 00866 - Values \c "fname" and \c "lineno" show the file and line of the 00867 executed test. 00868 - Usuallyy \c "fname" and \c "lineno" are values obtained with global 00869 macros \c "__FILE__" and \c "__LINE__". 00870 - The value for \c "must_copy" indicates whether it is necessary to 00871 make a copy of string \c "label"; this copy will be destroyed when 00872 the record of not successful test is deleted. 00873 - Most of the time string \c "label" is a constant genertated by the 00874 preprocessor when using macro \c \#cond its memory must not be 00875 returned. 00876 This method is invoked using macro \c BUnit_TEST(). 00877 */ 00878 #endif 00879 /** \dontinclude test_BUnit.cpp 00880 \skipline test::testThis() 00881 \until }} 00882 \see test_BUnit::test_testThis() 00883 */ 00884 inline void TestCase::testThis( 00885 bool cond, const char * label, const char* fname, long lineno, bool must_copy ) 00886 { 00887 if (cond) { 00888 recordSuccess(); 00889 } 00890 else { 00891 recordFailure( label, fname, lineno, must_copy ); 00892 } 00893 } 00894 00895 #ifdef Spanish_dox 00896 /// Sinónimo de \c testThis(). 00897 #endif 00898 #ifdef English_dox 00899 /// Synonym for \c testThis(). 00900 #endif 00901 inline void TestCase::testThis( 00902 bool cond, const std::string& label, const char* fname, long lineno ) 00903 { 00904 testThis( cond, label.c_str(), fname, lineno, true /* must_copy == true */ ); 00905 /* NOTE: In the class instance the name for the test case is stored as 00906 a (char*). If a std::string is used for "label", it must be converted to 00907 a (char*) that will have to be destroyed when the test instance gets 00908 destroyed. This is why parameter "must_copy" must be set to "true". 00909 */ 00910 } 00911 00912 #ifdef Spanish_dox 00913 /** Registra que la prueba no tuvo éxito. 00914 - Los valores \c "fname" y \c "lineno" indican el archivo y el renglón 00915 en donde se ejecuta la prueba. 00916 - Usualmente los valores de \c "fname" y \c "lineno" se obtienen invocando 00917 las macros globales \c "__FILE__" y \c "__LINE__". 00918 - El valor \c "must_copy" indica que es necesario hacer una copia de la 00919 hilera \c "label" en memoria dinámica. Este memoria dinámica será destruida 00920 cuando el caso de prueba sea destruido o cuando el método \c TestCase::reset() 00921 sea invocado. 00922 - En la mayor parte de los casos, la hilera \c "label" es una constante 00923 generada por el preprocesador al usar la macro \c \#cond; como esta hilera 00924 constante no está almacenada en la memoria dinámica no debe ser destruida. 00925 00926 Este método es invocado usando la macro \c BUnit_FAILURE(). 00927 */ 00928 #endif 00929 #ifdef English_dox 00930 /** Records that the test run did not succeed. 00931 - Values \c "fname" and \c "lineno" indicate the file and line where 00932 the test run is executed. 00933 - The values form \c "fname" and \c "lineno" are usuallly obtained 00934 invoking global macros \c "__FILE__" and \c "__LINE__". 00935 - \c "must_copy" forces a copy of string label to be created in dynamic 00936 memory. This dynamic memory will be destroyed when the test case gets 00937 destroyed or when method \c TestCase::reset() gets invoked. 00938 - Oftentimes string \c "label" is a constant string generated by the 00939 preprocessor macro using \c \#cond; this string constant is not stored 00940 in dynamic memory and it must not be destroyed. 00941 00942 This method is invoked using macro \c BUnit_FAILURE(). 00943 */ 00944 #endif 00945 inline void TestCase::recordFailure( 00946 const char* label, const char* fname, int lineno, bool must_copy ) 00947 { 00948 if ( must_copy ) { 00949 size_t len = strlen(label)+1; 00950 char* str = new char[ len ]; // copies the failure message 00951 memcpy( str, label, len ); 00952 label = str; 00953 } 00954 m_failureList.push_back( TestCaseFailure ( fname, lineno, label, must_copy ) ); 00955 m_failure++; 00956 /* NOTE: When this method is invoked directly it is because "label" is a 00957 constant (char*) string, produced by one of the BUnit_TEST() macro using 00958 operator "#" (as in #cond). As thi