generated from freudenreichan/info2Praktikum-DobleSpiel
Compare commits
8 Commits
BranchAlex
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| eb07a70c5c | |||
| 80c2bfd3e0 | |||
| 9a37803c35 | |||
| 2edd01effb | |||
| e316a4a785 | |||
| 6600b12893 | |||
| 850c7ed798 | |||
| 510edf8585 |
76
bintree.c
76
bintree.c
@ -12,7 +12,43 @@
|
|||||||
// if isDuplicate is NULL, otherwise ignores duplicates and sets isDuplicate to 1 (or to 0 if a new entry is added).
|
// 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)
|
TreeNode *addToTree(TreeNode *root, const void *data, size_t dataSize, CompareFctType compareFct, int *isDuplicate)
|
||||||
{
|
{
|
||||||
|
// 1. Leerer Baum -> neuen Knoten anlegen
|
||||||
|
if (root == NULL)
|
||||||
|
{
|
||||||
|
TreeNode *node = malloc(sizeof(TreeNode)); //Speicherreservierung
|
||||||
|
if (!node) return NULL; //Abbruch, wenn kein Speicher verfügbar
|
||||||
|
|
||||||
|
node->data = malloc(dataSize); //Speicher für Daten reservieren
|
||||||
|
if(!node->data) //Bei Fehler -> freigeben des Knotens und abbrechen
|
||||||
|
{
|
||||||
|
free(node);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
memcpy(node->data, data, dataSize); //Daten kopieren (nicht Zeiger)
|
||||||
|
|
||||||
|
node->left = node->right = NULL; //Neuer Knoten hat keine Kinder
|
||||||
|
|
||||||
|
if (isDuplicate) *isDuplicate = 0; //Rückmeldung (kein Duplikat)
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
//2. Vergleich, um Einfügerichtung zu bestimmen
|
||||||
|
int cmp = compareFct(data, root->data);
|
||||||
|
|
||||||
|
if (cmp < 0) //kleiner nach links weitergeben (rekursiv)
|
||||||
|
{
|
||||||
|
root->left = addToTree(root->left, data, dataSize, compareFct, isDuplicate);
|
||||||
|
}
|
||||||
|
else if (cmp > 0) //größer nach rechts weitergeben
|
||||||
|
{
|
||||||
|
root->right = addToTree(root->right, data, dataSize, compareFct, isDuplicate);
|
||||||
|
}
|
||||||
|
else //Duplikat -> wird nicht eingefügt (keine Änderung am Baum)
|
||||||
|
{
|
||||||
|
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.
|
// 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.
|
||||||
@ -20,17 +56,57 @@ TreeNode *addToTree(TreeNode *root, const void *data, size_t dataSize, CompareFc
|
|||||||
// push the top node and push all its left nodes.
|
// push the top node and push all its left nodes.
|
||||||
void *nextTreeData(TreeNode *root)
|
void *nextTreeData(TreeNode *root)
|
||||||
{
|
{
|
||||||
|
static StackNode *iterStack = NULL; //behält den Wert zwischen Funktionsaufrufen
|
||||||
|
|
||||||
|
if (root != NULL) //Wird ein neuer Baum übergeben?
|
||||||
|
{
|
||||||
|
clearStack(iterStack); // alten Stack löschen
|
||||||
|
iterStack = NULL;
|
||||||
|
|
||||||
|
TreeNode *cur = root; //Root + alle linken Knoten auf Stack pushen
|
||||||
|
while (cur != NULL)
|
||||||
|
{
|
||||||
|
iterStack = push(iterStack, cur);
|
||||||
|
cur = cur->left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iterStack == NULL) //Kein Baum mehr -> besuchen aller Knoten beendet
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
//Top-Knoten (als nächtes Reihe)
|
||||||
|
TreeNode *node = (TreeNode *)top(iterStack); //Top-Knoten als nächste Reihe
|
||||||
|
iterStack = pop(iterStack); //entfernen des Kontens
|
||||||
|
|
||||||
|
//Rechtsknoten
|
||||||
|
TreeNode *right = node->right; //nach Besuch bei rechten Knoten in rechten Teilbaum
|
||||||
|
while (right != NULL)
|
||||||
|
{
|
||||||
|
iterStack = push(iterStack, right);
|
||||||
|
right = right->left; //von dort ganz nach links und alles pushen
|
||||||
|
}
|
||||||
|
|
||||||
|
return node->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Releases all memory resources (including data copies).
|
// Releases all memory resources (including data copies).
|
||||||
void clearTree(TreeNode *root)
|
void clearTree(TreeNode *root)
|
||||||
{
|
{
|
||||||
|
if (root == NULL) //Abbruchbedienung
|
||||||
|
return;
|
||||||
|
|
||||||
|
clearTree(root->left); //links und rechts löschen
|
||||||
|
clearTree(root->right);
|
||||||
|
|
||||||
|
free(root->data); //Daten freigeben
|
||||||
|
free(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the number of entries in the tree given by 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) //leerer Baum
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return 1 + treeSize(root->left) + treeSize(root->right); //Größe = 1 + Größe links + Größe rechts
|
||||||
}
|
}
|
||||||
@ -1,2 +0,0 @@
|
|||||||
Alex;14964
|
|
||||||
player1;3999
|
|
||||||
39
makefile
39
makefile
@ -34,19 +34,45 @@ doble : $(program_obj_files)
|
|||||||
# Unit Tests
|
# Unit Tests
|
||||||
# --------------------------
|
# --------------------------
|
||||||
TEST_STACK_EXEC = runtest_stack.exe
|
TEST_STACK_EXEC = runtest_stack.exe
|
||||||
|
TEST_NUMBERS_EXEC = runtest_numbers.exe # NEU: Ausführbare Datei für numbers-Tests
|
||||||
|
|
||||||
unitTests: $(TEST_STACK_EXEC)
|
.PHONY: unitTests
|
||||||
@echo "--- Starte Stack Unit Tests ---"
|
unitTests: $(TEST_STACK_EXEC) $(TEST_NUMBERS_EXEC)
|
||||||
|
@echo "=========================================="
|
||||||
|
@echo "--- Starte ALLE Unit Tests ---"
|
||||||
|
@echo "=========================================="
|
||||||
|
|
||||||
|
@echo "\n--- Starte Stack Unit Tests ---"
|
||||||
@echo "Versuche auszuführen: $(TEST_STACK_EXEC)"
|
@echo "Versuche auszuführen: $(TEST_STACK_EXEC)"
|
||||||
$(TEST_STACK_EXEC)
|
$(TEST_STACK_EXEC)
|
||||||
@echo "--- Stack Unit Tests abgeschlossen ---"
|
@echo "--- Stack Unit Tests abgeschlossen ---\n"
|
||||||
|
|
||||||
|
@echo "--- Starte Numbers Unit Tests ---"
|
||||||
|
@echo "Versuche auszuführen: $(TEST_NUMBERS_EXEC)"
|
||||||
|
$(TEST_NUMBERS_EXEC)
|
||||||
|
@echo "--- Numbers Unit Tests abgeschlossen ---"
|
||||||
|
|
||||||
|
# --- Regeln für Stack-Tests (Unverändert) ---
|
||||||
$(TEST_STACK_EXEC): test_stack.o stack.o
|
$(TEST_STACK_EXEC): test_stack.o stack.o
|
||||||
$(CC) $(CFLAGS) -I$(unityfolder) test_stack.o stack.o $(unityfolder)/unity.c -o $@ $(BINARIES)/libdoble_complete.a
|
$(CC) $(CFLAGS) -I$(unityfolder) test_stack.o stack.o $(unityfolder)/unity.c -o $@ $(BINARIES)/libdoble_complete.a
|
||||||
|
|
||||||
test_stack.o: test_stack.c
|
test_stack.o: test_stack.c
|
||||||
$(CC) -c $(CFLAGS) -I$(unityfolder) $< -o $@
|
$(CC) -c $(CFLAGS) -I$(unityfolder) $< -o $@
|
||||||
|
|
||||||
|
# --- Regeln für Numbers-Tests (Nach Muster gebaut, ohne NUMBERS_TEST_OBJ) ---
|
||||||
|
|
||||||
|
# Linken des Numbers-Test-Executables. Die Abhängigkeiten sind explizit gelistet.
|
||||||
|
$(TEST_NUMBERS_EXEC): numbersTests.o numbers.o bintree.o stack.o
|
||||||
|
# Linkt Test-Objekt, die Implementierung und Abhängigkeiten (bintree, stack) + Unity + Bibliothek
|
||||||
|
$(CC) $(CFLAGS) -I$(unityfolder) numbersTests.o numbers.o bintree.o stack.o $(unityfolder)/unity.c -o $@ $(BINARIES)/libdoble_complete.a
|
||||||
|
|
||||||
|
# Kompilierung der Numbers-Test-Datei.
|
||||||
|
numbersTests.o: numbersTests.c
|
||||||
|
$(CC) -c $(CFLAGS) -I$(unityfolder) $< -o $@
|
||||||
|
|
||||||
|
# --------------------------
|
||||||
|
# Generische Regel für .o-Dateien (Beibehalten)
|
||||||
|
# --------------------------
|
||||||
%.o: %.c
|
%.o: %.c
|
||||||
$(CC) -c $(CFLAGS) $< -o $@
|
$(CC) -c $(CFLAGS) $< -o $@
|
||||||
|
|
||||||
@ -55,9 +81,10 @@ test_stack.o: test_stack.c
|
|||||||
# --------------------------
|
# --------------------------
|
||||||
clean:
|
clean:
|
||||||
ifeq ($(OS),Windows_NT)
|
ifeq ($(OS),Windows_NT)
|
||||||
del /f *.o *.exe doble $(TEST_STACK_EXEC)
|
del /f *.o *.exe doble $(TEST_STACK_EXEC) $(TEST_NUMBERS_EXEC)
|
||||||
else
|
else
|
||||||
rm -f *.o *.exe doble $(TEST_STACK_EXEC)
|
rm -f *.o *.exe doble $(TEST_STACK_EXEC) $(TEST_NUMBERS_EXEC)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
.PHONY: doble_initial doble unitTests $(TEST_STACK_EXEC) clean
|
# --- PHONY-Ziele am Ende (Erweitert und bereinigt) ---
|
||||||
|
.PHONY: doble_initial doble unitTests $(TEST_STACK_EXEC) $(TEST_NUMBERS_EXEC) clean
|
||||||
63
makefile alt
Normal file
63
makefile alt
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
CC = gcc
|
||||||
|
CFLAGS = -g -Wall -lm
|
||||||
|
|
||||||
|
ifeq ($(OS),Windows_NT)
|
||||||
|
include makefile_windows.variables
|
||||||
|
else
|
||||||
|
UNAME = $(shell uname)
|
||||||
|
ifeq ($(UNAME),Linux)
|
||||||
|
include makefile_linux.variables
|
||||||
|
else
|
||||||
|
include makefile_mac.variables
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
raylibfolder = ./raylib
|
||||||
|
unityfolder = ./unity
|
||||||
|
|
||||||
|
# --------------------------
|
||||||
|
# Initiales Programm bauen (zum ausprobieren)
|
||||||
|
# --------------------------
|
||||||
|
doble_initial:
|
||||||
|
$(CC) -o doble_initial $(BINARIES)/libdoble_complete.a
|
||||||
|
|
||||||
|
# --------------------------
|
||||||
|
# Selbst implementiertes Programm bauen
|
||||||
|
# --------------------------
|
||||||
|
program_obj_files = main.o stack.o bintree.o numbers.o timer.o highscore.o
|
||||||
|
|
||||||
|
doble : $(program_obj_files)
|
||||||
|
$(CC) $(CFLAGS) $^ -o doble
|
||||||
|
|
||||||
|
|
||||||
|
# --------------------------
|
||||||
|
# Unit Tests
|
||||||
|
# --------------------------
|
||||||
|
TEST_STACK_EXEC = runtest_stack.exe
|
||||||
|
|
||||||
|
unitTests: $(TEST_STACK_EXEC)
|
||||||
|
@echo "--- Starte Stack Unit Tests ---"
|
||||||
|
@echo "Versuche auszuführen: $(TEST_STACK_EXEC)"
|
||||||
|
$(TEST_STACK_EXEC)
|
||||||
|
@echo "--- Stack Unit Tests abgeschlossen ---"
|
||||||
|
|
||||||
|
$(TEST_STACK_EXEC): test_stack.o stack.o
|
||||||
|
$(CC) $(CFLAGS) -I$(unityfolder) test_stack.o stack.o $(unityfolder)/unity.c -o $@ $(BINARIES)/libdoble_complete.a
|
||||||
|
|
||||||
|
test_stack.o: test_stack.c
|
||||||
|
$(CC) -c $(CFLAGS) -I$(unityfolder) $< -o $@
|
||||||
|
|
||||||
|
%.o: %.c
|
||||||
|
$(CC) -c $(CFLAGS) $< -o $@
|
||||||
|
|
||||||
|
# --------------------------
|
||||||
|
# Clean
|
||||||
|
# --------------------------
|
||||||
|
clean:
|
||||||
|
ifeq ($(OS),Windows_NT)
|
||||||
|
del /f *.o *.exe doble $(TEST_STACK_EXEC)
|
||||||
|
else
|
||||||
|
rm -f *.o *.exe doble $(TEST_STACK_EXEC)
|
||||||
|
endif
|
||||||
|
|
||||||
|
.PHONY: doble_initial doble unitTests $(TEST_STACK_EXEC) clean
|
||||||
120
numbers.c
120
numbers.c
@ -5,22 +5,116 @@
|
|||||||
#include "numbers.h"
|
#include "numbers.h"
|
||||||
#include "bintree.h"
|
#include "bintree.h"
|
||||||
|
|
||||||
//TODO: getDuplicate und createNumbers implementieren
|
// --- Vergleichsfunktionen ---
|
||||||
/* * * 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.
|
// 1. Vergleichsfunktion für qsort
|
||||||
// Returns NULL on errors. Use your implementation of the binary search tree to check for possible duplicates while
|
int compare_unsigned_int(const void *a, const void *b) {
|
||||||
// creating random numbers.
|
unsigned int arg1 = *(const unsigned int*)a;
|
||||||
unsigned int *createNumbers(unsigned int len)
|
unsigned int arg2 = *(const unsigned int*)b;
|
||||||
{
|
|
||||||
|
|
||||||
|
if (arg1 < arg2) return -1;
|
||||||
|
if (arg1 > arg2) return 1;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns only the only number in numbers which is present twice. Returns zero on errors.
|
// 2. Vergleichsfunktion für den Binärbaum
|
||||||
unsigned int getDuplicate(const unsigned int numbers[], unsigned int len)
|
int compare_tree_data(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;
|
||||||
|
if (val1 > val2) return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* * Erzeugt ein Array mit (len - 1) eindeutigen Zufallszahlen und einem Duplikat. */
|
||||||
|
unsigned int *createNumbers(unsigned int len) {
|
||||||
|
if (len == 0) return NULL;
|
||||||
|
|
||||||
|
|
||||||
|
// Wir verwenden eine statische Variable, damit srand nur ein einziges Mal
|
||||||
|
// aufgerufen wird, auch wenn createNumbers mehrfach benutzt wird.
|
||||||
|
static int is_seeded = 0;
|
||||||
|
if (!is_seeded) {
|
||||||
|
srand(time(NULL)); // Initialisiert den Generator mit der aktuellen Zeit
|
||||||
|
is_seeded = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TreeNode *root = NULL;
|
||||||
|
|
||||||
|
unsigned int *numbers = (unsigned int *)malloc(len * sizeof(unsigned int));
|
||||||
|
if (numbers == NULL) return NULL;
|
||||||
|
|
||||||
|
unsigned int count = 0;
|
||||||
|
unsigned int max_val = 2 * len;
|
||||||
|
unsigned int value_to_duplicate = 0;
|
||||||
|
|
||||||
|
// Erzeugen von len - 1 eindeutigen Zufallszahlen
|
||||||
|
while (count < len - 1) {
|
||||||
|
unsigned int random_num = (rand() % max_val) + 1;
|
||||||
|
int is_duplicate = 0;
|
||||||
|
|
||||||
|
// Wir übergeben die Adresse der lokalen Variable. addToTree kopiert den Wert.
|
||||||
|
root = addToTree(root, &random_num, sizeof(unsigned int), compare_tree_data, &is_duplicate);
|
||||||
|
|
||||||
|
if (root == NULL) {
|
||||||
|
free(numbers);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_duplicate == 0) {
|
||||||
|
// Erfolg: Zahl war neu
|
||||||
|
numbers[count] = random_num;
|
||||||
|
count++;
|
||||||
|
|
||||||
|
// Merken für späteres Duplizieren
|
||||||
|
value_to_duplicate = random_num;
|
||||||
|
}
|
||||||
|
// Bei Duplikat (is_duplicate == 1) einfach weitermachen -> while läuft weiter
|
||||||
|
}
|
||||||
|
|
||||||
|
// Duplizieren eines Eintrags an die letzte Stelle
|
||||||
|
if (len > 1) {
|
||||||
|
// Fallback, falls value_to_duplicate noch 0 ist (sollte logisch nicht passieren bei len > 1)
|
||||||
|
if (value_to_duplicate == 0) {
|
||||||
|
value_to_duplicate = numbers[rand() % (len - 1)];
|
||||||
|
}
|
||||||
|
numbers[len - 1] = value_to_duplicate;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Speicher des Baumes freigeben
|
||||||
|
clearTree(root);
|
||||||
|
|
||||||
|
// Mischen (Fisher-Yates Shuffle)
|
||||||
|
for (unsigned int i = len - 1; i > 0; i--) {
|
||||||
|
unsigned int j = rand() % (i + 1);
|
||||||
|
unsigned int temp = numbers[i];
|
||||||
|
numbers[i] = numbers[j];
|
||||||
|
numbers[j] = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return numbers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* * Sortiert das Array und erkennt das Duplikat. */
|
||||||
|
unsigned int getDuplicate(const unsigned int numbers[], unsigned int len) {
|
||||||
|
if (len < 2) return 0;
|
||||||
|
|
||||||
|
unsigned int *sorted_numbers = (unsigned int *)malloc(len * sizeof(unsigned int));
|
||||||
|
if (sorted_numbers == NULL) return 0;
|
||||||
|
|
||||||
|
memcpy(sorted_numbers, numbers, len * sizeof(unsigned int));
|
||||||
|
|
||||||
|
qsort(sorted_numbers, len, sizeof(unsigned int), compare_unsigned_int);
|
||||||
|
|
||||||
|
unsigned int duplicate = 0;
|
||||||
|
for (unsigned int i = 0; i < len - 1; i++) {
|
||||||
|
if (sorted_numbers[i] == sorted_numbers[i+1]) {
|
||||||
|
duplicate = sorted_numbers[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(sorted_numbers);
|
||||||
|
return duplicate;
|
||||||
}
|
}
|
||||||
202
numbersTests.c
Normal file
202
numbersTests.c
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include "numbers.h"
|
||||||
|
#include "unity.h"
|
||||||
|
|
||||||
|
// --- UNITY FRAMEWORK NOTWENDIGKEITEN ---
|
||||||
|
// Diese Funktionen MÜSSEN existieren, damit unity.c gelinkt werden kann.
|
||||||
|
void setUp(void) {
|
||||||
|
// Hier könnte Code stehen, der vor jedem Test läuft.
|
||||||
|
// Wir lassen es leer.
|
||||||
|
}
|
||||||
|
|
||||||
|
void tearDown(void) {
|
||||||
|
// Hier könnte Code stehen, der nach jedem Test aufräumt.
|
||||||
|
// Wir lassen es leer.
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- HILFSFUNKTIONEN ---
|
||||||
|
|
||||||
|
// WICHTIG: Diese Funktion muss VOR ihrer Verwendung definiert sein.
|
||||||
|
// Wir nennen sie "compare_helper" und machen sie "static".
|
||||||
|
static int compare_helper(const void *a, const void *b) {
|
||||||
|
unsigned int arg1 = *(const unsigned int*)a;
|
||||||
|
unsigned int arg2 = *(const unsigned int*)b;
|
||||||
|
|
||||||
|
if (arg1 < arg2) return -1;
|
||||||
|
if (arg1 > arg2) return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int count_occurrences(const unsigned int arr[], unsigned int len, unsigned int value) {
|
||||||
|
unsigned int count = 0;
|
||||||
|
for (unsigned int i = 0; i < len; i++) {
|
||||||
|
if (arr[i] == value) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Makro für einfache Test-Prüfung
|
||||||
|
#define ASSERT_TRUE(condition, message) \
|
||||||
|
do { \
|
||||||
|
if (!(condition)) { \
|
||||||
|
fprintf(stderr, "FEHLER in %s, Zeile %d: %s\n", __FILE__, __LINE__, message); \
|
||||||
|
return 0; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
|
// --- TEST FUNKTIONEN ---
|
||||||
|
|
||||||
|
int test_createNumbers_basic() {
|
||||||
|
// Setzt den Zufallszahlengenerator
|
||||||
|
srand(time(NULL));
|
||||||
|
|
||||||
|
unsigned int len = 10;
|
||||||
|
unsigned int *arr = createNumbers(len);
|
||||||
|
|
||||||
|
ASSERT_TRUE(arr != NULL, "createNumbers sollte bei len=10 nicht NULL zurueckgeben.");
|
||||||
|
|
||||||
|
// Sortiere eine Kopie
|
||||||
|
unsigned int *temp_copy = (unsigned int *)malloc(len * sizeof(unsigned int));
|
||||||
|
if (temp_copy == NULL) return 0;
|
||||||
|
memcpy(temp_copy, arr, len * sizeof(unsigned int));
|
||||||
|
|
||||||
|
// Verwendung der lokalen compare_helper Funktion
|
||||||
|
qsort(temp_copy, len, sizeof(unsigned int), compare_helper);
|
||||||
|
|
||||||
|
unsigned int unique_count = 0;
|
||||||
|
unsigned int duplicate_value = 0;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < len; i++) {
|
||||||
|
// Zählen der eindeutigen Werte
|
||||||
|
if (i == 0 || temp_copy[i] != temp_copy[i-1]) {
|
||||||
|
unique_count++;
|
||||||
|
}
|
||||||
|
// Identifizieren des Duplikats
|
||||||
|
if (i > 0 && temp_copy[i] == temp_copy[i-1]) {
|
||||||
|
duplicate_value = temp_copy[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT_TRUE(unique_count == len - 1, "Array sollte genau len-1 eindeutige Werte enthalten.");
|
||||||
|
ASSERT_TRUE(duplicate_value != 0, "Es sollte genau ein Duplikat gefunden werden.");
|
||||||
|
|
||||||
|
free(temp_copy);
|
||||||
|
free(arr);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int test_createNumbers_edgeCases() {
|
||||||
|
// 1. Test mit minimaler Länge (len=2)
|
||||||
|
unsigned int len_min = 2;
|
||||||
|
unsigned int *arr_min = createNumbers(len_min);
|
||||||
|
ASSERT_TRUE(arr_min != NULL, "createNumbers sollte bei len=2 nicht NULL zurueckgeben.");
|
||||||
|
ASSERT_TRUE(getDuplicate(arr_min, len_min) != 0, "Bei len=2 sollte ein Duplikat gefunden werden.");
|
||||||
|
free(arr_min);
|
||||||
|
|
||||||
|
// 2. Test mit len=0
|
||||||
|
unsigned int *arr_zero = createNumbers(0);
|
||||||
|
ASSERT_TRUE(arr_zero == NULL, "createNumbers sollte bei len=0 NULL zurueckgeben.");
|
||||||
|
|
||||||
|
// 3. Test mit größerer Länge (len=500)
|
||||||
|
unsigned int len_large = 500;
|
||||||
|
unsigned int *arr_large = createNumbers(len_large);
|
||||||
|
ASSERT_TRUE(arr_large != NULL, "createNumbers sollte bei len=500 nicht NULL zurueckgeben.");
|
||||||
|
unsigned int duplicate_val = getDuplicate(arr_large, len_large);
|
||||||
|
ASSERT_TRUE(duplicate_val != 0, "Bei len=500 sollte ein Duplikat gefunden werden.");
|
||||||
|
|
||||||
|
ASSERT_TRUE(count_occurrences(arr_large, len_large, duplicate_val) == 2, "Duplikat sollte genau 2-mal vorkommen.");
|
||||||
|
free(arr_large);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int test_getDuplicate_findsDuplicate() {
|
||||||
|
unsigned int arr1[] = {1, 5, 3, 5, 2};
|
||||||
|
unsigned int len1 = 5;
|
||||||
|
unsigned int result1 = getDuplicate(arr1, len1);
|
||||||
|
ASSERT_TRUE(result1 == 5, "Duplikat 5 sollte gefunden werden.");
|
||||||
|
|
||||||
|
unsigned int arr2[] = {42, 1, 99, 1, 0};
|
||||||
|
unsigned int len2 = 5;
|
||||||
|
unsigned int result2 = getDuplicate(arr2, len2);
|
||||||
|
ASSERT_TRUE(result2 == 1, "Duplikat 1 sollte gefunden werden.");
|
||||||
|
|
||||||
|
// Test mit Duplikat am Anfang/Ende
|
||||||
|
unsigned int arr3[] = {10, 20, 30, 40, 10};
|
||||||
|
unsigned int len3 = 5;
|
||||||
|
unsigned int result3 = getDuplicate(arr3, len3);
|
||||||
|
ASSERT_TRUE(result3 == 10, "Duplikat 10 sollte gefunden werden.");
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int test_getDuplicate_noDuplicateOrEdgeCases() {
|
||||||
|
// 1. Kein Duplikat
|
||||||
|
unsigned int arr1[] = {1, 2, 3, 4};
|
||||||
|
unsigned int len1 = 4;
|
||||||
|
unsigned int result1 = getDuplicate(arr1, len1);
|
||||||
|
ASSERT_TRUE(result1 == 0, "Kein Duplikat sollte 0 zurueckgeben.");
|
||||||
|
|
||||||
|
// 2. Leeres Array
|
||||||
|
unsigned int arr2[] = {};
|
||||||
|
unsigned int len2 = 0;
|
||||||
|
unsigned int result2 = getDuplicate(arr2, len2);
|
||||||
|
ASSERT_TRUE(result2 == 0, "Leeres Array sollte 0 zurueckgeben.");
|
||||||
|
|
||||||
|
// 3. Array mit einem Element
|
||||||
|
unsigned int arr3[] = {5};
|
||||||
|
unsigned int len3 = 1;
|
||||||
|
unsigned int result3 = getDuplicate(arr3, len3);
|
||||||
|
ASSERT_TRUE(result3 == 0, "Array mit einem Element sollte 0 zurueckgeben.");
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// --- HAUPTFUNKTION (Test Runner) ---
|
||||||
|
|
||||||
|
typedef int (*test_func)(void);
|
||||||
|
|
||||||
|
struct {
|
||||||
|
const char *name;
|
||||||
|
test_func func;
|
||||||
|
} tests[] = {
|
||||||
|
{"test_createNumbers_basic", test_createNumbers_basic},
|
||||||
|
{"test_createNumbers_edgeCases", test_createNumbers_edgeCases},
|
||||||
|
{"test_getDuplicate_findsDuplicate", test_getDuplicate_findsDuplicate},
|
||||||
|
{"test_getDuplicate_noDuplicateOrEdgeCases", test_getDuplicate_noDuplicateOrEdgeCases},
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
int total_tests = sizeof(tests) / sizeof(tests[0]);
|
||||||
|
int successful_tests = 0;
|
||||||
|
|
||||||
|
printf("Starte %d Unit-Tests...\n", total_tests);
|
||||||
|
printf("------------------------------------------\n");
|
||||||
|
|
||||||
|
for (int i = 0; i < total_tests; i++) {
|
||||||
|
printf("Teste: %s ... ", tests[i].name);
|
||||||
|
fflush(stdout);
|
||||||
|
if (tests[i].func()) {
|
||||||
|
printf("PASSED \n");
|
||||||
|
successful_tests++;
|
||||||
|
} else {
|
||||||
|
printf("FAILED \n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("------------------------------------------\n");
|
||||||
|
if (successful_tests == total_tests) {
|
||||||
|
printf("ERGEBNIS: ALLE %d TESTS ERFOLGREICH BESTANDEN.\n", total_tests);
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
} else {
|
||||||
|
printf("ERGEBNIS: %d von %d TESTS FEHLGESCHLAGEN.\n", total_tests - successful_tests, total_tests);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user