Universidad de Costa Rica

 

 

 

Ciencias de la Computación e Informática

 

 

 

Curso:

Programación II

 

 

 

Documentación

III Tarea Programada

 

 

 

Profesor: Adolfo Di-Mare

 

 

 

Alumnos:

Elsie Castro Villalobos A41369

Armando Soto Rodríguez A55609

 

 

 

 

06/09/2007

 

Índice

 

 

Introducción: 2

Dirección Internet en dónde está la documentación: 3

Descripción del problema a resolver: 3

Abstracción: 4

Especificación de la clase Rational: 4

Operaciones / métodos: 4

Especificación de las clases de prueba: 5

Especificación del programa: 6

Implementación. 6

Invariante de la clase Rational: 7

Compilador usado. 7

¿Cómo compilar el programa?. 7

Guía de uso del programa. 7

Datos de prueba del programa. 7

Formato de los datos de prueba. 7

Entradas vs Salidas esperadas: 7

Código fuente. 9

rational.h. 9

adh_port.h. 21

adh_test.h. 25

test_rational.cpp. 36

Bibliografía: 39

 

 

 

 

 

Introducción:

 

         

          El siguiente trabajo  a realizar se basa en la utilización de casos y datos de prueba, los cuales sirven para probar de una manera eficiente las clases q se están implementando, esto es de gran ayuda ya que el mantenimiento del programa resulta más barato porque es posible verificarde una manera automática si las mejoras que se le han hecho a los modulos no tienen errores.

 

 

          También se usó emplantillamiento de clases que es sumamente importante para la reutilización de módulos disponibles, lo cual disminuye el tiempo de fabricación de programas.

    

 

Dirección Internet en dónde está la documentación:

http://www.geocities.com/elsiecv21/Documentacion3.htm

http://www.geocities.com/arsoro1986/Tarea3.htm

 

 

Descripción del problema a resolver:

 

El objetivo de esta tarea programada es que usted use como base una clase ya implementada para encontrarle todos los errores que tiene. La idea de hacer datos y casos de prueba es construir piezas de programación que ya incluyen los casos y datos de prueba, para que su mantenimiento sea más barato porque es posible verificar de manera automática si las sucesivas mejoras que se le hagan a los módulos no introducen errores. Recuerde las siguientes definiciones:

Casos de prueba:

Son las condiciones o criterios que se deben cumplir para que funcione el programa.

 

Datos de prueba:

Sirven para constatar que los casos de prueba se cumplen.

Los datos de prueba sirven para constatar que se cumplan las condiciones de los casos de prueba del programa.

      Tome la implementación de la clase rational que le fue entregada en clase y mejore los métodos para probar los operadores aritméticos de manera que la prueba sea más exhaustiva.

 

 

 

 

 

 

 

Abstracción:

  Especificación de la clase Rational:

 

       La clase racional sirve para definir un número racional y así poder realizar operaciones matemáticas básicas con los mismos; suma, resta multiplicación y división, además esta clase esta emplantillada lo cual permite definir un racional a base de diferentes tipos de clases como por ejemplo: short, int, long.

 

 

Operaciones / métodos:

 

void Simplify(): Simplifica la fracción para que \c m_num y \c m_den sean números primos relativos.

 

void set(INT num=0, INT den=1)   Le cambia el valor a  *this

 

INT num() const { return m_num; }   Copia del numerador

INT den() const { return m_den; }   Copia del denominador

 

rational& operator  = (const rational&):   Asignación de copia; copia desde "o", el valor anterior de "*this" se pierde.

 

rational& operator  = (INT): Asignación desde un "long".

rational& swap ( rational& ): Intercambia los valores de "*this" y "o".

 

rational& operator += (const rational&): Le suma a "*this" el valor de "otro".

rational& operator -= (const rational&): Le resta a "*this" el valor de "otro".

rational& operator *= (const rational&): Multiplica "*this" por "num".

rational& operator /= (const rational&): Divide "*this" por el valor de "num".

 

 

rational operator  - () const: Calcula y retorna el valor "-x".

friend rational<T> operator + (const rational<T>&, const rational<T>&): Calcula y retorna la suma "x+y".

 

friend rational<T> operator - (const rational<T>&, const rational<T>&): Calcula y retorna la resta "x-y".

   

friend rational<T> operator * (const rational<T>&, const rational<T>&): Calcula y retorna la multiplicación "x*y".

   

friend rational<T> operator / (const rational<T>&, const rational<T>&): Calcula y retorna la división "x/y".

 

   

friend bool operator == (const rational<T>&, const rational<T>&): compara dos numeros racionales x == y

     

friend bool operator <  (const rational<T>&, const rational<T>&):

compara si un racional es menor a otro x < y

 

friend bool operator != (const rational<T>&, const rational<T>&):

compara si un racional es disferente de otro x != y

     

friend bool operator <= (const rational<T>&, const rational<T>&):

compara si un racional es menor o igual a otro x <= y

     

friend bool operator >= (const rational<T>&, const rational<T>&):

compara si un racional es mayor o igual a otro x >= y

 

friend bool operator >  (const rational<T>&, const rational<T>&):

compara si un racional es mayor a otro x > y

     

friend ostream& operator << (ostream &, const rational<T>& ): Graba el valor de "r" en el flujo "COUT".

     

friend istream& operator >> (istream &, rational<T>& ): Lee del flujo de texto "CIN" el valor de "r".

rational& fromString (const char* nStr): Establece el varlor de "*this" a partir de la hilera "nStr".

     

friend double real   (const rational<T>& ): Conversión a real.

     

friend INT   integer(const rational<T>& ): Conversión a long.

 

     

friend bool check_ok( const rational<T>& r ): Revisa la invariante.

 

   Especificación de las clases de prueba:

 

bool run () : Función principal del la prueba - Requiere que recién haya sido ejecutado setUp().

virtual void setUp (): Establece el ambiente de prueba.

bool Run (): Sinónimo de run().

bool runTest (): Sinónimo de run().

int nPass () const:  Cantidad de pruebas exitosas.

int nError () const: Cantidad de pruebas que han fallado.

void recordSuccess (): Registra como exitoso el resultado de una prueba.

virtual void reset (): Anula los contadores de pruebas.

int countTestCases () const:  Cantidad de pruebas realizadas.

std::string getName () const:  Obtiene el nombre de la prueba.

void setName (const char *name=0): Le cambia el nombre a la prueba.

const std::string & toString () const: Hilera "enooorme" para registrar los mensajes de

pruebas fallidas, separados por "\n".

const std::string & errorString () const: Sinónimo de toString().

virtual void tearDown (): Destruye el ambiente de prueba.

  Especificación del programa:

 

            El programa realiza una serie de casos de pruebas para corroborar que los operadores matemáaticos para la clase Rational funcionan correctamente.

 

 

 

Implementación

 

Invariante de la clase Rational:

       -Ningún objeto puede estar almacenado en la posición nula.

       -El denominador debe ser un número positivo.

       -El cero debe representarse con denominador igual a "1".

       -El numerador y el denominador deben ser primos relativos.

 

Compilador usado

       Visual Studio 2005

 

¿Cómo compilar el programa?

       Abrir el proyecto y darle click en la opción build, build rat-calc.

 

Guía de uso del programa

       Este es un programa de casos y datos prueba, por lo cual el usuario no necesita ingresar ningún dato ya que las pruebas se realizan de manera automática, lo único que imprime el programa es el número de pruebas exitosas y el número de errores además de indicar en donde se encuentran estos últimos.

Datos de prueba del programa

 

  Formato de los datos de prueba

            Los datos de prueba que se utilizaron son números racionales, los cuales fueron:

 
1/2
1/4    
1/5    
1/8
1

 

   Entradas vs Salidas esperadas:

 

 

Pruebas de la suma:

 

 

 

Pruebas de la resta:

 

 

 

Pruebas de la multiplicación:

 

 

 

 

Pruebas de la división:

 

 

 

 

 

 

 

 

 

 

 

 

 

Código fuente

rational.h

 

