Skip to content

Instantly share code, notes, and snippets.

@mrwonko
Created December 1, 2012 21:01
Show Gist options
  • Save mrwonko/4185085 to your computer and use it in GitHub Desktop.
Save mrwonko/4185085 to your computer and use it in GitHub Desktop.
uni: ueb04test
# --------------------------------------------- #
# Fachhochschule Wedel, Wintersemester 2012 #
# C-Uebung 04 - ALU #
# Hanno Sternberg #
# #
# Makefile #
# --------------------------------------------- #
# Compiler
CC = gcc
# Archiver
AR = ar
# Doc generator
DOC = doxygen
# Library name
LIBNAME =number
LIBRARY =lib$(LIBNAME).a
# Executable
BINARY =ueb04
# Bits
BITS =50
# Basistyp
BASETYPE =unsigned short
# Stringlänge
STR_LEN =5
# Include directories
INCLUDES =
# Precompiler flags
CPPFLAGS =-DNUMBER_BITS=$(BITS) -DDEBUG "-DNUMBER_BASETYPE=$(BASETYPE)" -DNUMBER_STR_LEN=$(STR_LEN)
# Compiler flags
CFLAGS =-c -g -Wall -Werror -Wextra -pedantic -pedantic-errors -ansi
# Linker flags
LDFLAGS =-L./ -static
# Linker libraries
LDLIBS =-l$(LIBNAME)
# Archiver flags - insert files, create if not exist, write an object-file index
ARFLAGS =rcs
# Library sources
LIBSOURCE = number.c
LIBOBJECTS =$(LIBSOURCE:.c=.o)
# Sources
SOURCE =alu.c operation.c handler.c main.c
OBJECTS =$(SOURCE:.c=.o)
# Test
TEST_BINARY =ueb04test
TEST_SOURCE =test.c
TEST_OBJECTS =$(TEST_SOURCE:.c=.o)
.PHONY: all help clean doc rebuild doc lib test
default: all
all: $(LIBRARY) $(BINARY) $(TEST_BINARY)
# Compile a single file
%.o : %.c
@echo ""
@echo " - Building $@"
$(CC) $(CPPFLAGS) $(CFLAGS) $(INCLUDES) -o $@ $<
@echo " ... done"
# Link files to an executable
$(BINARY): $(OBJECTS) $(LIBRARY)
@echo ""
@echo " - linking $@"
$(CC) $(LDFLAGS) $(OBJECTS) $(LDLIBS) -o $(BINARY)
@echo " ... done"
# Test
test: $(TEST_BINARY)
$(TEST_BINARY): $(TEST_OBJECTS) $(LIBRARY)
@echo ""
@echo " -linking $@"
# libs after objects because order matters
$(CC) $(LDFLAGS) $(TEST_OBJECTS) $(LDLIBS) -o $(TEST_BINARY)
@echo " ... done"
lib: $(LIBRARY)
# Create library
$(LIBRARY): $(LIBOBJECTS)
@echo ""
@echo " - linking $@"
$(AR) $(ARFLAGS) $(LIBRARY) $(LIBOBJECTS)
@echo " ... done"
# Clean the project
clean:
@echo ""
@echo " - delete object all files"
rm -f $(OBJECTS) $(LIBOBJECTS) $(BINARY) $(LIBRARY) $(TEST_BINARY) $(TEST_OBJECTS) *~ doxygen.log
rm -rf doc/
@echo " ... done"
doc:
@echo ""
@echo " - creating documentation"
$(DOC)
@echo " ... done"
# Rebuild: Clean build
rebuild: clean all
# Show help
help:
@echo "Options:"
@echo "make all - create program, library and test"
@echo "make $(BINARY) - create program"
@echo "make lib - create library"
@echo "make clean - clean up"
@echo "make doc - create documentation"
@echo "make test - create test program"
/* 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;
}

Wie nutze ich den test?

  • test.c und das Makefile in einen Ordner mit der number.h und number.c stecken (am einfachsten direkt ins normale Projektverzeichnis)
  • Sofern einige Funktionen noch nicht implementiert wurden (sprich es zu Kompilierungsfehlern ihretwegen kommen würde), in der test.c oben die entsprechenden #defines auf 0 setzen
  • Mittels "make test" kompilieren
  • mit "ueb04test" ausführen

Was gibt es beim neuen Makefile zu beachten?

  • Es gibt "make test"
  • Die Bitbreite wurde auf einen Defaultwert von 50 geändert
  • Der Basetype kann nun beim Make mit angegeben werden und hat den Defaultwert unsigned short statt unsigned char
  • NUMBER_STR_LEN kann nun beim Make mit angegeben werden und hat den Defaultwert 5, damit die Tests auch mal terminieren
  • Das Link-Kommando ist minimal anders, da es unter Windows mit MinGW nicht wollte
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment