#include #include #include #include "unity.h" #include "stack.h" // ========================================================================= // HILFSFUNKTIONEN FÜR DIE TESTS // ========================================================================= /** * Erstellt eine Kopie eines Integer-Wertes auf dem Heap. * Dies ist notwendig, da der Stack void* Pointer speichert. */ static int *createIntPointer(int value) { int *ptr = (int *)malloc(sizeof(int)); TEST_ASSERT_NOT_NULL(ptr); // Stelle sicher, dass malloc erfolgreich war *ptr = value; return ptr; } /** * Räumt den Stack und die darauf gespeicherten Datenpointer auf (spezifisch für Integer-Tests). * Im Gegensatz zu clearStack() befreit diese Funktion auch die Daten, da sie im Test hier allokiert wurden. */ static void clearStackWithData(StackNode *stack) { while (stack != NULL) { StackNode *next = stack->next; if (stack->data != NULL) { free(stack->data); // Gib die Daten (Integer-Pointer) frei } free(stack); // Gib den Knoten selbst frei stack = next; } } // ========================================================================= // DIE WICHTIGSTEN TESTFÄLLE (REDUZIERT) // ========================================================================= // Testet Push und Top (LIFO-Prinzip, 1 Element) void test_pushAndTop(void) { StackNode *stack = NULL; int *data = createIntPointer(42); // 1. Push stack = push(stack, data); TEST_ASSERT_NOT_NULL(stack); // 2. Top (LIFO - Last In) int *top_data = (int *)top(stack); TEST_ASSERT_EQUAL_INT(42, *top_data); // Aufräumen: Da die Daten hier nur einmalig gepusht wurden, // können wir den Knoten poppen und die Daten separat freigeben (wie es pop() erfordert). stack = pop(stack); free(data); TEST_ASSERT_NULL(stack); } // Testet die LIFO-Reihenfolge mit mehreren Elementen und die Pop-Funktion. void test_popMultipleElements(void) { StackNode *stack = NULL; int *data1 = createIntPointer(1); int *data2 = createIntPointer(2); int *data3 = createIntPointer(3); // Stack: [3 (oben), 2, 1 (unten)] stack = push(NULL, data1); stack = push(stack, data2); stack = push(stack, data3); // 1. Pop: Prüfe 3 TEST_ASSERT_EQUAL_INT(3, *(int *)top(stack)); free(data3); stack = pop(stack); // 2. Pop: Prüfe 2 TEST_ASSERT_EQUAL_INT(2, *(int *)top(stack)); free(data2); stack = pop(stack); // 3. Pop: Prüfe 1 TEST_ASSERT_EQUAL_INT(1, *(int *)top(stack)); free(data1); stack = pop(stack); TEST_ASSERT_NULL(stack); } // Testet den Grenzfall: Pop auf einem leeren Stack. void test_popOnEmptyStack(void) { StackNode *stack = NULL; // Pop sollte NULL zurückgeben, wenn der Stack leer ist. TEST_ASSERT_NULL(pop(stack)); } // Testet die Speicherfreigabe (die wichtigste Anforderung der Aufgabenstellung). void test_clearStackFunctionality(void) { StackNode *stack = NULL; // Allokiere Daten und pushe sie auf den Stack stack = push(stack, createIntPointer(10)); stack = push(stack, createIntPointer(20)); stack = push(stack, createIntPointer(30)); // Die Helferfunktion clearStackWithData ruft free() auf allen Knoten und Daten auf. // Wir prüfen implizit, ob die clearStack Logik fehlerfrei durchläuft. clearStackWithData(stack); stack = NULL; // Wenn der Test ohne Speicherzugriffsverletzung durchläuft, war clearStack erfolgreich. } // ========================================================================= // MAIN SETUP / RUNNER // ========================================================================= void setUp(void) { // Wird vor jedem Test aufgerufen } void tearDown(void) { // Wird nach jedem Test aufgerufen } int main(void) { UNITY_BEGIN(); printf("\n============================\nStack Module Tests\n============================\n"); // Die essentiellen Tests RUN_TEST(test_pushAndTop); RUN_TEST(test_popMultipleElements); RUN_TEST(test_popOnEmptyStack); RUN_TEST(test_clearStackFunctionality); return UNITY_END(); }