#ifndef rational_h

#define rational_h ///< Evita la inclusión múltiple

 

#include "ADH_port.h"

 

#include <iostream>

using namespace std;

 

/**  La clase \c rational implementa las operaciones aritméticas

     principales para números rationales.

     - <code> [1/3] == [2/6] ==  ...   [9/27] == ... </code>

     - <code> [1/3]  * [2/6] / [3/9] - [9/27] </code>

*/

template <class INT>

class rational {

private:

    INT m_num; ///< Numerador

    INT m_den; ///< Denominador

 

    void Simplify();

 

public:

    // constructores

    rational() : m_num(0), m_den(1) { }  ///< Constructor de vector

    rational(INT num) : m_num(num), m_den(1) { } ///< Constructor a partir de un valor entero

    rational(INT num, INT den)

        : m_num(num), m_den(den) { Simplify(); } ///< Constructor a partir de un valor quedbrado

    rational(const rational& o)       /// Constructor de copia

        { m_num = o.m_num, m_den = o.m_den; }

    ~rational() { }      ///< Destructor

 

    void set(INT num=0, INT den=1);  // Le cambia el valor a \c "*this"

 

    INT num() const { return m_num; }  ///< Copia del numerador

    INT den() const { return m_den; }  ///< Copia del denominador

 

//  void num(long n) { m_num=n; Simplify(); }  // FEO

//  void den(long d) { m_den= ( d!=0 ? d : m_den) ; Simplify(); }  // FEO

 

    rational& operator  = (const rational&);  // Asignación (copia)

    rational& operator  = (INT);

    rational& swap ( rational& );

 

    rational& operator += (const rational&);

    rational& operator -= (const rational&);

    rational& operator *= (const rational&);

    rational& operator /= (const rational&);

 

    rational operator  - () const;              // menos unario

      template <class T> friend rational<T> operator + (const rational<T>&, const rational<T>&);

      template <class T> friend rational<T> operator - (const rational<T>&, const rational<T>&);

    template <class T> friend rational<T> operator * (const rational<T>&, const rational<T>&);

    template <class T> friend rational<T> operator / (const rational<T>&, const rational<T>&);

 

    template <class T> friend bool operator == (const rational<T>&, const rational<T>&);

      template <class T> friend bool operator <  (const rational<T>&, const rational<T>&);

      template <class T> friend bool operator != (const rational<T>&, const rational<T>&);

      template <class T> friend bool operator <= (const rational<T>&, const rational<T>&);

      template <class T> friend bool operator >= (const rational<T>&, const rational<T>&);

      template <class T> friend bool operator >  (const rational<T>&, const rational<T>&);

 

      template <class T> friend ostream& operator << (ostream &, const rational<T>& );

      template <class T> friend istream& operator >> (istream &,       rational<T>& );

    rational& fromString (const char* nStr);

 

      template <class T> friend double real   (const rational<T>& );   // Conversión a real

      template <class T> friend INT   integer(const rational<T>& );   // Conversión a long

 

      template <class T> friend bool check_ok( const rational<T>& r ); // Ok()

//  excluidos porque producen ambigüedad con operadores aritméticos

//  operator double () { return double(m_num) / double(m_den); }

//  operator long   () { return        m_num  /        m_den ; }

}; // rational

 

template <class INT>

INT mcd(INT x, INT y); // Calcula el Máximo Común Divisor

 

/// Sinónimo de \c mcd(x,y) <code> [ inline ] </code>

template <class INT>

inline INT gcd(INT x, INT y) { return mcd(x,y); }

 

/// Cambia el valor del número rational a \c "n/d"

template <class INT>

inline void rational<INT>::set(INT n, INT d) {

    m_num = n;

    m_den = d;

    Simplify();

}

 

/** Copia desde \c "o".

    - El valor anterior de \c "*this" se pierde.

    \par Complejidad:

         O( \c 1 )

    \returns *this

    \see http://www.di-mare.com/adolfo/binder/c04.htm#sc05

*/

template <class INT>

inline rational<INT>& rational<INT>::operator = (const rational<INT>& o) {

    m_num = o.m_num,

    m_den = o.m_den;

 

//  sobra invocar a "Simplify()" pues "o" ya está simplificado

    return *this;

}  // operator =

 

/** Intercambia los valores de \c "*this" y \c "o".

      \par Complejidad:

         O( \c 1 )

 

    \returns *this

 

    \see http://www.di-mare.com/adolfo/binder/c04.htm#sc08

*/

template <class INT>

inline rational<INT>& rational<INT>::swap ( rational<INT>& o ) {

    #if 1

        rational tmp = o;

        o = *this;

        *this = tmp;

    #else

        // Esto NO funciona para objetos, métodos virtuales, etc.

        char tmp[ sizeof( *this ) ];

        memcpy( tmp,   o,     sizeof( *this ) ); // tmp = o;

        memcpy( o,    *this,  sizeof( *this ) ); // o = *this;

        memcpy( *this, tmp,   sizeof( *this ) ); // *this = tmp;

    #endif

    return *this;

}

 

/// Asignación desde un \c "long".

template <class INT>

inline rational<INT>& rational<INT>::operator = (INT entero) {

    m_num = entero;

    m_den = 1;

    return *this;

}  // operator =

 

/// Multiplica \c "*this" por \c "num".

template <class INT>

inline rational<INT>& rational<INT>::operator *= (const rational<INT>& num) {

    m_num *= num.m_num;

    m_den *= num.m_den;

    Simplify();

    return *this;

}  // operator *=

 

/**  Divide \c "*this" por el valor de \c "num".

    \pre

    - (num != 0)

*/

template <class INT>

inline rational<INT>& rational<INT>::operator /= (const rational<INT>& num) {

    m_num *= num.m_den;

    m_den *= num.m_num;

    Simplify();

    return *this;

}  // operator /=

 

/// \c "-x".

/// - Menos unario

/// - Calcula y retorna el valor \c "-x"

template <class INT>

inline rational<INT> rational<INT>::operator - () const {

    rational tmp = (*this);  // tmp.rational( *this );

    tmp.m_num = - tmp.m_num;

    return tmp;

}  // operator -

 

/// ¿ x == y ?

template <class INT>

inline bool operator == (const rational<INT> &x, const rational<INT> &y) {

    return (x.m_num == y.m_num) && (x.m_den == y.m_den);

/*  Nota:

    Como los números racionales siempre están simplificados, no puede

    ocurrir que [1/1] está almacenado como [3/3] y en consecuencia

    basta comparar los valores campo por campo para determinar si se

    da o no la igualdad.

*/

}  // operator ==

 

/// ¿ x < y ?

template <class INT>

inline bool operator < (const rational<INT> &x, const rational<INT> &y) {

    return (x.m_num * y.m_den) < (x.m_den * y.m_num);

/*  Nota:

    Una desigualdad de fracciones se preserva siempre que se

    multiplique a ambos lados por un número positivo. Por eso:

          [a/b] <       [c/d]   <==>

    [(b*d)*a/b] < [(b*d)*c/d]   <==>

          [d*a] < [b*c]

 

    [a/b] > [c/d] <==> [(b*d)*a/b] > [(b*d)*c/d] <==> [d*a] > [b*c]

 

    Debido a que el denominador siempre es un número positivo, el

    trabajo de comparar 2 racionales se puede lograr haciendo 2

    multiplicaciones de números enteros, en lugar de convertirlos

    a punto flotante para hacer la división, que es hasta un orden

    de magnitud más lento.

*/

//  return double(x.m_num) / double(x.m_den) < double(y.m_num) / double(y.m_den);

}  // operator <

 

/// ¿ x > y ?

template <class INT>

inline bool operator > (const rational<INT> &x, const rational<INT> &y) {

    return (y < x);

}  // operator >

 

/// ¿ x != y ?

template <class INT>

inline bool operator != (const rational<INT>& x, const rational<INT>& y) {

    return !(x == y);

}  // operator !=

 

/// ¿ x <= y ?

template <class INT>

