diff --git a/bintree.c b/bintree.c index 5cf82a9..a07d6e0 100644 --- a/bintree.c +++ b/bintree.c @@ -1,36 +1,119 @@ -#include -#include "stack.h" #include "bintree.h" +#include "stack.h" +#include -//TODO: binären Suchbaum implementieren +// TODO: binären Suchbaum implementieren /* * `addToTree`: fügt ein neues Element in den Baum ein (rekursiv), - * `clearTree`: gibt den gesamten Baum frei (rekursiv), - * `treeSize`: zählt die Knoten im Baum (rekursiv), - * `nextTreeData`: Traversierung mit Hilfe des zuvor implementierten Stacks. */ + * `clearTree`: gibt den gesamten Baum frei (rekursiv), + * `treeSize`: zählt die Knoten im Baum (rekursiv), + * `nextTreeData`: Traversierung mit Hilfe des zuvor implementierten Stacks. */ -// Adds a copy of data's pointer destination to the tree using compareFct for ordering. Accepts duplicates -// if isDuplicate is NULL, otherwise ignores duplicates and sets isDuplicate to 1 (or to 0 if a new entry is added). -TreeNode *addToTree(TreeNode *root, const void *data, size_t dataSize, CompareFctType compareFct, int *isDuplicate) -{ +// typedef int (*CompareFctType)(const void *arg1, const void *arg2); +// Adds a copy of data's pointer destination to the tree using compareFct for +// ordering. Accepts duplicates if isDuplicate is NULL, otherwise ignores +// duplicates and sets isDuplicate to 1 (or to 0 if a new entry is added). +void copyData(void *dest, const void *src, size_t size) { + unsigned char *d = dest; + const unsigned char *s = src; + for (size_t i = 0; i < size; i++) { + d[i] = s[i]; + } } -// Iterates over the tree given by root. Follows the usage of strtok. If tree is NULL, the next entry of the last tree given is returned in ordering direction. -// Use your implementation of a stack to organize the iterator. Push the root node and all left nodes first. On returning the next element, -// push the top node and push all its left nodes. -void *nextTreeData(TreeNode *root) -{ +TreeNode *addToTree(TreeNode *root, const void *data, size_t dataSize, + CompareFctType compareFct, int *isDuplicate) { + // isDuplicate initialisieren (auf 0 setzen) + if (isDuplicate) { + *isDuplicate = 0; + } + + // leerer Baum + if (root == NULL) { + TreeNode *node = malloc(sizeof(TreeNode)); + node->data = malloc(dataSize); + copyData(node->data, data, dataSize); + node->left = NULL; + node->right = NULL; + return node; + } + + // mit compareFct <0 links >0 rechts =0 Duplikat + int cmp = compareFct(data, root->data); + + if (cmp < 0) { + root->left = addToTree(root->left, data, dataSize, compareFct, isDuplicate); + } else if (cmp > 0) { + root->right = + addToTree(root->right, data, dataSize, compareFct, isDuplicate); + } else { + // isDuplicate auf 1 setzen + if (isDuplicate) { + *isDuplicate = 1; + } + } + return root; +} + +// Iterates over the tree given by root. Follows the usage of strtok. If tree is +// NULL, the next entry of the last tree given is returned in ordering +// direction. Use your implementation of a stack to organize the iterator. Push +// the root node and all left nodes first. On returning the next element, push +// the top node and push all its left nodes. +void *nextTreeData(TreeNode *root) { + static StackNode *stack = NULL; + + // Neue Iteration starten + if (root != NULL) { + clearStack(&stack); + + TreeNode *curr = root; + while (curr != NULL) { + StackNode *oldStack = stack; + StackNode *newStack = push(stack, curr); + if (newStack == oldStack) + return NULL; // push fehlgeschlagen + stack = newStack; + curr = curr->left; + } + } + if (stack == NULL) + return NULL; // alles durchlaufen + + // Oberstes Element abrufen + TreeNode *node = (TreeNode *)top(stack); + stack = pop(stack); + + // Rechten Teilbaum pushen + TreeNode *curr = node->right; + while (curr != NULL) { + StackNode *oldStack = stack; + StackNode *newStack = push(stack, curr); + if (newStack == oldStack) + return NULL; // push fehlgeschlagen + stack = newStack; + curr = curr->left; + } + return node->data; } // Releases all memory resources (including data copies). -void clearTree(TreeNode *root) -{ +void clearTree(TreeNode *root) { + if (root == NULL) + return; + clearTree(root->left); + clearTree(root->right); + + free(root->data); + free(root); } // Returns the number of entries in the tree given by root. -unsigned int treeSize(const TreeNode *root) -{ +unsigned int treeSize(const TreeNode *root) { + if (root == NULL) + return 0; + return 1 + treeSize(root->left) + treeSize(root->right); } \ No newline at end of file diff --git a/bintree.h b/bintree.h index 25e16b2..1ced26b 100644 --- a/bintree.h +++ b/bintree.h @@ -5,19 +5,24 @@ typedef int (*CompareFctType)(const void *arg1, const void *arg2); -typedef struct node -{ - void *data; - struct node *left; - struct node *right; +typedef struct node { + void *data; + struct node *left; + struct node *right; } TreeNode; -// Adds a copy of data's pointer destination to the tree using compareFct for ordering. Accepts duplicates -// if isDuplicate is NULL, otherwise ignores duplicates and sets isDuplicate to 1 (or to 0 if a new entry is added). -TreeNode *addToTree(TreeNode *root, const void *data, size_t dataSize, CompareFctType compareFct, int *isDuplicate); -// Iterates over the tree given by root. Follows the usage of strtok. If tree is NULL, the next entry of the last tree given is returned in ordering direction. -// Use your implementation of a stack to organize the iterator. Push the root node and all left nodes first. On returning the next element, -// push the top node and push all its left nodes. +void copyData(void *dest, const void *src, size_t size); + +// Adds a copy of data's pointer destination to the tree using compareFct for +// ordering. Accepts duplicates if isDuplicate is NULL, otherwise ignores +// duplicates and sets isDuplicate to 1 (or to 0 if a new entry is added). +TreeNode *addToTree(TreeNode *root, const void *data, size_t dataSize, + CompareFctType compareFct, int *isDuplicate); +// Iterates over the tree given by root. Follows the usage of strtok. If tree is +// NULL, the next entry of the last tree given is returned in ordering +// direction. Use your implementation of a stack to organize the iterator. Push +// the root node and all left nodes first. On returning the next element, push +// the top node and push all its left nodes. void *nextTreeData(TreeNode *root); // Releases all memory resources (including data copies). void clearTree(TreeNode *root); diff --git a/highscores.txt b/highscores.txt index ca5950d..2924551 100644 --- a/highscores.txt +++ b/highscores.txt @@ -1,2 +1,10 @@ +Kristin;9944 +Kristin;7947 +Kristin;6962 +Kristin;5987 +Kristin;5975 krisp;4986 +krisp;4985 +Kristin;4972 player1;3999 +Kristin;3992 diff --git a/makefile b/makefile index 20256ce..a0cba60 100644 --- a/makefile +++ b/makefile @@ -25,28 +25,49 @@ doble_initial: # -------------------------- # Selbst implementiertes Programm bauen # -------------------------- +# alle Objektdateien program_obj_files = stack.o bintree.o numbers.o timer.o highscore.o - +# alle ausführbaren Dateien zu ausführbarem Programm linken doble : main.o $(program_obj_files) $(CC) $(FLAGS) $^ -o doble - +# Regel Kompilieren allgemein $(program_obj_files): %.o: %.c $(CC) -c $(FLAGS) $^ -o $@ # -------------------------- # Unit Tests # -------------------------- -unitTests: -TEST_BIN = runTests -unitTests: stack.o test_stack.o - $(CC) $(FLAGS) $(ASAN_FLAGS) -I$(unityfolder) -o $(TEST_BIN) stack.o test_stack.o $(unityfolder)/unity.c +STACK_TEST_BIN = runStackTests +NUMBERS_TEST_BIN = runNumbersTests +BINARY_TEST_BIN = runBinaryTests + +# --- Stack Tests --- +stackTests: stack.o test_stack.o + $(CC) $(FLAGS) -I$(unityfolder) -o $(STACK_TEST_BIN) stack.o test_stack.o $(unityfolder)/unity.c test_stack.o: test_stack.c $(CC) $(FLAGS) -I$(unityfolder) -c test_stack.c -o test_stack.o + +# --- Numbers Tests --- +numbersTests: numbers.o bintree.o stack.o test_numbers.o + $(CC) $(FLAGS) -I$(unityfolder) -o $(NUMBERS_TEST_BIN) numbers.o bintree.o stack.o test_numbers.o $(unityfolder)/unity.c + +test_numbers.o: test_numbers.c + $(CC) $(FLAGS) -I$(unityfolder) -c test_numbers.c -o test_numbers.o + + +# --- Binary Tree Tests --- +binaryTests: bintree.o stack.o test_binary.o + $(CC) $(FLAGS) -I$(unityfolder) -o $(BINARY_TEST_BIN) bintree.o stack.o test_binary.o $(unityfolder)/unity.c + +test_binary.o: test_binary.c + $(CC) $(FLAGS) -I$(unityfolder) -c test_binary.c -o test_binary.o + + # -------------------------- # Clean # -------------------------- clean: - rm -f *.o doble \ No newline at end of file + rm -f *.o doble $(STACK_TEST_BIN) $(NUMBERS_TEST_BIN) $(BINARY_TEST_BIN) \ No newline at end of file diff --git a/numbers.c b/numbers.c index f59d9a2..414a4a4 100644 --- a/numbers.c +++ b/numbers.c @@ -1,26 +1,91 @@ -#include -#include -#include -#include #include "numbers.h" #include "bintree.h" +#include +#include +#include +#include -//TODO: getDuplicate und createNumbers implementieren -/* * * Erzeugen eines Arrays mit der vom Nutzer eingegebenen Anzahl an Zufallszahlen. - * Sicherstellen, dass beim Befüllen keine Duplikate entstehen. - * Duplizieren eines zufälligen Eintrags im Array. - * in `getDuplicate()`: Sortieren des Arrays und Erkennen der doppelten Zahl durch Vergleich benachbarter Elemente. */ - -// Returns len random numbers between 1 and 2x len in random order which are all different, except for two entries. -// Returns NULL on errors. Use your implementation of the binary search tree to check for possible duplicates while -// creating random numbers. -unsigned int *createNumbers(unsigned int len) -{ +int compareUnsignedInt(const void *a, const void *b) { + unsigned int x = *(unsigned int *)a; + unsigned int y = *(unsigned int *)b; + if (x < y) + return -1; + if (x > y) + return 1; + return 0; } -// Returns only the only number in numbers which is present twice. Returns zero on errors. -unsigned int getDuplicate(const unsigned int numbers[], unsigned int len) -{ +// TODO: getDuplicate und createNumbers implementieren +/**Erzeugen eines Arrays mit der vom Nutzer eingegebenen Anzahl an + * Zufallszahlen. Sicherstellen, dass beim Befüllen keine Duplikate entstehen. + * Duplizieren eines zufälligen Eintrags im Array. + * in `getDuplicate()`: Sortieren des Arrays und Erkennen der doppelten Zahl + * durch Vergleich benachbarter Elemente. */ -} \ No newline at end of file +// Returns len random numbers between 1 and 2x len in random order which are all +// different, except for two entries. Returns NULL on errors. Use your +// implementation of the binary search tree to check for possible duplicates +// while creating random numbers. +unsigned int *createNumbers(unsigned int len) { + if (len < 2) + return NULL; + + unsigned int *arr = malloc(sizeof(unsigned int) * len); + if (!arr) + return NULL; + + TreeNode *root = NULL; + srand((unsigned int)time(NULL)); + + for (unsigned int i = 0; i < len - 1; i++) { + unsigned int num; + int isDuplicate; + + do { + num = (rand() % (2 * len)) + 1; + isDuplicate = 0; + + root = addToTree(root, &num, sizeof(unsigned int), compareUnsignedInt, + &isDuplicate); + + } while (isDuplicate); // nur akzeptieren, wenn eindeutig + + arr[i] = num; + } + + // Jetzt gezielt EIN Duplikat erzeugen + unsigned int duplicateIndex = rand() % (len - 1); + arr[len - 1] = arr[duplicateIndex]; + + clearTree(root); + return arr; +} + +// Returns only the only number in numbers which is present twice. Returns zero +// on errors. +unsigned int getDuplicate(const unsigned int numbers[], unsigned int len) { + if (!numbers || len < 2) + return 0; + + unsigned int *copy = malloc(sizeof(unsigned int) * len); + if (!copy) + return 0; + + memcpy(copy, numbers, sizeof(unsigned int) * len); + + // Sortierung + qsort(copy, len, sizeof(unsigned int), compareUnsignedInt); + + // Duplikat finden: zwei gleiche nebeneinander + unsigned int duplicate = 0; + for (unsigned int i = 0; i < len - 1; i++) { + if (copy[i] == copy[i + 1]) { + duplicate = copy[i]; + break; + } + } + + free(copy); + return duplicate; +} diff --git a/stack.c b/stack.c index 5cd0d1a..f2b1d23 100644 --- a/stack.c +++ b/stack.c @@ -6,6 +6,7 @@ void *data; struct StackNode *next; + struct StackNode *prev; } StackNode;*/ @@ -15,71 +16,85 @@ * `top`: liefert das oberste Element zurück, * `clearStack`: gibt den gesamten Speicher frei. */ -StackNode *createNode(void *data) -{ +// [A] -> [B] -> [C] -> NULL +// stack -> stack.next - StackNode *node = - malloc(sizeof(StackNode)); // Speicher reservieren, Speicherplatz für das - // struct StackNode +// Funktion zum erstellen neuer nodes +StackNode *createNode(void *data) { + // Speicher reservieren + StackNode *node = malloc(sizeof(StackNode)); + // Speicher konnte nicht reserviert werden + if (node == NULL) + return NULL; - if (node == NULL) - return NULL; // Speicher konnte nicht reserviert werden + node->data = data; + node->next = NULL; + node->prev = NULL; - node->data = data; // Zeiger auf data neuer node - node->next = NULL; // nächster Zeiger ist NULL, Ende der Liste - - return node; // pointer auf den neuen Knoten zurückgeben + return node; } // Pushes data as pointer onto the stack. -StackNode *push(StackNode *stack, void *data) -{ - StackNode *newNode = createNode(data); // Speicher für neuen Knoten - // reservieren +StackNode *push(StackNode *stack, void *data) { - if (newNode == NULL) - { // wenn Speicher nicht reserviert werden konnte, wird - // stack unverändert zurückgegeben - return stack; - } + StackNode *newNode = createNode(data); - newNode->next = stack; // pointer verschieben + // Fehler beim Reservieren des Speichers, stack wird unverändert zurückgegeben + if (newNode == NULL) { + return stack; + } - return newNode; // Zeiger auf neuen Speicherbereich zurückgeben + // der aktuelle Kopf wird der nächste Node + newNode->next = stack; + + // bisheriger Kopf bekommt Pointer auf oberstes Element + if (stack != NULL) { + stack->prev = newNode; + } + + return newNode; // neuer Kopf wird zurückgegeben } -// Deletes the top element of the stack (latest added element) and releases its memory. (Pointer to data has to be -// freed by caller.) -StackNode *pop(StackNode *stack) -{ - if (stack == NULL) - return NULL; +// Deletes the top element of the stack (latest added element) and releases its +// memory. (Pointer to data has to be freed by caller.) +StackNode *pop(StackNode *stack) { - StackNode *nextNode = stack->next; + // Stack ohne Elemente + if (stack == NULL) + return NULL; + + // Element unter Kopf wird als nextNode gespeichert + StackNode *nextNode = stack->next; + if (nextNode != NULL) { + nextNode->prev = NULL; // der Zeiger zum Kopf wird auf NULL gesetzt + } free(stack); - stack = NULL; + stack = NULL; // Speicher des Kopfes freigeben - return nextNode; + return nextNode; // neuen Kopf zurückgeben } // Returns the data of the top element. -void *top(StackNode *stack) { return stack != NULL ? stack->data : NULL; } +void *top(StackNode *stack) { + // wenn stack leer ist, wird NULL zurückgegeben + // Zeiger auf Daten des obersten Elements + return stack ? stack->data : NULL; +} // Clears stack and releases all memory. -void clearStack(StackNode **stack) -{ - while (*stack != NULL) - { +void clearStack(StackNode **stack) { // Zeiger auf den Zeiger auf den Stackkopf + // verändert den Zeiger selbst, mit *stack lokale Kopie + // im Aufruf &stack verwenden + while (*stack != NULL) { - StackNode *next = (*stack)->next; - free(*stack); - (*stack)->data = NULL; - (*stack)->next = NULL; - (*stack)->prev = NULL; - (*stack) = next; + (*stack)->prev = NULL; // späteren Pointerzugriff verhindern + StackNode *next = (*stack)->next; // nächstes Element speichern - } - + (*stack)->next = NULL; // späteren Pointerzugriff verhindern + + free(*stack); // aktuelles Element freigeben + *stack = next; // Zeiger auf nächsten Knoten setzen + } } \ No newline at end of file diff --git a/stack.h b/stack.h index 8119b2c..bbb3fce 100644 --- a/stack.h +++ b/stack.h @@ -19,16 +19,6 @@ typedef struct StackNode { StackNode *createNode(void *data); -typedef struct StackNode { - - void *data; - struct StackNode *next; - struct StackNode *prev; - -} StackNode; - -StackNode *createNode(void *data); - // Pushes data as pointer onto the stack. StackNode *push(StackNode *stack, void *data); diff --git a/test_binary.c b/test_binary.c new file mode 100644 index 0000000..a0d9cbc --- /dev/null +++ b/test_binary.c @@ -0,0 +1,105 @@ +#include "unity.h" +#include +#include +#include + +#include "bintree.h" +int compareUnsignedInt(const void *a, const void *b) { + unsigned int x = *(unsigned int *)a; + unsigned int y = *(unsigned int *)b; + + if (x < y) + return -1; + if (x > y) + return 1; + return 0; +} + +TreeNode *root = NULL; + +void setUp(void) { + root = NULL; // vor jedem Test leeren +} + +void tearDown(void) { clearTree(root); } + +// Test, ob addToTree Knoten korrekt hinzufügt +void test_addToTree_basic(void) { + int isDup; + unsigned int val = 10; + root = addToTree(root, &val, sizeof(val), compareUnsignedInt, &isDup); + TEST_ASSERT_NOT_NULL(root); + TEST_ASSERT_EQUAL_UINT(10, *(unsigned int *)root->data); + TEST_ASSERT_EQUAL_INT(0, isDup); + TEST_ASSERT_EQUAL_UINT(1, treeSize(root)); +} + +// Test, dass Duplikate erkannt werden +void test_addToTree_duplicate(void) { + int isDup; + unsigned int val1 = 10, val2 = 10; + root = addToTree(root, &val1, sizeof(val1), compareUnsignedInt, &isDup); + TEST_ASSERT_EQUAL_INT(0, isDup); + root = addToTree(root, &val2, sizeof(val2), compareUnsignedInt, &isDup); + TEST_ASSERT_EQUAL_INT(1, isDup); + TEST_ASSERT_EQUAL_UINT(1, treeSize(root)); // Duplikate nicht hinzufügen +} + +// Test nextTreeData Traversierung +void test_nextTreeData_in_order(void) { + unsigned int values[] = {20, 10, 30}; + int isDup; + for (int i = 0; i < 3; i++) { + root = addToTree(root, &values[i], sizeof(values[i]), compareUnsignedInt, + &isDup); + } + + unsigned int expected[] = {10, 20, 30}; + int idx = 0; + void *data; + + // **Neue Iteration starten** + data = nextTreeData(root); + while (data != NULL) { + TEST_ASSERT_EQUAL_UINT(expected[idx], *(unsigned int *)data); + idx++; + data = nextTreeData(NULL); // weitere Elemente abrufen + } + + TEST_ASSERT_EQUAL_INT(3, idx); // alle 3 Knoten besucht +} + +// Test clearTree gibt Speicher frei +void test_clearTree(void) { + unsigned int val = 42; + int isDup; + root = addToTree(root, &val, sizeof(val), compareUnsignedInt, &isDup); + clearTree(root); + root = NULL; // clearTree löscht nicht die root-Variable selbst + TEST_ASSERT_NULL(root); +} + +// Test treeSize zählt korrekt +void test_treeSize(void) { + unsigned int vals[] = {10, 20, 5}; + int isDup; + for (int i = 0; i < 3; i++) { + root = + addToTree(root, &vals[i], sizeof(vals[i]), compareUnsignedInt, &isDup); + } + TEST_ASSERT_EQUAL_UINT(3, treeSize(root)); +} + +int main(void) { + UNITY_BEGIN(); + + printf( + "\n------------------------binarytree test------------------------\n\n"); + + RUN_TEST(test_addToTree_basic); + RUN_TEST(test_addToTree_duplicate); + RUN_TEST(test_nextTreeData_in_order); + RUN_TEST(test_clearTree); + RUN_TEST(test_treeSize); + return UNITY_END(); +} \ No newline at end of file diff --git a/test_numbers.c b/test_numbers.c new file mode 100644 index 0000000..8992bb8 --- /dev/null +++ b/test_numbers.c @@ -0,0 +1,61 @@ +#include "unity.h" +#include +#include +#include + +#include "numbers.h" + +#define TEST_ARRAY_LEN 100 + +void test_createNumbers_length(void) { + unsigned int *arr = createNumbers(TEST_ARRAY_LEN); + TEST_ASSERT_NOT_NULL(arr); + free(arr); +} + +void test_createNumbers_single_duplicate(void) { + unsigned int *arr = createNumbers(TEST_ARRAY_LEN); + TEST_ASSERT_NOT_NULL(arr); + + unsigned int duplicate = getDuplicate(arr, TEST_ARRAY_LEN); + TEST_ASSERT_TRUE(duplicate > 0); + + unsigned int count = 0; + for (unsigned int i = 0; i < TEST_ARRAY_LEN; i++) { + if (arr[i] == duplicate) { + count++; + } + } + TEST_ASSERT_EQUAL_UINT(2, count); + + free(arr); +} + +void test_getDuplicate_manual_array(void) { + unsigned int numbers[5] = {10, 20, 30, 40, 20}; + unsigned int dup = getDuplicate(numbers, 5); + TEST_ASSERT_EQUAL_UINT(20, dup); +} + +void test_getDuplicate_invalid_input(void) { + TEST_ASSERT_EQUAL_UINT(0, getDuplicate(NULL, 5)); + unsigned int arr[1] = {42}; + TEST_ASSERT_EQUAL_UINT(0, getDuplicate(arr, 1)); +} + +void setUp(void) {} +void tearDown(void) {} + +int main(void) { + + UNITY_BEGIN(); + + printf("\n------------------------numbers test------------------------\n\n"); + + RUN_TEST(test_createNumbers_length); + RUN_TEST(test_createNumbers_single_duplicate); + RUN_TEST(test_getDuplicate_manual_array); + RUN_TEST(test_getDuplicate_invalid_input); + + return UNITY_END(); +} diff --git a/test_stack.c b/test_stack.c index a9f9914..ee3a6e5 100644 --- a/test_stack.c +++ b/test_stack.c @@ -5,40 +5,124 @@ #include "stack.h" +// StackNode *createNode(void *data) testen void test_createNode(void) { int testInt = 26; + StackNode *testNode = createNode(&testInt); // Adresse des testInts - StackNode *testNode = createNode(&testInt); + TEST_ASSERT_NOT_NULL( + testNode); // Speicher konnte reserviert werden, malloc ist nicht NULL + TEST_ASSERT_EQUAL_PTR(&testInt, testNode->data); // data pointer gesetzt + TEST_ASSERT_NULL(testNode->next); // vorheriger und nächster Eintrag NULL + TEST_ASSERT_NULL(testNode->prev); - TEST_ASSERT_NOT_NULL(testNode); - - TEST_ASSERT_EQUAL_PTR(&testInt, testNode->data); - - TEST_ASSERT_NULL(testNode->next); - - free(testNode); + free(testNode); // Speicher freigeben } -void test_pushDataToStack(void) {} +// StackNode *push(StackNode *stack, void *data) testen +void test_pushDataToStack(void) { -void test_deleteTopElement(void) {} + int testInts[] = {27, 28}; -void test_returnData(void) {} + StackNode *testStack = NULL; // leeren testStack initialisieren + + testStack = + push(testStack, &testInts[0]); // leerer Stack mit Adresse des testInts + + TEST_ASSERT_NOT_NULL(testStack); // im Fehlerfall wird testStack unverändert + // zurückgegeben -> bei Fehler NULL + TEST_ASSERT_EQUAL_PTR(&testInts[0], testStack->data); // data pointer gesetzt + TEST_ASSERT_NULL(testStack->next); // vorheriger und nächster pointer auf NULL + // gesetzt, da es nur einen Knoten gibt + TEST_ASSERT_NULL(testStack->prev); + + // zweiter Push + StackNode *oldHead = testStack; // bisherigen head speichern + testStack = push(testStack, &testInts[1]); + + TEST_ASSERT_NOT_NULL(testStack); + TEST_ASSERT_NOT_EQUAL( + oldHead, + testStack); // bei malloc Fehler wird der head unverändert zurückgegeben + + TEST_ASSERT_EQUAL_PTR(&testInts[0], + oldHead->data); // data pointer wurden richtig gesetzt + TEST_ASSERT_EQUAL_PTR(&testInts[1], testStack->data); + + // richtige Verkettung: NULL <- testStack -> testStack->next -> oldHead -> + // NULL + TEST_ASSERT_EQUAL_PTR(oldHead, testStack->next); + TEST_ASSERT_EQUAL_PTR(testStack, oldHead->prev); + TEST_ASSERT_NULL(testStack->prev); + + // Speicherfreigabe + testStack->next = NULL; // pointer ungültig machen, damit nicht ausversehen + // später aufgerufen + oldHead->prev = NULL; + + free(oldHead); + free(testStack); +} + +void test_deleteTopElement(void) { + + int testInts[] = {10, 20, 30}; + StackNode *stack = NULL; + + for (int i = 0; i < 3; + i++) { // Stack mit drei Elementen, oberestes Element mit data 30 + stack = push(stack, &testInts[i]); + } + + TEST_ASSERT_EQUAL_PTR(&testInts[2], stack->data); // oberstes Element ist 30 + + stack = pop(stack); // oberstes Element löschen + TEST_ASSERT_EQUAL_PTR(&testInts[1], stack->data); + TEST_ASSERT_NULL( + stack->prev); // pointer zum alten head wurde auf NULL gesetzt + + stack = pop(stack); + TEST_ASSERT_EQUAL_PTR(&testInts[0], stack->data); + TEST_ASSERT_NULL(stack->prev); + + stack = pop(stack); // bei leerem Stack wird NULL zurückgegeben + TEST_ASSERT_NULL(stack); +} + +void test_returnData(void) { + + int testInts[] = {10, 20, 30}; + StackNode *stack = NULL; + + for (int i = 0; i < 3; i++) { + stack = push(stack, &testInts[i]); + } + + TEST_ASSERT_EQUAL_PTR(&testInts[2], + top(stack)); // top gibt richtige Adresse zurück + stack = pop(stack); // oberstes Element löschen + TEST_ASSERT_EQUAL_PTR(&testInts[1], top(stack)); + + stack = pop(stack); + TEST_ASSERT_EQUAL_PTR(&testInts[0], top(stack)); + + stack = pop(stack); // bei leerem Stack wird NULL zurückgegeben + TEST_ASSERT_NULL(stack); +} void test_clearStack(void) { - int testInts[] = {1, 2, 3, 4, 5}; - StackNode *testStack = NULL; + StackNode *stack = NULL; for (int i = 0; i < 5; i++) { - - testStack = push(testStack, &testInts[i]); + stack = push(stack, &testInts[i]); } //printf("testints: %d,%d,%d,%d,%d",testInts[0],testInts[1],testInts[2],testInts[3],testInts[4]); - clearStack(&testStack); - TEST_ASSERT_NULL(testStack); + clearStack(&stack); + + TEST_ASSERT_NULL(stack); } void setUp(void) {} @@ -48,13 +132,13 @@ int main(void) { UNITY_BEGIN(); - printf("------------------------stack test------------------------\n"); + printf("\n------------------------stack test------------------------\n\n"); + RUN_TEST(test_createNode); RUN_TEST(test_pushDataToStack); RUN_TEST(test_deleteTopElement); RUN_TEST(test_returnData); RUN_TEST(test_clearStack); - RUN_TEST(test_clearStack); return UNITY_END(); }