Página principal | Lista de namespace | Lista de componentes | Directories | Lista de archivos | Miembros de las clases | Archivos de los miembros

test_deque.cpp

Ir a la documentación de este archivo.
00001 // test_deque.cpp (C) 2006 [email protected]
00002 
00003 /** \file  test_deque.cpp
00004     \brief Módulo de prueba para la clase \c deque
00005 
00006     Este código está basado en el trabajo de Chuck Allison
00007     para probar la clase \c Stack.h
00008 
00009     Aquí lo que se hizo fue implementar esta clase siguiendo
00010     el paradigma de la biblioteca STL de C++, lo que dio por
00011     resultado la clase \c deque.
00012     - http://www.google.com/search?num=100&as_q=Simplest+Unit+Test+Allison
00013     - http://search.yahoo.com/search?n=100&p=Simplest+Unit+Test+Allison
00014 
00015     \author Adolfo Di Mare <[email protected]>
00016     \date   2006
00017 */
00018 
00019 #include "deque.h" // Clase de prueba
00020 using namespace std;
00021 
00022 // En algún manual debe estar descrito qué significa este error
00023 // - http://www.google.com/search?num=100&as_q=c%2B%2B+C4675+Compiler+Warning
00024 #pragma warning( push, 1 )       // check_ok( Q ); ==> Compiler Warning (level 1) C4675
00025 #pragma warning( disable: 4675 ) // check_ok( Q ); ==> Compiler Warning (level 1) C4675
00026 
00027 #include "ADH_test.h" // Módulo para prueba unitaria de programas
00028 
00029 /// Clase para probar el contenedor \c deque<T>
00030 template <class T>
00031 class test_deque : public TestCase {
00032     enum {
00033         N_REPEAT = 100, ///< Las pruebas se hacen para contenedores de tamaño <code>[0..N_REPEAT-1]</code>
00034     };
00035 public:
00036     test_deque() { } ///< Constructor
00037     void test_deque_deque();
00038     void test_empty();
00039     void test_size();
00040     void test_capacity();
00041     void test_front();
00042     void test_front_const();
00043     void test_back();
00044     void test_back_const();
00045 
00046     void test_push_front();
00047     void test_push_back();
00048     void test_pop_front();
00049     void test_pop_back();
00050 
00051     void test_at();
00052 
00053     void test_example();
00054 
00055     /// Método base que ejecuta todas las pruebas de la clase.
00056     bool run() {
00057         //  Estos los estoy construyendo ahora
00058         test_example();
00059 
00060         // Lista de métodos a probar
00061         test_deque_deque();
00062         test_empty();
00063    //   test_size();
00064    //   test_capacity();
00065         test_front();
00066         test_front_const();
00067    //   test_back();
00068         test_back_const();
00069         test_push_front();
00070         test_push_back();
00071         test_at();
00072 
00073         return nError() == 0;
00074     }
00075 };
00076 
00077 /// \fn void deque<T>::deque( size_type N )
00078 /// \see test_deque<T>::test_deque()
00079 
00080 /// Datos de prueba para el constructor y destructor de la clase
00081 template <class T>
00082 void test_deque<T>::test_deque_deque() {
00083     try {
00084         deque<T> Q(0);
00085         fail_Msg("test_deque() ==> Es incorrecto usar contenedores de tamaño cero (0)");
00086     }
00087     catch (std::length_error) {
00088         assertTrue(true); // Esta es la forma de decir: "la prueba sí tuvo éxito"
00089     }
00090     for (int i = 1; i<N_REPEAT; ++i) {
00091         try {
00092             deque<T> Q(i);
00093             assertTrue(true);
00094             assertTrue( check_ok( Q ));
00095         }
00096         catch (...) {
00097             fail_Msg("test_deque() ==> Es correcto usar contenedores de tamaño " + ::toString(i));
00098         }
00099     }
00100 }
00101 
00102 // Esta es la forma Doxygen de documentar métodos que están en otro lado:
00103 /// \fn bool deque<T>::empty() const
00104 /// \see test_deque<T>::test_empty()
00105 
00106 /// Datos de prueba para \c deque<T>::size() && \c deque<T>::capacity() && \c deque<T>::empty().
00107 /// - La idea de esta prueba es crear \c N_REPEAT contenedores de capacidad máxima <code> j in [1..N_REPEAT[ </code>.
00108 ///   - Para cada una de estos contenedores, se prueban los 3 métodos variando el principio del
00109 ///     contenedor desde el índice \c 0 hasta <code> (N_REPEAT-1) </code> del vector \c m_vec[].
00110 /// - Es necesario metérsele al <em>Rep</em> de la clase para implementar esta prueba.
00111 template <class T>
00112 void test_deque<T>::test_empty() {
00113     deque<T>::value_type temp;
00114     for (int i=1; i<N_REPEAT; ++i) { // "i" es la capacidad del contenedor de prueba
00115         for (int j=0; j<i; ++j) {    // "j" sirve para variar el sitio "m_front" donde comienza el contenedor
00116             deque<T> Q(i);
00117             Q.m_front = j; // prueba con todos los valores válidos para Q.m_front == j
00118             assertTrue(Q.size() == 0);
00119             assertTrue(Q.empty());
00120             assertTrue(Q.capacity() == i);
00121             for (int k=0; k<i; ++k) { // llena de valores el contenedor
00122                 assertTrue(Q.size() == k);
00123                 assertTrue(Q.capacity() == i);
00124                 Q.push_back(temp);
00125                 assertTrue( check_ok( Q ));
00126                 assertTrue(Q.size() == k+1);
00127                 assertTrue(Q.capacity() == i);
00128             }
00129         }
00130     }
00131 }
00132 
00133 /// \fn size_type deque<T>::size() const
00134 /// \see test_deque<T>::test_size()
00135 
00136 /// Datos de prueba para \c deque<T>::size() && \c deque<T>::capacity() && \c deque<T>::empty()
00137 template <class T>
00138 void test_deque<T>::test_size() { test_empty(); }
00139 
00140 /// \fn size_type deque<T>::capacity() const
00141 /// \see test_deque<T>::test_capacity()
00142 
00143 /// Datos de prueba para \c deque<T>::size() && \c deque<T>::capacity() && \c deque<T>::empty()
00144 template <class T>
00145 inline void test_deque<T>::test_capacity() { test_size(); }
00146 
00147 /// Datos de prueba para \c deque<T>::front() && \c deque<T>::back().
00148 /// - La idea de esta prueba es crear \c N_REPEAT contenedores de capacidad máxima <code> j in [1..N_REPEAT[ </code>.
00149 ///   - Para cada una de estos contenedores, se prueba el método \c front() variando el principio del
00150 ///     contenedor desde el índice \c 0 hasta <code> (N_REPEAT-1) </code> del vector \c m_vec[].
00151 /// - Es necesario metérsele al <em>Rep</em> de la clase para implementar esta prueba.
00152 /// - Para verficar que el valor que está almacenado en cada posición de \c m_vec[] esta
00153 ///   prueba no usa contenedores de tipo \c T (el parámetro de la plantilla). El contenedor de prueba
00154 ///   almacena número enteros, \c deque<int>, porque de esta manera se pueden usar las
00155 ///   operaciones aritméticas para incrementar paulatinamente el valor agregado al contenedor.
00156 template <class T>
00157 void test_deque<T>::test_front() {
00158     // m_vec
00159     //   ||
00160     //   \/ <1> <2>==m_front    <6>
00161     // +---+---+---+---+---+---+---+
00162     // | _ | _ | 0 | 1 | 2 | 3 | _ |
00163     // +---+---+---+---+---+---+---+
00164     //  <0>      |-----------+
00165     // m_front---+  #2  #3  #4
00166     //            m_size == 4
00167     for (int i=1; i<N_REPEAT; ++i) { // "i" es la capacidad del contenedor de prueba
00168         for (int j=0; j<i; ++j) {
00169             deque<int> Q(i);
00170             Q.m_front = j; // prueba con todos los valores válidos para Q.m_front == j
00171             assertTrue(Q.size() == 0);
00172 
00173             for (int k=0; k<i; ++k) { // llena de valores el contenedor
00174                 Q.push_back(k);
00175                 assertTrue( check_ok( Q ));
00176                 assertTrue(Q.front() == 0);
00177                 assertTrue(Q.back() == k);
00178                 assertTrue(Q.size() == k+1);
00179             }
00180             assertTrue(Q.front() == 0);
00181             assertTrue(Q.back() == i-1);
00182             assertTrue(Q.size()==i);
00183             for (int k=0; k<i; ++k) { // ahora lo vacea
00184                 assertTrue(Q.front() == k);
00185                 assertTrue(Q.back() == i-1);
00186                 assertTrue(Q.size() == i-k);
00187                 Q.pop_front();
00188                 assertTrue( check_ok( Q ));
00189             }
00190             assertTrue_Msg( "Q.size()==" + ::toString(Q.size()) , Q.empty() );
00191         }
00192     }
00193 }
00194 
00195 /// Datos de prueba para \c deque<T>::front() const
00196 template <class T>
00197 void test_deque<T>::test_front_const() {
00198     // Sólo se asegura de que sea invocada el método "const"
00199     // - La lógica de front() se prueba con test_front()
00200     const deque<T> Q_const(4);
00201     const_cast< deque<T>& >(Q_const).m_size = 1;
00202     assertTrue(Q_const.front() == Q_const.front());
00203 }
00204 
00205 /// Datos de prueba para \c deque<T>::front() && \c deque<T>::back()
00206 template <class T>
00207 void test_deque<T>::test_back() { test_front(); }
00208 
00209 /// Datos de prueba para deque<T>::back() const
00210 template <class T>
00211 void test_deque<T>::test_back_const() {
00212     // Sólo se asegura de que sea invocada el método "const"
00213     // - La lógica de back() se prueba con test_back()
00214     const deque<T> Q_const(4);
00215     const_cast< deque<T>& >(Q_const).m_size = 1;
00216     assertTrue(Q_const.back() == Q_const.back());
00217 }
00218 
00219 /// Datos de prueba para \c deque<T>::push_front() y \c deque<T>::pop_front()
00220 template <class T>
00221 void test_deque<T>::test_push_front() {
00222     deque<T>::value_type temp;
00223     for (int i=1; i<N_REPEAT; ++i) {
00224         for (int j=0; j<i; ++j) {
00225             deque<T> Q(i);
00226             assertTrue(Q.size() == 0);
00227             Q.m_front = j; // prueba con todos los valores válidos para Q.m_front == j
00228             assertTrue(Q.size() == 0);
00229                         
00230                         int k;
00231 
00232             for (k=0; k<i; ++k) { // llena de valores el contenedor
00233                 assertTrue(Q.size() == k);
00234                 Q.push_front(temp);
00235                 assertTrue( check_ok( Q ));
00236                 assertTrue(Q.size() == k+1);
00237             }
00238  
00239             for (; k>0; --k) { // ahora lo vacea
00240                 assertTrue(Q.size() == k);
00241                 Q.pop_front();
00242                 assertTrue( check_ok( Q ));
00243                 assertTrue(Q.size() == k-1);
00244             }
00245             if (!Q.empty()) {
00246                 assertTrue_Msg( "k==" + ::toString(k) , k==0 );
00247                 assertTrue_Msg( "Q.size()==" + ::toString(Q.size()) , Q.empty() );
00248             }
00249         }
00250     }
00251 }
00252 
00253 /// Datos de prueba para \c deque<T>::push_back() y \c deque<T>::pop_back()
00254 template <class T>
00255 void test_deque<T>::test_push_back() {
00256     deque<T>::value_type temp;
00257     for (int i=1; i<N_REPEAT; ++i) {
00258         for (int j=0; j<i; ++j) {
00259             deque<T> Q(i);
00260             assertTrue(Q.size() == 0);
00261             Q.m_front = j; // prueba con todos los valores válidos para Q.m_front == j
00262             assertTrue(Q.size() == 0);
00263 
00264                         int k;
00265             for (k=0; k<i; ++k) { // llena de valores el contenedor
00266                 assertTrue(Q.size() == k);
00267                 Q.push_back(temp);
00268                 assertTrue( check_ok( Q ));
00269                 assertTrue(Q.size() == k+1);
00270             }
00271 
00272             for (; k>0; --k) { // ahora lo vacea
00273                 assertTrue(Q.size() == k);
00274                 Q.pop_back();
00275                 assertTrue( check_ok( Q ));
00276                 assertTrue(Q.size() == k-1);
00277             }
00278             if (!Q.empty()) {
00279                 assertTrue_Msg( "k==" + ::toString(k) , k==0 );
00280                 assertTrue_Msg( "Q.size()==" + ::toString(Q.size()) , Q.empty() );
00281             }
00282         }
00283     }
00284 }
00285 
00286 /// Datos de prueba para \c deque<T>::pop_front()
00287 template <class T>
00288 inline void test_deque<T>::test_pop_front() { test_push_front(); }
00289 
00290 /// Datos de prueba para \c deque<T>::pop_back()
00291 template <class T>
00292 inline void test_deque<T>::test_pop_back() { test_push_back(); }
00293 
00294 /// Datos de prueba para \c deque<T>::at().
00295 ///  - Es necesario metérsele al <em>Rep</em> de la clase para implementar esta prueba.
00296 ///  - Para verficar que el valor que está almacenado en cada posición de \c m_vec[] esta
00297 ///    prueba no usa contenedores de tipo \c T (el parámetro de la plantilla). El contenedor de prueba
00298 ///    almacena número enteros, \c deque<int>, porque de esta manera se pueden usar las
00299 ///    operaciones aritméticas para incrementar paulatinamente el valor agregado al contenedor.
00300 ///  - Independientemente de cuál sea el tipo \c T, la prueba siempre se hace usando enteros para
00301 ///    poder verificar qué es lo que está almacenado en \c Q[i].
00302 ///    - Se puede probar con todos los valores para \c Q.capacity() en \c [0..N_REPEAT[
00303 ///      - Sin embargo, esta prueba dura DEMASIADO pues cada vez que se levanta
00304 ///        una excepción la máquina se traga el CPU haciendo cálculos.
00305 ///      - En lugar de probar con todos los valores, se prueba sólo con los del vector
00306 ///        \c Pruebe_Con_Estos[].
00307 template <class T>
00308 void test_deque<T>::test_at() {
00309     deque<int> Q(4); // cualquier n>0 funciona
00310     deque<int>::value_type *remember = Q.m_vec; // vector viejo
00311     try {
00312         assertTrue(Q.capacity() < N_REPEAT*2);
00313         try {
00314             // "Agranda" el vector a Q para poder usar valores "fuera de rango"
00315             deque<int>::value_type *Doble_Vec;
00316             Doble_Vec = new deque<int>::value_type [ 2*N_REPEAT ];
00317             Q.m_vec = Doble_Vec; // usa el vectorsote de prueba
00318             assertTrue( check_ok( Q ));
00319         }
00320         catch (...) {
00321             fail_Msg("test_at()");
00322             throw;
00323         }
00324 
00325         // Prueba con algunos para que la prueba no dure demasiado
00326         int Pruebe_Con_Estos[] ={ 1,2,3,4,5, 7,9,11,12,13, 23,50, 77,N_REPEAT-2,N_REPEAT-1 };
00327         assertTrue(77<N_REPEAT-2);
00328         int CUANTOS = sizeof(Pruebe_Con_Estos)/sizeof(*Pruebe_Con_Estos);
00329         int i,j,k;
00330         for (i=0; i<CUANTOS; ++i) {
00331             for (j=0; j<Pruebe_Con_Estos[i]; ++j) {
00332                 Q.m_front = j; // prueba con todos los valores válidos para Q.m_front == j
00333                 Q.m_size = 0; // contenedor vacío
00334                 Q.m_capacity = Pruebe_Con_Estos[i]; // usa Pruebe_Con_Estos[i] en lugar de "i"
00335 
00336                 // marca todos los campos del vector como valores "fuera de rango"
00337                 for (k=0; k<2*N_REPEAT; ++k) {
00338                     Q.m_vec[k] = -1;
00339                 }
00340                 // Pone en el contenedor los valores 1.2....N_REPEAT
00341                 for (k=0; k<Pruebe_Con_Estos[i]; ++k) {
00342                     Q.push_back(k);
00343                 }
00344                 for (k=0; k<Pruebe_Con_Estos[i]; ++k) {
00345                     assertTrue( k == Q[k]    );
00346                     assertTrue( k == Q.at(k) );
00347                 }
00348                 // Euler dijo que la suma (1..N_REPEAT) se calcula por fórmula
00349                 //   1 + 2 + ... +n-1 ==\   n*(n-1) / 2
00350                 //  n-1+         + 1  ==/
00351                 int suma_euler = Q.m_capacity * (Q.m_capacity - 1) / 2;
00352                 // Ahora suma los que sí están dentro del vector
00353                 deque<int>::value_type suma_real = 0;
00354                 for (k=0; k<Pruebe_Con_Estos[i]; ++k) {
00355                     deque<int>::value_type val = Q.front();
00356                     suma_real += val;
00357                     Q.pop_front();
00358                 }
00359                 assertTrue(suma_euler == suma_real);
00360 
00361                 // Aquí debe haber únicamente Q.m_capacity valores diferentes de -1
00362                 int count=0;
00363                 for (k=0; k<2*N_REPEAT; ++k) {
00364                     if (Q.m_vec[k] >= 0) {
00365                         ++count; // cuenta los que están en rango
00366                     }
00367                     else {
00368                         try { // estos están fuera de rango
00369                             int bomba = Q.at(k);
00370                             fail_Msg("test_at()");
00371                         }
00372                         catch (std::out_of_range) {
00373                             // estos son los que están "fuera de rango" de acuerdo a push_back()
00374                             assertTrue(true);
00375                         }
00376                         catch (...) {
00377                             fail_Msg("test_at()");
00378                             throw;
00379                         }
00380                     }
00381                 }
00382                 assertTrue(Q.m_capacity==count);
00383             }
00384         }
00385     }
00386     catch (...) {
00387         // Si cae aquí es porque algo falló.
00388         // - No hay que hacer nada porque en otro lugar ya el
00389         //   problema fue registrado invocando fail_Msg("...");
00390     }
00391     // se deshace del "vectorsototote"
00392     delete [] Q.m_vec;
00393     Q.m_vec = remember; // restaura Q.m_vec[]
00394     // Ahora el destructor de "Q" se encarga de devolver 
00395     // la memoria dinámica que está usando m_vec[]
00396 }
00397 
00398 /// Ejemplo de uso de la clase \c deque<T>.
00399 template <class T>
00400 void test_deque<T>::test_example() {
00401     const unsigned SIZE = 7; // Capacidad del contenedor de prueba \c Q<T> para \c test_example()
00402     {   // La capacidad del contenedor debe ser definido en el momento de construcción
00403         try { // Es incorrecto usar contenedores de tamaño cero (0)
00404             deque<T> Q(0); // Es incorrecto usar contenedores de capacidad cero (0)
00405             fail_Msg("deque<unsigned> Q(0);");
00406         }
00407         catch (std::logic_error&) {
00408             assertTrue(true);
00409         }
00410         catch (...) {
00411             fail_Msg("Execpción inesperada");
00412         }
00413     }
00414     assertTrue(SIZE > 0);
00415 
00416     {   // El contenedor está vacío y su tamaño debe ser cero (0)
00417         deque<T> Q(SIZE);
00418         assertTrue( check_ok( Q ));
00419         assertTrue(Q.size() == 0);
00420         try { // Es incorrecto usar un valor del contenedor si el contenedor está vacío
00421             Q.front();
00422             fail_Msg("Q.front();");
00423         }
00424         catch (std::logic_error&) {
00425             assertTrue(true);
00426         }
00427         catch (...) {
00428             fail_Msg("Q.front();");
00429         }
00430 
00431         try { // Es incorrecto eliminar un valor del contenedor si el contenedor está vacío
00432             Q.pop_front();
00433             fail_Msg("Q.pop_front();");
00434         }
00435         catch (std::logic_error&) {
00436             assertTrue(true);
00437         }
00438         catch (...) {
00439             fail_Msg("Q.pop_front();");
00440         }
00441         assertTrue( check_ok( Q ));
00442     }
00443 
00444     {   // Es incorrecto almacenar más de Q.capacity() valores en el contenedor
00445         deque<unsigned> Q(SIZE);
00446         try {
00447             for (unsigned i = 0; i < SIZE; ++i) {
00448                 Q.push_back(i);
00449             }
00450             assertTrue(true);
00451             assertTrue( check_ok( Q ));
00452         }
00453         catch (...) {
00454             fail_Msg("Execpción inesperada");
00455             return;
00456         }
00457 
00458         assertTrue(Q.size() == SIZE);
00459         assertTrue(Q.back() == SIZE-1);
00460 
00461         try { // Ya el contenedor está llena y no le caba nada más
00462             Q.push_back(SIZE);
00463             fail_Msg("Q.push_back(SIZE);");
00464         }
00465         catch (std::logic_error&) {
00466             assertTrue(true);
00467         }
00468         catch (...) {
00469             fail_Msg("Execpción inesperada");
00470         }
00471 
00472         for (unsigned i = 0; i < SIZE; ++i) {
00473             assertTrue(Q.front() == i); // ¿¿¿ AQUI ???
00474             try {
00475                 Q.pop_front();
00476                 assertTrue(true);
00477             }
00478             catch (...) {
00479                 fail_Msg("Q.pop_front();");
00480                 return;
00481             }
00482         }
00483         assertTrue(Q.size() == 0);
00484         assertTrue( check_ok( Q ) );
00485 
00486         try { // Ya el contenedor está vacío y no se le puede sacar nada más
00487             Q.pop_front();
00488             fail_Msg("Q.pop_front();");
00489         }
00490         catch (std::logic_error&) {
00491             assertTrue(true);
00492         }
00493         catch (...) {
00494             fail_Msg("Q.pop_front();");
00495         }
00496     }
00497 }
00498 
00499 /// Prueba \c TestCase.
00500 /// - Como ocurre con la mayor parte de los programas de prueba,
00501 ///   este programa no imprime nada, pues un programa de prueba
00502 ///   sólo debiera imprimir un mensaje de error si alguna prueba
00503 ///   falla, en cuyo caso el programador debería revisar la
00504 ///   rutina o método que quebró la implementación.
00505 /// - Lo que este programa imprime es una salida muy simple:
00506 ///   \code
00507 ///   TestCase "class deque_test<int>":
00508 ///       OK: 8380993 ERROR: 0
00509 ///   TestCase "class deque_test<float>":
00510 ///       OK: 8380993 ERROR: 0
00511 ///   \endcode
00512 int main_TestCase() {
00513     test_deque<int>   Test_I;
00514     test_deque<float> Test_F;
00515 
00516     Test_I.run();
00517     Report( cout, Test_I );
00518     Test_F.run();
00519     Report( cout, Test_F );
00520     return Test_I.nError() + Test_F.nError();
00521 }
00522 
00523 /// Programa principal que ejecuta todas las pruebas.
00524 int main() {
00525     return main_TestCase();
00526 }
00527 
00528 #pragma warning( pop ) // check_ok( Q ); ==> Compiler Warning (level 1) C4675
00529 
00530 // EOF: test_deque.cpp

Generado el Tue Aug 21 14:45:39 2007 para Contenedor deque: por  doxygen 1.4.1
Hosted by www.Geocities.ws

1