inline bool operator <= (const rational<INT>& x, const rational<INT>& y) {

    return !(y < x);

}  // operator <=

 

/// ¿ x >= y ?

template <class INT>

inline bool operator >= (const rational<INT>& x, const rational<INT>& y) {

    return !(x < y);

}  // operator >=

 

/// Convertidor a punto flotante.

template <class INT>

inline double real(const rational<INT>& num) {

    return double (num.m_num) / double (num.m_den);

} // real()

 

/// Convertidor a punto fijo.

template <class INT>

inline INT integer(const rational<INT>& num) {

    return INT   (num.m_num /          num.m_den);

} // integer()

 

#if 0

    /// Convertidor a punto fijo

    inline rational::operator INT() {

        return INT (m_num / m_den);

    }  // rational::operator long

#endif

template <class INT>

bool check_ok_externo( const rational<INT>& r );

 

 

#include  <cstdlib>

#include  <cctype>     // isdigit()

 

 

/** Verifica la invariante de la clase \c rational.

    \par <em>Rep</em> Modelo de la clase:

    \code

    +---+

    | 3 | <==  m_num == numerador del número racional

    +---+

    |134| <==  m_den == denominador del número racional

    +---+

    \endcode

    - http://www.di-mare.com/adolfo/binder/c03.htm#k1-Rep

 

    \remark

    Libera al programador de implementar el método \c Ok()

    - http://www.di-mare.com/adolfo/binder/c04.htm#sc11

*/

template <class INT>

bool check_ok( const rational<INT>& r ) {

    if (&r == 0) {

        /// - Invariante: ningún objeto puede estar almacenado en la posición nula.

        return false;

    }

 

    if ( ! (r.m_den > 0) )  {

        /// - Invariante: el denominador debe ser un número positivo.

        return false;

    }

    if (r.m_num == 0) {

        if ( r.m_den == 1 ) {

            /// - Invariante: el cero debe representarse con denominador igual a "1".

            return true;

        }

        else {

            return false;

        }

    }

    if ( ! ( mcd(r.m_num, r.m_den) == 1 ) ) {

        /// - Invariante: el numerador y el denominador deben ser primos relativos.

        return false;

    }

    return true;

} // check_ok()

 

/** Verifica la invariante de la clase \c rational.

    \remark

    Esta implementación nos se le mete al <em>Rep</em>

    (casi siempre no es posible implementar una función como ésta).

      - http://www.di-mare.com/adolfo/binder/c03.htm#k1-Rep

    \remark

    Libera al programador de implementar el método \c Ok()

    - http://www.di-mare.com/adolfo/binder/c04.htm#sc11

*/

template <class INT>

bool check_ok_no_Rep( const rational<INT>& r ) {

    if (&r == 0) {

        /// - Invariante: ningún objeto puede estar almacenado en la posición nula.

        return false;

    }

 

    if ( ! (r.den() > 0) )  {

        /// - Invariante: el denominador debe ser un número positivo.

        return false;

    }

    if (r.num() == 0) {

        if ( r.den() == 1 ) {

            /// - Invariante: el cero debe representarse con denominador igual a "1".

            return true;

        }

        else {

            return false;

        }

    }

    if ( ! ( mcd(r.num(), r.den()) == 1 ) ) {

        /// - Invariante: el numerador y el denominador deben ser primos relativos.

        return false;

    }

    return true;

} // check_ok_no_Rep()

 

 

/** Calcula el Máximo Común Divisor de los números \c "x" y \c "y".

    - <code> mcd(x,y) >= 1 </code> siempre.

    - MCD <==> GCD: <em> Greatest Common Divisor </em>.

 

    \pre

    <code> (y != 0) </code>

 

    \remark

    Se usa el algoritmo de Euclides para hacer el cálculo.

 

    \par Ejemplo:

    \code

    2*3*5 == mcd( 2*2*2*2 * 3*3 * 5*5, 2*3*5 )

       30 == mcd( -3600, -30 )

    \endcode

*/

template <class INT>

INT mcd(INT x, INT y) {

    INT g = (x < 0 ? -x : x); // trabaja con valores positivos

    INT r = (y < 0 ? -y : y); // "r" es el resto

    INT temp;

 

    do {

        temp = r;

        r    = g % r;

        g    = temp;

    } while (0 != r);

 

    return g;

}  // mcd()

 

 

/** Simplifica el numerador y el denomidador.

    - Transforma el número rational de manera que el numerador y el

      denominador sean primos relativos, asegurando además que el

      denominador es siempre positivo.

    - Si <code>(m_num==0) ==> (m_den==1)</code>.

    - Simplifica la fracción para que \c m_num y \c m_den sean números

      primos relativos ie, <code>mcd(m_num,m_den) == 1</code>.

    - Asegura que \c m_den sea un número positivo.

    - Restaura la invariante de la clase \c rational.

*/

template <class INT>

void rational<INT>::Simplify() {

    if (m_num == 0) {

       m_den = 1;

    }

    INT divisor = mcd(m_num, m_den);

    if (divisor > 1) {   // ==> (divisor != 0)

        m_num /= divisor;

        m_den /= divisor;

    }

    if (m_den < 0) {

        m_num = -m_num;

        m_den = -m_den;

    }

}  // rational::Simplify()

 

/// Le suma a \c "*this" el valor de \c "otro".

template <class INT>

rational<INT>& rational<INT>::operator += (const rational<INT>& otro) {

    m_num  = m_num * otro.m_den + m_den * otro.m_num;

    m_den *= otro.m_den;

    Simplify();

 

    return *this;

}  // operator +=

 

 

/// Le resta a \c "*this" el valor de \c "otro".

template <class INT>

rational<INT>& rational<INT>::operator -= (const rational<INT>& otro) {

    INT oldm_den = m_den;

    INT oldm_num = m_num;

    INT d       = otro.m_den;

    INT n       = otro.m_num;

 

    m_den *= d;

    m_num = oldm_num * d - oldm_den * n;

    Simplify();

 

    return *this;

}  // operator -=

 

/// Establece el varlor de \c "*this" a partir de la hilera \c "nStr".

/// \pre \c "nStr" debe estar escrita en el formato "[num/den]".

template <class INT>

rational<INT>& rational<INT>::fromString (const char* nStr) {

    char ch;  // valor obtenido, caracter por caracter, de "nStr"

 

    bool es_positivo = true;    // manejo de los signos + y -

 

    // se brinca todo hasta el primer dígito

    do {

        ch = *nStr; nStr++;

        if (ch == '-') {  // cambia de signo

            es_positivo = !es_positivo;

        }

    } while (!isdigit(ch));

 

    // se traga el numerador

    INT num = 0;

    while (isdigit(ch)) { // convierte a decimal: izq --> der

        num = 10 * num + (ch-'0');

        ch = *nStr; nStr++;

    }

 

    // se brinca los blancos después del numerador

    while (isspace(ch)) {

        ch = *nStr; nStr++;

    }

 

    INT den;

    if (ch ==']') { // es un número entero

        den = 1;

    }

    else {

        do {  // se brinca todo hasta el denominador

            ch = *nStr; nStr++;

            if (ch == '-') {

                es_positivo = !es_positivo;

            }

        } while (!isdigit(ch));

 

        // se traga el denominador

        den = 0;

        while (isdigit(ch)) {

            den = 10 * den + (ch-'0');

            ch = *nStr; nStr++;

        }

        // Ya no importa si aparece o no el ']' del final del número

    }

 

 

    // le cambia el signo, si hace falta

    if (! es_positivo) {

        num = -num;

    }

    set( num, den );

    return *this;

}

 

/** Graba el valor de \c "r" en el flujo \c "COUT".

    - Graba el valor en el formato [num/den].

    - En particular, este es el operador que se invoca

      cuando se usa, por ejemplo, este tipo de instrucción:

     \code

          cout << r << q;

     \endcode

*/

template <class INT>

ostream& operator<< (ostream &COUT, const rational<INT>& r) {

    if ( r.m_den == 1 ) { // no hay parte fraccional

        return COUT << "[" << r.m_num << "]" ;

    } else {

        return COUT << "[" << r.m_num << "/" << r.m_den << "]" ;

    }

}  // operator <<

 

