Universidad de Costa Rica
Ciencias de
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
Dirección
Internet en dónde está la documentación:
Descripción
del problema a resolver:
Especificación
de la clase Rational:
Especificación
de las clases de prueba:
Invariante de
la clase Rational:
Formato de los
datos de prueba
Entradas vs
Salidas esperadas:
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.
http://www.geocities.com/elsiecv21/Documentacion3.htm
http://www.geocities.com/arsoro1986/Tarea3.htm
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.
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.
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.
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.
El programa realiza una serie de casos de pruebas para
corroborar que los operadores matemáaticos para la clase Rational funcionan
correctamente.
-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.
Visual Studio
2005
Abrir el
proyecto y darle click en la opción build, build rat-calc.
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.
Los datos de prueba que se utilizaron son números racionales, los cuales
fueron:
1/21/4 1/5 1/81
Pruebas de la suma:

Pruebas de la resta:

Pruebas de la multiplicación:

Pruebas de la división:

#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
#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; //
#endif
class istream;
class ostream;
#define using //
#define
namespace
#define std
#define ADH
#define
OPEN_namespace(N) //
#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
#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
(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
/// \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
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
http://di-mare.com/pub/pg2/00-Material-CI-1201.htm
http://www.di-mare.com/adolfo/cursos/2007-2/p2-ta-3.htm