erste tests

This commit is contained in:
Luis Gessnitzer 2025-12-12 14:33:45 +01:00
parent c325131503
commit f5af439e99
12 changed files with 1388 additions and 5 deletions

423
Test_bintree.c Normal file
View File

@ -0,0 +1,423 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#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;
}
}

336
Test_numbers.c Normal file
View File

@ -0,0 +1,336 @@
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <time.h>
#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;
}
}

276
Test_stack.c Normal file
View File

@ -0,0 +1,276 @@
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#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;
}
}

104
bintree.c
View File

@ -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;
}
// Rekursiv: 1 (aktueller Knoten) + linker Teilbaum + rechter Teilbaum
return 1 + treeSize(root->left) + treeSize(root->right);
}

4
main.c
View File

@ -1,5 +1,6 @@
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#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 <player name>\n", argv[0]);

View File

@ -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;
}

80
run_all_tests.bat Normal file
View File

@ -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

16
run_bintree_test.bat Normal file
View File

@ -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

16
run_numbers_test.bat Normal file
View File

@ -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

16
run_stack_test.bat Normal file
View File

@ -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

26
stack.c
View File

@ -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
}
}

View File

@ -8,7 +8,11 @@ The latest element is taken from the stack. */
#include <stdlib.h>
//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);