/** Lee del flujo de texto \c "CIN" el valor de \c "r".

    \pre

    El número rational debe haber sido escrito usando

    el formato "[r/den]", aunque es permisible usar

    algunos blancos.

    - Se termina de leer el valor sólo cuando encuentra \c "]".

    - <code> [ -+-+-+-+- 4 / -- -+ -- 32  ] </code> se lee como

      <code> [1/8] </code>

*/

template <class INT>

istream& operator >> (istream &CIN, rational<INT>& r) {

    char ch;  // valor leido, letra por letra, de "CIN"

 

    bool es_positivo = true;    // manejo de los signos + y -

 

    // se brinca todo hasta el primer dígito

    do {

        CIN >> ch;

        if (ch == '-') {  // cambia de signo

            es_positivo = !es_positivo;

        }

    } while (!isdigit(ch));

 

    // se traga el numerador

    r.m_num = 0;

    while (isdigit(ch)) { // convierte a decimal: izq --> der

        r.m_num = 10 * r.m_num + (ch-'0');

        CIN >> ch;

    }

 

    // se brinca los blancos después del numerador

    while (isspace(ch)) {

        CIN >> ch;

    }

 

    if (ch ==']') { // es un número entero

        r.m_den = 1;

    }

    else {

        do {  // se brinca todo hasta el denominador

            CIN >> ch;

            if (ch == '-') {

                es_positivo = !es_positivo;

            }

        } while (!isdigit(ch));

 

        // se traga el denominador

        r.m_den = 0;

        while (isdigit(ch)) {

            r.m_den = 10 * r.m_den + (ch-'0');

            CIN >> ch;

        }

 

        // El programa se duerme si en el flujo de entrada

        // NO aparece el caracter delimitador final "]",

        // pues la lectura termina hasta encontrar el "]".

        while (ch != ']') {

            CIN >> ch;

        }

    }   // corrección: Andrés Arias <e980300@anubis.ecci.ucr.ac.cr>

 

 

    // le cambia el signo, si hace falta

    if (! es_positivo) {

        r.m_num = -r.m_num;

    }

 

    r.Simplify();

    return CIN;

/*

    no detecta errores...

    [1/0] lo lee y no se queja

    [ !#!#!$#@! 3/ aaaa 4  jajaja ] lo lee como 3/4

    ... pero no se supone que el usuario cometa errores...

*/

 

}  // operator >>

 

/// \c "x+y".

/// - Calcula y retorna la suma \c "x+y".

template <class INT>

rational<INT> operator + (const rational<INT> &x, const rational<INT> &y) {

    INT res_num, res_den;

    res_den = x.m_den * y.m_den;

    res_num = x.m_num * y.m_den + x.m_den * y.m_num;

 

    return rational<INT>(res_num, res_den);

}  // operator + ()

 

/// \c "x-y".

/// - Calcula y retorna la resta \c "x-y".

template <class INT>

rational<INT> operator - (const rational<INT> &x, const rational<INT> &y) {

    INT res_num, res_den;

 

    res_den = x.m_den * y.m_den;

    res_num = x.m_num * y.m_den - x.m_den * y.m_num;

 

    return rational<INT>(res_num, res_den);

}  // operator - ()

 

/// \c "x*y".

/// - Calcula y retorna la multiplicación \c "x*y".

template <class INT>

rational<int> operator * (const rational<INT> &x, const rational<INT> &y) {

    INT res_num, res_den;

 

    res_num = x.m_num * y.m_num;

    res_den = x.m_den * y.m_den;

 

    return rational<INT>(res_num, res_den);

}  // operator * ()

 

/// \c "x/y".

/// - Calcula y retorna la división \c "x/y".

/// \pre <code> y != 0 </code>

template <class INT>

rational<INT> operator / (const rational<INT> &x, const rational<INT> &y) {

    INT res_num, res_den;

    if (0 != y.m_num) {

        res_num = x.m_num * y.m_den;

        res_den = x.m_den * y.m_num;

    }

    return rational<INT>(res_num, res_den);

}  // operator / ()

 

#endif // rational_h

 

// EOF: rational.h

 

adh_port.h

 

#ifndef ADH_port_h

#define ADH_port_h ///< Evita la inclusión múltiple

 

// Documentados acá para Doxygen

#undef  CLOSE_namespace

#undef  USING_namespace

#undef  OPEN_namespace

 

/// Abre namespace   \c "N"

#define OPEN_namespace(N) namespace N {

 

/// Cierra namespace \c "N"

#define CLOSE_namespace(N) }

 

/// Usa namespace    \c "N"

#define USING_namespace(N) using namespace N

 

// Los anula para luego definirlos dentro del #ifdef correcto

#undef  CLOSE_namespace

#undef  USING_namespace

#undef  OPEN_namespace

 

#ifdef DOXYGEN_COMMENT   // Documentados acá para Doxygen

    /// Definido por la biblioteca C++ estándar

    namespace std {} // Está acá para que Doxygen lo documente

    /// ADH son las siglas de \c adolfo@di-mare.com

    namespace ADH {} // Está acá para que Doxygen lo documente

    #define INCLUDE_fstream   Truco para "include <fstream>"   portable

    #define INCLUDE_io        Truco para "include <io>"        portable

    #define INCLUDE_iomanip   Truco para "include <iomanip>"   portable

    #define INCLUDE_iostream  Truco para "include <iostream>"  portable

    #define INCLUDE_list      Truco para "include <list>"      portable

    #define INCLUDE_map       Truco para "include <map>"       portable

    #define INCLUDE_stdexcept Truco para "include <stdexcept>" portable

    #define INCLUDE_vector    Truco para "include <vector>"    portable

#endif

 

// Borland C++

#ifdef __BORLANDC__               ///< Definida para Borland C++

    #if (__BORLANDC__ <= 0x0410)  //   Identifica a BC++ v3.1 y anterior

 

        // Declara el tipo "bool" porque BC++ v3.1 NO tiene "bool"

        #ifndef _bool_h

        #define _bool_h

            #undef false

            #undef true

            #undef bool

 

            typedef int bool;

            const int false = 0;

            const int true  = ! false; // BC++ v3.1 NO tiene "bool"

        #endif

 

        class istream; class ostream;

 

        #define using              // BC++ v3.1 NO tiene "namespace"

        #define namespace

        #define std

        #define ADH

 

        #define OPEN_namespace(N)  // BC++ v3.1 NO tiene "namespace"

        #define CLOSE_namespace(N)

        #define USING_namespace(N)

 

        #ifdef INCLUDE_fstream

            #include  <fstream.h>

        #endif

        #ifdef INCLUDE_io

            #include  <io.h>

        #endif

        #ifdef INCLUDE_iomanip

            #include  <iomanip.h>

        #endif

        #ifdef INCLUDE_iostream

            #include  <iostream.h>

        #endif

        #ifdef INCLUDE_list

            #include  <list.h>

        #endif

        #ifdef INCLUDE_map

            #include  <map.h>

        #endif

        #ifdef INCLUDE_set

            #include  <set.h>

        #endif

        #ifdef INCLUDE_stdexcept

            #include  <stdexcept.h>

        #endif

        #ifdef INCLUDE_string

            #include  <string.h>

        #endif

        #ifdef INCLUDE_vector

            #include  <vector.h>

        #endif

    #endif

 

    #if (__BORLANDC__ >  0x0410)  // Versiones posteriores a BC++ v3.1

        #define OPEN_namespace(N) namespace N {

        #define CLOSE_namespace(N) }

        #define USING_namespace(N) using namespace N

        #error Ajuste ADH_port.h para compìlar con versiones nuevas de BC++

    #endif

#endif

 

// Microsoft C++ (Visual Studio)

