Of course

This commit is contained in:
MarcUs7i 2025-02-13 16:52:14 +01:00
parent d6cffc16e4
commit 8edc8dab71
13 changed files with 951 additions and 951 deletions

View file

@ -1 +1 @@
[![Review Assignment Due Date](https://classroom.github.com/assets/deadline-readme-button-22041afd0340ce965d47ae6ef1cefeee28c7c493a6346c4f15d667ab976d596c.svg)](https://classroom.github.com/a/Ra2fY2sl)
[![Review Assignment Due Date](https://classroom.github.com/assets/deadline-readme-button-22041afd0340ce965d47ae6ef1cefeee28c7c493a6346c4f15d667ab976d596c.svg)](https://classroom.github.com/a/Ra2fY2sl)

View file

@ -1,77 +1,77 @@
### if.03.22 Procedural Programming
# Römische Zahlen
Diese Aufgabe zielt auf die Analyse und Validierung von Zeichenketten, die Bearbeitung von Zeigern sowie eine einfache rekursive Berechnung ab.
## Einführung
Römische Zahlen werden seit der Antike verwendet. Sie werden durch Buchstaben ausgedrückt, die folgende Werte haben:
+ I: 1
+ V: 5
+ X: 10
+ L: 50
+ C: 100
+ D: 500
+ M: 1000
+ einige weitere Zeichen mit höheren Werten
Der numerische Wert wird einfach durch Addition des Werts jedes Buchstabens berechnet:
> MMCLXXXVII => 1000 + 1000 + 100 + 50 + 10 + 10 + 10 + 5 + 1 + 1 = 2187
Zusätzlich werden Werte abgezogen, wenn ein `I, X oder C` vor dem nächsten größeren Wert steht.
> IV => -1 + 5 = 4
> IX => -1 + 10 = 9
> XL => -10 + 50 = 40
> CD => -100 + 500 = 400
Eine Erweiterung dieser Regel erlaubt das Subtrahieren der darüber liegenden Buchstaben, wenn sie vor noch größeren Werten stehen.
> IC => -1 + 100 = 99 anstelle von XCIX => -10 + 100 - 1 + 10
was die Verwendung der Zahlen vereinfacht. Die Buchstaben `V, L, D` werden niemals als subtraktive Werte verwendet.
Römische Zahlen werden in absteigender Reihenfolge ihres Nennwerts geschrieben, mit Ausnahme des speziellen Falls der Subtraktion.
> MCMLXVII (1967) darf nicht in anderer Reihenfolge geschrieben werden, z.B. IIVXLMCM ist nicht erlaubt
## Aufgabe
Ihre Aufgabe besteht darin, einen abstrakten Datentyp namens `RomanNumber` zu implementieren, der die numerische Darstellung einer Zeichenkette kapselt, die eine gültige römische Zahl darstellt.
Die folgenden Funktionen für den ADT `RomanNumber` sollen implementiert werden:
+ `rn_is_valid_number_str`
Eine private Funktion, die feststellt, ob eine gegebene Zeichenkette eine gültige römische Zahl darstellt. Wenn die Zeichenkette andere Zeichen als die oben definierten enthält, stellt sie KEINE gültige Zahl dar!
Die Gültigkeit kann leicht überprüft werden, indem alle Zeichen der Zeichenkette durchlaufen und getestet wird, ob der aktuelle Buchstabe einer definierten entspricht und sein numerischer Wert gleich oder kleiner ist als der numerische Wert des vorherigen Buchstabens. Die einzige Ausnahme von dieser Regel sind gültige Subtraktionsmuster (z.B. IX). Wenn das aktuelle und das nächste Zeichen ein gültiges Subtraktionsmuster bilden, kann mit der bereits implementierten privaten Funktion `rn_is_valid_subtraction` getestet werden. Wenn ein solches gültiges Muster erkannt wurde, bleibt die Zeichenkette für den aktuellen Buchstaben gültig, und die oben genannte Überprüfung kann übersprungen werden. Trotzdem muss der 'nächste' Buchstabe (der zum Testen des Subtraktionsmusters verwendet wurde) weiterhin regelmäßig überprüft werden.
+ `rn_get_value_for_letter`:
Eine private Funktion, die den numerischen Wert eines einzelnen Buchstabens liefert. Beachten Sie, dass `switch / case`-Anweisungen auch für Zeichen funktionieren.
+ `rn_create`:
Alloziert eine neue `RomanNumber` aus einem statisch allokierten Pool von Datenstrukturen für den ADT. Der Pool von `RomanNumber`-Daten wird im globalen Bereich mit einer Größe von `MAX_ROMAN_NUMBER_COUNT` wie in `roman_number.c` definiert, allokiert.
Es kann darauf vertraut werden, dass der Pool ausreichend groß ist, um Instanzen für alle Unittests bereitzustellen, ohne dass Instanzen an den Pool zurückgegeben werden müssen.
Es kann darauf vertraut werden, dass eine gültige Zeichenkette bereitgestellt wird, jedoch nicht unbedingt eine gültige römische Zahl. Wenn die Zeichenkette keine gültige römische Zahl darstellt, soll eine ungültige (nicht-null) `RomanNumber` bereitgestellt werden. Die gegebene Zeichenkette muss daher mit der privaten Funktion `rn_is_valid_number_str` überprüft werden, ob die Zeichenkette eine gültige römische Zahl darstellt.
Wenn die gegebene Zeichenkette eine gültige römische Zahl ist, soll ihr numerischer Wert bei der Erstellung berechnet und in den Daten des ADTs gespeichert werden. Die römische Zahl wird einfach durch Addition der Werte ihrer Buchstaben umgewandelt, es sei denn, ein Subtraktionsmuster wird erkannt. In diesem Fall muss der Wert des Buchstabens subtrahiert werden. Verwenden Sie die Funktion `rn_is_valid_subtraction`, um nach Subtraktionen zu suchen.
*Beachten Sie*, dass eine leere Zeichenkette gültig ist und zu einem Wert von null (0) führt, während eine null-Zeichenkette ungültig ist.
+ `rn_is_valid`:
Bestimmt, ob die gegebene `RomanNumber` gültig ist. Sie ist gültig, wenn sie weder 0 ist noch aus einer ungültigen römischen Zahl erstellt wurde.
+ `rn_get_value`:
Liefert den numerischen Wert der gegebenen `RomanNumber`, wie er in den Daten des ADTs gespeichert ist, oder einen Wert kleiner als null, wenn die `RomanNumber` nicht gültig ist.
+ `rn_gcd`:
Berechnet den größten gemeinsamen Teiler (GGT / GCD) von zwei `RomanNumber`s und gibt das Ergebnis erneut als `RomanNumber` zurück.
__Wichtiger Hinweis:__ Diese Funktion berechnet DEN GGT NICHT tatsächlich, sondern verwendet die Funktion `int_gcd` zu diesem Zweck. Sie wandelt die römische Zahl nur hin und her.
+ `int_gcd`:
Berechnet tatsächlich den größten gemeinsamen Teiler (GGT / GCD) von zwei positiven Ganzzahlen __mit Rekursion__. Es kann darauf vertraut werden, dass die gegebenen Ganzzahlen immer positiv sind.
Der GGT ist definiert als:
- `ggd(x, 0) = x;`
- `ggd(x, y) = ggd(y, x % y);`
wobei `%` der Modulo-Operator ist.
_Beachten Sie_, dass diese Funktion unabhängig getestet wird und implementiert werden kann, auch wenn der ADT nicht funktioniert.
## Aufgaben
+ Erstellen Sie eine Skelettimplementierung des ADTs, um die Unittests kompilierbar zu machen.
+ Implementieren Sie alle erforderlichen Funktionen, um die Unittests zu bestehen.
+ Eine Hauptanwendung ist nicht erforderlich.
### if.03.22 Procedural Programming
# Römische Zahlen
Diese Aufgabe zielt auf die Analyse und Validierung von Zeichenketten, die Bearbeitung von Zeigern sowie eine einfache rekursive Berechnung ab.
## Einführung
Römische Zahlen werden seit der Antike verwendet. Sie werden durch Buchstaben ausgedrückt, die folgende Werte haben:
+ I: 1
+ V: 5
+ X: 10
+ L: 50
+ C: 100
+ D: 500
+ M: 1000
+ einige weitere Zeichen mit höheren Werten
Der numerische Wert wird einfach durch Addition des Werts jedes Buchstabens berechnet:
> MMCLXXXVII => 1000 + 1000 + 100 + 50 + 10 + 10 + 10 + 5 + 1 + 1 = 2187
Zusätzlich werden Werte abgezogen, wenn ein `I, X oder C` vor dem nächsten größeren Wert steht.
> IV => -1 + 5 = 4
> IX => -1 + 10 = 9
> XL => -10 + 50 = 40
> CD => -100 + 500 = 400
Eine Erweiterung dieser Regel erlaubt das Subtrahieren der darüber liegenden Buchstaben, wenn sie vor noch größeren Werten stehen.
> IC => -1 + 100 = 99 anstelle von XCIX => -10 + 100 - 1 + 10
was die Verwendung der Zahlen vereinfacht. Die Buchstaben `V, L, D` werden niemals als subtraktive Werte verwendet.
Römische Zahlen werden in absteigender Reihenfolge ihres Nennwerts geschrieben, mit Ausnahme des speziellen Falls der Subtraktion.
> MCMLXVII (1967) darf nicht in anderer Reihenfolge geschrieben werden, z.B. IIVXLMCM ist nicht erlaubt
## Aufgabe
Ihre Aufgabe besteht darin, einen abstrakten Datentyp namens `RomanNumber` zu implementieren, der die numerische Darstellung einer Zeichenkette kapselt, die eine gültige römische Zahl darstellt.
Die folgenden Funktionen für den ADT `RomanNumber` sollen implementiert werden:
+ `rn_is_valid_number_str`
Eine private Funktion, die feststellt, ob eine gegebene Zeichenkette eine gültige römische Zahl darstellt. Wenn die Zeichenkette andere Zeichen als die oben definierten enthält, stellt sie KEINE gültige Zahl dar!
Die Gültigkeit kann leicht überprüft werden, indem alle Zeichen der Zeichenkette durchlaufen und getestet wird, ob der aktuelle Buchstabe einer definierten entspricht und sein numerischer Wert gleich oder kleiner ist als der numerische Wert des vorherigen Buchstabens. Die einzige Ausnahme von dieser Regel sind gültige Subtraktionsmuster (z.B. IX). Wenn das aktuelle und das nächste Zeichen ein gültiges Subtraktionsmuster bilden, kann mit der bereits implementierten privaten Funktion `rn_is_valid_subtraction` getestet werden. Wenn ein solches gültiges Muster erkannt wurde, bleibt die Zeichenkette für den aktuellen Buchstaben gültig, und die oben genannte Überprüfung kann übersprungen werden. Trotzdem muss der 'nächste' Buchstabe (der zum Testen des Subtraktionsmusters verwendet wurde) weiterhin regelmäßig überprüft werden.
+ `rn_get_value_for_letter`:
Eine private Funktion, die den numerischen Wert eines einzelnen Buchstabens liefert. Beachten Sie, dass `switch / case`-Anweisungen auch für Zeichen funktionieren.
+ `rn_create`:
Alloziert eine neue `RomanNumber` aus einem statisch allokierten Pool von Datenstrukturen für den ADT. Der Pool von `RomanNumber`-Daten wird im globalen Bereich mit einer Größe von `MAX_ROMAN_NUMBER_COUNT` wie in `roman_number.c` definiert, allokiert.
Es kann darauf vertraut werden, dass der Pool ausreichend groß ist, um Instanzen für alle Unittests bereitzustellen, ohne dass Instanzen an den Pool zurückgegeben werden müssen.
Es kann darauf vertraut werden, dass eine gültige Zeichenkette bereitgestellt wird, jedoch nicht unbedingt eine gültige römische Zahl. Wenn die Zeichenkette keine gültige römische Zahl darstellt, soll eine ungültige (nicht-null) `RomanNumber` bereitgestellt werden. Die gegebene Zeichenkette muss daher mit der privaten Funktion `rn_is_valid_number_str` überprüft werden, ob die Zeichenkette eine gültige römische Zahl darstellt.
Wenn die gegebene Zeichenkette eine gültige römische Zahl ist, soll ihr numerischer Wert bei der Erstellung berechnet und in den Daten des ADTs gespeichert werden. Die römische Zahl wird einfach durch Addition der Werte ihrer Buchstaben umgewandelt, es sei denn, ein Subtraktionsmuster wird erkannt. In diesem Fall muss der Wert des Buchstabens subtrahiert werden. Verwenden Sie die Funktion `rn_is_valid_subtraction`, um nach Subtraktionen zu suchen.
*Beachten Sie*, dass eine leere Zeichenkette gültig ist und zu einem Wert von null (0) führt, während eine null-Zeichenkette ungültig ist.
+ `rn_is_valid`:
Bestimmt, ob die gegebene `RomanNumber` gültig ist. Sie ist gültig, wenn sie weder 0 ist noch aus einer ungültigen römischen Zahl erstellt wurde.
+ `rn_get_value`:
Liefert den numerischen Wert der gegebenen `RomanNumber`, wie er in den Daten des ADTs gespeichert ist, oder einen Wert kleiner als null, wenn die `RomanNumber` nicht gültig ist.
+ `rn_gcd`:
Berechnet den größten gemeinsamen Teiler (GGT / GCD) von zwei `RomanNumber`s und gibt das Ergebnis erneut als `RomanNumber` zurück.
__Wichtiger Hinweis:__ Diese Funktion berechnet DEN GGT NICHT tatsächlich, sondern verwendet die Funktion `int_gcd` zu diesem Zweck. Sie wandelt die römische Zahl nur hin und her.
+ `int_gcd`:
Berechnet tatsächlich den größten gemeinsamen Teiler (GGT / GCD) von zwei positiven Ganzzahlen __mit Rekursion__. Es kann darauf vertraut werden, dass die gegebenen Ganzzahlen immer positiv sind.
Der GGT ist definiert als:
- `ggd(x, 0) = x;`
- `ggd(x, y) = ggd(y, x % y);`
wobei `%` der Modulo-Operator ist.
_Beachten Sie_, dass diese Funktion unabhängig getestet wird und implementiert werden kann, auch wenn der ADT nicht funktioniert.
## Aufgaben
+ Erstellen Sie eine Skelettimplementierung des ADTs, um die Unittests kompilierbar zu machen.
+ Implementieren Sie alle erforderlichen Funktionen, um die Unittests zu bestehen.
+ Eine Hauptanwendung ist nicht erforderlich.
### Viel Erfolg!

View file

@ -1,79 +1,79 @@
### if.03.22 Procedural Programming
# Roman numbers
This assignment targets on string analysis and validation,
pointer handling as well as a simple recursive calculation.
## Introduction
Roman numbers are used since ancient ages. They are expressed via letters which have the following values:
+ I: 1
+ V: 5
+ X: 10
+ L: 50
+ C: 100
+ D: 500
+ M: 1000
+ some more higher value signs
The numerical value is calculated by simply adding the value of each letter:
> MMCLXXXVII => 1000 + 1000 + 100 + 50 + 10 + 10 + 10 + 5 + 1 + 1 = 2187
In addition, values are subtracted, if one `I, X, or C` is placed before the next larger value.
> IV => -1 + 5 = 4
> IX => -1 + 10 = 9
> XL => -10 + 50 = 40
> CD => -100 + 500 = 400
An extension of this rule allows subtraction of the letters above if they are placed in front of even larger values
> IC => -1 + 100 = 99 instead of XCIX => -10 + 100 - 1 + 10
which simplifies the usage of the numbers.
The letters `V, L, D` are never used as subtractive values.
Roman number letters are written in descending order of their nominal value, except for the special case of subtraction.
> MCMLXVII (1967) must not be written in different order, e.g. IIVXLMCM is not allowed
## Assignment
Your task is to implement an abstract data type calls `RomanNumber`, which encapsulates the numerical representation of a string that expresses a valid roman number.
The following functions for the ADT `RomanNumber` shall be implemented:
+ `rn_is_valid_number_str`
A private function which determines whether a given string represents a valid roman number. If the string contains any other characters but the above defined ones, it DOES NOT represent a valid number!
The validity can easily be done by iterating through all characters of the string and testing if the current letter is a defined one and its numerical value is equal or less the numerical letter of the previous letter. The only exception to this rule are valid subtraction patterns (e.g. IX). If the current and next letter form a valid subtraction pattern can be tested with the already implemented private function `rn_is_valid_subtraction`. If such a valid pattern was detected, the string remains valid for the current letter and the check stated above can be skipped. Nevertheless, the 'next' letter (which was used to test the subtraction pattern) still need regularly be checked.
+ `rn_get_value_for_letter`:
A private function that provides the numerical value of a single letter. Note that `switch / case` instructions work for characters as well.
+ `rn_create`:
Allocates a new `RomanNumber` out of a statically allocated pool of data structs for the ADT. The pool of `RomanNumber` data is allocated on the global scope with a size of `MAX_ROMAN_NUMBER_COUNT` as defined in `roman_number.c`.
It MAY be trusted, that the pool is sufficiently large to provide instances for all unit tests without the need of returning instances to the pool.
It MAY be trusted that a valid string is provided, although not necessarily a valid roman number string. If the string does not represent a valid roman number, an invalid (non-null)`RomanNumber` shall be provided. The given string need therefore be checked using the private function `rn_is_valid_number_str`, whether the string represents a valid roman number.
If the given string is a valid roman number, its numerical value shall be calculated upon creation and stored within the ADTs data. The roman number is converted by simply adding the values of its letters, except a subtraction pattern is detected. In this case the value of the letter has to be subtracted. Use the function `rn_is_valid_subtraction` to check for subtractions.
*Note* that an empty string is valid and results in the value zero (0), while a null-string is invalid.
+ `rn_is_valid`:
Determines whether or not the given `RomanNumber` is valid. It is, if it is neither 0 nor was created from an invalid roman number.
+ `rn_get_value`:
Provides the numerical value of the given `RomanNumber` as stored in the ADTs data or a value less than zero, if the `RomanNumber` is not valid.
+ `rn_gcd`:
Calculates the greatest common divisor of two `RomanNumber`s and returns the result again as `RomanNumber`.
__Important note:__ This function DOES NOT actually calculate the GCD but uses the function `int_gcd` for this purpose. It only 'converts' the roman number back and forth.
+ `int_gcd`:
Actually calculates the greatest common divisor (GCD) of two positive integer values __using recursion__. It MAY be trusted, that the given integers are always positive.
The GCD is defined as:
- `gcd(x, 0) = x;`
- `gcd(x, y) = gcd(y, x % y);`
where `%` is the modulo operator.
_Note_ the this function is independently tested and can be implemented even if the ADT is not working.
## Tasks
+ Create a skeleton implmentation of the ADT to make the unit tests compilable.
+ Implement all required functions to make the unit tests pass.
+ A main application is not required.
### Good Luck!
### if.03.22 Procedural Programming
# Roman numbers
This assignment targets on string analysis and validation,
pointer handling as well as a simple recursive calculation.
## Introduction
Roman numbers are used since ancient ages. They are expressed via letters which have the following values:
+ I: 1
+ V: 5
+ X: 10
+ L: 50
+ C: 100
+ D: 500
+ M: 1000
+ some more higher value signs
The numerical value is calculated by simply adding the value of each letter:
> MMCLXXXVII => 1000 + 1000 + 100 + 50 + 10 + 10 + 10 + 5 + 1 + 1 = 2187
In addition, values are subtracted, if one `I, X, or C` is placed before the next larger value.
> IV => -1 + 5 = 4
> IX => -1 + 10 = 9
> XL => -10 + 50 = 40
> CD => -100 + 500 = 400
An extension of this rule allows subtraction of the letters above if they are placed in front of even larger values
> IC => -1 + 100 = 99 instead of XCIX => -10 + 100 - 1 + 10
which simplifies the usage of the numbers.
The letters `V, L, D` are never used as subtractive values.
Roman number letters are written in descending order of their nominal value, except for the special case of subtraction.
> MCMLXVII (1967) must not be written in different order, e.g. IIVXLMCM is not allowed
## Assignment
Your task is to implement an abstract data type calls `RomanNumber`, which encapsulates the numerical representation of a string that expresses a valid roman number.
The following functions for the ADT `RomanNumber` shall be implemented:
+ `rn_is_valid_number_str`
A private function which determines whether a given string represents a valid roman number. If the string contains any other characters but the above defined ones, it DOES NOT represent a valid number!
The validity can easily be done by iterating through all characters of the string and testing if the current letter is a defined one and its numerical value is equal or less the numerical letter of the previous letter. The only exception to this rule are valid subtraction patterns (e.g. IX). If the current and next letter form a valid subtraction pattern can be tested with the already implemented private function `rn_is_valid_subtraction`. If such a valid pattern was detected, the string remains valid for the current letter and the check stated above can be skipped. Nevertheless, the 'next' letter (which was used to test the subtraction pattern) still need regularly be checked.
+ `rn_get_value_for_letter`:
A private function that provides the numerical value of a single letter. Note that `switch / case` instructions work for characters as well.
+ `rn_create`:
Allocates a new `RomanNumber` out of a statically allocated pool of data structs for the ADT. The pool of `RomanNumber` data is allocated on the global scope with a size of `MAX_ROMAN_NUMBER_COUNT` as defined in `roman_number.c`.
It MAY be trusted, that the pool is sufficiently large to provide instances for all unit tests without the need of returning instances to the pool.
It MAY be trusted that a valid string is provided, although not necessarily a valid roman number string. If the string does not represent a valid roman number, an invalid (non-null)`RomanNumber` shall be provided. The given string need therefore be checked using the private function `rn_is_valid_number_str`, whether the string represents a valid roman number.
If the given string is a valid roman number, its numerical value shall be calculated upon creation and stored within the ADTs data. The roman number is converted by simply adding the values of its letters, except a subtraction pattern is detected. In this case the value of the letter has to be subtracted. Use the function `rn_is_valid_subtraction` to check for subtractions.
*Note* that an empty string is valid and results in the value zero (0), while a null-string is invalid.
+ `rn_is_valid`:
Determines whether or not the given `RomanNumber` is valid. It is, if it is neither 0 nor was created from an invalid roman number.
+ `rn_get_value`:
Provides the numerical value of the given `RomanNumber` as stored in the ADTs data or a value less than zero, if the `RomanNumber` is not valid.
+ `rn_gcd`:
Calculates the greatest common divisor of two `RomanNumber`s and returns the result again as `RomanNumber`.
__Important note:__ This function DOES NOT actually calculate the GCD but uses the function `int_gcd` for this purpose. It only 'converts' the roman number back and forth.
+ `int_gcd`:
Actually calculates the greatest common divisor (GCD) of two positive integer values __using recursion__. It MAY be trusted, that the given integers are always positive.
The GCD is defined as:
- `gcd(x, 0) = x;`
- `gcd(x, y) = gcd(y, x % y);`
where `%` is the modulo operator.
_Note_ the this function is independently tested and can be implemented even if the ADT is not working.
## Tasks
+ Create a skeleton implmentation of the ADT to make the unit tests compilable.
+ Implement all required functions to make the unit tests pass.
+ A main application is not required.
### Good Luck!

View file

@ -1,20 +1,20 @@
/*----------------------------------------------------------
* HTBLA-Leonding
* ---------------------------------------------------------
* Exercise Number: n/a
* Title: general.h
* Author: P. Bauer, S. Schraml
* ----------------------------------------------------------
* Description:
* General usable definitions and types.
* ----------------------------------------------------------
*/
#ifndef ___GENERAL_H
#define ___GENERAL_H
/** Convenience macro do get maximum of two numbers */
#define MAX(x, y) ((x) > (y) ? (x) : (y))
/** Convenience macro do get maximum of two numbers */
#define MIN(x, y) ((x) < (y) ? (x) : (y))
#endif
/*----------------------------------------------------------
* HTBLA-Leonding
* ---------------------------------------------------------
* Exercise Number: n/a
* Title: general.h
* Author: P. Bauer, S. Schraml
* ----------------------------------------------------------
* Description:
* General usable definitions and types.
* ----------------------------------------------------------
*/
#ifndef ___GENERAL_H
#define ___GENERAL_H
/** Convenience macro do get maximum of two numbers */
#define MAX(x, y) ((x) > (y) ? (x) : (y))
/** Convenience macro do get maximum of two numbers */
#define MIN(x, y) ((x) < (y) ? (x) : (y))
#endif

View file

@ -1,19 +1,19 @@
/*----------------------------------------------------------
* HTBLA-Leonding
* ---------------------------------------------------------
* Author: S. Schraml
* ----------------------------------------------------------
* Description:
* The Roman Number Calculator.
* ----------------------------------------------------------
*/
/**
* The main entry point of the application.
*/
int main(int argc, char *argv[])
{
/* No implementation needed */
return 0;
/*----------------------------------------------------------
* HTBLA-Leonding
* ---------------------------------------------------------
* Author: S. Schraml
* ----------------------------------------------------------
* Description:
* The Roman Number Calculator.
* ----------------------------------------------------------
*/
/**
* The main entry point of the application.
*/
int main(int argc, char *argv[])
{
/* No implementation needed */
return 0;
}

200
makefile
View file

@ -1,100 +1,100 @@
CC = gcc
CCLINK = g++
LIBS =
CCOPTIONS = -Wall -pedantic -std=c11 -g
LDOPTIONS =
BUILD_DIR = build
TEST = test_roman_number
PROGRAM = roman_number
COMMON_HDRS = general.h
LIBRARY_FILES = shortcut
ASSIGNMENT_HDRS =
ASSIGNMENT_FILES = roman_number
MAIN_DRIVER = main_driver
TEST_DRIVER = test_driver
LIBRARY_H = $(addsuffix .h, $(LIBRARY_FILES))
ASSIGNMENT_H = $(addsuffix .h, $(ASSIGNMENT_FILES)) $(ASSIGNMENT_HDRS)
ASSIGNMENT_C = $(addsuffix .c, $(ASSIGNMENT_FILES))
HDRS = $(ASSIGNEMT_H) $(SHARED_HDRS) $(COMMON_HDRS) $(LIBRARY_H)
TESTOBJECT = $(addprefix $(BUILD_DIR)/, $(TEST_DRIVER).o)
MAINOBJECT = $(addprefix $(BUILD_DIR)/, $(MAIN_DRIVER).o)
LIBRARY_OBJS = $(addprefix $(BUILD_DIR)/, $(addsuffix .o, $(LIBRARY_FILES)))
TEST_OBJS = $(addprefix $(BUILD_DIR)/, $(addprefix test_, $(addsuffix .o, $(ASSIGNMENT_FILES))))
MAIN_OBJ = $(addprefix $(BUILD_DIR)/, $(addsuffix .o, $(ASSIGNMENT_FILES)))
OBJS = $(LIBRARY_OBJS) $(MAIN_OBJ) $(TEST_OBJS)
DOXY = doxygen
all: $(PROGRAM)
./$(PROGRAM)
./$(PROGRAM) -arg1 -arg2 -arg3
./$(PROGRAM) -arg1 -arg2 -arg3 --change
./$(PROGRAM) -arg1 a r g --change -argument -ARG5 -another6 77 -arg8
$(TEST): $(BUILD_DIR) $(OBJS) $(TESTOBJECT)
$(CCLINK) -o $@ $(LDOPTIONS) $(OBJS) $(TESTOBJECT)
$(PROGRAM): $(BUILD_DIR) $(OBJS) $(MAINOBJECT)
$(CCLINK) -o $@ $(LDOPTIONS) $(OBJS) $(MAINOBJECT)
.PHONY: clean cleanall doxy test setsample setassignment definesample defineassignment assignmentfolder
clean:
rm -f $(PROGRAM) $(TEST) $(TESTOBJECT) $(MAINOBJECT) $(OBJS)
rm -rf $(BUILD_DIR)
rm -f *.o
cleanall: clean
rm -f index.html
rm -rf html
doxy:
$(DOXY)
rm -f index.html
ln -s html/index.html index.html
test: $(TEST)
./$(TEST)
cleantest: clean
clear
make test
$(BUILD_DIR):
mkdir -p $(BUILD_DIR)
$(BUILD_DIR)/%.o: %.c
$(CC) $(CCOPTIONS) -c -o $@ $<
#sets project as sample solution
setsample:
$(foreach name, $(ASSIGNMENT_H) $(ASSIGNMENT_C), cp $(name).sample $(name);)
#sets project as assignment
setassignment:
$(foreach name, $(ASSIGNMENT_H) $(ASSIGNMENT_C), cp $(name).assignment $(name);)
# defines current state of project as sample solution
definesample:
$(foreach name, $(ASSIGNMENT_H) $(ASSIGNMENT_C), cp $(name) $(name).sample;)
# defines current sate of project as assignment
defineassignment :
$(foreach name, $(ASSIGNMENT_H) $(ASSIGNMENT_C), cp $(name) $(name).assignment;)
# creates a folder which can serve as a publishable assignment
assignmentfolder:
make setassignment
rm -rf ../assignment
mkdir ../assignment
cp -R * ../assignment
cp .gitignore ../assignment
rm ../assignment/*.sample
rm ../assignment/*.assignment
make cleanall
CC = gcc
CCLINK = g++
LIBS =
CCOPTIONS = -Wall -pedantic -std=c11 -g
LDOPTIONS =
BUILD_DIR = build
TEST = test_roman_number
PROGRAM = roman_number
COMMON_HDRS = general.h
LIBRARY_FILES = shortcut
ASSIGNMENT_HDRS =
ASSIGNMENT_FILES = roman_number
MAIN_DRIVER = main_driver
TEST_DRIVER = test_driver
LIBRARY_H = $(addsuffix .h, $(LIBRARY_FILES))
ASSIGNMENT_H = $(addsuffix .h, $(ASSIGNMENT_FILES)) $(ASSIGNMENT_HDRS)
ASSIGNMENT_C = $(addsuffix .c, $(ASSIGNMENT_FILES))
HDRS = $(ASSIGNEMT_H) $(SHARED_HDRS) $(COMMON_HDRS) $(LIBRARY_H)
TESTOBJECT = $(addprefix $(BUILD_DIR)/, $(TEST_DRIVER).o)
MAINOBJECT = $(addprefix $(BUILD_DIR)/, $(MAIN_DRIVER).o)
LIBRARY_OBJS = $(addprefix $(BUILD_DIR)/, $(addsuffix .o, $(LIBRARY_FILES)))
TEST_OBJS = $(addprefix $(BUILD_DIR)/, $(addprefix test_, $(addsuffix .o, $(ASSIGNMENT_FILES))))
MAIN_OBJ = $(addprefix $(BUILD_DIR)/, $(addsuffix .o, $(ASSIGNMENT_FILES)))
OBJS = $(LIBRARY_OBJS) $(MAIN_OBJ) $(TEST_OBJS)
DOXY = doxygen
all: $(PROGRAM)
./$(PROGRAM)
./$(PROGRAM) -arg1 -arg2 -arg3
./$(PROGRAM) -arg1 -arg2 -arg3 --change
./$(PROGRAM) -arg1 a r g --change -argument -ARG5 -another6 77 -arg8
$(TEST): $(BUILD_DIR) $(OBJS) $(TESTOBJECT)
$(CCLINK) -o $@ $(LDOPTIONS) $(OBJS) $(TESTOBJECT)
$(PROGRAM): $(BUILD_DIR) $(OBJS) $(MAINOBJECT)
$(CCLINK) -o $@ $(LDOPTIONS) $(OBJS) $(MAINOBJECT)
.PHONY: clean cleanall doxy test setsample setassignment definesample defineassignment assignmentfolder
clean:
rm -f $(PROGRAM) $(TEST) $(TESTOBJECT) $(MAINOBJECT) $(OBJS)
rm -rf $(BUILD_DIR)
rm -f *.o
cleanall: clean
rm -f index.html
rm -rf html
doxy:
$(DOXY)
rm -f index.html
ln -s html/index.html index.html
test: $(TEST)
./$(TEST)
cleantest: clean
clear
make test
$(BUILD_DIR):
mkdir -p $(BUILD_DIR)
$(BUILD_DIR)/%.o: %.c
$(CC) $(CCOPTIONS) -c -o $@ $<
#sets project as sample solution
setsample:
$(foreach name, $(ASSIGNMENT_H) $(ASSIGNMENT_C), cp $(name).sample $(name);)
#sets project as assignment
setassignment:
$(foreach name, $(ASSIGNMENT_H) $(ASSIGNMENT_C), cp $(name).assignment $(name);)
# defines current state of project as sample solution
definesample:
$(foreach name, $(ASSIGNMENT_H) $(ASSIGNMENT_C), cp $(name) $(name).sample;)
# defines current sate of project as assignment
defineassignment :
$(foreach name, $(ASSIGNMENT_H) $(ASSIGNMENT_C), cp $(name) $(name).assignment;)
# creates a folder which can serve as a publishable assignment
assignmentfolder:
make setassignment
rm -rf ../assignment
mkdir ../assignment
cp -R * ../assignment
cp .gitignore ../assignment
rm ../assignment/*.sample
rm ../assignment/*.assignment
make cleanall

View file

@ -1,193 +1,193 @@
/*-----------------------------------------------------------------------------
* HTBLA-Leonding
*-----------------------------------------------------------------------------
* Author(s): Marc Tismonar
*-----------------------------------------------------------------------------
* Description:
* Encapsulates roman numbers and provides basic mathematical operations.
*-----------------------------------------------------------------------------
*/
#include "roman_number.h"
// the maximum number of RomanNumbers
#define MAX_ROMAN_NUMBER_COUNT 32
struct RomanNumberData {
char* number;
int length;
};
static RomanNumber romanNumber = {0};
/* Determines whether or not the letter followed by next_letter is a valid subtraction pattern of roman numbers */
static bool rn_is_valid_subtraction(char letter, char next_letter) {
return (letter == 'I' && (next_letter == 'V' || next_letter == 'X' || next_letter == 'L' || next_letter == 'C' || next_letter == 'D' || next_letter == 'M'))
|| (letter == 'X' && (next_letter == 'L' || next_letter == 'C' || next_letter == 'D' || next_letter == 'M'))
|| (letter == 'C' && (next_letter == 'D' || next_letter == 'M'));
}
static int roman_char_to_int(char romanNumber) {
switch(romanNumber) {
case 'I':
{
return 1;
}
case 'V':
{
return 5;
}
case 'X':
{
return 10;
}
case 'L':
{
return 50;
}
case 'C':
{
return 100;
}
case 'D':
{
return 500;
}
case 'M':
{
return 1000;
}
default:
{
return 0;
}
}
}
static char int_to_roman_char(int number) {
switch(number) {
case 1:
{
return 'I';
}
case 5:
{
return 'V';
}
case 10:
{
return 'X';
}
case 50:
{
return 'L';
}
case 100:
{
return 'C';
}
case 500:
{
return 'D';
}
case 1000:
{
return 'M';
}
default:
{
return 0;
}
}
}
static bool rn_is_valid_number_str(char* string_number) {
if(string_number == 0) {
return 0;
}
for(int i = 0; i < strlen(string_number); i++) {
if(roman_char_to_int(string_number[i]) == 0) {
return false;
}
}
return true;
}
RomanNumber rn_create(char* value) {
if(value == 0) {
return 0;
}
romanNumber = (RomanNumber)calloc(1, sizeof(struct RomanNumberData));
romanNumber->number = value;
romanNumber->length = strlen(value);
return romanNumber;
}
int rn_get_value(RomanNumber number) {
if(number == 0 || !rn_is_valid(number)) {
return -1;
}
int next_number = 0;
int current_number = 0;
int total_number = 0;
for(int i = 0; i < strlen(number->number); i++) {
current_number = roman_char_to_int(number->number[i]);
if (number->number[i+1] == '\0') {
total_number += current_number;
return total_number;
}
next_number = roman_char_to_int(number->number[i+1]);
if(current_number < next_number) {
if(!rn_is_valid_subtraction(number->number[i], number->number[i+1])) {
return -1;
}
total_number -= current_number;
} else {
total_number += current_number;
}
}
return total_number;
}
bool rn_is_valid(RomanNumber number) {
if(number == 0) {
return 0;
}
for(int i = 0; i < number->length; i++) {
if(roman_char_to_int(number->number[i]) == 0) {
return false;
}
}
return true;
}
RomanNumber rn_gcd(RomanNumber x, RomanNumber y) {
if(x == 0 || y == 0) {
return -1;
}
int intX = rn_get_value(x);
int intY = rn_get_value(y);
int result = int_gcd(intX, intY);
}
int int_gcd(int x, int y) {
return 0;
/*-----------------------------------------------------------------------------
* HTBLA-Leonding
*-----------------------------------------------------------------------------
* Author(s): Marc Tismonar
*-----------------------------------------------------------------------------
* Description:
* Encapsulates roman numbers and provides basic mathematical operations.
*-----------------------------------------------------------------------------
*/
#include "roman_number.h"
// the maximum number of RomanNumbers
#define MAX_ROMAN_NUMBER_COUNT 32
struct RomanNumberData {
char* number;
int length;
};
static RomanNumber romanNumber = {0};
/* Determines whether or not the letter followed by next_letter is a valid subtraction pattern of roman numbers */
static bool rn_is_valid_subtraction(char letter, char next_letter) {
return (letter == 'I' && (next_letter == 'V' || next_letter == 'X' || next_letter == 'L' || next_letter == 'C' || next_letter == 'D' || next_letter == 'M'))
|| (letter == 'X' && (next_letter == 'L' || next_letter == 'C' || next_letter == 'D' || next_letter == 'M'))
|| (letter == 'C' && (next_letter == 'D' || next_letter == 'M'));
}
static int roman_char_to_int(char romanNumber) {
switch(romanNumber) {
case 'I':
{
return 1;
}
case 'V':
{
return 5;
}
case 'X':
{
return 10;
}
case 'L':
{
return 50;
}
case 'C':
{
return 100;
}
case 'D':
{
return 500;
}
case 'M':
{
return 1000;
}
default:
{
return 0;
}
}
}
static char int_to_roman_char(int number) {
switch(number) {
case 1:
{
return 'I';
}
case 5:
{
return 'V';
}
case 10:
{
return 'X';
}
case 50:
{
return 'L';
}
case 100:
{
return 'C';
}
case 500:
{
return 'D';
}
case 1000:
{
return 'M';
}
default:
{
return 0;
}
}
}
static bool rn_is_valid_number_str(char* string_number) {
if(string_number == 0) {
return 0;
}
for(int i = 0; i < strlen(string_number); i++) {
if(roman_char_to_int(string_number[i]) == 0) {
return false;
}
}
return true;
}
RomanNumber rn_create(char* value) {
if(value == 0) {
return 0;
}
romanNumber = (RomanNumber)calloc(1, sizeof(struct RomanNumberData));
romanNumber->number = value;
romanNumber->length = strlen(value);
return romanNumber;
}
int rn_get_value(RomanNumber number) {
if(number == 0 || !rn_is_valid(number)) {
return -1;
}
int next_number = 0;
int current_number = 0;
int total_number = 0;
for(int i = 0; i < strlen(number->number); i++) {
current_number = roman_char_to_int(number->number[i]);
if (number->number[i+1] == '\0') {
total_number += current_number;
return total_number;
}
next_number = roman_char_to_int(number->number[i+1]);
if(current_number < next_number) {
if(!rn_is_valid_subtraction(number->number[i], number->number[i+1])) {
return -1;
}
total_number -= current_number;
} else {
total_number += current_number;
}
}
return total_number;
}
bool rn_is_valid(RomanNumber number) {
if(number == 0) {
return 0;
}
for(int i = 0; i < number->length; i++) {
if(roman_char_to_int(number->number[i]) == 0) {
return false;
}
}
return true;
}
RomanNumber rn_gcd(RomanNumber x, RomanNumber y) {
if(x == 0 || y == 0) {
return -1;
}
int intX = rn_get_value(x);
int intY = rn_get_value(y);
int result = int_gcd(intX, intY);
}
int int_gcd(int x, int y) {
return 0;
}

View file

@ -1,67 +1,67 @@
/*----------------------------------------------------------
* HTBLA-Leonding
* ---------------------------------------------------------
* Author: Marc Tismonar
* ----------------------------------------------------------
* Description:
* Encapsulates roman numbers and provides basic mathematical operations.
* ----------------------------------------------------------
*/
#ifndef ___ROMAN_NUMBER
#define ___ROMAN_NUMBER
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
typedef struct RomanNumberData* RomanNumber;
/**
* Creates a roman number from the given string.
* If the given string is not valid or not a valid
* number, an invalid RomanNumber is provided.
*
* @param value The roman number string.
* @return RomanNumber
*/
RomanNumber rn_create(char* value);
/**
* Determines whether or not the RomanNumber is valid.
*
* @param number The number to test.
* @return true if the number is valid, false otherwise.
*/
bool rn_is_valid(RomanNumber number);
/**
* Provides the value of the RomanNumber or a value less
* than zero, if the number is not valid.
*
* @param number The number to convert.
* @return The integral value of the roman number or a value
* less than 0;
*/
int rn_get_value(RomanNumber number);
/**
* Calculates the greatest common divisor of two roman numbers.
*
* @param x The first number.
* @param y The second number.
* @return The result or an invalid roman number, if at least one
* of the given values is invalid.
*/
RomanNumber rn_gcd(RomanNumber x, RomanNumber y);
/**
* Calculates the greatest common divisor of two integers.
*
* @param x The first operand.
* @param y The second operand
* @return The result.
*/
int int_gcd(int x, int y);
/*----------------------------------------------------------
* HTBLA-Leonding
* ---------------------------------------------------------
* Author: Marc Tismonar
* ----------------------------------------------------------
* Description:
* Encapsulates roman numbers and provides basic mathematical operations.
* ----------------------------------------------------------
*/
#ifndef ___ROMAN_NUMBER
#define ___ROMAN_NUMBER
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
typedef struct RomanNumberData* RomanNumber;
/**
* Creates a roman number from the given string.
* If the given string is not valid or not a valid
* number, an invalid RomanNumber is provided.
*
* @param value The roman number string.
* @return RomanNumber
*/
RomanNumber rn_create(char* value);
/**
* Determines whether or not the RomanNumber is valid.
*
* @param number The number to test.
* @return true if the number is valid, false otherwise.
*/
bool rn_is_valid(RomanNumber number);
/**
* Provides the value of the RomanNumber or a value less
* than zero, if the number is not valid.
*
* @param number The number to convert.
* @return The integral value of the roman number or a value
* less than 0;
*/
int rn_get_value(RomanNumber number);
/**
* Calculates the greatest common divisor of two roman numbers.
*
* @param x The first number.
* @param y The second number.
* @return The result or an invalid roman number, if at least one
* of the given values is invalid.
*/
RomanNumber rn_gcd(RomanNumber x, RomanNumber y);
/**
* Calculates the greatest common divisor of two integers.
*
* @param x The first operand.
* @param y The second operand
* @return The result.
*/
int int_gcd(int x, int y);
#endif

View file

@ -1,151 +1,151 @@
/*----------------------------------------------------------
* HTBLA-Leonding
* ---------------------------------------------------------
* Title: shortcut.c
* Author: P. Bauer
* Date: November 08, 2010
* ----------------------------------------------------------
* Description:
* Test driver.
* ----------------------------------------------------------
*/
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include "shortcut.h"
#define MAX_TEST_FUNCTIONS 256
static char assert_msg_buffer[1024];
static int tc_count = 0;
static int tc_fail_count = 0;
static struct TestCase test_cases[MAX_TEST_FUNCTIONS];
const char* version()
{
return "ShortCut v. 1.3.0";
}
char* format_msg(char* format, ...) {
va_list args;
va_start (args, format);
vsprintf(assert_msg_buffer, format, args);
return assert_msg_buffer;
}
void assert_true(bool bool_expr, struct TestCase *tc, const char *msg,
const char* file, int line)
{
if (!bool_expr) {
if (tc->success) {
tc->success = false;
tc_fail_count++;
}
printf("\n\tFailure (file: %s, line %d): %s: %s", file, line, tc->name, msg);
}
}
void assert_false(bool bool_expr, struct TestCase *tc, const char *msg,
const char* file, int line)
{
assert_true(!bool_expr, tc, msg, file, line);
}
static void assert_string_failure(const char *expected, char *actual, struct TestCase *tc,
const char *msg, const char* file, int line);
void assert_equals_str(const char *expected, char *actual, struct TestCase *tc,
const char *msg, const char* file, int line)
{
if (expected == actual) {
return;
}
if (expected == 0 || actual == 0) {
assert_string_failure(expected, actual, tc, msg, file, line);
return;
}
if (strcmp(actual, expected) != 0) {
assert_string_failure(expected, actual, tc, msg, file, line);
return;
}
}
#define MAX_MSG_LEN 128
static void assert_string_failure(const char *expected, char *actual, struct TestCase *tc,
const char *msg, const char* file, int line)
{
char new_msg[MAX_MSG_LEN];
sprintf(new_msg, "Expected \"%s\", actual \"%s\". %s", expected, actual, msg);
assert_true(false, tc, new_msg, file, line);
}
void assert_equals(int expected, int actual, struct TestCase *tc,
const char *msg, const char* file, int line)
{
char new_msg[MAX_MSG_LEN];
sprintf(new_msg, "Expected %d, actual %d. %s", expected, actual, msg);
assert_true(expected == actual, tc, new_msg, file, line);
}
void assert_equals_f(double expected, double actual, double tolerance, struct TestCase* tc,
const char* msg, const char* file, int line)
{
char new_msg[MAX_MSG_LEN];
sprintf(new_msg, "Expected %f, actual %f. %s", expected, actual, msg);
double min_val = expected - tolerance;
double max_val = expected + tolerance;
assert_true(min_val <= actual && actual <= max_val, tc, new_msg, file, line);
}
int get_test_count()
{
return tc_count;
}
bool add_test(void (*test_function)(struct TestCase *tc), const char *test_name)
{
if (tc_count == MAX_TEST_FUNCTIONS) {
return false;
}
else {
test_cases[tc_count].success = true;
test_cases[tc_count].name = test_name;
test_cases[tc_count].test_function = test_function;
tc_count++;
return true;
}
}
void run_tests()
{
int i;
printf("\n%s: Running tests\n", version());
for (i = 0; i < get_test_count(); i++) {
printf("Running test %s ...", test_cases[i].name);
test_cases[i].test_function(&test_cases[i]);
if (test_cases[i].success) {
printf("\033[32m OK\033[m");
}
else {
printf("\033[31m ... FAIL\033[m");
}
printf("\n");
}
printf("\nTotal tests run: %d\n", tc_count);
if (tc_fail_count > 0) {
printf("\033[31mTests failed: %d\033[m\n", tc_fail_count);
}
else {
printf("\033[32mAll tests run successfully\033[m\n");
}
}
/*----------------------------------------------------------
* HTBLA-Leonding
* ---------------------------------------------------------
* Title: shortcut.c
* Author: P. Bauer
* Date: November 08, 2010
* ----------------------------------------------------------
* Description:
* Test driver.
* ----------------------------------------------------------
*/
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include "shortcut.h"
#define MAX_TEST_FUNCTIONS 256
static char assert_msg_buffer[1024];
static int tc_count = 0;
static int tc_fail_count = 0;
static struct TestCase test_cases[MAX_TEST_FUNCTIONS];
const char* version()
{
return "ShortCut v. 1.3.0";
}
char* format_msg(char* format, ...) {
va_list args;
va_start (args, format);
vsprintf(assert_msg_buffer, format, args);
return assert_msg_buffer;
}
void assert_true(bool bool_expr, struct TestCase *tc, const char *msg,
const char* file, int line)
{
if (!bool_expr) {
if (tc->success) {
tc->success = false;
tc_fail_count++;
}
printf("\n\tFailure (file: %s, line %d): %s: %s", file, line, tc->name, msg);
}
}
void assert_false(bool bool_expr, struct TestCase *tc, const char *msg,
const char* file, int line)
{
assert_true(!bool_expr, tc, msg, file, line);
}
static void assert_string_failure(const char *expected, char *actual, struct TestCase *tc,
const char *msg, const char* file, int line);
void assert_equals_str(const char *expected, char *actual, struct TestCase *tc,
const char *msg, const char* file, int line)
{
if (expected == actual) {
return;
}
if (expected == 0 || actual == 0) {
assert_string_failure(expected, actual, tc, msg, file, line);
return;
}
if (strcmp(actual, expected) != 0) {
assert_string_failure(expected, actual, tc, msg, file, line);
return;
}
}
#define MAX_MSG_LEN 128
static void assert_string_failure(const char *expected, char *actual, struct TestCase *tc,
const char *msg, const char* file, int line)
{
char new_msg[MAX_MSG_LEN];
sprintf(new_msg, "Expected \"%s\", actual \"%s\". %s", expected, actual, msg);
assert_true(false, tc, new_msg, file, line);
}
void assert_equals(int expected, int actual, struct TestCase *tc,
const char *msg, const char* file, int line)
{
char new_msg[MAX_MSG_LEN];
sprintf(new_msg, "Expected %d, actual %d. %s", expected, actual, msg);
assert_true(expected == actual, tc, new_msg, file, line);
}
void assert_equals_f(double expected, double actual, double tolerance, struct TestCase* tc,
const char* msg, const char* file, int line)
{
char new_msg[MAX_MSG_LEN];
sprintf(new_msg, "Expected %f, actual %f. %s", expected, actual, msg);
double min_val = expected - tolerance;
double max_val = expected + tolerance;
assert_true(min_val <= actual && actual <= max_val, tc, new_msg, file, line);
}
int get_test_count()
{
return tc_count;
}
bool add_test(void (*test_function)(struct TestCase *tc), const char *test_name)
{
if (tc_count == MAX_TEST_FUNCTIONS) {
return false;
}
else {
test_cases[tc_count].success = true;
test_cases[tc_count].name = test_name;
test_cases[tc_count].test_function = test_function;
tc_count++;
return true;
}
}
void run_tests()
{
int i;
printf("\n%s: Running tests\n", version());
for (i = 0; i < get_test_count(); i++) {
printf("Running test %s ...", test_cases[i].name);
test_cases[i].test_function(&test_cases[i]);
if (test_cases[i].success) {
printf("\033[32m OK\033[m");
}
else {
printf("\033[31m ... FAIL\033[m");
}
printf("\n");
}
printf("\nTotal tests run: %d\n", tc_count);
if (tc_fail_count > 0) {
printf("\033[31mTests failed: %d\033[m\n", tc_fail_count);
}
else {
printf("\033[32mAll tests run successfully\033[m\n");
}
}

View file

@ -1,110 +1,110 @@
/*----------------------------------------------------------
* HTBLA-Leonding
* ---------------------------------------------------------
* Title: shortcut
* Author: P. Bauer
* Date: November 03, 2010
* ----------------------------------------------------------
* Description:
* A simple unit testing frame work for C.
* ----------------------------------------------------------
*/
#ifndef ___SHORTCUT_H
#define ___SHORTCUT_H
#include <stdbool.h>
/** TestCase is the struct to define one test case. A test case can
*** be added to a test. If the test is run all added test cases are
*** run and the result of the run of each test case is checked automatically.
*/
struct TestCase {
const char *name;
/** true if the test passed, false otherwise. */
bool success;
/** The test function which is executed by the test framework. */
void (*test_function)(struct TestCase *tc);
};
/**
*** @return Version of shortcut as string
***/
const char* version();
/**
*** @return The fromated string as generated using sprintf(format, ...)
***/
char* format_msg(char* format, ...);
/** assert_true checks, whether a boolean expression passed is true or false.
*** in case it is false the test case stating the assertion is marked
*** as failed and msg is printed.
*** @param bool_expr Expression which is evaluated.
*** @param tc Pointer to the test case which states this assertion.
*** @param msg Message to be printed if assertion evaluates to false.
*** @param file File in which the assert is given.
*** @param line Line in which the assert is given.
*/
void assert_true(bool bool_expr, struct TestCase *tc, const char *msg,
const char* file, int line);
/** assert_false does the same as assert() but the boolean expression
*** has to evaluate to false. If it evaluates to true the assertion
*** fails.
*** @see assert
*/
void assert_false(bool bool_expr, struct TestCase* tc, const char* msg,
const char* file, int line);
/** assert_equals checks whether two values are equal. Currently the following
*** data formats are supported:
*** - strings
*** - integer
*** @param expected The expected string value
*** @param actual The actual string value
*** @param tc Pointer to the test case which states this assertion.
*** @param msg Message to be printed if assertion evaluates to false.
*** @param file File in which the assert is given.
*** @param line Line in which the assert is given.
*** @see assert
*/
void assert_equals(int expected, int actual, struct TestCase* tc,
const char* msg, const char* file, int line);
void assert_equals_str(const char* expected, char* actual, struct TestCase* tc,
const char* msg, const char* file, int line);
void assert_equals_f(double expected, double actual, double tolerance, struct TestCase* tc,
const char* msg, const char* file, int line);
/** @return The total number of test cases added to the test.
*/
int get_test_count();
/** add_test creates a new test case and adds the a test function to
*** this test case.
*** @param test_function Pointer to the test function to be added
*** to the newly created test case.
*** @param test_case_name Name which should be assigned to the newly
*** created test case.
*/
bool add_test(void (*test_function)(struct TestCase *tc), const char *test_case_name);
void run_tests();
#define TEST(testname) void testname(struct TestCase *tc)
#define MSG(format, ...) format_msg(format, ##__VA_ARGS__)
#define ASSERT_TRUE(condition, msg) assert_true(condition, tc, msg, __FILE__, __LINE__)
#define ASSERT_FALSE(condition, msg) assert_false(condition, tc, msg, __FILE__, __LINE__)
#define ASSERT_EQUALS(expected, actual) assert_equals(expected, actual, tc, "", __FILE__, __LINE__)
#define ASSERT_EQUALS_STR(expected, actual) assert_equals_str(expected, actual, tc, "", __FILE__, __LINE__)
#define ASSERT_EQUALS_TOLERANCE(expected, actual, tolerance) assert_equals_f(expected, actual, tolerance, tc, "", __FILE__, __LINE__)
#define ADD_TEST(testfunction) add_test(testfunction, #testfunction)
#endif
/*----------------------------------------------------------
* HTBLA-Leonding
* ---------------------------------------------------------
* Title: shortcut
* Author: P. Bauer
* Date: November 03, 2010
* ----------------------------------------------------------
* Description:
* A simple unit testing frame work for C.
* ----------------------------------------------------------
*/
#ifndef ___SHORTCUT_H
#define ___SHORTCUT_H
#include <stdbool.h>
/** TestCase is the struct to define one test case. A test case can
*** be added to a test. If the test is run all added test cases are
*** run and the result of the run of each test case is checked automatically.
*/
struct TestCase {
const char *name;
/** true if the test passed, false otherwise. */
bool success;
/** The test function which is executed by the test framework. */
void (*test_function)(struct TestCase *tc);
};
/**
*** @return Version of shortcut as string
***/
const char* version();
/**
*** @return The fromated string as generated using sprintf(format, ...)
***/
char* format_msg(char* format, ...);
/** assert_true checks, whether a boolean expression passed is true or false.
*** in case it is false the test case stating the assertion is marked
*** as failed and msg is printed.
*** @param bool_expr Expression which is evaluated.
*** @param tc Pointer to the test case which states this assertion.
*** @param msg Message to be printed if assertion evaluates to false.
*** @param file File in which the assert is given.
*** @param line Line in which the assert is given.
*/
void assert_true(bool bool_expr, struct TestCase *tc, const char *msg,
const char* file, int line);
/** assert_false does the same as assert() but the boolean expression
*** has to evaluate to false. If it evaluates to true the assertion
*** fails.
*** @see assert
*/
void assert_false(bool bool_expr, struct TestCase* tc, const char* msg,
const char* file, int line);
/** assert_equals checks whether two values are equal. Currently the following
*** data formats are supported:
*** - strings
*** - integer
*** @param expected The expected string value
*** @param actual The actual string value
*** @param tc Pointer to the test case which states this assertion.
*** @param msg Message to be printed if assertion evaluates to false.
*** @param file File in which the assert is given.
*** @param line Line in which the assert is given.
*** @see assert
*/
void assert_equals(int expected, int actual, struct TestCase* tc,
const char* msg, const char* file, int line);
void assert_equals_str(const char* expected, char* actual, struct TestCase* tc,
const char* msg, const char* file, int line);
void assert_equals_f(double expected, double actual, double tolerance, struct TestCase* tc,
const char* msg, const char* file, int line);
/** @return The total number of test cases added to the test.
*/
int get_test_count();
/** add_test creates a new test case and adds the a test function to
*** this test case.
*** @param test_function Pointer to the test function to be added
*** to the newly created test case.
*** @param test_case_name Name which should be assigned to the newly
*** created test case.
*/
bool add_test(void (*test_function)(struct TestCase *tc), const char *test_case_name);
void run_tests();
#define TEST(testname) void testname(struct TestCase *tc)
#define MSG(format, ...) format_msg(format, ##__VA_ARGS__)
#define ASSERT_TRUE(condition, msg) assert_true(condition, tc, msg, __FILE__, __LINE__)
#define ASSERT_FALSE(condition, msg) assert_false(condition, tc, msg, __FILE__, __LINE__)
#define ASSERT_EQUALS(expected, actual) assert_equals(expected, actual, tc, "", __FILE__, __LINE__)
#define ASSERT_EQUALS_STR(expected, actual) assert_equals_str(expected, actual, tc, "", __FILE__, __LINE__)
#define ASSERT_EQUALS_TOLERANCE(expected, actual, tolerance) assert_equals_f(expected, actual, tolerance, tc, "", __FILE__, __LINE__)
#define ADD_TEST(testfunction) add_test(testfunction, #testfunction)
#endif

View file

@ -1,26 +1,26 @@
/*----------------------------------------------------------
* HTBLA-Leonding
* ---------------------------------------------------------
* Author: S. Schraml
* ----------------------------------------------------------
* Description:
* Executes all unit tests of Roman Number.
* ----------------------------------------------------------
*/
#include "shortcut.h"
#include "test_roman_number.h"
int main(int argc, char *argv[])
{
ADD_TEST(test_create_with_valid_number);
ADD_TEST(test_create_with_invalid_number);
ADD_TEST(test_create_with_null_string);
ADD_TEST(test_get_valid_value);
ADD_TEST(test_get_value_from_invalid_number);
ADD_TEST(test_calc_roman_gcd);
ADD_TEST(test_int_gdc);
run_tests();
return 0;
}
/*----------------------------------------------------------
* HTBLA-Leonding
* ---------------------------------------------------------
* Author: S. Schraml
* ----------------------------------------------------------
* Description:
* Executes all unit tests of Roman Number.
* ----------------------------------------------------------
*/
#include "shortcut.h"
#include "test_roman_number.h"
int main(int argc, char *argv[])
{
ADD_TEST(test_create_with_valid_number);
ADD_TEST(test_create_with_invalid_number);
ADD_TEST(test_create_with_null_string);
ADD_TEST(test_get_valid_value);
ADD_TEST(test_get_value_from_invalid_number);
ADD_TEST(test_calc_roman_gcd);
ADD_TEST(test_int_gdc);
run_tests();
return 0;
}

View file

@ -1,89 +1,89 @@
/*----------------------------------------------------------
* HTBLA-Leonding
* ---------------------------------------------------------
* Author: S. Schraml
* ----------------------------------------------------------
* Description:
* Test functions for Roman Number.
* ----------------------------------------------------------
*/
#include "test_roman_number.h"
#include "roman_number.h"
#include <stdio.h>
#include <string.h>
#include "shortcut.h"
char* number_strs[] = {"MDCCCCLXXXIIII", "CMXLIXIV", "V", "", "CXI", "CCLIX"};
int number_vals[] = {1984, 953, 5, 0, 111, 259};
int number_cnt = sizeof(number_vals) / sizeof(number_vals[0]);
struct Tuple {
int x;
int y;
int exp_res;
};
static struct Tuple gdc_values[] = {
{111, 259, 37},
{ 12, 9, 3},
{ 23, 92, 23},
{527, 899, 31},
{ 42, 42, 42},
{ 83, 97, 1},
};
static int gdc_value_cnt = sizeof(gdc_values) / sizeof(gdc_values[0]);
TEST(test_create_with_valid_number) {
for(int i = 0; i < number_cnt; i++) {
RomanNumber result = rn_create(number_strs[i]);
ASSERT_TRUE(rn_is_valid(result), MSG("Expected that string '%s' is be a valid number", number_strs[i]));
}
}
TEST(test_create_with_invalid_number) {
char* number = "MCDR";
RomanNumber result = rn_create(number);
ASSERT_TRUE(!rn_is_valid(result), MSG("Expected that string '%s' is not be a valid number", number));
}
TEST(test_create_with_null_string) {
RomanNumber result = rn_create(0);
ASSERT_TRUE(!rn_is_valid(result), MSG("Expected that NULL (%d) string is not a valid number", 0));
}
TEST(test_get_valid_value) {
for(int i = 0; i < number_cnt; i++) {
RomanNumber result = rn_create(number_strs[i]);
int value = rn_get_value(result);
ASSERT_TRUE(value == number_vals[i], MSG("Expected that string '%s' is converted to %d but retrieved %d", number_strs[i], number_vals[i], value));
}
}
TEST(test_get_value_from_invalid_number) {
char* number = "MCDR";
RomanNumber result = rn_create(number);
int value = rn_get_value(result);
ASSERT_TRUE(value < 0, MSG("Expected that value of string '%s' is less than 0, but got %d", number, value));
}
TEST(test_calc_roman_gcd) {
int exp_res = 37;
RomanNumber x = rn_create(number_strs[4]);
RomanNumber y = rn_create(number_strs[5]);
RomanNumber result = rn_gcd(x, y);
ASSERT_TRUE(rn_is_valid(result), MSG("Expected that result (%d) of GCD is a valid roman number", exp_res));
int value = rn_get_value(result);
ASSERT_TRUE(value == exp_res, MSG("Expected that result of GCD for strings '%s' and '%s' is '%d', but got '%d'", number_strs[4], number_strs[5], exp_res, value));
}
TEST(test_int_gdc) {
for(int i = 0; i < gdc_value_cnt; i++) {
int act_res = int_gcd(gdc_values[i].x, gdc_values[i].y);
ASSERT_TRUE(act_res == gdc_values[i].exp_res, MSG("Expected that GDC of %d and %d is %d, but got %d",
gdc_values[i].x, gdc_values[i].y, gdc_values[i].exp_res, act_res));
}
}
/*----------------------------------------------------------
* HTBLA-Leonding
* ---------------------------------------------------------
* Author: S. Schraml
* ----------------------------------------------------------
* Description:
* Test functions for Roman Number.
* ----------------------------------------------------------
*/
#include "test_roman_number.h"
#include "roman_number.h"
#include <stdio.h>
#include <string.h>
#include "shortcut.h"
char* number_strs[] = {"MDCCCCLXXXIIII", "CMXLIXIV", "V", "", "CXI", "CCLIX"};
int number_vals[] = {1984, 953, 5, 0, 111, 259};
int number_cnt = sizeof(number_vals) / sizeof(number_vals[0]);
struct Tuple {
int x;
int y;
int exp_res;
};
static struct Tuple gdc_values[] = {
{111, 259, 37},
{ 12, 9, 3},
{ 23, 92, 23},
{527, 899, 31},
{ 42, 42, 42},
{ 83, 97, 1},
};
static int gdc_value_cnt = sizeof(gdc_values) / sizeof(gdc_values[0]);
TEST(test_create_with_valid_number) {
for(int i = 0; i < number_cnt; i++) {
RomanNumber result = rn_create(number_strs[i]);
ASSERT_TRUE(rn_is_valid(result), MSG("Expected that string '%s' is be a valid number", number_strs[i]));
}
}
TEST(test_create_with_invalid_number) {
char* number = "MCDR";
RomanNumber result = rn_create(number);
ASSERT_TRUE(!rn_is_valid(result), MSG("Expected that string '%s' is not be a valid number", number));
}
TEST(test_create_with_null_string) {
RomanNumber result = rn_create(0);
ASSERT_TRUE(!rn_is_valid(result), MSG("Expected that NULL (%d) string is not a valid number", 0));
}
TEST(test_get_valid_value) {
for(int i = 0; i < number_cnt; i++) {
RomanNumber result = rn_create(number_strs[i]);
int value = rn_get_value(result);
ASSERT_TRUE(value == number_vals[i], MSG("Expected that string '%s' is converted to %d but retrieved %d", number_strs[i], number_vals[i], value));
}
}
TEST(test_get_value_from_invalid_number) {
char* number = "MCDR";
RomanNumber result = rn_create(number);
int value = rn_get_value(result);
ASSERT_TRUE(value < 0, MSG("Expected that value of string '%s' is less than 0, but got %d", number, value));
}
TEST(test_calc_roman_gcd) {
int exp_res = 37;
RomanNumber x = rn_create(number_strs[4]);
RomanNumber y = rn_create(number_strs[5]);
RomanNumber result = rn_gcd(x, y);
ASSERT_TRUE(rn_is_valid(result), MSG("Expected that result (%d) of GCD is a valid roman number", exp_res));
int value = rn_get_value(result);
ASSERT_TRUE(value == exp_res, MSG("Expected that result of GCD for strings '%s' and '%s' is '%d', but got '%d'", number_strs[4], number_strs[5], exp_res, value));
}
TEST(test_int_gdc) {
for(int i = 0; i < gdc_value_cnt; i++) {
int act_res = int_gcd(gdc_values[i].x, gdc_values[i].y);
ASSERT_TRUE(act_res == gdc_values[i].exp_res, MSG("Expected that GDC of %d and %d is %d, but got %d",
gdc_values[i].x, gdc_values[i].y, gdc_values[i].exp_res, act_res));
}
}

View file

@ -1,23 +1,23 @@
/*----------------------------------------------------------
* HTBLA-Leonding
* ---------------------------------------------------------
* Author: S. Schraml
* ----------------------------------------------------------
* Description:
* Test functions for Roman Number.
* ----------------------------------------------------------
*/
#ifndef ___TEST_ROMAN_NUMBER_H
#define ___TEST_ROMAN_NUMBER_H
#include "shortcut.h"
TEST(test_create_with_valid_number);
TEST(test_create_with_invalid_number);
TEST(test_create_with_null_string);
TEST(test_get_valid_value);
TEST(test_get_value_from_invalid_number);
TEST(test_calc_roman_gcd);
TEST(test_int_gdc);
#endif
/*----------------------------------------------------------
* HTBLA-Leonding
* ---------------------------------------------------------
* Author: S. Schraml
* ----------------------------------------------------------
* Description:
* Test functions for Roman Number.
* ----------------------------------------------------------
*/
#ifndef ___TEST_ROMAN_NUMBER_H
#define ___TEST_ROMAN_NUMBER_H
#include "shortcut.h"
TEST(test_create_with_valid_number);
TEST(test_create_with_invalid_number);
TEST(test_create_with_null_string);
TEST(test_get_valid_value);
TEST(test_get_value_from_invalid_number);
TEST(test_calc_roman_gcd);
TEST(test_int_gdc);
#endif