Doble-Spiel/test_stack.c

149 lines
4.1 KiB
C

#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#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();
}