#ifdef _MSC_VER                   ///< Definida para Micrsoft C++

    // namespace

    #define OPEN_namespace(N) namespace N {

    #define CLOSE_namespace(N) }

    #define USING_namespace(N) using namespace N

 

    #if (_MSC_VER >= 1300)        //   Identifica a VC++ .net

        /// Definido por la biblioteca C++ estándar

        namespace std {} // Está acá para que Doxygen lo documente

        using namespace std;

 

        #ifdef INCLUDE_fstream

            #include  <fstream>

        #endif

        #ifdef INCLUDE_io

            #include  <io>

        #endif

        #ifdef INCLUDE_iomanip

            #include  <iomanip>

        #endif

        #ifdef INCLUDE_iostream

            #include  <iostream>

        #endif

        #ifdef INCLUDE_list

            #include  <list>

        #endif

        #ifdef INCLUDE_map

            #include  <map>

        #endif

        #ifdef INCLUDE_set

            #include  <set>

        #endif

        #ifdef INCLUDE_stdexcept

            #include  <stdexcept>

        #endif

        #ifdef INCLUDE_string

            #include  <string>

        #endif

        #ifdef INCLUDE_vector

            #include  <vector>

        #endif

    #endif

 

    #if (_MSC_VER < 1300)         //   Identifica a VC++ v6 y anterior

        namespace std {} // Está acá para que Doxygen lo documente

        using namespace std;

        // Antes de MSC++ .NET hay que usar <.h>

        #ifdef INCLUDE_fstream

            #include  <fstream.h>

        #endif

        #ifdef INCLUDE_io

            #include  <io.h>

        #endif

        #ifdef INCLUDE_iomanip

            #include  <iomanip.h>

        #endif

        #ifdef INCLUDE_iostream

            #include  <iostream.h>

        #endif

        #ifdef INCLUDE_list

            #include  <list.h>

        #endif

        #ifdef INCLUDE_map

            #include  <map.h>

        #endif

        #ifdef INCLUDE_set

            #include  <set.h>

        #endif

        #ifdef INCLUDE_stdexcept

            #include  <stdexcept.h>

        #endif

        #ifdef INCLUDE_string

            #include  <string.h>

        #endif

        #ifdef INCLUDE_vector

            #include  <vector.h>

        #endif

    #endif

#endif

 

#endif // ADH_port_h

 

// EOF: ADH_port.h

 

adh_test.h

 

// ADH_test.h (C) 2006  adolfo@di-mare.com

 

/** \file  ADH_test.h

    \brief Módulo para prueba unitaria de programas.

 

    \author Adolfo Di Mare <adolfo@di-mare.com>

    \date   2006

*/

 

/** \mainpage

 

\section sec-01 Módulo para prueba unitaria de programas

 

El archivo de encabezado \c ADH_test.h apoya la escritura de módulos de prueba de

unitaria programas. El modelo que se usa para esta implementación es

similar al expuesto en este artículo "The Simplest Automated Unit

Test Framework That Could Possibly Work" de Chuck Allison, que se

puede obtener aquí:

- http://www.stickyminds.com/getfile.asp?ot=XML&id=3129&fn=XDD3129filelistfilename1%2Epdf

- http://www.google.com/search?num=100&as_q=Simplest+Unit+Test+Allison

- http://search.yahoo.com/search?n=100&p=Simplest+Unit+Test+Allison

 

- Este marco de pruebas es similar a JUnit, pues se presume que en

  el futuro los estudiantes usarán Java como su lenguaje principal

  para desarrollo de programas (pues usan C++ sólo para adiestrarse

  profundamente en técnicas de programación).

  \see http://search.yahoo.com/search?n=100&p=JUnit+Java

- Como el lenguaje C++ no tiene un mecanismo similar al de "reflexión"

  de Java, en cada prueba fallida se registra la condición de prueba

  exacta, obtenida a través de una invocación de la macro \c TEST_THIS()

  que registra el nombre del archivo \c __FILE__ y el renglón \c __LINE__

  de la prueba.

  \see http://search.yahoo.com/search?n=100&p=reflection+Java

- Para simplificar este marco de pruebas no se usa la clase \c TestResult

  que sirve para acumular resultados de las pruebas. En su lugar, se usa

  una hilera enorme, implementada con \c std::string.

- Para simplificar esta plataforma de pruebas, no se hace diferencia entre

  un caso de prueba de prueba existoso y uno que tiene éxito porque se

  ha levantado la excepción adecuada. Esto contrasta con JUnit, que llama

  "falla" a un caso de prueba exitoso que ha levantado una excepción. Por

  eso los valor

- En JUnit la clase \c TestCase es una subclase de \c Assert; aquí no existe

  la clase \c Assert pero para mantener una leve compatibiliidad sí se provée

  una funcionalidad similar con macros cuyo nombres comienzan con "assert".

  \see http://search.yahoo.com/search?n=100&p=JUnit+Java+Assert+Method

*/

 

#ifndef ADH_test_h

#define ADH_test_h ///< Evita la inclusión múltiple

 

#include <string>      // class std::string

#include <sstream>     // class basic_ostringstream<T,Ch>

//#include <limits.h>    //

 

// using namespace std;

/// Definido por la biblioteca C++ estándar.

namespace std {} // Está acá para que Doxygen lo documente

 

/// Escuela de Ciencias de la Computación e Informática.

/// \see http:www.ecci.ucr.ac.cr

namespace ECCI { }

 

/// Establece el ambiente en que se realizará cada prueba.

/// - \c TestSuite<TestCase>::run() invoca los métodos

///   \c TestCase::setUp() y \c TestCase::tearDown()

///   cuando ejecuta cada prueba.

/// - Como \c TestCase::run() es un método abstracto,

///   para facilitar la programación lo usual es que el

///   programador no incluya invocaciones a

///   \c TestCase::setUp() y \c TestCase::tearDown()

///   pues es más simple dejar que lo haga

///   \c TestSuite<TestCase>::run().

/// - Por eso, si el programador cliente quiere que cada

///   prueba se ejecute luego de establecer el ambiente con

///   su \c TestFixture, lo más práctico es que agregue sus

///   pruebas a una colección de pruebas \c TestSuite.

class TestFixture {

public:

    virtual void setUp() { } ///< Establece el ambiente de prueba

    virtual void tearDown() { } ///< Destruye el ambiente de prueba

//  virtual ~TestCase() { tearDown(); } ///< Destructor

}; // TestFixture

 

/// NO IMPLEMENTADO ==> Colector genérico de resultados de prueba.

/// - No está implementado para \c ADH_test.h

/// - En \c ADH_test.h se usa una hilera \c std::string para colectar

///   todos los resultados. \see \c TestCase::toString().

/// - C++ tiene la ventaja sobre Java porque el programador puede

///   usar las macros \c __FILE__ y \c __LINE__  para registrar el

///   sitio en que se produce un error en tiempo de ejecución.

class TestResult {

    private: TestResult(); ///< Prohibe crear objetos de tipo \c TestResult.

};

 

/// NO IMPLEMENTADO ==> Clase abastracta para ejecutar las pruebas y recolectar los resultados.

/// - No está implementado para \c ADH_test.h

/// - En \c ADH_test.h se usa una hilera \c std::string para colectar

///   todos los resultados. \see \c TestCase::toString().

class Test {

private: Test(); ///< Prohibe crear objetos de tipo \c Test.

public:

    /// Retorna la cantidad de pruebas a realizar

    virtual int countTestCases() = 0;

    /// Ejecuta la prueba y recolecta sus resultados en \c result

    virtual void run(TestResult& result) = 0;

};

 

#include <typeinfo.h>  // class std::type_info ==> char* typeid().name();

 

/// Cada caso de prueba es una instancia derivada de esta clase abstracta.

/// - Siempre es obligatorio implementar \c TestCase::run().

class TestCase : public TestFixture {

protected:

    int m_pass; ///< Cantidad de pruebas exitosas

    int m_error; ///< Cantidad de pruebas que han fallado

    const char * m_name; ///< Nombre del caso de prueba

    /// Hilera "enooorme" para registrar los mensajes de pruebas fallidas, separados por \c "\n"

    std::string m_errorString;

public:

