diff --git a/Test_bintree.c b/Test_bintree.c new file mode 100644 index 0000000..f38f253 --- /dev/null +++ b/Test_bintree.c @@ -0,0 +1,423 @@ +#include +#include +#include +#include +#include "bintree.h" + +#define GREEN "\033[0;32m" +#define RED "\033[0;31m" +#define RESET "\033[0m" +#define BLUE "\033[0;34m" + +int testsPassed = 0; +int testsFailed = 0; + +void printTestResult(const char *testName, int passed) +{ + if (passed) + { + printf(GREEN "[PASS]" RESET " %s\n", testName); + testsPassed++; + } + else + { + printf(RED "[FAIL]" RESET " %s\n", testName); + testsFailed++; + } +} + +// Vergleichsfunktion für Integers +int compareInt(const void *arg1, const void *arg2) +{ + int val1 = *(const int *)arg1; + int val2 = *(const int *)arg2; + + if (val1 < val2) return -1; + if (val1 > val2) return 1; + return 0; +} + +// Vergleichsfunktion für Strings +int compareString(const void *arg1, const void *arg2) +{ + return strcmp(*(const char **)arg1, *(const char **)arg2); +} + +// Test 1: addToTree mit einem Element +void test_add_single_element() +{ + printf(BLUE "\n--- Test 1: addToTree mit einem Element ---" RESET "\n"); + + TreeNode *root = NULL; + int value = 42; + + root = addToTree(root, &value, sizeof(int), compareInt, NULL); + + printTestResult("Baum wurde erstellt", root != NULL); + printTestResult("Root-Daten sind korrekt", root != NULL && *(int *)root->data == 42); + printTestResult("Root hat keine Kinder", root != NULL && root->left == NULL && root->right == NULL); + + clearTree(root); +} + +// Test 2: addToTree mit mehreren Elementen +void test_add_multiple_elements() +{ + printf(BLUE "\n--- Test 2: addToTree mit mehreren Elementen ---" RESET "\n"); + + TreeNode *root = NULL; + int values[] = {50, 30, 70, 20, 40, 60, 80}; + + for (int i = 0; i < 7; i++) + { + root = addToTree(root, &values[i], sizeof(int), compareInt, NULL); + } + + printTestResult("Baum mit 7 Elementen erstellt", root != NULL); + printTestResult("Root ist 50", *(int *)root->data == 50); + printTestResult("Linkes Kind ist 30", root->left != NULL && *(int *)root->left->data == 30); + printTestResult("Rechtes Kind ist 70", root->right != NULL && *(int *)root->right->data == 70); + + clearTree(root); +} + +// Test 3: addToTree mit Duplikat-Erkennung +void test_duplicate_detection() +{ + printf(BLUE "\n--- Test 3: Duplikat-Erkennung ---" RESET "\n"); + + TreeNode *root = NULL; + int value1 = 42; + int value2 = 17; + int value3 = 42; // Duplikat! + int isDuplicate = 0; + + root = addToTree(root, &value1, sizeof(int), compareInt, &isDuplicate); + printTestResult("Erstes Element: kein Duplikat", isDuplicate == 0); + + isDuplicate = 0; + root = addToTree(root, &value2, sizeof(int), compareInt, &isDuplicate); + printTestResult("Zweites Element: kein Duplikat", isDuplicate == 0); + + isDuplicate = 0; + root = addToTree(root, &value3, sizeof(int), compareInt, &isDuplicate); + printTestResult("Drittes Element: Duplikat erkannt", isDuplicate == 1); + + clearTree(root); +} + +// Test 4: addToTree mit Duplikaten erlaubt +void test_allow_duplicates() +{ + printf(BLUE "\n--- Test 4: Duplikate erlauben (isDuplicate = NULL) ---" RESET "\n"); + + TreeNode *root = NULL; + int values[] = {50, 30, 50, 30}; // Mit Duplikaten + + for (int i = 0; i < 4; i++) + { + root = addToTree(root, &values[i], sizeof(int), compareInt, NULL); + } + + unsigned int size = treeSize(root); + printTestResult("Alle 4 Elemente wurden eingefuegt (inkl. Duplikate)", size == 4); + + clearTree(root); +} + +// Test 5: treeSize +void test_tree_size() +{ + printf(BLUE "\n--- Test 5: treeSize ---" RESET "\n"); + + TreeNode *root = NULL; + + printTestResult("Leerer Baum hat Groesse 0", treeSize(root) == 0); + + int values[] = {50, 30, 70, 20, 40}; + + for (int i = 0; i < 5; i++) + { + root = addToTree(root, &values[i], sizeof(int), compareInt, NULL); + } + + printTestResult("Baum mit 5 Elementen hat Groesse 5", treeSize(root) == 5); + + // Füge mehr hinzu + int value6 = 60; + int value7 = 80; + root = addToTree(root, &value6, sizeof(int), compareInt, NULL); + root = addToTree(root, &value7, sizeof(int), compareInt, NULL); + + printTestResult("Nach Hinzufuegen von 2 Elementen: Groesse 7", treeSize(root) == 7); + + clearTree(root); +} + +// Test 6: nextTreeData In-Order Traversierung +void test_next_tree_data() +{ + printf(BLUE "\n--- Test 6: nextTreeData (In-Order Traversierung) ---" RESET "\n"); + + TreeNode *root = NULL; + int values[] = {50, 30, 70, 20, 40, 60, 80}; + + for (int i = 0; i < 7; i++) + { + root = addToTree(root, &values[i], sizeof(int), compareInt, NULL); + } + + // Erwartete Reihenfolge: 20, 30, 40, 50, 60, 70, 80 (sortiert!) + int expected[] = {20, 30, 40, 50, 60, 70, 80}; + int index = 0; + int allCorrect = 1; + + int *data = (int *)nextTreeData(root); + while (data != NULL) + { + if (index >= 7 || *data != expected[index]) + { + allCorrect = 0; + printf(" Fehler bei Index %d: Erwartet %d, bekommen %d\n", index, expected[index], *data); + } + index++; + data = (int *)nextTreeData(NULL); + } + + printTestResult("In-Order Traversierung gibt sortierte Reihenfolge", allCorrect && index == 7); + + clearTree(root); +} + +// Test 7: nextTreeData mit einzelnem Element +void test_next_tree_data_single() +{ + printf(BLUE "\n--- Test 7: nextTreeData mit einem Element ---" RESET "\n"); + + TreeNode *root = NULL; + int value = 42; + + root = addToTree(root, &value, sizeof(int), compareInt, NULL); + + int *data = (int *)nextTreeData(root); + int correct = (data != NULL && *data == 42); + + data = (int *)nextTreeData(NULL); + correct = correct && (data == NULL); + + printTestResult("nextTreeData mit einem Element funktioniert", correct); + + clearTree(root); +} + +// Test 8: nextTreeData mit leerem Baum +void test_next_tree_data_empty() +{ + printf(BLUE "\n--- Test 8: nextTreeData mit leerem Baum ---" RESET "\n"); + + TreeNode *root = NULL; + + int *data = (int *)nextTreeData(root); + + printTestResult("nextTreeData mit leerem Baum gibt NULL zurueck", data == NULL); +} + +// Test 9: Mehrfache Traversierungen +void test_multiple_traversals() +{ + printf(BLUE "\n--- Test 9: Mehrfache Traversierungen ---" RESET "\n"); + + TreeNode *root = NULL; + int values[] = {50, 30, 70}; + + for (int i = 0; i < 3; i++) + { + root = addToTree(root, &values[i], sizeof(int), compareInt, NULL); + } + + // Erste Traversierung + int count1 = 0; + int *data = (int *)nextTreeData(root); + while (data != NULL) + { + count1++; + data = (int *)nextTreeData(NULL); + } + + // Zweite Traversierung (neu starten) + int count2 = 0; + data = (int *)nextTreeData(root); + while (data != NULL) + { + count2++; + data = (int *)nextTreeData(NULL); + } + + printTestResult("Mehrfache Traversierungen moeglich", count1 == 3 && count2 == 3); + + clearTree(root); +} + +// Test 10: clearTree +void test_clear_tree() +{ + printf(BLUE "\n--- Test 10: clearTree ---" RESET "\n"); + + TreeNode *root = NULL; + int values[] = {50, 30, 70, 20, 40, 60, 80}; + + for (int i = 0; i < 7; i++) + { + root = addToTree(root, &values[i], sizeof(int), compareInt, NULL); + } + + clearTree(root); + root = NULL; + + printTestResult("clearTree ausgefuehrt (valgrind prueft Speicher)", 1); + + // Neuer Baum nach Clear + int newValue = 100; + root = addToTree(root, &newValue, sizeof(int), compareInt, NULL); + + printTestResult("Nach clearTree kann neuer Baum aufgebaut werden", root != NULL && *(int *)root->data == 100); + + clearTree(root); +} + +// Test 11: Strings im Baum +void test_string_tree() +{ + printf(BLUE "\n--- Test 11: Baum mit Strings ---" RESET "\n"); + + TreeNode *root = NULL; + char *words[] = {"dog", "cat", "elephant", "ant", "bear"}; + + for (int i = 0; i < 5; i++) + { + root = addToTree(root, &words[i], sizeof(char *), compareString, NULL); + } + + printTestResult("String-Baum erstellt", root != NULL); + + // Traversierung sollte alphabetisch sortiert sein + char *expected[] = {"ant", "bear", "cat", "dog", "elephant"}; + int index = 0; + int allCorrect = 1; + + char **data = (char **)nextTreeData(root); + while (data != NULL) + { + if (index >= 5 || strcmp(*data, expected[index]) != 0) + { + allCorrect = 0; + printf(" Fehler bei Index %d: Erwartet '%s', bekommen '%s'\n", index, expected[index], *data); + } + index++; + data = (char **)nextTreeData(NULL); + } + + printTestResult("String-Baum gibt alphabetisch sortierte Reihenfolge", allCorrect && index == 5); + + clearTree(root); +} + +// Test 12: Stress-Test mit vielen Elementen +void test_large_tree() +{ + printf(BLUE "\n--- Test 12: Stress-Test (1000 Elemente) ---" RESET "\n"); + + TreeNode *root = NULL; + + // 1000 zufällige Zahlen einfügen + for (int i = 0; i < 1000; i++) + { + int value = i; + root = addToTree(root, &value, sizeof(int), compareInt, NULL); + } + + printTestResult("1000 Elemente eingefuegt", treeSize(root) == 1000); + + // Traversierung zählen + int count = 0; + int *data = (int *)nextTreeData(root); + while (data != NULL) + { + count++; + data = (int *)nextTreeData(NULL); + } + + printTestResult("Traversierung ueber alle 1000 Elemente", count == 1000); + + clearTree(root); +} + +// Test 13: Einseitiger Baum (nur rechts) +void test_unbalanced_tree() +{ + printf(BLUE "\n--- Test 13: Einseitiger Baum ---" RESET "\n"); + + TreeNode *root = NULL; + + // Aufsteigende Reihenfolge -> nur rechte Kinder + for (int i = 1; i <= 5; i++) + { + root = addToTree(root, &i, sizeof(int), compareInt, NULL); + } + + printTestResult("Einseitiger Baum erstellt", treeSize(root) == 5); + + // Traversierung sollte trotzdem funktionieren + int count = 0; + int *data = (int *)nextTreeData(root); + while (data != NULL) + { + count++; + data = (int *)nextTreeData(NULL); + } + + printTestResult("Traversierung ueber einseitigen Baum funktioniert", count == 5); + + clearTree(root); +} + +int main() +{ + printf("\n"); + printf("+----------------------------------------------+\n"); + printf("| BINARY TREE UNIT TESTS |\n"); + printf("+----------------------------------------------+\n"); + + test_add_single_element(); + test_add_multiple_elements(); + test_duplicate_detection(); + test_allow_duplicates(); + test_tree_size(); + test_next_tree_data(); + test_next_tree_data_single(); + test_next_tree_data_empty(); + test_multiple_traversals(); + test_clear_tree(); + test_string_tree(); + test_large_tree(); + test_unbalanced_tree(); + + printf("\n"); + printf("+----------------------------------------------+\n"); + printf("| TEST ZUSAMMENFASSUNG |\n"); + printf("+----------------------------------------------+\n"); + printf(GREEN "Tests bestanden: %d" RESET "\n", testsPassed); + printf(RED "Tests fehlgeschlagen: %d" RESET "\n", testsFailed); + printf("Gesamt: %d\n", testsPassed + testsFailed); + + if (testsFailed == 0) + { + printf(GREEN "\n==> Alle Tests erfolgreich!\n" RESET); + return EXIT_SUCCESS; + } + else + { + printf(RED "\n==> Einige Tests sind fehlgeschlagen!\n" RESET); + return EXIT_FAILURE; + } +} \ No newline at end of file diff --git a/Test_numbers.c b/Test_numbers.c new file mode 100644 index 0000000..544a251 --- /dev/null +++ b/Test_numbers.c @@ -0,0 +1,336 @@ +#include +#include +#include +#include +#include "numbers.h" + +#define GREEN "\033[0;32m" +#define RED "\033[0;31m" +#define RESET "\033[0m" +#define BLUE "\033[0;34m" + +int testsPassed = 0; +int testsFailed = 0; + +void printTestResult(const char *testName, int passed) +{ + if (passed) + { + printf(GREEN "[PASS]" RESET " %s\n", testName); + testsPassed++; + } + else + { + printf(RED "[FAIL]" RESET " %s\n", testName); + testsFailed++; + } +} + +// Hilfsfunktion: Prüft ob eine Zahl im Array vorkommt +int countOccurrences(const unsigned int *array, unsigned int len, unsigned int value) +{ + int count = 0; + for (unsigned int i = 0; i < len; i++) + { + if (array[i] == value) + count++; + } + return count; +} + +// Hilfsfunktion: Prüft ob alle Zahlen im gültigen Bereich sind +int allNumbersInRange(const unsigned int *array, unsigned int len, unsigned int min, unsigned int max) +{ + for (unsigned int i = 0; i < len; i++) + { + if (array[i] < min || array[i] > max) + return 0; + } + return 1; +} + +// Test 1: createNumbers mit kleiner Anzahl +void test_create_numbers_small() +{ + printf(BLUE "\n--- Test 1: createNumbers mit 5 Zahlen ---" RESET "\n"); + + unsigned int len = 5; + unsigned int *numbers = createNumbers(len); + + printTestResult("createNumbers gibt nicht-NULL zurueck", numbers != NULL); + + if (numbers != NULL) + { + // Alle Zahlen zwischen 1 und 2*len? + int inRange = allNumbersInRange(numbers, len, 1, 2 * len); + printTestResult("Alle Zahlen im Bereich [1, 10]", inRange); + + // Genau ein Duplikat zählen + int duplicateCount = 0; + for (unsigned int i = 0; i < len; i++) + { + int occurrences = countOccurrences(numbers, len, numbers[i]); + if (occurrences == 2) + duplicateCount++; + } + + // duplicateCount sollte 2 sein (2 mal die gleiche Zahl) + printTestResult("Genau ein Duplikat vorhanden", duplicateCount == 2); + + free(numbers); + } +} + +// Test 2: createNumbers mit mittlerer Anzahl +void test_create_numbers_medium() +{ + printf(BLUE "\n--- Test 2: createNumbers mit 20 Zahlen ---" RESET "\n"); + + unsigned int len = 20; + unsigned int *numbers = createNumbers(len); + + printTestResult("createNumbers(20) gibt nicht-NULL zurueck", numbers != NULL); + + if (numbers != NULL) + { + int inRange = allNumbersInRange(numbers, len, 1, 2 * len); + printTestResult("Alle Zahlen im Bereich [1, 40]", inRange); + + free(numbers); + } +} + +// Test 3: createNumbers mit Minimum (3 Zahlen) +void test_create_numbers_minimum() +{ + printf(BLUE "\n--- Test 3: createNumbers mit Minimum (3 Zahlen) ---" RESET "\n"); + + unsigned int len = 3; + unsigned int *numbers = createNumbers(len); + + printTestResult("createNumbers(3) funktioniert", numbers != NULL); + + if (numbers != NULL) + { + int inRange = allNumbersInRange(numbers, len, 1, 2 * len); + printTestResult("Alle Zahlen im Bereich [1, 6]", inRange); + + free(numbers); + } +} + +// Test 4: createNumbers mit größerer Anzahl +void test_create_numbers_large() +{ + printf(BLUE "\n--- Test 4: createNumbers mit 100 Zahlen ---" RESET "\n"); + + unsigned int len = 100; + unsigned int *numbers = createNumbers(len); + + printTestResult("createNumbers(100) gibt nicht-NULL zurueck", numbers != NULL); + + if (numbers != NULL) + { + int inRange = allNumbersInRange(numbers, len, 1, 2 * len); + printTestResult("Alle Zahlen im Bereich [1, 200]", inRange); + + free(numbers); + } +} + +// Test 5: getDuplicate findet das Duplikat +void test_get_duplicate_finds_duplicate() +{ + printf(BLUE "\n--- Test 5: getDuplicate findet Duplikat ---" RESET "\n"); + + // Manuelles Test-Array mit bekanntem Duplikat + unsigned int testArray[] = {5, 12, 7, 3, 12, 9}; + unsigned int len = 6; + + unsigned int duplicate = getDuplicate(testArray, len); + + printTestResult("getDuplicate findet korrektes Duplikat (12)", duplicate == 12); +} + +// Test 6: getDuplicate mit sortiertem Array +void test_get_duplicate_sorted() +{ + printf(BLUE "\n--- Test 6: getDuplicate mit sortiertem Array ---" RESET "\n"); + + unsigned int testArray[] = {1, 2, 3, 3, 4, 5}; + unsigned int len = 6; + + unsigned int duplicate = getDuplicate(testArray, len); + + printTestResult("getDuplicate funktioniert mit sortiertem Array", duplicate == 3); +} + +// Test 7: getDuplicate mit unsortiertem Array +void test_get_duplicate_unsorted() +{ + printf(BLUE "\n--- Test 7: getDuplicate mit unsortiertem Array ---" RESET "\n"); + + unsigned int testArray[] = {42, 17, 8, 99, 3, 42, 55}; + unsigned int len = 7; + + unsigned int duplicate = getDuplicate(testArray, len); + + printTestResult("getDuplicate funktioniert mit unsortiertem Array", duplicate == 42); +} + +// Test 8: Integration - createNumbers und getDuplicate +void test_integration_create_and_get() +{ + printf(BLUE "\n--- Test 8: Integration createNumbers + getDuplicate ---" RESET "\n"); + + int allCorrect = 1; + + // Teste mehrmals mit verschiedenen Größen + unsigned int sizes[] = {5, 10, 20, 50}; + + for (int i = 0; i < 4; i++) + { + unsigned int len = sizes[i]; + unsigned int *numbers = createNumbers(len); + + if (numbers == NULL) + { + allCorrect = 0; + break; + } + + unsigned int duplicate = getDuplicate(numbers, len); + + // Prüfe ob das gefundene Duplikat tatsächlich 2x vorkommt + int occurrences = countOccurrences(numbers, len, duplicate); + + if (duplicate == 0 || occurrences != 2) + { + printf(" Fehler bei len=%u: duplicate=%u, occurrences=%d\n", len, duplicate, occurrences); + allCorrect = 0; + } + + free(numbers); + } + + printTestResult("Integration funktioniert fuer verschiedene Groessen", allCorrect); +} + +// Test 9: Fehlerbehandlung - NULL-Pointer +void test_get_duplicate_null() +{ + printf(BLUE "\n--- Test 9: Fehlerbehandlung NULL-Pointer ---" RESET "\n"); + + unsigned int result = getDuplicate(NULL, 10); + + printTestResult("getDuplicate(NULL) gibt 0 zurueck", result == 0); +} + +// Test 10: Fehlerbehandlung - Zu kleine Länge +void test_get_duplicate_too_small() +{ + printf(BLUE "\n--- Test 10: Fehlerbehandlung zu kleine Laenge ---" RESET "\n"); + + unsigned int testArray[] = {42}; + unsigned int result = getDuplicate(testArray, 1); + + printTestResult("getDuplicate mit len=1 gibt 0 zurueck", result == 0); +} + +// Test 11: Eindeutigkeit - Verschiedene Runs erzeugen verschiedene Arrays +void test_randomness() +{ + printf(BLUE "\n--- Test 11: Zufaelligkeit ---" RESET "\n"); + + unsigned int len = 10; + unsigned int *numbers1 = createNumbers(len); + unsigned int *numbers2 = createNumbers(len); + + if (numbers1 == NULL || numbers2 == NULL) + { + printTestResult("Arrays konnten erstellt werden", 0); + free(numbers1); + free(numbers2); + return; + } + + // Prüfe ob Arrays unterschiedlich sind + int different = 0; + for (unsigned int i = 0; i < len; i++) + { + if (numbers1[i] != numbers2[i]) + { + different = 1; + break; + } + } + + printTestResult("Zwei Aufrufe erzeugen unterschiedliche Arrays", different); + + free(numbers1); + free(numbers2); +} + +// Test 12: Stress-Test +void test_stress() +{ + printf(BLUE "\n--- Test 12: Stress-Test (500 Zahlen) ---" RESET "\n"); + + unsigned int len = 500; + unsigned int *numbers = createNumbers(len); + + printTestResult("createNumbers(500) erfolgreich", numbers != NULL); + + if (numbers != NULL) + { + unsigned int duplicate = getDuplicate(numbers, len); + int occurrences = countOccurrences(numbers, len, duplicate); + + printTestResult("getDuplicate findet Duplikat in grossem Array", occurrences == 2); + + free(numbers); + } +} + +int main() +{ + // Zufallsgenerator EINMAL zu Beginn initialisieren + srand(time(NULL)); + + printf("\n"); + printf("+----------------------------------------------+\n"); + printf("| NUMBERS UNIT TESTS |\n"); + printf("+----------------------------------------------+\n"); + + test_create_numbers_small(); + test_create_numbers_medium(); + test_create_numbers_minimum(); + test_create_numbers_large(); + test_get_duplicate_finds_duplicate(); + test_get_duplicate_sorted(); + test_get_duplicate_unsorted(); + test_integration_create_and_get(); + test_get_duplicate_null(); + test_get_duplicate_too_small(); + test_randomness(); + test_stress(); + + printf("\n"); + printf("+----------------------------------------------+\n"); + printf("| TEST ZUSAMMENFASSUNG |\n"); + printf("+----------------------------------------------+\n"); + printf(GREEN "Tests bestanden: %d" RESET "\n", testsPassed); + printf(RED "Tests fehlgeschlagen: %d" RESET "\n", testsFailed); + printf("Gesamt: %d\n", testsPassed + testsFailed); + + if (testsFailed == 0) + { + printf(GREEN "\n==> Alle Tests erfolgreich!\n" RESET); + return EXIT_SUCCESS; + } + else + { + printf(RED "\n==> Einige Tests sind fehlgeschlagen!\n" RESET); + return EXIT_FAILURE; + } +} \ No newline at end of file diff --git a/Test_stack.c b/Test_stack.c new file mode 100644 index 0000000..6a41b85 --- /dev/null +++ b/Test_stack.c @@ -0,0 +1,276 @@ +#include +#include +#include +#include +#include "stack.h" + +// ANSI Farben für bessere Lesbarkeit +#define GREEN "\033[0;32m" +#define RED "\033[0;31m" +#define RESET "\033[0m" +#define BLUE "\033[0;34m" + +int testsPassed = 0; +int testsFailed = 0; + +void printTestResult(const char *testName, int passed) +{ + if (passed) + { + printf(GREEN "[PASS]" RESET " %s\n", testName); + testsPassed++; + } + else + { + printf(RED "[FAIL]" RESET " %s\n", testName); + testsFailed++; + } +} + +// Test 1: Push und Top +void test_push_and_top() +{ + printf(BLUE "\n--- Test 1: Push und Top ---" RESET "\n"); + + StackNode *stack = NULL; + int value1 = 42; + int value2 = 17; + + // Erstes Element pushen + stack = push(stack, &value1); + int *topValue = (int *)top(stack); + + printTestResult("Push eines Elements", stack != NULL); + printTestResult("Top gibt korrekten Wert zurueck", topValue != NULL && *topValue == 42); + + // Zweites Element pushen + stack = push(stack, &value2); + topValue = (int *)top(stack); + + printTestResult("Push eines zweiten Elements", stack != NULL); + printTestResult("Top gibt neuesten Wert zurueck (LIFO)", topValue != NULL && *topValue == 17); + + // Aufräumen + clearStack(stack); +} + +// Test 2: Pop +void test_pop() +{ + printf(BLUE "\n--- Test 2: Pop ---" RESET "\n"); + + StackNode *stack = NULL; + int value1 = 100; + int value2 = 200; + int value3 = 300; + + // Drei Elemente pushen + stack = push(stack, &value1); + stack = push(stack, &value2); + stack = push(stack, &value3); + + // Erstes Pop + int *topBefore = (int *)top(stack); + stack = pop(stack); + int *topAfter = (int *)top(stack); + + printTestResult("Pop entfernt oberstes Element", topBefore != NULL && *topBefore == 300); + printTestResult("Nach Pop ist naechstes Element oben", topAfter != NULL && *topAfter == 200); + + // Zweites Pop + stack = pop(stack); + topAfter = (int *)top(stack); + + printTestResult("Nach zweitem Pop ist letztes Element oben", topAfter != NULL && *topAfter == 100); + + // Letztes Pop + stack = pop(stack); + + printTestResult("Nach letztem Pop ist Stack leer", stack == NULL); + + // Pop auf leerem Stack + stack = pop(stack); + printTestResult("Pop auf leerem Stack gibt NULL zurueck", stack == NULL); +} + +// Test 3: Top auf leerem Stack +void test_top_empty_stack() +{ + printf(BLUE "\n--- Test 3: Top auf leerem Stack ---" RESET "\n"); + + StackNode *stack = NULL; + void *result = top(stack); + + printTestResult("Top auf leerem Stack gibt NULL zurueck", result == NULL); +} + +// Test 4: ClearStack +void test_clear_stack() +{ + printf(BLUE "\n--- Test 4: ClearStack ---" RESET "\n"); + + StackNode *stack = NULL; + int values[5] = {10, 20, 30, 40, 50}; + + // Mehrere Elemente pushen + for (int i = 0; i < 5; i++) + { + stack = push(stack, &values[i]); + } + + printTestResult("Stack wurde mit 5 Elementen gefuellt", stack != NULL); + + // Stack löschen + clearStack(stack); + stack = NULL; + + printTestResult("ClearStack wurde ausgefuehrt (manuell pruefen mit valgrind)", 1); + + // Neuer Push nach Clear + int newValue = 999; + stack = push(stack, &newValue); + int *topValue = (int *)top(stack); + + printTestResult("Nach Clear kann neuer Stack aufgebaut werden", topValue != NULL && *topValue == 999); + + clearStack(stack); +} + +// Test 5: LIFO-Prinzip mit mehreren Elementen +void test_lifo_principle() +{ + printf(BLUE "\n--- Test 5: LIFO-Prinzip ---" RESET "\n"); + + StackNode *stack = NULL; + int values[10]; + + // 10 Elemente in aufsteigender Reihenfolge pushen + for (int i = 0; i < 10; i++) + { + values[i] = i; + stack = push(stack, &values[i]); + } + + // In umgekehrter Reihenfolge poppen und prüfen + int allCorrect = 1; + for (int i = 9; i >= 0; i--) + { + int *topValue = (int *)top(stack); + if (topValue == NULL || *topValue != i) + { + allCorrect = 0; + break; + } + stack = pop(stack); + } + + printTestResult("LIFO-Prinzip: Elemente kommen in umgekehrter Reihenfolge zurueck", allCorrect); + printTestResult("Nach allen Pops ist Stack leer", stack == NULL); +} + +// Test 6: Push mit verschiedenen Datentypen +void test_different_data_types() +{ + printf(BLUE "\n--- Test 6: Verschiedene Datentypen ---" RESET "\n"); + + StackNode *stack = NULL; + + // Integer + int intVal = 42; + stack = push(stack, &intVal); + + // Double + double doubleVal = 3.14159; + stack = push(stack, &doubleVal); + + // String + char *stringVal = "Hello Stack!"; + stack = push(stack, &stringVal); + + // Rückwärts prüfen + char **topString = (char **)top(stack); + stack = pop(stack); + + double *topDouble = (double *)top(stack); + stack = pop(stack); + + int *topInt = (int *)top(stack); + stack = pop(stack); + + int stringCorrect = (topString != NULL && strcmp(*topString, "Hello Stack!") == 0); + int doubleCorrect = (topDouble != NULL && *topDouble > 3.14 && *topDouble < 3.15); + int intCorrect = (topInt != NULL && *topInt == 42); + + printTestResult("Stack funktioniert mit String", stringCorrect); + printTestResult("Stack funktioniert mit Double", doubleCorrect); + printTestResult("Stack funktioniert mit Integer", intCorrect); + + clearStack(stack); +} + +// Test 7: Stress-Test mit vielen Elementen +void test_large_stack() +{ + printf(BLUE "\n--- Test 7: Stress-Test (1000 Elemente) ---" RESET "\n"); + + StackNode *stack = NULL; + int *values = malloc(1000 * sizeof(int)); + + // 1000 Elemente pushen + for (int i = 0; i < 1000; i++) + { + values[i] = i; + stack = push(stack, &values[i]); + } + + // Prüfe Top + int *topValue = (int *)top(stack); + printTestResult("1000 Elemente gepusht, Top ist korrekt", topValue != NULL && *topValue == 999); + + // Alle wieder poppen + int count = 0; + while (stack != NULL) + { + stack = pop(stack); + count++; + } + + printTestResult("Alle 1000 Elemente erfolgreich gepoppt", count == 1000); + + free(values); +} + +int main() +{ + printf("\n"); + printf("+----------------------------------------------+\n"); + printf("| STACK UNIT TESTS |\n"); + printf("+----------------------------------------------+\n"); + + test_push_and_top(); + test_pop(); + test_top_empty_stack(); + test_clear_stack(); + test_lifo_principle(); + test_different_data_types(); + test_large_stack(); + + printf("\n"); + printf("+----------------------------------------------+\n"); + printf("| TEST ZUSAMMENFASSUNG |\n"); + printf("+----------------------------------------------+\n"); + printf(GREEN "Tests bestanden: %d" RESET "\n", testsPassed); + printf(RED "Tests fehlgeschlagen: %d" RESET "\n", testsFailed); + printf("Gesamt: %d\n", testsPassed + testsFailed); + + if (testsFailed == 0) + { + printf(GREEN "\n==> Alle Tests erfolgreich!\n" RESET); + return EXIT_SUCCESS; + } + else + { + printf(RED "\n==> Einige Tests sind fehlgeschlagen!\n" RESET); + return EXIT_FAILURE; + } +} \ No newline at end of file diff --git a/bintree.c b/bintree.c index 5cf82a9..bf778b8 100644 --- a/bintree.c +++ b/bintree.c @@ -12,25 +12,127 @@ // 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) { + // Basisfall: Leerer Baum -> neuen Knoten erstellen + if (root == NULL) + { + TreeNode *newNode = (TreeNode *)malloc(sizeof(TreeNode)); + if (newNode == NULL) + return NULL; + // Datenkopie erstellen + newNode->data = malloc(dataSize); + if (newNode->data == NULL) + { + free(newNode); + return NULL; + } + + memcpy(newNode->data, data, dataSize); + newNode->left = NULL; + newNode->right = NULL; + + // Neues Element wurde hinzugefügt + if (isDuplicate != NULL) + *isDuplicate = 0; + + return newNode; + } + + // Rekursiver Fall: Vergleiche mit aktuellem Knoten + int cmp = compareFct(data, root->data); + + if (cmp < 0) + { + // Kleiner -> links einfügen + root->left = addToTree(root->left, data, dataSize, compareFct, isDuplicate); + } + else if (cmp > 0) + { + // Größer -> rechts einfügen + root->right = addToTree(root->right, data, dataSize, compareFct, isDuplicate); + } + else + { + // Gleich -> Duplikat gefunden + if (isDuplicate != NULL) + { + *isDuplicate = 1; // Duplikat erkannt + // Nichts einfügen, nur isDuplicate setzen + } + else + { + // Duplikate erlaubt -> füge rechts ein + root->right = addToTree(root->right, data, dataSize, compareFct, NULL); + } + } + + return root; } +// Statischer Stack für nextTreeData (wie bei strtok) +static StackNode *iteratorStack = NULL; + // 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) { + // Neuer Durchlauf: Stack leeren und initialisieren + if (root != NULL) + { + clearStack(iteratorStack); + iteratorStack = NULL; + // Wurzel und alle linken Knoten auf den Stack + TreeNode *current = root; + while (current != NULL) + { + iteratorStack = push(iteratorStack, current); + current = current->left; + } + } + + // Stack leer -> keine weiteren Elemente + if (iteratorStack == NULL) + return NULL; + + // Obersten Knoten vom Stack holen + TreeNode *node = (TreeNode *)top(iteratorStack); + iteratorStack = pop(iteratorStack); + + // Rechten Teilbaum vorbereiten (alle linken Knoten auf Stack) + TreeNode *current = node->right; + while (current != NULL) + { + iteratorStack = push(iteratorStack, current); + current = current->left; + } + + return node->data; } // Releases all memory resources (including data copies). void clearTree(TreeNode *root) { + if (root == NULL) + return; + // Post-Order: Links -> Rechts -> Wurzel + clearTree(root->left); + clearTree(root->right); + + // Datenkopie freigeben + free(root->data); + // Knoten freigeben + free(root); } // Returns the number of entries in the tree given by root. unsigned int treeSize(const TreeNode *root) { + if (root == NULL) + return 0; -} \ No newline at end of file + // Rekursiv: 1 (aktueller Knoten) + linker Teilbaum + rechter Teilbaum + return 1 + treeSize(root->left) + treeSize(root->right); +} diff --git a/main.c b/main.c index 34163d0..6b9f540 100644 --- a/main.c +++ b/main.c @@ -1,5 +1,6 @@ #include #include +#include #include "numbers.h" #include "timer.h" #include "highscore.h" @@ -39,6 +40,9 @@ int main(int argc, char *argv[]) { int exitCode = EXIT_FAILURE; + + // Zufallsgenerator EINMAL initialisieren + srand(time(NULL)); if(argc != 2) { fprintf(stderr, "Usage: %s \n", argv[0]); diff --git a/numbers.c b/numbers.c index f59d9a2..ca51099 100644 --- a/numbers.c +++ b/numbers.c @@ -7,20 +7,106 @@ //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. + * 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. */ +static int compareUnsignedInt(const void *arg1, const void *arg2) +{ + unsigned int val1 = *(const unsigned int *)arg1; + unsigned int val2 = *(const unsigned int *)arg2; + if (val1 < val2) + return -1; + else if (val1 > val2) + return 1; + else + return 0; +} // 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 < 1) + return NULL; + // Array allokieren + unsigned int *numbers = (unsigned int *)malloc(len * sizeof(unsigned int)); + if (numbers == NULL) + return NULL; + + + // Binärbaum für Duplikaterkennung + TreeNode *tree = NULL; + + // len verschiedene Zufallszahlen erzeugen (zwischen 1 und 2*len) + for (unsigned int i = 0; i < len; i++) + { + unsigned int randomNum; + int isDuplicate; + + // Wiederhole, bis eine neue (nicht-doppelte) Zahl gefunden wird + do + { + isDuplicate = 0; + randomNum = (rand() % (2 * len)) + 1; // Zahlen zwischen 1 und 2*len + + // Versuche in Baum einzufügen und prüfe auf Duplikat + tree = addToTree(tree, &randomNum, sizeof(unsigned int), compareUnsignedInt, &isDuplicate); + } while (isDuplicate == 1); + + numbers[i] = randomNum; + } + + // Baum freigeben + clearTree(tree); + + // Zufälligen Index wählen und diesen Wert duplizieren + unsigned int duplicateIndex = rand() % len; + unsigned int duplicateValue = numbers[duplicateIndex]; + + // Einen anderen zufälligen Index finden, um das Duplikat einzufügen + unsigned int targetIndex; + do + { + targetIndex = rand() % len; + } while (targetIndex == duplicateIndex); + + // Duplikat einfügen + numbers[targetIndex] = duplicateValue; + + return numbers; } // 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 == NULL || len < 2) + return 0; + // Kopie des Arrays erstellen (da qsort das Original verändert) + unsigned int *sortedNumbers = (unsigned int *)malloc(len * sizeof(unsigned int)); + if (sortedNumbers == NULL) + return 0; + + memcpy(sortedNumbers, numbers, len * sizeof(unsigned int)); + + // Array sortieren + qsort(sortedNumbers, len, sizeof(unsigned int), compareUnsignedInt); + + // Benachbarte Elemente vergleichen + unsigned int duplicate = 0; + for (unsigned int i = 0; i < len - 1; i++) + { + if (sortedNumbers[i] == sortedNumbers[i + 1]) + { + duplicate = sortedNumbers[i]; + break; + } + } + + // Speicher freigeben + free(sortedNumbers); + + return duplicate; } \ No newline at end of file diff --git a/run_all_tests.bat b/run_all_tests.bat new file mode 100644 index 0000000..5ccd387 --- /dev/null +++ b/run_all_tests.bat @@ -0,0 +1,80 @@ +@echo off +REM Alle Tests ausführen (Windows Version) + +echo ================================================ +echo DOBLE - Alle Unit Tests ausfuehren +echo ================================================ +echo. + +REM Test 1: Stack +echo ================================================ +echo 1. STACK TESTS +echo ================================================ +gcc -g -Wall -o test_stack.exe Test_stack.c stack.c +if %ERRORLEVEL% EQU 0 ( + test_stack.exe + set STACK_RESULT=%ERRORLEVEL% +) else ( + echo Fehler: Stack Tests konnten nicht kompiliert werden + set STACK_RESULT=1 +) +echo. + +REM Test 2: Binärbaum +echo ================================================ +echo 2. BINAERBAUM TESTS +echo ================================================ +gcc -g -Wall -o test_bintree.exe Test_bintree.c bintree.c stack.c +if %ERRORLEVEL% EQU 0 ( + test_bintree.exe + set BINTREE_RESULT=%ERRORLEVEL% +) else ( + echo Fehler: Binaerbaum Tests konnten nicht kompiliert werden + set BINTREE_RESULT=1 +) +echo. + +REM Test 3: Numbers +echo ================================================ +echo 3. NUMBERS TESTS +echo ================================================ +gcc -g -Wall -o test_numbers.exe Test_numbers.c numbers.c bintree.c stack.c -lm +if %ERRORLEVEL% EQU 0 ( + test_numbers.exe + set NUMBERS_RESULT=%ERRORLEVEL% +) else ( + echo Fehler: Numbers Tests konnten nicht kompiliert werden + set NUMBERS_RESULT=1 +) +echo. + +REM Zusammenfassung +echo ================================================ +echo GESAMTERGEBNIS +echo ================================================ +if %STACK_RESULT% EQU 0 ( + echo [OK] Stack Tests: BESTANDEN +) else ( + echo [FEHLER] Stack Tests: FEHLGESCHLAGEN +) + +if %BINTREE_RESULT% EQU 0 ( + echo [OK] Binaerbaum Tests: BESTANDEN +) else ( + echo [FEHLER] Binaerbaum Tests: FEHLGESCHLAGEN +) + +if %NUMBERS_RESULT% EQU 0 ( + echo [OK] Numbers Tests: BESTANDEN +) else ( + echo [FEHLER] Numbers Tests: FEHLGESCHLAGEN +) + +echo. +if %STACK_RESULT% EQU 0 if %BINTREE_RESULT% EQU 0 if %NUMBERS_RESULT% EQU 0 ( + echo ALLE TESTS ERFOLGREICH! +) else ( + echo Einige Tests sind fehlgeschlagen +) + +pause diff --git a/run_bintree_test.bat b/run_bintree_test.bat new file mode 100644 index 0000000..7e1f0f0 --- /dev/null +++ b/run_bintree_test.bat @@ -0,0 +1,16 @@ +@echo off +REM Binaerbaum Tests kompilieren und ausfuehren + +echo === Binaerbaum Tests kompilieren === +gcc -g -Wall -o test_bintree.exe Test_bintree.c bintree.c stack.c + +if %ERRORLEVEL% EQU 0 ( + echo Kompilierung erfolgreich! + echo. + echo === Binaerbaum Tests ausfuehren === + test_bintree.exe +) else ( + echo Kompilierung fehlgeschlagen! +) + +pause diff --git a/run_numbers_test.bat b/run_numbers_test.bat new file mode 100644 index 0000000..9661260 --- /dev/null +++ b/run_numbers_test.bat @@ -0,0 +1,16 @@ +@echo off +REM Numbers Tests kompilieren und ausfuehren + +echo === Numbers Tests kompilieren === +gcc -g -Wall -o test_numbers.exe Test_numbers.c numbers.c bintree.c stack.c -lm + +if %ERRORLEVEL% EQU 0 ( + echo Kompilierung erfolgreich! + echo. + echo === Numbers Tests ausfuehren === + test_numbers.exe +) else ( + echo Kompilierung fehlgeschlagen! +) + +pause diff --git a/run_stack_test.bat b/run_stack_test.bat new file mode 100644 index 0000000..68e9323 --- /dev/null +++ b/run_stack_test.bat @@ -0,0 +1,16 @@ +@echo off +REM Stack Tests kompilieren und ausfuehren + +echo === Stack Tests kompilieren === +gcc -g -Wall -o test_stack.exe Test_stack.c stack.c + +if %ERRORLEVEL% EQU 0 ( + echo Kompilierung erfolgreich! + echo. + echo === Stack Tests ausfuehren === + test_stack.exe +) else ( + echo Kompilierung fehlgeschlagen! +) + +pause diff --git a/stack.c b/stack.c index e3a90d4..85a5567 100644 --- a/stack.c +++ b/stack.c @@ -10,24 +10,48 @@ // Pushes data as pointer onto the stack. StackNode *push(StackNode *stack, void *data) { + // Neuen Knoten erstellen + StackNode *newNode = (StackNode *)malloc(sizeof(StackNode)); + if (newNode == NULL) + return stack; // Bei Fehler: alter Stack zurück + + // Daten eintragen + newNode->data = data; + newNode->next = stack; // Alter Stack wird zum "nächsten" Element + + return newNode; // Neuer Knoten ist jetzt oben } // 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; // Leerer Stack + StackNode *nextNode = stack->next; // Merke dir das nächste Element + free(stack); // Gib den obersten Knoten frei + + return nextNode; // Nächstes Element ist jetzt oben } // Returns the data of the top element. void *top(StackNode *stack) { + if (stack == NULL) + return NULL; // Leerer Stack + return stack->data; } // Clears stack and releases all memory. void clearStack(StackNode *stack) { - + while (stack != NULL) + { + StackNode *next = stack->next; // Merke dir das nächste Element + free(stack); // Gib aktuellen Knoten frei + stack = next; // Gehe zum nächsten + } } \ No newline at end of file diff --git a/stack.h b/stack.h index f7d542d..87e51ce 100644 --- a/stack.h +++ b/stack.h @@ -8,7 +8,11 @@ The latest element is taken from the stack. */ #include //TODO: passenden Datentyp als struct anlegen - +typedef struct StackNode +{ + void *data; // Zeiger auf die gespeicherten Daten + struct StackNode *next; // Zeiger auf das nächste Element im Stack +} StackNode; // Pushes data as pointer onto the stack. StackNode *push(StackNode *stack, void *data);