|
/* Ausgabe */ |
|
#include <stdio.h> |
|
/* Für Exit-Codes (EXIT_SUCCES, EXIT_FAILURE) */ |
|
#include <stdlib.h> |
|
/* Speicher-Funktionen */ |
|
#include <string.h> |
|
#include <limits.h> |
|
#include <assert.h> |
|
/* vararg */ |
|
#include <stdarg.h> |
|
/* number Bibliothek */ |
|
#include "number.h" |
|
|
|
/* Hier die bereits implementierten Funktionen mit 1 markieren, den Rest mit 0 */ |
|
|
|
#define NUMBER_CLEAR_IMPLEMENTED 1 |
|
#define NUMBER_INIT_IMPLEMENTED 1 |
|
#define NUMBER_COPY_DATA_IMPLEMENTED 1 |
|
#define NUMBER_IS_ZERO_IMPLEMENTED 1 |
|
#define NUMBER_IS_NEGATIVE_IMPLEMENTED 1 |
|
#define NUMBER_IS_OVERFLOWN_IMPLEMENTED 1 |
|
#define NUMBER_LESSER_IMPLEMENTED 1 |
|
#define NUMBER_EQUALS_IMPLEMENTED 1 |
|
#define NUMBER_GREATER_IMPLEMENTED 1 |
|
#define NUMBER_INVERT_IMPLEMENTED 1 |
|
#define NUMBER_AND_IMPLEMENTED 1 |
|
#define NUMBER_OR_IMPLEMENTED 1 |
|
#define NUMBER_XOR_IMPLEMENTED 1 |
|
#define NUMBER_SUM_IMPLEMENTED 1 |
|
#define NUMBER_TWO_COMPLEMENT_IMPLEMENTED 1 |
|
#define NUMBER_DIFFERENCE_IMPLEMENTED 1 |
|
#define NUMBER_PRODUCT_IMPLEMENTED 1 |
|
#define NUMBER_QUOTIENT_IMPLEMENTED 1 |
|
#define NUMBER_MODULO_IMPLEMENTED 1 |
|
#define NUMBER_NUMBER_TO_STRING_IMPLEMENTED 1 |
|
#define NUMBER_STRING_TO_NUMBER_IMPLEMENTED 1 |
|
|
|
typedef enum StatusCode_e |
|
{ |
|
STATUS_SUCCESS = 0, |
|
STATUS_ERROR = 1 << 0, |
|
STATUS_WARNING = 1 << 1 |
|
} StatusCode; |
|
|
|
/** |
|
Gibt "Fehler: " und den gegebenen Formatstring-Fehler sowie "\n" auf stderr aus und setzt ERR_FAILURE in status. |
|
**/ |
|
void Errorf( StatusCode* status, const char* const message, ... ) |
|
{ |
|
va_list args; |
|
fputs( " Fehler: ", stderr ); |
|
va_start( args, message ); |
|
vfprintf( stderr, message, args ); |
|
va_end( args ); |
|
fputs( "\n", stderr ); |
|
*status |= STATUS_ERROR; |
|
} |
|
|
|
/** |
|
Gibt "Warnung: " und die gegebenen Formatstring-Warnung sowie "\n" auf stderr aus und setzt ERR_WARNING in status. |
|
**/ |
|
void Warningf( StatusCode* status, const char* const message, ... ) |
|
{ |
|
va_list args; |
|
fputs( " Warnung: ", stderr ); |
|
va_start( args, message ); |
|
vfprintf( stderr, message, args ); |
|
va_end( args ); |
|
fputs( "\n", stderr ); |
|
*status |= STATUS_WARNING; |
|
} |
|
|
|
/** |
|
@brief Prüft, ob der gegebene Array gegebener Bitlänge nur aus Nullen besteht. |
|
**/ |
|
int IsNull( const unsigned char* arr, const unsigned int numBits ) |
|
{ |
|
unsigned int i = 0; |
|
for( i = 0; i < numBits; ++i ) |
|
{ |
|
if( ( *arr & ( 1 << ( i % CHAR_BIT ) ) ) != 0 ) |
|
{ |
|
printf( "Bit %d nicht auf 0. (Benachbarte bits: 0x%x)\n", i, (unsigned int)*arr ); |
|
return 0; |
|
} |
|
if( ( ( i + 1 ) % CHAR_BIT ) == 0 ) |
|
{ |
|
++arr; |
|
} |
|
} |
|
return 1; |
|
} |
|
|
|
unsigned int GetBit( const Number num, unsigned int bit ) |
|
{ |
|
return !!( num.data[ bit / NUMBER_CHUNKSIZE ] & ( 1 << ( bit % NUMBER_CHUNKSIZE ) ) ); |
|
} |
|
|
|
void SetBit( Number* num, unsigned int bit, unsigned int value ) |
|
{ |
|
if( value ) |
|
{ |
|
num->data[ bit / NUMBER_CHUNKSIZE ] |= ( ( ( NUMBER_BASETYPE ) 1 ) << ( bit % NUMBER_CHUNKSIZE ) ); |
|
} |
|
else |
|
{ |
|
num->data[ bit / NUMBER_CHUNKSIZE ] &= ~( ( ( NUMBER_BASETYPE ) 1 ) << ( bit % NUMBER_CHUNKSIZE ) ); |
|
} |
|
} |
|
|
|
int Equals( Number num1, Number num2 ) |
|
{ |
|
unsigned int i = 0; |
|
for( i = 0; i < NUMBER_CHUNKCOUNT * NUMBER_CHUNKSIZE; ++i ) |
|
{ |
|
if( GetBit( num1, i ) != GetBit( num2, i ) ) return 0; |
|
} |
|
return 1; |
|
} |
|
|
|
int UnusedBitsZero( const Number num ) |
|
{ |
|
unsigned int i = 0; |
|
for( i = NUMBER_BITS; i < NUMBER_CHUNKCOUNT * NUMBER_CHUNKSIZE; ++i ) |
|
{ |
|
if( GetBit( num, i ) ) |
|
{ |
|
return 0; |
|
} |
|
} |
|
return 1; |
|
} |
|
|
|
/** |
|
@note Always uses the same memory! e.g. printf("num1: %s num2: %s", NumberToString(num1), NumberToString(num2)) will print the same number twice! |
|
On the bright side, there's no need to free any memory. |
|
**/ |
|
const char* NumberToString( const Number num ) |
|
{ |
|
static char str[ NUMBER_CHUNKCOUNT * NUMBER_CHUNKSIZE + 2 + 1 ]; |
|
unsigned int i = 0; |
|
for( i = 0; i < NUMBER_CHUNKCOUNT * NUMBER_CHUNKSIZE; ++i ) |
|
{ |
|
const char chr = '0' + GetBit( num, i ); |
|
if( i < NUMBER_BITS ) |
|
{ |
|
str[ NUMBER_CHUNKCOUNT * NUMBER_CHUNKSIZE + 2 - i - 1 ] = chr; |
|
} |
|
else |
|
{ |
|
str[ NUMBER_CHUNKCOUNT * NUMBER_CHUNKSIZE + 2 - i - 2 ] = chr; |
|
} |
|
} |
|
str[ 0 ] = '['; |
|
str[ NUMBER_CHUNKCOUNT * NUMBER_CHUNKSIZE - NUMBER_BITS + 1 ] = ']'; |
|
str[ NUMBER_CHUNKCOUNT * NUMBER_CHUNKSIZE + 2 ] = '\0'; |
|
return str; |
|
} |
|
|
|
Number GetZero() |
|
{ |
|
Number num; |
|
num.status = number_valid; |
|
num.chunks = NUMBER_CHUNKCOUNT; |
|
num.length = NUMBER_BITS; |
|
assert( NUMBER_BITS >= 1 ); |
|
memset( (void*)&num.data[0], 0, NUMBER_CHUNKCOUNT * sizeof( NUMBER_BASETYPE ) ); |
|
return num; |
|
} |
|
|
|
Number ToNumber( const int integer ) |
|
{ |
|
Number num = GetZero(); |
|
unsigned int i = 0; |
|
/* Negative Zahl: mit -1 auffüllen */ |
|
if( integer < 0 ) |
|
{ |
|
memset( (char*)&num.data[0], 0xFF, NUMBER_CHUNKCOUNT * sizeof( NUMBER_BASETYPE ) ); |
|
} |
|
/* Wenn eine int komplett reinpasst, einfach in den ersten Chunk schreiben. */ |
|
if( sizeof( NUMBER_BASETYPE ) >= sizeof( int ) ) |
|
{ |
|
assert( NUMBER_CHUNKCOUNT > 0 ); |
|
num.data[0] = integer; |
|
} |
|
/* Sonst Stück für Stück */ |
|
else |
|
{ |
|
for( i = 0; i < NUMBER_CHUNKCOUNT && i * NUMBER_CHUNKSIZE < CHAR_BIT * sizeof( int ); ++i ) |
|
{ |
|
num.data[i] = ((int)integer) >> ( i * NUMBER_CHUNKSIZE ); |
|
} |
|
} |
|
/* ungenutzte Bits auf 0 */ |
|
for( i = NUMBER_BITS; i < NUMBER_CHUNKCOUNT * NUMBER_CHUNKSIZE; ++i ) |
|
{ |
|
SetBit( &num, i, 0 ); |
|
} |
|
return num; |
|
} |
|
|
|
#define GetMinusOne() ToNumber(-1) |
|
|
|
#define GetOne() ToNumber(1) |
|
|
|
#define GetTwo() ToNumber(2) |
|
|
|
#define GetThree() ToNumber(3) |
|
|
|
#define GetFour() ToNumber(4) |
|
|
|
#define GetMinusTwo() ToNumber(-2) |
|
|
|
Number GetMin() |
|
{ |
|
Number num = GetZero(); |
|
SetBit( &num, NUMBER_BITS - 1, 1 ); |
|
return num; |
|
} |
|
|
|
Number GetMax() |
|
{ |
|
Number num = GetMinusOne(); |
|
SetBit( &num, NUMBER_BITS - 1, 0 ); |
|
return num; |
|
} |
|
|
|
Number GetMinPlusOne() |
|
{ |
|
Number num = GetZero(); |
|
SetBit( &num, NUMBER_BITS - 1, 1 ); |
|
assert( NUMBER_BITS >= 2 ); |
|
SetBit( &num, 0, 1 ); |
|
return num; |
|
} |
|
|
|
Number GetMaxMinusOne() |
|
{ |
|
Number num = GetMinusOne(); |
|
SetBit( &num, NUMBER_BITS - 1, 0 ); |
|
assert( NUMBER_BITS >= 2 ); |
|
SetBit( &num, 0, 0 ); |
|
return num; |
|
} |
|
|
|
#if NUMBER_CLEAR_IMPLEMENTED |
|
StatusCode TestClear() |
|
{ |
|
Number num; |
|
StatusCode status = STATUS_SUCCESS; |
|
num.chunks = NUMBER_CHUNKCOUNT; |
|
num.length = NUMBER_BITS; |
|
num.status = 0xDEADC0DE; |
|
memset( num.data, 0xFF, NUMBER_CHUNKCOUNT * sizeof( NUMBER_BASETYPE ) ); |
|
|
|
num = number_clear(num); |
|
|
|
if( num.chunks != NUMBER_CHUNKCOUNT ) Errorf( &status, "number_clear verändert num.chunks!"); |
|
if( num.length != NUMBER_BITS ) Errorf( &status, "number_clear verändert num.length!" ); |
|
if( num.status != 0xDEADC0DE ) Errorf( &status, "number_clear verändert num.status!" ); |
|
if( !IsNull( (unsigned char*) &num.data[0], NUMBER_BITS ) ) Errorf( &status, "number_clear setzt die Zahl nicht auf 0!" ); |
|
|
|
/* Test auf Änderung ungenutzter Bits macht nur Sinn, wenn es solche gibt. */ |
|
if( NUMBER_CHUNKCOUNT * NUMBER_CHUNKSIZE == NUMBER_BITS ) |
|
{ |
|
Warningf( &status, "NUM_BITS entsprich genau der Arraygroeße, somit koennen manche moegliche Fehlerfälle (ungenutzte Bits sollen 0 sein) nicht eintreten!" ); |
|
} |
|
else |
|
{ |
|
if( UnusedBitsZero( num ) ) puts( " Info: number_clear setzt ungenutzte bits auf 0. (Das muesste richtig so sein.)" ); |
|
else Warningf( &status, "number_clear setzt ungenutzte Bits nicht auf 0. (Das ist vermutlich falsch.)" ); |
|
} |
|
return status; |
|
} |
|
#endif |
|
|
|
#if NUMBER_INIT_IMPLEMENTED |
|
StatusCode TestInit() |
|
{ |
|
Number num; |
|
StatusCode status = STATUS_SUCCESS; |
|
|
|
|
|
num = number_init(); |
|
if( num.chunks != NUMBER_CHUNKCOUNT ) Errorf( &status, "number_init setzt chunks nicht auf NUMBER_CHUNKCOUNT!" ); |
|
if( num.length != NUMBER_BITS ) Errorf( &status, "number_init setzt length nicht auf NUMBER_BITS!" ); |
|
if( num.status != number_valid ) Errorf( &status, "nnumber_init setzt status nicht auf number_valid!" ); |
|
if( !IsNull( (unsigned char*) &num.data[0], NUMBER_BITS ) ) Errorf( &status, "number_init setzt die Zahl nicht auf 0!" ); |
|
|
|
/* Test auf Änderung ungenutzter Bits macht nur Sinn, wenn es solche gibt. */ |
|
if( NUMBER_CHUNKCOUNT * NUMBER_CHUNKSIZE == NUMBER_BITS ) |
|
{ |
|
Warningf( &status, "NUM_BITS entsprich genau der Arraygroeße, somit koennen manche moegliche Fehlerfälle (ungenutzte Bits sollen 0 sein) nicht eintreten!" ); |
|
} |
|
else |
|
{ |
|
if( UnusedBitsZero( num ) ) puts( " Info: number_init setzt ungenutzte bits auf 0. (Das muesste richtig so sein.)" ); |
|
else Warningf( &status, "number_init setzt ungenutzte Bits nicht auf 0. (Das ist vermutlich falsch.)"); |
|
} |
|
return status; |
|
} |
|
#endif |
|
|
|
#if NUMBER_COPY_DATA_IMPLEMENTED |
|
|
|
StatusCode TestCopy() |
|
{ |
|
Number num1; |
|
num1.chunks = NUMBER_CHUNKCOUNT; |
|
num1.length = NUMBER_BITS; |
|
num1.status = 0xDEADC0DE; |
|
memset( num1.data, 0xFF, NUMBER_CHUNKCOUNT * sizeof( NUMBER_BASETYPE ) ); |
|
{ |
|
Number num2 = number_copyData(num1); |
|
StatusCode status = STATUS_SUCCESS; |
|
if( num2.chunks != num1.chunks ) Errorf( &status, "number_copyData kopiert chunks nicht!" ); |
|
if( num2.length != num1.length ) Errorf( &status, "number_copyData kopiert length nicht!" ); |
|
if( num2.status != num1.status ) Errorf( &status, "number_copyData kopiert status nicht!" ); |
|
if( memcmp( &num1.data[0], &num2.data[0], ( NUMBER_CHUNKCOUNT - 1 ) * sizeof( NUMBER_BASETYPE ) ) != 0 ) Errorf( &status, "number_copyData kopiert data nicht!" ); |
|
{ |
|
unsigned int i = 0; |
|
for( i = ( NUMBER_CHUNKCOUNT - 1 ) * sizeof( NUMBER_BASETYPE ) * CHAR_BIT; i < NUMBER_BITS; ++i ) |
|
{ |
|
if( ( num1.data[ NUMBER_CHUNKCOUNT - 1 ] & ( 1 << ( i % NUMBER_CHUNKSIZE ) ) ) != |
|
( num2.data[ NUMBER_CHUNKCOUNT - 1 ] & ( 1 << ( i % NUMBER_CHUNKSIZE ) ) ) ) |
|
{ |
|
Errorf( &status, "number_copyData hat bit %d nicht korrekt kopiert!\n", i + 1 ); |
|
break; |
|
} |
|
} |
|
if( !UnusedBitsZero( num2 ) ) |
|
{ |
|
Warningf( &status, "number_copyData hat bit %d kopiert, das nicht mehr Teil der Zahl ist! In der Regel muesste das gut gehen.", i + 1 ); |
|
} |
|
} |
|
return status; |
|
} |
|
} |
|
|
|
#endif |
|
|
|
#if NUMBER_IS_ZERO_IMPLEMENTED |
|
|
|
StatusCode TestIsZeroPositive() |
|
{ |
|
StatusCode status = STATUS_SUCCESS; |
|
Number num = GetZero(); |
|
|
|
if( !number_isZero( num ) ) Errorf( &status, "0 != 0 (False Negative)" ); |
|
return status; |
|
} |
|
|
|
StatusCode TestIsZeroNegative() |
|
{ |
|
StatusCode status = STATUS_SUCCESS; |
|
unsigned int i = 0; |
|
Number num = GetZero(); |
|
/* let's set all but one bit to 0, that ought to catch most problems. */ |
|
for( i = 0; i < NUMBER_BITS; ++i ) |
|
{ |
|
SetBit( &num, i, 1 ); |
|
if( number_isZero( num ) ) Errorf( &status, "%s == 0 (False Positive)", NumberToString( num ) ); |
|
SetBit( &num, i, 0 ); |
|
} |
|
return status; |
|
} |
|
|
|
#endif |
|
|
|
#if NUMBER_IS_NEGATIVE_IMPLEMENTED |
|
|
|
StatusCode TestIsNegativeNegative() |
|
{ |
|
StatusCode status = STATUS_SUCCESS; |
|
unsigned int i = 0; |
|
Number num = GetZero(); |
|
|
|
/* let's set all but one bit to 0, that ought to catch most problems. */ |
|
for( i = 0; i < NUMBER_BITS - 1; ++i ) |
|
{ |
|
SetBit( &num, i, 1 ); |
|
if( number_isNegative( num ) ) Errorf( &status, "%s is negative? Wrong!", NumberToString( num ) ); |
|
SetBit( &num, i, 0 ); |
|
} |
|
return status; |
|
} |
|
|
|
StatusCode TestIsNegativePositive() |
|
{ |
|
StatusCode status = STATUS_SUCCESS; |
|
unsigned int i = 0; |
|
Number num = GetZero(); |
|
|
|
/* let's set all but one bit to 0, that ought to catch most problems. */ |
|
SetBit( &num, NUMBER_BITS - 1, 1 ); |
|
for( i = 0; i < NUMBER_BITS - 1; ++i ) |
|
{ |
|
SetBit( &num, i, 1 ); |
|
if( !number_isNegative( num ) ) Errorf( &status, "%s is not negative? Wrong!", NumberToString( num ) ); |
|
SetBit( &num, i, 0 ); |
|
} |
|
return status; |
|
} |
|
|
|
#endif |
|
|
|
#if NUMBER_IS_OVERFLOWN_IMPLEMENTED |
|
|
|
StatusCode IsOverflownTestNegative() |
|
{ |
|
StatusCode status = STATUS_SUCCESS; |
|
Number num; |
|
num.status = number_valid; |
|
if( number_isOverflown( num ) ) Errorf( &status, "isOverflown() False Positive" ); |
|
num.status = number_overflow; |
|
return status; |
|
} |
|
|
|
StatusCode IsOverflownTestNegativeComplex() |
|
{ |
|
StatusCode status = STATUS_SUCCESS; |
|
Number num; |
|
num.status = number_unknownError | number_divByZero; |
|
if( number_isOverflown( num ) ) Errorf( &status, "isOverflown() False Positive" ); |
|
num.status = number_overflow; |
|
return status; |
|
} |
|
|
|
StatusCode IsOverflownTestPositive() |
|
{ |
|
StatusCode status = STATUS_SUCCESS; |
|
Number num; |
|
num.status = number_overflow; |
|
if( !number_isOverflown( num ) ) Errorf( &status, "isOverflown() False Negative" ); |
|
return status; |
|
} |
|
|
|
StatusCode IsOverflownTestPositiveComplex() |
|
{ |
|
StatusCode status = STATUS_SUCCESS; |
|
Number num; |
|
num.status = number_overflow | number_unknownError; |
|
if( !number_isOverflown( num ) ) Errorf( &status, "isOverflown() False Negative" ); |
|
return status; |
|
} |
|
|
|
#endif |
|
|
|
#if NUMBER_LESSER_IMPLEMENTED |
|
|
|
/* Anonymous Functions would be great... */ |
|
|
|
/* Equal */ |
|
|
|
StatusCode LesserTestOneOne() |
|
{ |
|
return number_lesser( GetOne(), GetOne() ) ? STATUS_ERROR : STATUS_SUCCESS; |
|
} |
|
|
|
StatusCode LesserTestZeroZero() |
|
{ |
|
return number_lesser( GetZero(), GetZero() ) ? STATUS_ERROR : STATUS_SUCCESS; |
|
} |
|
|
|
StatusCode LesserTestMinusOneMinusOne() |
|
{ |
|
return number_lesser( GetMinusOne(), GetMinusOne() ) ? STATUS_ERROR : STATUS_SUCCESS; |
|
} |
|
|
|
/* Smaller */ |
|
|
|
StatusCode LesserTestZeroOne() |
|
{ |
|
return number_lesser( GetZero(), GetOne() ) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode LesserTestOneTwo() |
|
{ |
|
return number_lesser( GetOne(), GetTwo() ) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode LesserTestMinusOneZero() |
|
{ |
|
return number_lesser( GetMinusOne(), GetZero() ) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode LesserTestMinusTwoMinusOne() |
|
{ |
|
return number_lesser( GetMinusTwo(), GetMinusOne() ) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode LesserTestMinusTwoTwo() |
|
{ |
|
return number_lesser( GetMinusTwo(), GetTwo() ) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
/* Greater */ |
|
|
|
StatusCode LesserTestOneZero() |
|
{ |
|
return number_lesser( GetOne(), GetZero() ) ? STATUS_ERROR : STATUS_SUCCESS; |
|
} |
|
|
|
StatusCode LesserTestTwoOne() |
|
{ |
|
return number_lesser( GetTwo(), GetOne() ) ? STATUS_ERROR : STATUS_SUCCESS; |
|
} |
|
|
|
StatusCode LesserTestZeroMinusOne() |
|
{ |
|
return number_lesser( GetZero(), GetMinusOne() ) ? STATUS_ERROR : STATUS_SUCCESS; |
|
} |
|
|
|
StatusCode LesserTestMinusOneMinusTwo() |
|
{ |
|
return number_lesser( GetMinusOne(), GetMinusTwo() ) ? STATUS_ERROR : STATUS_SUCCESS; |
|
} |
|
|
|
StatusCode LesserTestTwoMinusTwo() |
|
{ |
|
return number_lesser( GetTwo(), GetMinusTwo() ) ? STATUS_ERROR : STATUS_SUCCESS; |
|
} |
|
|
|
#endif |
|
|
|
#if NUMBER_EQUALS_IMPLEMENTED |
|
|
|
StatusCode EqualsTestZeroZero() |
|
{ |
|
return number_equals( GetZero(), GetZero() ) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode EqualsTestOneOne() |
|
{ |
|
return number_equals( GetZero(), GetZero() ) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode EqualsTestZeroOne() |
|
{ |
|
return number_equals( GetZero(), GetOne() ) ? STATUS_ERROR : STATUS_SUCCESS; |
|
} |
|
|
|
StatusCode EqualsTestZeroMin() |
|
{ |
|
return number_equals( GetZero(), GetMin() ) ? STATUS_ERROR : STATUS_SUCCESS; |
|
} |
|
|
|
StatusCode EqualsUnusedBits() |
|
{ |
|
StatusCode status = STATUS_SUCCESS; |
|
Number num1 = GetZero(); |
|
Number num2 = GetZero(); |
|
if( NUMBER_BITS < NUMBER_CHUNKCOUNT * NUMBER_CHUNKSIZE ) |
|
{ |
|
unsigned int i = 0; |
|
for( i = NUMBER_BITS; i < NUMBER_CHUNKCOUNT * NUMBER_CHUNKSIZE; ++i ) |
|
{ |
|
SetBit( &num1, i, 1 ); |
|
} |
|
if( !number_equals( num1, num2 ) ) |
|
{ |
|
Warningf( &status, "number_equals vergleicht ungenutzte Bits" ); |
|
} |
|
} |
|
else |
|
{ |
|
Warningf( &status, "NUMBER_BITS nutzt Array komplett aus, ungenutzte Bits koennen nicht getestet werden!" ); |
|
} |
|
return status; |
|
} |
|
|
|
#endif |
|
|
|
#if NUMBER_GREATER_IMPLEMENTED |
|
/* Equal */ |
|
|
|
StatusCode GreaterTestOneOne() |
|
{ |
|
return number_greater( GetOne(), GetOne() ) ? STATUS_ERROR : STATUS_SUCCESS; |
|
} |
|
|
|
StatusCode GreaterTestZeroZero() |
|
{ |
|
return number_greater( GetZero(), GetZero() ) ? STATUS_ERROR : STATUS_SUCCESS; |
|
} |
|
|
|
StatusCode GreaterTestMinusOneMinusOne() |
|
{ |
|
return number_greater( GetMinusOne(), GetMinusOne() ) ? STATUS_ERROR : STATUS_SUCCESS; |
|
} |
|
|
|
/* Bigger */ |
|
|
|
StatusCode GreaterTestOneZero() |
|
{ |
|
return number_greater( GetOne(), GetZero() ) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode GreaterTestTwoOne() |
|
{ |
|
return number_greater( GetTwo(), GetOne() ) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode GreaterTestZeroMinusOne() |
|
{ |
|
return number_greater( GetZero(), GetMinusOne() ) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode GreaterTestMinusOneMinusTwo() |
|
{ |
|
return number_greater( GetMinusOne(), GetMinusTwo() ) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode GreaterTestTwoMinusTwo() |
|
{ |
|
return number_greater( GetTwo(), GetMinusTwo() ) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
/* Smaller */ |
|
|
|
StatusCode GreaterTestZeroOne() |
|
{ |
|
return number_greater( GetZero(), GetOne() ) ? STATUS_ERROR : STATUS_SUCCESS; |
|
} |
|
|
|
StatusCode GreaterTestOneTwo() |
|
{ |
|
return number_greater( GetOne(), GetTwo() ) ? STATUS_ERROR : STATUS_SUCCESS; |
|
} |
|
|
|
StatusCode GreaterTestMinusOneZero() |
|
{ |
|
return number_greater( GetMinusOne(), GetZero() ) ? STATUS_ERROR : STATUS_SUCCESS; |
|
} |
|
|
|
StatusCode GreaterTestMinusTwoMinusOne() |
|
{ |
|
return number_greater( GetMinusTwo(), GetMinusOne() ) ? STATUS_ERROR : STATUS_SUCCESS; |
|
} |
|
|
|
StatusCode GreaterTestMinusTwoTwo() |
|
{ |
|
return number_greater( GetMinusTwo(), GetTwo() ) ? STATUS_ERROR : STATUS_SUCCESS; |
|
} |
|
|
|
#endif |
|
|
|
#if NUMBER_INVERT_IMPLEMENTED |
|
|
|
StatusCode InvertTestMinusOne() |
|
{ |
|
return Equals( GetZero(), number_invert( GetMinusOne() ) ) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode InvertTestMax() |
|
{ |
|
return Equals( GetMin(), number_invert( GetMax() ) ) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode InvertTestOne() |
|
{ |
|
return Equals( GetMinusTwo(), number_invert( GetOne() ) ) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode InvertTestUnused() |
|
{ |
|
return UnusedBitsZero( number_invert( GetZero() ) ) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
#endif |
|
|
|
#if NUMBER_AND_IMPLEMENTED |
|
|
|
StatusCode AndTestMinMax() |
|
{ |
|
return Equals( number_and( GetMin(), GetMax() ), GetZero() ) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode AndTestZeroMinusOne() |
|
{ |
|
return Equals( number_and( GetZero(), GetMinusOne() ), GetZero() ) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode AndTestOneThree() |
|
{ |
|
return Equals( number_and( GetOne(), GetThree() ), GetOne() ) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode AndTestThreeMinusOne() |
|
{ |
|
return Equals( number_and( GetThree(), GetMinusOne() ), GetThree() ) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
#endif |
|
|
|
#if NUMBER_OR_IMPLEMENTED |
|
|
|
StatusCode OrTestMinMax() |
|
{ |
|
return Equals( number_or( GetMin(), GetMax() ), GetMinusOne() ) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode OrTestZeroMinusOne() |
|
{ |
|
return Equals( number_or( GetZero(), GetMinusOne() ), GetMinusOne() ) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode OrTestOneThree() |
|
{ |
|
return Equals( number_or( GetOne(), GetThree() ), GetThree() ) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode OrTestThreeMinusOne() |
|
{ |
|
return Equals( number_or( GetThree(), GetMinusOne() ), GetMinusOne() ) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode OrTestOneTwo() |
|
{ |
|
return Equals( number_or( GetOne(), GetTwo() ), GetThree() ) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
#endif |
|
|
|
#if NUMBER_XOR_IMPLEMENTED |
|
|
|
StatusCode XorTestOneTwo() |
|
{ |
|
return Equals( number_xor( GetOne(), GetTwo() ), GetThree() ) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode XorTestMinusOneOne() |
|
{ |
|
return Equals( number_xor( GetMinusOne(), GetOne() ), GetMinusTwo() ) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode XorTestMinMax() |
|
{ |
|
return Equals( number_xor( GetMin(), GetMax() ), GetMinusOne() ) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode XorTestTwoThree() |
|
{ |
|
return Equals( number_xor( GetTwo(), GetThree() ), GetOne() ) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
#endif |
|
|
|
#if NUMBER_SUM_IMPLEMENTED |
|
|
|
StatusCode SumTestZeroOne() |
|
{ |
|
return Equals( number_sum( GetZero(), GetOne() ), GetOne() ) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode SumTestOneOne() |
|
{ |
|
return Equals( number_sum( GetOne(), GetOne() ), GetTwo() ) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode SumTestOneTwo() |
|
{ |
|
return Equals( number_sum( GetOne(), GetTwo() ), GetThree() ) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode SumTestOneMinusOne() |
|
{ |
|
StatusCode status = STATUS_SUCCESS; |
|
Number result = number_sum( GetOne(), GetMinusOne() ); |
|
if( result.status != number_valid ) Errorf( &status, "-1 + 1 resultiert nicht in Status number_valid" ); |
|
if( !Equals( result, GetZero() ) ) status = STATUS_ERROR; |
|
return status; |
|
} |
|
|
|
StatusCode SumTestMaxOne() |
|
{ |
|
StatusCode status = STATUS_SUCCESS; |
|
Number num = number_sum( GetMax(), GetOne() ); |
|
if( !Equals( num, GetMin() ) ) Errorf( &status, "number_sum() kommt zum falschen Ergebnis!" );; |
|
if( !( num.status & number_overflow ) ) Errorf( &status, "number_sum() setzt Overflow bit nicht!" ); |
|
return status; |
|
} |
|
|
|
StatusCode SumTestChunkCarry() |
|
{ |
|
StatusCode status = STATUS_SUCCESS; |
|
if( NUMBER_CHUNKCOUNT < 2 ) |
|
{ |
|
Warningf( &status, "Number hat nur einen Chunk, Test auf chunkuebergreifenden Carry unmoeglich!" ); |
|
} |
|
else |
|
{ |
|
Number operand = GetZero(); |
|
Number result = GetZero(); |
|
SetBit( &operand, NUMBER_CHUNKSIZE - 1, 1 ); |
|
SetBit( &result, NUMBER_CHUNKSIZE, 1 ); |
|
if( !Equals( number_sum( operand, operand ), result ) ) |
|
{ |
|
status = STATUS_ERROR; |
|
} |
|
} |
|
return status; |
|
} |
|
|
|
#endif |
|
|
|
#if NUMBER_TWO_COMPLEMENT_IMPLEMENTED |
|
|
|
StatusCode ComplementTestZero() |
|
{ |
|
return Equals( GetZero(), number_twoComplement( GetZero() ) ) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode ComplementTestOne() |
|
{ |
|
return Equals( GetMinusOne(), number_twoComplement( GetOne() ) ) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode ComplementTestMinusOne() |
|
{ |
|
return Equals( GetOne(), number_twoComplement( GetMinusOne() ) ) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode ComplementTestMinusMax() |
|
{ |
|
return Equals( GetMinPlusOne(), number_twoComplement( GetMax() ) ) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode ComplementTestMinusMin() |
|
{ |
|
StatusCode status = STATUS_SUCCESS; |
|
Number num = number_twoComplement( GetMin() ); |
|
if( !Equals( num, GetMin() ) ) |
|
{ |
|
Errorf( &status, "number_twoComplement mit der kleinstmoeglichen Zahl ergibt nicht die kleinstmoegliche Zahl - das ist allerdings vermutlich kein Problem?" ); |
|
} |
|
else if( ! ( num.status & number_overflow ) ) |
|
{ |
|
Errorf( &status, "number_twoComplement mit der kleinstmoeglichen Zahl setzt den Overflow Status nicht - das ist allerdings vermutlich kein Problem?" ); |
|
} |
|
return status; |
|
} |
|
|
|
#endif |
|
|
|
#if NUMBER_DIFFERENCE_IMPLEMENTED |
|
|
|
StatusCode DifferenceTestOneZero() |
|
{ |
|
return Equals( number_difference( GetOne(), GetZero() ), GetOne() ) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode DifferenceTestOneOne() |
|
{ |
|
return Equals( number_difference( GetOne(), GetOne() ), GetZero() ) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode DifferenceTestOneTwo() |
|
{ |
|
return Equals( number_difference( GetOne(), GetTwo() ), GetMinusOne() ) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode DifferenceTestMinusOneOne() |
|
{ |
|
return Equals( number_difference( GetMinusOne(), GetOne() ), GetMinusTwo() ) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode DifferenceTestOneMinusOne() |
|
{ |
|
return Equals( number_difference( GetOne(), GetMinusOne() ), GetTwo() ) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode DifferenceTestMinMinusOne() |
|
{ |
|
StatusCode status = STATUS_SUCCESS; |
|
Number num = number_difference( GetMin(), GetOne() ); |
|
if( !Equals( num, GetMax() ) ) Errorf( &status, "number_difference() kommt zum falschen Ergebnis!" );; |
|
if( !( num.status & number_overflow ) ) Errorf( &status, "number_difference() setzt Overflow bit nicht!" ); |
|
return status; |
|
} |
|
|
|
StatusCode DifferenceTestChunkCarry() |
|
{ |
|
StatusCode status = STATUS_SUCCESS; |
|
if( NUMBER_CHUNKCOUNT < 2 ) |
|
{ |
|
Warningf( &status, "Number hat nur einen Chunk, Test auf chunkuebergreifenden Carry unmoeglich!" ); |
|
} |
|
else |
|
{ |
|
Number n = GetZero(); |
|
Number nShl1 = GetZero(); |
|
SetBit( &n, NUMBER_CHUNKSIZE - 1, 1 ); |
|
SetBit( &nShl1, NUMBER_CHUNKSIZE, 1 ); |
|
if( !Equals( number_difference( nShl1, n ), n ) ) |
|
{ |
|
status = STATUS_ERROR; |
|
} |
|
} |
|
return status; |
|
} |
|
|
|
#endif |
|
|
|
#if NUMBER_PRODUCT_IMPLEMENTED |
|
|
|
StatusCode ProductTest1() |
|
{ |
|
return Equals( number_product( ToNumber( 0 ), ToNumber( 1 ) ), ToNumber( 0 )) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode ProductTest1_2() |
|
{ |
|
return Equals( number_product( ToNumber( 1 ), ToNumber( 0 ) ), ToNumber( 0 )) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode ProductTest2() |
|
{ |
|
return Equals( number_product( ToNumber( 4 ), ToNumber( 5 ) ), ToNumber( 20 )) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode ProductTest3() |
|
{ |
|
return Equals( number_product( ToNumber( -1 ), ToNumber( 1 ) ), ToNumber( -1 )) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode ProductTest3_2() |
|
{ |
|
return Equals( number_product( ToNumber( 2 ), ToNumber( -2 ) ), ToNumber( -4 )) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode ProductTest4() |
|
{ |
|
return Equals( number_product( ToNumber( -4 ), ToNumber( 3 ) ), ToNumber( -12 )) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode ProductTest5() |
|
{ |
|
return Equals( number_product( ToNumber( -4 ), ToNumber( -2 ) ), ToNumber( 8 )) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
#endif |
|
|
|
#if NUMBER_QUOTIENT_IMPLEMENTED |
|
|
|
StatusCode QuotientTest1() |
|
{ |
|
return Equals( number_quotient( ToNumber( 0 ), ToNumber( 1 ) ), ToNumber( 0 )) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode QuotientTest2() |
|
{ |
|
return Equals( number_quotient( ToNumber( 2 ), ToNumber( 1 ) ), ToNumber( 2 )) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode QuotientTest3() |
|
{ |
|
return Equals( number_quotient( ToNumber( 5 ), ToNumber( 2 ) ), ToNumber( 2 )) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode QuotientTest4() |
|
{ |
|
return Equals( number_quotient( ToNumber( -10 ), ToNumber( 5 ) ), ToNumber( -2 )) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode QuotientTest5() |
|
{ |
|
return Equals( number_quotient( ToNumber( 14 ), ToNumber( -6 ) ), ToNumber( -2 )) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode QuotientTest6() |
|
{ |
|
return Equals( number_quotient( ToNumber( -5 ), ToNumber( -4 ) ), ToNumber( 1 )) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode QuotientTestDivByZero() |
|
{ |
|
Number num = number_quotient( ToNumber( 1 ), ToNumber( 0 ) ); |
|
return (num.status & number_divByZero) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
#endif |
|
|
|
#if NUMBER_MODULO_IMPLEMENTED |
|
|
|
StatusCode ModuloTest1() |
|
{ |
|
return Equals( number_modulo( ToNumber( 0 ), ToNumber( 1 ) ), ToNumber( 0 ) ) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode ModuloTest2() |
|
{ |
|
return Equals( number_modulo( ToNumber( 2 ), ToNumber( 1 ) ), ToNumber( 0 ) ) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode ModuloTest3() |
|
{ |
|
return Equals( number_modulo( ToNumber( 5 ), ToNumber( 2 ) ), ToNumber( 1 ) ) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode ModuloTestDivByZero() |
|
{ |
|
Number num = number_modulo( ToNumber( 1 ), ToNumber( 0 ) ); |
|
return (num.status & number_divByZero) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
#endif |
|
|
|
#if NUMBER_NUMBER_TO_STRING_IMPLEMENTED |
|
|
|
StatusCode NumberToStringTest1() |
|
{ |
|
char str[ NUMBER_STR_LEN + 1 ]; |
|
char expected[ NUMBER_STR_LEN + 1 ]; |
|
assert( NUMBER_STR_LEN >= 2 ); |
|
memset( str, '\0', NUMBER_STR_LEN + 1 ); |
|
memset( expected, '\0', NUMBER_STR_LEN + 1 ); |
|
expected[0] = '4'; |
|
expected[1] = '2'; |
|
number_numberToString( ToNumber( 42 ), str ); |
|
return memcmp( str, expected, NUMBER_STR_LEN + 1 ) == 0 ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode NumberToStringTest2() |
|
{ |
|
char str[ NUMBER_STR_LEN + 1 ]; |
|
char expected[ NUMBER_STR_LEN + 1 ]; |
|
assert( NUMBER_STR_LEN >= 3 ); |
|
memset( str, '\0', NUMBER_STR_LEN + 1 ); |
|
memset( expected, '\0', NUMBER_STR_LEN + 1 ); |
|
expected[0] = '-'; |
|
expected[1] = '4'; |
|
expected[2] = '2'; |
|
number_numberToString( ToNumber( -42 ), str ); |
|
return memcmp( str, expected, NUMBER_STR_LEN + 1 ) == 0 ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
/* Speicherverletzung */ |
|
StatusCode NumberToStringTestTooLong() |
|
{ |
|
enum |
|
{ |
|
BUFFER_CHAR = 0x01, |
|
BUFFER_LEN = NUMBER_BITS + NUMBER_STR_LEN + 1 |
|
}; |
|
char str[ BUFFER_LEN ]; |
|
Number num = GetZero(); |
|
memset( str, BUFFER_CHAR, sizeof(str) ); |
|
puts( " Achtung: Je nach gesetzten #defines kann es sein, dass die groesstmoegliche Zahl in Dezimaldarstellung weniger als NUMBER_STR_LEN Zeichen benoetigt - in dem Fall kann dieser Test gar nicht fehlschlagen, es sei denn, irgendetwas laeuft gewaltig schief." ); |
|
puts( " Wenn dieser Test scheinbar nicht zum Ende kommt, sollte NUMBER_STR_LEN verringert werden - Software-Arithmetik ist langsam."); |
|
/* Wir brauchen eine möglichst kleine Zahl, die nicht mehr mit NUMBER_STR_LEN Zeichen darstellbar ist. Bei GetMax() (sprich größtmöglicher Zahl) rechnet das Programm bei vielen NUMBER_BITS ewigst. */ |
|
/* Also: Je 10^3 nehme ich 2^10 (1000 -> 1024) */ |
|
SetBit( &num, ( ( NUMBER_STR_LEN + 2 ) / 3) * 10 , 1 ); |
|
number_numberToString( num, str ); |
|
{ |
|
unsigned int i = 0; |
|
/* Die ersten NUMBER_STR_LEN dürfen verändert worden sein. Der Rest nicht. */ |
|
/* Sehr viel cooler als dieser Check wäre ein Memory Breakpoint... Ich wieder. */ |
|
if( str[ NUMBER_STR_LEN ] != BUFFER_CHAR && str[ NUMBER_STR_LEN ] != '\0' ) |
|
{ |
|
return STATUS_ERROR; |
|
} |
|
for( i = NUMBER_STR_LEN + 1 ; i < BUFFER_LEN; ++i ) |
|
{ |
|
if( str[i] != BUFFER_CHAR ) |
|
{ |
|
return STATUS_ERROR; |
|
} |
|
} |
|
} |
|
return STATUS_SUCCESS; |
|
} |
|
|
|
#endif |
|
|
|
#if NUMBER_STRING_TO_NUMBER_IMPLEMENTED |
|
|
|
StatusCode StringToNumberTest1() |
|
{ |
|
return Equals( number_stringToNumber( "420", 2 ), ToNumber( 42 ) ) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode StringToNumberTest2() |
|
{ |
|
return Equals( number_stringToNumber( "-420", 3 ), ToNumber( -42 ) ) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
StatusCode StringToNumberTest3() |
|
{ |
|
return ( number_stringToNumber( "foobar", 6 ).status & ( number_notANumber | number_unknownError ) ) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
|
|
/* Overflow-Test */ |
|
StatusCode StringToNumberTestOverflow() |
|
{ |
|
char str[ NUMBER_BITS + 2 ]; |
|
unsigned int i = 0; |
|
for( i = 0; i <= NUMBER_BITS; ++i ) |
|
{ |
|
str[i] = '9'; |
|
} |
|
str[ NUMBER_BITS + 1 ] = '\0'; |
|
{ |
|
Number num = number_stringToNumber(str, NUMBER_BITS + 1); |
|
return (num.status & number_overflow) ? STATUS_SUCCESS : STATUS_ERROR; |
|
} |
|
} |
|
|
|
#endif |
|
|
|
|
|
typedef StatusCode (*TestFuncPtr)(); |
|
|
|
typedef struct Test_s |
|
{ |
|
TestFuncPtr func; |
|
const char* description; |
|
} Test_t; |
|
|
|
/** |
|
@brief Lässt einen Test laufen, erhöht je nach Ergebnis die Zahl der erfolgreichen Tests |
|
**/ |
|
void RunTest( Test_t test, unsigned int* numSuccessfulTests, unsigned int* numWarnings ) |
|
{ |
|
StatusCode status = STATUS_SUCCESS; |
|
printf( "Starte Test \"%s\"...\n", test.description ); |
|
if( !test.func ) |
|
{ |
|
Errorf( &status, "Fehlerhafter Test: func == 0\n" ); |
|
} |
|
else |
|
{ |
|
status = test.func(); |
|
} |
|
if( status & STATUS_WARNING ) |
|
{ |
|
*numWarnings += 1; |
|
} |
|
if( status & STATUS_ERROR ) |
|
{ |
|
fprintf( stderr, "Misserfolg bei Test \"%s\"!\n", test.description ); |
|
} |
|
else |
|
{ |
|
puts( "Erfolg!" ); |
|
*numSuccessfulTests += 1; |
|
} |
|
} |
|
|
|
int main( void ) |
|
{ |
|
unsigned int numSuccessfulTests = 0; |
|
unsigned int numWarnings = 0; |
|
unsigned int curTestIndex = 0; |
|
Test_t tests[] = |
|
{ |
|
#if NUMBER_CLEAR_IMPLEMENTED |
|
{ |
|
TestClear, |
|
"number_clear()", |
|
}, |
|
#endif |
|
|
|
#if NUMBER_INIT_IMPLEMENTED |
|
{ |
|
TestInit, |
|
"number_init()" |
|
}, |
|
#endif |
|
|
|
#if NUMBER_COPY_DATA_IMPLEMENTED |
|
{ |
|
TestCopy, |
|
"number_copy()" |
|
}, |
|
#endif |
|
|
|
#if NUMBER_IS_ZERO_IMPLEMENTED |
|
{ |
|
TestIsZeroPositive, |
|
"number_isZero() bei 0" |
|
}, |
|
{ |
|
TestIsZeroNegative, |
|
"number_isZero() bei nicht 0" |
|
}, |
|
#endif |
|
|
|
#if NUMBER_IS_NEGATIVE_IMPLEMENTED |
|
{ |
|
TestIsNegativePositive, |
|
"number_isNegative() bei x < 0" |
|
}, |
|
{ |
|
TestIsNegativeNegative, |
|
"number_isNegative() bei x >= 0" |
|
}, |
|
#endif |
|
|
|
#if NUMBER_IS_OVERFLOWN_IMPLEMENTED |
|
{ |
|
IsOverflownTestNegative, |
|
"number_isOverflown() bei status = number_valid" |
|
}, |
|
{ |
|
IsOverflownTestNegativeComplex, |
|
"number_isOverflown() bei status = number_unknownError | number_divByZero" |
|
}, |
|
{ |
|
IsOverflownTestPositive, |
|
"number_isOverflown() bei status = number_overflown" |
|
}, |
|
{ |
|
IsOverflownTestPositiveComplex, |
|
"number_isOverflown() bei status = number_overflown | number_unknownError" |
|
}, |
|
#endif |
|
|
|
#if NUMBER_LESSER_IMPLEMENTED |
|
{ |
|
LesserTestZeroZero, |
|
"number_lesser() mit 0 und 0" |
|
}, |
|
{ |
|
LesserTestOneOne, |
|
"number_lesser() mit 1 und 1" |
|
}, |
|
{ |
|
LesserTestMinusOneMinusOne, |
|
"number_lesser() mit -1 und -1" |
|
}, |
|
{ |
|
LesserTestZeroOne, |
|
"number_lesser() mit 0 und 1" |
|
}, |
|
{ |
|
LesserTestOneTwo, |
|
"number_lesser() mit 1 und 2" |
|
}, |
|
{ |
|
LesserTestMinusOneZero, |
|
"number_lesser() mit -1 und 0" |
|
}, |
|
{ |
|
LesserTestMinusTwoMinusOne, |
|
"number_lesser() mit -2 und -1" |
|
}, |
|
{ |
|
LesserTestOneZero, |
|
"number_lesser() mit 1 und 0" |
|
}, |
|
{ |
|
LesserTestTwoOne, |
|
"number_lesser() mit 2 und 1" |
|
}, |
|
{ |
|
LesserTestZeroMinusOne, |
|
"number_lesser() mit 0 und -1" |
|
}, |
|
{ |
|
LesserTestMinusOneMinusTwo, |
|
"number_lesser() mit -1 und -2" |
|
}, |
|
{ |
|
LesserTestMinusTwoTwo, |
|
"number_lesser() mit -2 und 2" |
|
}, |
|
{ |
|
LesserTestTwoMinusTwo, |
|
"number_lesser() mit 2 und -2" |
|
}, |
|
#endif |
|
|
|
#if NUMBER_EQUALS_IMPLEMENTED |
|
{ |
|
EqualsTestZeroZero, |
|
"number_equals() mit 0 und 0" |
|
}, |
|
{ |
|
EqualsTestOneOne, |
|
"number_equals() mit 1 und 1" |
|
}, |
|
{ |
|
EqualsTestZeroOne, |
|
"number_equals() mit 0 und 1" |
|
}, |
|
{ |
|
EqualsTestZeroMin, |
|
"number_equals() mit 0 und der kleinstmoeglichen Zahl" |
|
}, |
|
{ |
|
EqualsUnusedBits, |
|
"number_equals() mit Zahlen, die sich nur in ungenutzten Bits unterscheiden" |
|
}, |
|
#endif |
|
|
|
#if NUMBER_GREATER_IMPLEMENTED |
|
{ |
|
GreaterTestZeroZero, |
|
"number_greater() mit 0 und 0" |
|
}, |
|
{ |
|
GreaterTestOneOne, |
|
"number_greater() mit 1 und 1" |
|
}, |
|
{ |
|
GreaterTestMinusOneMinusOne, |
|
"number_greater() mit -1 und -1" |
|
}, |
|
{ |
|
GreaterTestZeroOne, |
|
"number_greater() mit 1 und 0" |
|
}, |
|
{ |
|
GreaterTestTwoOne, |
|
"number_greater() mit 2 und 1" |
|
}, |
|
{ |
|
GreaterTestZeroMinusOne, |
|
"number_greater() mit 0 und -1" |
|
}, |
|
{ |
|
GreaterTestMinusOneMinusTwo, |
|
"number_greater() mit -1 und -2" |
|
}, |
|
{ |
|
GreaterTestOneZero, |
|
"number_greater() mit 0 und 1" |
|
}, |
|
{ |
|
GreaterTestOneTwo, |
|
"number_greater() mit 1 und 2" |
|
}, |
|
{ |
|
GreaterTestMinusOneZero, |
|
"number_greater() mit -1 und 0" |
|
}, |
|
{ |
|
GreaterTestMinusTwoMinusOne, |
|
"number_greater() mit -2 und -1" |
|
}, |
|
{ |
|
GreaterTestTwoMinusTwo, |
|
"number_greater() mit 2 und -2" |
|
}, |
|
{ |
|
GreaterTestMinusTwoTwo, |
|
"number_greater() mit -2 und 2" |
|
}, |
|
#endif |
|
|
|
#if NUMBER_INVERT_IMPLEMENTED |
|
{ |
|
InvertTestOne, |
|
"number_invert() mit 1" |
|
}, |
|
{ |
|
InvertTestMinusOne, |
|
"number_invert() mit -1" |
|
}, |
|
{ |
|
InvertTestMax, |
|
"number_invert() mit groesster moeglicher Zahl" |
|
}, |
|
{ |
|
InvertTestUnused, |
|
"number_invert() mit Pruefung auf Invertierung ungenutzter Bits" |
|
}, |
|
#endif |
|
|
|
#if NUMBER_AND_IMPLEMENTED |
|
{ |
|
AndTestMinMax, |
|
"number_and() mit kleinster und groesster moeglicher Zahl" |
|
}, |
|
{ |
|
AndTestZeroMinusOne, |
|
"number_and() mit 0 und -1" |
|
}, |
|
{ |
|
AndTestOneThree, |
|
"number_and() mit 1 und 3" |
|
}, |
|
{ |
|
AndTestThreeMinusOne, |
|
"number_and() mit 3 und -1" |
|
}, |
|
#endif |
|
|
|
#if NUMBER_OR_IMPLEMENTED |
|
{ |
|
OrTestMinMax, |
|
"number_or() mit kleinster und groesster moeglicher Zahl" |
|
}, |
|
{ |
|
OrTestZeroMinusOne, |
|
"number_or() mit 0 und -1" |
|
}, |
|
{ |
|
OrTestOneThree, |
|
"number_or() mit 1 und 3" |
|
}, |
|
{ |
|
OrTestThreeMinusOne, |
|
"number_or() mit 3 und -1" |
|
}, |
|
{ |
|
OrTestOneTwo, |
|
"number_or() mit 1 und 2" |
|
}, |
|
#endif |
|
|
|
#if NUMBER_XOR_IMPLEMENTED |
|
{ |
|
XorTestOneTwo, |
|
"number_xor() mit 1 und 2" |
|
}, |
|
{ |
|
XorTestMinusOneOne, |
|
"number_xor() mit -1 und 1" |
|
}, |
|
{ |
|
XorTestMinMax, |
|
"number_xor() mit kleinster und groesster moeglicher Zahl" |
|
}, |
|
{ |
|
XorTestTwoThree, |
|
"number_xor() mit 2 und 3" |
|
}, |
|
#endif |
|
|
|
#if NUMBER_SUM_IMPLEMENTED |
|
{ |
|
SumTestZeroOne, |
|
"number_sum() mit 0 und 1" |
|
}, |
|
{ |
|
SumTestOneOne, |
|
"number_sum() mit 1 und 1" |
|
}, |
|
{ |
|
SumTestOneTwo, |
|
"number_sum() mit 1 und 2" |
|
}, |
|
{ |
|
SumTestOneMinusOne, |
|
"number_sum() mit -1 und 1" |
|
}, |
|
{ |
|
SumTestMaxOne, |
|
"number_sum() mit groesster moeglicher Zahl und 1" |
|
}, |
|
{ |
|
SumTestChunkCarry, |
|
"number_sum() mit chunkuebergreifendem Carry" |
|
}, |
|
#endif |
|
|
|
#if NUMBER_TWO_COMPLEMENT_IMPLEMENTED |
|
{ |
|
ComplementTestZero, |
|
"number_twoComplement() mit 0" |
|
}, |
|
{ |
|
ComplementTestOne, |
|
"number_twoComplement() mit 1" |
|
}, |
|
{ |
|
ComplementTestMinusOne, |
|
"number_twoComplement() mit -1" |
|
}, |
|
{ |
|
ComplementTestMinusMax, |
|
"number_twoComplement() mit groesster moeglicher Nummer" |
|
}, |
|
{ |
|
ComplementTestMinusMin, |
|
"number_twoComplement() mit kleinster moeglicher Nummer" |
|
}, |
|
#endif |
|
|
|
#if NUMBER_DIFFERENCE_IMPLEMENTED |
|
{ |
|
DifferenceTestOneZero, |
|
"number_difference() mit 1 und 0" |
|
}, |
|
{ |
|
DifferenceTestOneOne, |
|
"number_difference() mit 1 und 1" |
|
}, |
|
{ |
|
DifferenceTestOneTwo, |
|
"number_difference() mit 1 und 2" |
|
}, |
|
{ |
|
DifferenceTestMinusOneOne, |
|
"number_difference() mit -1 und 1" |
|
}, |
|
{ |
|
DifferenceTestOneMinusOne, |
|
"number_difference() mit 1 und -1" |
|
}, |
|
{ |
|
DifferenceTestMinMinusOne, |
|
"number_difference() mit kleinster moeglicher Zahl und 1" |
|
}, |
|
{ |
|
DifferenceTestChunkCarry, |
|
"number_difference() mit chunkuebergreifendem Carry" |
|
}, |
|
#endif |
|
|
|
#if NUMBER_PRODUCT_IMPLEMENTED |
|
{ |
|
ProductTest1, |
|
"number_product() mit 0 und 1" |
|
}, |
|
{ |
|
ProductTest1_2, |
|
"number_product() mit 1 und 0" |
|
}, |
|
{ |
|
ProductTest2, |
|
"number_product() mit 4 und 5" |
|
}, |
|
{ |
|
ProductTest3, |
|
"number_product() mit -1 und 1" |
|
}, |
|
{ |
|
ProductTest3_2, |
|
"number_product() mit 2 und -2" |
|
}, |
|
{ |
|
ProductTest4, |
|
"number_product() mit -4 und 3" |
|
}, |
|
{ |
|
ProductTest5, |
|
"number_product() mit -4 und -2" |
|
}, |
|
#endif |
|
|
|
#if NUMBER_QUOTIENT_IMPLEMENTED |
|
{ |
|
QuotientTest1, |
|
"number_quotient() mit 0 und 1" |
|
}, |
|
{ |
|
QuotientTest2, |
|
"number_quotient() mit 2 und 1" |
|
}, |
|
{ |
|
QuotientTest3, |
|
"number_quotient() mit 5 und 2" |
|
}, |
|
{ |
|
QuotientTest4, |
|
"number_quotient() mit -10 und 5" |
|
}, |
|
{ |
|
QuotientTest5, |
|
"number_quotient() mit 14 und -6" |
|
}, |
|
{ |
|
QuotientTest6, |
|
"number_quotient() mit -5 und -4" |
|
}, |
|
{ |
|
QuotientTestDivByZero, |
|
"number_quotient() mit 1 und 0" |
|
}, |
|
#endif |
|
|
|
#if NUMBER_MODULO_IMPLEMENTED |
|
{ |
|
ModuloTest1, |
|
"number_modulo() mit 0 und 1" |
|
}, |
|
{ |
|
ModuloTest2, |
|
"number_modulo() mit 2 und 1" |
|
}, |
|
{ |
|
ModuloTest3, |
|
"number_modulo() mit 5 und 2" |
|
}, |
|
{ |
|
ModuloTestDivByZero, |
|
"number_modulo() mit 1 und 0" |
|
}, |
|
#endif |
|
|
|
#if NUMBER_NUMBER_TO_STRING_IMPLEMENTED |
|
{ |
|
NumberToStringTest1, |
|
"number_numberToString() mit 42" |
|
}, |
|
{ |
|
NumberToStringTest2, |
|
"number_numberToString() mit -42" |
|
}, |
|
{ |
|
NumberToStringTestTooLong, |
|
"number_numberToString() mit zu grosser Zahl (Pruefung, ob Speicherverletzung eintritt)" |
|
}, |
|
#endif |
|
|
|
#if NUMBER_STRING_TO_NUMBER_IMPLEMENTED |
|
{ |
|
StringToNumberTest1, |
|
"number_stringToNumber() mit 42" |
|
}, |
|
{ |
|
StringToNumberTest2, |
|
"number_stringToNumber() mit -42" |
|
}, |
|
{ |
|
StringToNumberTest3, |
|
"number_stringToNumber() mit foobar (Pruefung, ob Status auf Fehler gesetzt wird)" |
|
}, |
|
{ |
|
StringToNumberTestOverflow, |
|
"number_stringToNumber() mit zu grossem String (Pruefing, ob Overflow gesetzt wird)" |
|
}, |
|
#endif |
|
{ 0, 0 } |
|
}; |
|
|
|
unsigned int numTests = ( sizeof( tests ) / sizeof( tests[0] ) ) - 1; /* -1, da ein {0, 0} Test angehängt wird. */ |
|
|
|
printf( "Willis Ueb04 Funktionstests\n\n\ |
|
NUMBER_BITS = %d\n\ |
|
NUMBER_CHUNKSIZE = %d\n\ |
|
NUMBER_CHUNKCOUNT = %d\n\ |
|
sizeof(NUMBER_BASETYPE) = %d\n\ |
|
\n", (int)NUMBER_BITS, (int)NUMBER_CHUNKSIZE, (int)NUMBER_CHUNKCOUNT, (int)sizeof( NUMBER_BASETYPE ) ); |
|
|
|
for( curTestIndex = 0; curTestIndex < numTests; ++curTestIndex ) |
|
{ |
|
RunTest( tests[ curTestIndex ], &numSuccessfulTests, &numWarnings ); |
|
} |
|
printf( "%d / %d Tests bestanden (%.0f%%)\n%d %s\n", numSuccessfulTests, numTests, ( numTests == 0 ? 0. : (100. * numSuccessfulTests / numTests ) ), numWarnings, ( numWarnings == 1 ? "Warnung" : "Warnungen" ) ); |
|
return EXIT_SUCCESS; |
|
} |