    TestCase(const char * name=0);

    virtual ~TestCase() { }  ///< Destructor

    virtual bool run() = 0; ///< Ejecuta la prueba y retorna \c "false" si falla

    bool Run()        { return run(); } ///< Sinónimo de \c run()

    bool runTest()    { return run(); } ///< Sinónimo de \c run()

    int nPass() const { return m_pass; } ///< Cantidad de pruebas exitosas

    int nError() const { return m_error; } ///< Cantidad de pruebas que han fallado

    void recordSuccess() { ++m_pass; } ///< Registra como exitoso el resultado de una prueba

    virtual void reset() { m_pass =  m_error = 0; m_errorString = ""; } ///< Anula los contadores de pruebas

public:

    int countTestCases() const { return nPass()+nError(); } ///< Cantidad de pruebas realizadas

    /// Obtiene el nombre de la prueba

    std::string getName() const { return ( m_name != 0 ? m_name : typeid(*this).name()); }

    void setName( const char * name=0 ) { m_name = name; } ///< Le cambia el nombre a la prueba

    /// Hilera "enooorme" para registrar los mensajes de pruebas fallidas, separados por \c "\n"

    const std::string& toString() const { return m_errorString; }

    const std::string& errorString() const { return toString(); } ///< Sinónimo de \c toString()

protected:

    void recordError( const std::string& lbl, const char* fname, int lineno);

    void testThis( bool cond, const std::string& lbl, const char* fname, long lineno);

    void testThis( bool cond, const char*        lbl, const char* fname, long lineno) {

         testThis( cond, std::string(lbl), fname, lineno);

    } ///< Sinónimo de \c testThis()

private:

    TestCase(const TestCase&);            ///< \c "private" evita la copia de casos de prueba

    TestCase& operator=(const TestCase&); ///< \c "private" evita la copia de casos de prueba

}; // TestCase

 

/// NO IMPLEMENTADO ==> Colección de pruebas.

class TestSuite : public TestCase { };

 

inline TestCase::TestCase(const char * name) : m_pass(0), m_error(0), m_name(name), m_errorString() {

    m_errorString = "";

}  ///< Constructor

 

/** Efectúa la prueba y registra el resultado.

    - Si la prueba es exitosa sólo incrementa la cantidad de éxitos \c nPass().

    - Si la prueba falla reporta en \c toString()   el hecho.

    - La prueba es \c "cond".

    - Los valores \c "fname" y \c "lineno" indican el archivo y el renglón

      en donde se ejecuta la prueba.

    - Usualmente los valores de \c "fname" y \c "lineno" se obtienen con

      las macros globales \c "__FILE__" y \c "__LINE__".

 

    Este método es invocado usando la macro homónima \c TEST_THIS()  */

inline void TestCase::testThis( bool cond, const std::string& lbl, const char* fname, long lineno) {

    if (cond) {

        recordSuccess();

    }

    else {

        recordError(lbl, fname, lineno);

    }

}

 

/** Registra la falla de la prueba y luego lo acumula en la hilera de fallas \c toString().

    - Los valores \c "fname" y \c "lineno" indican el archivo y el renglón

      en donde se ejecuta la prueba.

    - Usualmente los valores de \c "fname" y \c "lineno" se obtienen con

      las macros globales \c "__FILE__" y \c "__LINE__".

 

    Este método es invocado usando la macro \c TEST_ERROR() */

inline void TestCase::recordError( const std::string& lbl, const char* fname, int lineno) {

//  typedef basic_ostringstream<char> ostringstream;

    std::basic_ostringstream<char> ost; // ostringstream ost;

    ost << "=\\_error: " << lbl << " \n=/ (" << lineno << ") " << fname << "\n";

    m_errorString += ost.str();

    m_error++;

}

 

/// [ADH_test] Macros propios de \c ADH_test.h

#define TEST_ADH_test()

#undef  TEST_ADH_test

 

/// [ADH_test] Efectúa la prueba \c cond y registra el resultado.

/// - Si la prueba \c cond tiene éxito invoca el método

///   \c TestCase::recordSuccess()

/// - Si la prueba \c cond falla invoca el método

///   \c TestCase::recordFail()

/// - Esta es una una macro que invoca el método

///   \c TestCase::testThis()

///   \code

///   TEST_THIS("0 != 1"); // Siempre tiene éxito

///   testThis(0 != 1, "0 != 1", __FILE__, __LINE__ ); // Siempre tiene éxito

///   \endcode

#define TEST_THIS(cond) testThis( cond, #cond, __FILE__, __LINE__ )

 

/// [ADH_test] Macro similar a \c TEST_THIS() que usa el mensaje \c msg en caso de falla.

/// - El mensaje \c msg debe ser una hilera literal o un objeto que pueda

///   convertirse en <code>const char *</code>

#define TEST_THIS_Msg(msg, cond) testThis( cond, msg, __FILE__, __LINE__ )

 

/// [ADH_test] Registra como "error" el resultado de una prueba.

/// - El programador cliente es quien determinó que la prueba

///   falló y por eso quiere registrar ese hecho.

/// - Está implementado comun una macro que invoca

///   el método \c TestCase::recordError()

///

///   \code

///   if (22==33) {

///       TEST_ERROR("22 != 33"); // Registra que la prueba falló

///   }

///   \endcode

#define TEST_ERROR(str) recordError( str, __FILE__, __LINE__ )

 

/// [ADH_test] Registra como "exitoso" el resultado de una prueba.

/// - El programador cliente es quien determinó que la prueba

///   fue exitosa y por eso quiere registrar ese hecho.

/// - Generalmente se usa después de atrapar una excepción que

///   se supone debió ser lanzada como resultado de la prueba.

/// - Está implementado comun una macro que invoca

///   el método \c TestCase::recordSuccess()

///

///   \code

///   queue<T> Q(SIZE); // la cola "Q" está vacía ==> no tiene "front()"

///   try {

///       Q.front();  // Es incorrecto usar un valor de la cola si la cola está vacía

///       TEST_ERROR("Q.front();"); // Fallaría si "front()" no levanta la excepción

///    }

///    catch (std::logic_error&) {

///       TEST_SUCCESS(); // Esto es lo correcto pues "front()" levanta "logic_error" para unca cola vacía

///   }

///   \endcode

#define TEST_SUCCESS() recordSuccess()

 

/// [ADH_test] Efectúa la prueba para determinar si <code>expected == actual</code>.

/// - Si la prueba tiene éxito invoca el método

///   \c TestCase::recordSuccess()

/// - Si la prueba falla invoca el método

///   \c TestCase::recordFail()

/// - Esta es una una macro que invoca el método

///   \c TestCase::testThis()

