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áticos 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
<[email protected]>
// 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
[email protected]
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 [email protected]
/** \file
ADH_test.h
\brief Módulo
para prueba unitaria de programas.
\author
Adolfo Di Mare <[email protected]>
\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