#define TEST_EQUAL(expected, actual) \

        testThis( (expected) == (actual), #expected " == " #actual, __FILE__, __LINE__ )

 

/// [ADH_test] Efectúa la prueba para determinar si <code>expected == actual</code>.

/// - Si la prueba tiene éxito invoca el método

///   \c TestCase::recordSuccess()

/// - Si la prueba falla invoca el método

///   \c TestCase::recordFail()

/// - Esta es una una macro que invoca el método

///   \c TestCase::testThis()

/// - Registra el mensaje \c MSG si la prueba falla.

#define TEST_EQUAL_Msg(MSG, expected, actual) \

        testThis( (expected) == (actual), MSG, __FILE__, __LINE__ )

 

/// Operación de grabado que permite reportar el resultado de la prueba \c test.

/// - Graba en \c COUT el nombre, cantidad de éxitos y cantidad de errores.

std::ostream & operator << (std::ostream& COUT, const TestCase& test) {

    COUT << "TestCase \""  << test.getName() << "\":\n"

         << "\tOK: "       << test.nPass()

         << "\tERROR: "    << test.nError() << "\n";

    return COUT;

}

 

/// Graba en \c "COUT" el resultado de la prueba \c test.

/// - Retorna la cantidad total de errores \c test.nError().

/// - Además, graba la cantidad de pruebas exitosas y erróneas.

/// - Si hubo pruebas no exitosas, graba los mensajes de error correspondientes.

inline long Report( std::ostream& COUT, const TestCase &test ) {

    COUT << test;

    if (test.nError() != 0) {

        COUT << test.errorString();

    }

    return test.nError();

}

 

// ¿¿¿ TestSuite ???

 

//inline bool check_ok<int>( const int & )      { return true; }

//template<class unsigned> inline bool check_ok( const unsigned & ) { return true; }

//template<class int> inline bool check_ok( const long & )     { return true; }

//template<class int> inline bool check_ok( const flota   & )  { return true; }

//template<class int> inline bool check_ok( const double & )   { return true; }

 

template <class T> bool check_ok( const T& ); ///< Declaración genérica para \c check_ok()

inline bool check_ok( const signed char &   ) { return true; } ///< \c check_ok<>()

inline bool check_ok( const unsigned char & ) { return true; } ///< \c check_ok<>()

inline bool check_ok( const signed int &    ) { return true; } ///< \c check_ok<>()

inline bool check_ok( const unsigned int&   ) { return true; } ///< \c check_ok<>()

inline bool check_ok( const signed long &   ) { return true; } ///< \c check_ok<>()

inline bool check_ok( const unsigned long & ) { return true; } ///< \c check_ok<>()

inline bool check_ok( const float &       )   { return true; } ///< \c check_ok<>()

inline bool check_ok( const double &      )   { return true; } ///< \c check_ok<>()

inline bool check_ok( const long double & )   { return true; } ///< \c check_ok<>()

 

/// Retorna una hilera que contiene el valor de \c val.

/// - \c toString() with standard C++

template <class T>

std::string toString( const T & val ) {

//  typedef basic_ostringstream<char> ostringstream;

    std::basic_ostringstream<char> temp; // ostringstream temp;

    temp << val;

    return temp.str( );

}

 

/// [CppUnit] Macros propios de \c CppUnit http://cppunit.sourceforge.net/doc/lastest

#define CPPUNIT_ADH_test()

#undef  CPPUNIT_ADH_test

 

/// [CppUnit] Assertions that a condition is true.

/// \see http://cppunit.sourceforge.net/doc/lastest/group___assertions.html#ga0

#define CPPUNIT_ASSERT(condition) TEST_THIS(condition)

 

/// [CppUnit] Assertion with a user specified message.

/// \see http://cppunit.sourceforge.net/doc/lastest/group___assertions.html#ga1

#define CPPUNIT_ASSERT_MESSAGE(message, condition) CPPUNIT_ASSERT(condition)

 

/// [CppUnit] Fails with the specified message.

/// \see http://cppunit.sourceforge.net/doc/lastest/group___assertions.html#ga2

#define CPPUNIT_FAIL(message) TEST_ERROR(message)

 

/// [CppUnit] Asserts that two values are equals.

/// \see http://cppunit.sourceforge.net/doc/lastest/group___assertions.html#ga3

#define CPPUNIT_ASSERT_EQUAL(expected, actual) TEST_EQUAL(expected, actual)

 

/// [CppUnit] Asserts that two values are equals, provides additional messafe on failure.

/// \see http://cppunit.sourceforge.net/doc/lastest/group___assertions.html#ga4

#define CPPUNIT_ASSERT_EQUAL_MESSAGE(message, expected, actual) \

        TEST_EQUAL_Msg(message, expected, actual)

 

/// [CppUnit] Macro for primitive value comparisons.

/// \see http://cppunit.sourceforge.net/doc/lastest/group___assertions.html#ga5

#define CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, actual, delta)                 \

        assertEquals_Delta(expected, actual, delta)

 

/// [CppUnit] Asserts that the given expression throws an exception of the specified type.

/// \see http://cppunit.sourceforge.net/doc/lastest/group___assertions.html#ga6

#define CPPUNIT_ASSERT_THROW(expression, ExceptionType)  \

        do {                                             \

            bool cpputExceptionThrown_ = false;          \

            try {                                        \

                expression;                              \

            } catch ( const ExceptionType & ) {          \

                cpputExceptionThrown_ = true;            \

            }                                            \

                                                         \

            if ( cpputExceptionThrown_ ) {               \

                break;                                   \

            }                                            \

            TEST_ERROR(                                  \

                "Expected exception: " #ExceptionType )  \

        } while ( false )

 

/// [CppUnit] Asserts that the given expression does not throw any exceptions.

/// \see http://cppunit.sourceforge.net/doc/lastest/group___assertions.html#ga7

#define CPPUNIT_ASSERT_NO_THROW(expression)                  \

        do {                                                 \

            try {                                            \

                expression;                                  \

            } catch ( ... ) {                                \

                TEST_ERROR("Unexpected exception caught");   \

            }                                                \

        } while ( false )

 

/// [CppUnit] Asserts that an assertion fail.

/// \see http://cppunit.sourceforge.net/doc/lastest/group___assertions.html#ga8

#define CPPUNIT_ASSERT_ASSERTION_FAIL(assertion)               \

        CPPUNIT_ASSERT_THROW( assertion, CPPUNIT_NS::Exception )

 

/// [CppUnit] Asserts that an assertion pass.

/// \see http://cppunit.sourceforge.net/doc/lastest/group___assertions.html#ga9

#define CPPUNIT_ASSERT_ASSERTION_PASS(assertion) \

        CPPUNIT_ASSERT_NO_THROW( assertion )

 

// /// Concatena la hilera \c THIS con la hilera \c THAT

// #define ADH_test_CAT( THIS, THAT ) (std::string(THIS) + std::string(THAT).c_str()

 

#define JUnit_ADH_test()

#undef  JUnit_ADH_test

 

/// [JUnit] Macros propios de \c JUnit http://junit.sourceforge.net/javadoc/junit/framework/Assert.html

///  Asserts that two objects are equal.

/// \see http://junit.sourceforge.net/javadoc/junit/framework/Assert.html#assertEquals(java.lang.Object,%20java.lang.Object)

#define assertEquals(          EXPECTED, ACTUAL ) TEST_EQUAL(EXPECTED, ACTUAL)

///  Asserts that two objects are equal (with message).

/// \see http://junit.sourceforge.net/javadoc/junit/framework/Assert.html#assertEquals(java.lang.String,%20java.lang.Object,%20java.lang.Object)

#define assertEquals_Msg( MSG, EXPECTED, ACTUAL ) TEST_EQUAL_Msg(MSG, EXPECTED, ACTUAL)

 

/// [JUnit] Asserts that a condition is true.

/// \see http://junit.sourceforge.net/javadoc/junit/framework/Assert.html#assertTrue(boolean)

#define assertTrue(           CONDITION ) testThis( CONDITION, #CONDITION, __FILE__, __LINE__ )

/// [JUnit] Asserts that a condition is true (with message).

/// \see http://junit.sourceforge.net/javadoc/junit/framework/Assert.html#assertTrue(java.lang.String,%20boolean)

#define assertTrue_Msg( MSG,  CONDITION ) testThis( CONDITION,  MSG,       __FILE__, __LINE__ )

 

/// [JUnit] Asserts that a condition is false.

/// \see http://junit.sourceforge.net/javadoc/junit/framework/Assert.html#assertFalse(boolean)

#define assertFalse(          CONDITION ) testThis( !(CONDITION), "!(" #CONDITION ")", __FILE__, __LINE__ )

/// [JUnit] Asserts that a condition is false (with message).

/// \see http://junit.sourceforge.net/javadoc/junit/framework/Assert.html#assertFalse(java.lang.String,%20boolean)

#define assertFalse_Msg( MSG, CONDITION ) testThis( !(CONDITION),       MSG,           __FILE__, __LINE__ )

 

#include <math.h> // fabs()

/// [JUnit] Asserts that two doubles are equal concerning a delta.

/// \see http://junit.sourceforge.net/javadoc/junit/framework/Assert.html#assertEquals(double,%20double,%20double)

#define assertEquals_Delta(EXPECTED, ACTUAL, DELTA ) \

        testThis( fabs( double(EXPECTED) -  double(ACTUAL) ) < double(DELTA), \

        "|"  #EXPECTED "-" #ACTUAL "| < " #DELTA,  __FILE__, __LINE__ )

 

/// [JUnit] Asserts that two doubles are equal concerning a delta (with message).

/// \see http://junit.sourceforge.net/javadoc/junit/framework/Assert.html#assertEquals(java.lang.String,%20double,%20double,%20double)

#define assertEquals_Delta_Msg( MSG, EXPECTED, ACTUAL, DELTA ) \

        testThis( fabs( double(EXPECTED) -  double(ACTUAL) ) < double(DELTA), \

        MSG, __FILE__, __LINE__ )

 

/// [JUnit] Asserts that an object is null.

/// \see http://junit.sourceforge.net/javadoc/junit/framework/Assert.html#assertNull(java.lang.Object)

#define assertNull(OBJECT)    testThis( 0==&(OBJECT), "assertNull("    #OBJECT ")", __FILE__, __LINE__ )

/// [JUnit] Asserts that an object isn't null.

/// \see http://junit.sourceforge.net/javadoc/junit/framework/Assert.html#assertNotNull(java.lang.Object)

#define assertNotNull(OBJECT) testThis( 0!=&(OBJECT), "assertNotNull(" #OBJECT ")", __FILE__, __LINE__ )

 

/// [JUnit] Asserts that two objects refer to the same object.

/// \see http://junit.sourceforge.net/javadoc/junit/framework/Assert.html#assertSame(java.lang.Object,%20java.lang.Object)

#define assertSame(THIS, THAT) testThis(    &(THIS)==&(THAT), "assertSame("    #THIS ", " #THAT ")", __FILE__, __LINE__ )

///  Asserts that two objects do not refer to the same object.

/// \see http://junit.sourceforge.net/javadoc/junit/framework/Assert.html#assertNotSame(java.lang.Object,%20java.lang.Object)

#define assertNotSame(THIS, THAT) testThis( &(THIS)!=&(THAT), "assertNotSame(" #THIS ", " #THAT ")", __FILE__, __LINE__ )

 

/// [JUnit] Fails a test with no message.

/// \see http://junit.sourceforge.net/javadoc/junit/framework/Assert.html#fail()

#define fail(     )     TEST_ERROR("ERROR")

/// [JUnit] Fails a test with the given message.

/// \see http://junit.sourceforge.net/javadoc/junit/framework/Assert.html#fail(java.lang.String)

#define fail_Msg( MSG ) TEST_ERROR(MSG)

 

#endif // ADH_test_h

 

// EOF: ADH_test.h

 

test_rational.cpp

 

template <class INT>

class rational_Test_Substract : public rational_TestFixture<INT> {

public:

    bool run();

}; // rational_TestFixture

 

/// Función principal del la prueba

/// - Requiere que recién haya sido ejecutado \c setUp()

template <class INT>

bool rational_Test_Substract<INT>::run() {

    assertTrue(  m_half-m_quarter == rational<INT>(10,40) );

    assertTrue(  rational<INT>(-10,40)  == m_quarter-m_half );

 

    assertTrue(  m_one-m_quarter   == rational<INT>(75,100) );

    assertTrue(  rational<INT>(-75,100) == m_quarter-m_one  );

 

    assertEquals( rational<INT>(75,100) ,  m_quarter-m_one );

    assertTrue(   rational<INT>(75,100) == m_one-m_quarter );

 

      assertTrue( m_eight-m_five == rational<INT>(-3,40) );

      assertTrue( rational<INT>(3,40) == m_five-m_eight );

 

    // Esto está aquí sólo para destrozar los valores de *this

    m_half = m_quarter = m_one = m_eight = m_five = 0;

    return nError() == 0;

}

 

template <class INT>

class rational_Test_Multiplication : public rational_TestFixture<INT> {

public:

    bool run();

}; // rational_TestFixture

 

/// Función principal del la prueba

/// - Requiere que recién haya sido ejecutado \c setUp()

template <class INT>

bool rational_Test_Multiplication<INT>::run() {

    assertTrue( m_half * m_quarter == rational<INT>(10,80) );

    assertTrue( rational<INT>(10,80) == m_quarter * m_half );

 

    assertTrue( m_one * m_quarter == rational<INT>(10,40) );

    assertTrue( rational<INT>(10,40) == m_quarter * m_one );

 

    assertTrue(  rational<INT>(1,3) == rational<INT>(33,100)  );

 

      assertTrue( m_eight*m_five == rational<INT>(1,40) );

      assertTrue( rational<INT>(1,40) == m_five*m_eight );

 

    // Esto está aquí sólo para destrozar los valores de *this

    m_half = m_quarter = m_one = m_eight = m_five = 0;

    return nError() == 0;

}

 

template <class INT>

class rational_Test_Division : public rational_TestFixture<INT> {

public:

    bool run();

}; // rational_TestFixture

 

/// Función principal del la prueba

/// - Requiere que recién haya sido ejecutado \c setUp()

template <class INT>

bool rational_Test_Division<INT>::run() {

    assertTrue( m_half/m_quarter == rational<INT>(4,2) );

    assertTrue( ( rational<INT>(1,2) ) == (m_quarter/m_half) );

 

    assertTrue( m_one/m_quarter == rational<INT>(4) );

    assertTrue( rational<INT>(1,4) == m_quarter/m_one );

 

    assertTrue(  rational<INT>(1,3) == rational<INT>(33,100)  );

 

      assertTrue( m_eight/m_five == rational<INT>(5,8) );

      assertTrue( rational<INT>(8,5) == m_five/m_eight );

 

    // Esto está aquí sólo para destrozar los valores de *this

    m_half = m_quarter = m_one = m_eight = m_five = 0;

    return nError() == 0;

}

 

/// Programa principal desde donse se invocan todas las pruebas

 

int main() {

    rational_Test_Add<long>        rational_Test_Add_Instance;

 

    cout << endl << endl << "1) Prueba directa con \"TestFixture\"" << endl;

    rational_Test_Add_Instance.setUp();

    rational_Test_Add_Instance.run();

    Report(cout, rational_Test_Add_Instance);

    if (rational_Test_Add_Instance.nError() != 0 ) {

        cout << "El error" << endl << rational_Test_Add_Instance.toString();

    }

   

    rational_Test_Substract<long>  rational_Test_Substract_Instance;

    cout << endl << endl << "2) Prueba directa con \"TestFixture\"" << endl;

    rational_Test_Substract_Instance.setUp();

    rational_Test_Substract_Instance.run();

    Report(cout, rational_Test_Substract_Instance);

    if (rational_Test_Substract_Instance.nError() != 0 ) {

        cout << "El error" << endl << rational_Test_Substract_Instance.toString();

    }

 

      rational_Test_Multiplication<long>        rational_Test_Multiplication_Instance;

 

    cout << endl << endl << "1) Prueba directa con \"TestFixture\"" << endl;

    rational_Test_Multiplication_Instance.setUp();

    rational_Test_Multiplication_Instance.run();

    Report(cout, rational_Test_Multiplication_Instance);

    if (rational_Test_Multiplication_Instance.nError() != 0 ) {

        cout << "El error" << endl << rational_Test_Multiplication_Instance.toString();

    }

 

      rational_Test_Division<long>        rational_Test_Division_Instance;

 

    cout << endl << endl << "1) Prueba directa con \"TestFixture\"" << endl;

    rational_Test_Division_Instance.setUp();

    rational_Test_Division_Instance.run();

    Report(cout, rational_Test_Division_Instance);

    if (rational_Test_Division_Instance.nError() != 0 ) {

        cout << "El error" << endl << rational_Test_Division_Instance.toString();

    }

 

      cin.get();

 

      return 0;

}

 

// EOF: test_rational.cpp

      

Bibliografía:               

 

http://di-mare.com/pub/pg2/

http://di-mare.com/pub/pg2/00-Material-CI-1201.htm

http://www.di-mare.com/adolfo/cursos/2007-2/p2-ta-3.htm