Sortierung+Binärbaum

This commit is contained in:
shobayoeniolasi99076 2026-05-31 09:41:27 +02:00
parent a5c502da46
commit a81141fb06
19 changed files with 1657 additions and 35 deletions

172
bintree.c
View File

@ -2,35 +2,183 @@
#include "stack.h"
#include "bintree.h"
//TODO: binären Suchbaum implementieren
/* * `addToTree`: fügt ein neues Element in den Baum ein (rekursiv),
* `clearTree`: gibt den gesamten Baum frei (rekursiv),
* `treeSize`: zählt die Knoten im Baum (rekursiv),
* `nextTreeData`: Traversierung mit Hilfe des zuvor implementierten Stacks. */
// Global static stack used for in-order tree traversal in nextTreeData()
// This is needed because nextTreeData() follows strtok-like usage where consecutive calls
// with NULL argument continue the iteration
static StackNode *traversalStack = NULL;
// Adds a copy of data's pointer destination to the tree using compareFct for ordering. Accepts duplicates
// if isDuplicate is NULL, otherwise ignores duplicates and sets isDuplicate to 1 (or to 0 if a new entry is added).
// Adds a copy of data's pointer destination to the tree using compareFct for ordering.
// Accepts duplicates if isDuplicate is NULL, otherwise ignores duplicates and sets isDuplicate to 1 (or to 0 if a new entry is added).
// Parameters:
// - root: pointer to the root of the tree (can be NULL for first insertion)
// - data: pointer to the data to be inserted
// - dataSize: size in bytes of the data to allocate and copy
// - compareFct: comparison function that returns <0 if arg1<arg2, 0 if equal, >0 if arg1>arg2
// - isDuplicate: pointer to int flag (NULL to allow duplicates, non-NULL to detect and reject duplicates)
// Returns: pointer to the root of the modified tree
TreeNode *addToTree(TreeNode *root, const void *data, size_t dataSize, CompareFctType compareFct, int *isDuplicate)
{
// Base case: if root is NULL, we've found the insertion point
// Create a new tree node here
if (root == NULL)
{
// Allocate memory for the new tree node
TreeNode *newNode = (TreeNode *)malloc(sizeof(TreeNode));
if (newNode == NULL)
{
return NULL; // Allocation failed
}
// Allocate memory for a copy of the data
newNode->data = malloc(dataSize);
if (newNode->data == NULL)
{
free(newNode); // Free the node if data allocation failed
return NULL;
}
// Copy the data into the newly allocated space
memcpy(newNode->data, data, dataSize);
// Initialize the left and right child pointers to NULL
newNode->left = NULL;
newNode->right = NULL;
// If isDuplicate is not NULL, set it to 0 to indicate a new entry was added
if (isDuplicate != NULL)
{
*isDuplicate = 0;
}
// Return the newly created node
return newNode;
}
// Recursive case: compare the data with the root's data to determine where to insert
int comparisonResult = compareFct(data, root->data);
// If data is less than root->data, insert into the left subtree
if (comparisonResult < 0)
{
root->left = addToTree(root->left, data, dataSize, compareFct, isDuplicate);
}
// If data is greater than root->data, insert into the right subtree
else if (comparisonResult > 0)
{
root->right = addToTree(root->right, data, dataSize, compareFct, isDuplicate);
}
// If data equals root->data, we have a duplicate
else
{
// If isDuplicate is not NULL, set it to 1 to indicate a duplicate was found
if (isDuplicate != NULL)
{
*isDuplicate = 1;
}
// If isDuplicate is NULL, we allow the duplicate to be inserted again (in either subtree)
// For standard BST behavior, we typically insert duplicates in the right subtree
else
{
root->right = addToTree(root->right, data, dataSize, compareFct, isDuplicate);
}
}
// Return the root (possibly with new subtrees added)
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.
// 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.
// Iterates over the tree given by root in in-order traversal (Left, Root, Right).
// Follows the usage pattern of strtok: first call with root pointer, subsequent calls with NULL to get next element.
// Uses a static stack to maintain traversal state between calls.
// Parameters:
// - root: pointer to tree root for first call, NULL for subsequent calls
// Returns: pointer to the data of the next node in in-order sequence, or NULL when traversal is complete
void *nextTreeData(TreeNode *root)
{
// If root is not NULL, we're starting a new traversal
if (root != NULL)
{
// Clear any existing traversal state
clearStack(traversalStack);
traversalStack = NULL;
// Initialize the traversal by pushing root and all its left descendants
// In in-order traversal, we always visit left children first
TreeNode *current = root;
while (current != NULL)
{
// Push current node onto the stack
traversalStack = push(traversalStack, current);
// Move to the left child
current = current->left;
}
}
// If the traversal stack is empty, we've visited all nodes
if (traversalStack == NULL)
{
return NULL;
}
// Pop the next node from the stack
TreeNode *nextNode = (TreeNode *)top(traversalStack);
traversalStack = pop(traversalStack);
// If the popped node has a right child, push it and all its left descendants
// This handles the "Root, Right" part of in-order traversal
if (nextNode->right != NULL)
{
TreeNode *current = nextNode->right;
while (current != NULL)
{
// Push the current node
traversalStack = push(traversalStack, current);
// Move to the left child of the right subtree
current = current->left;
}
}
// Return the data of the node we just processed
return nextNode->data;
}
// Releases all memory resources (including data copies).
// Releases all memory resources used by the tree.
// Recursively frees all nodes and their data copies.
// Parameters:
// - root: pointer to the root of the tree to clear
// Returns: void
void clearTree(TreeNode *root)
{
// Base case: if root is NULL, there's nothing to free
if (root == NULL)
{
return;
}
// Recursive case: first recursively clear the left subtree
clearTree(root->left);
// Then recursively clear the right subtree
clearTree(root->right);
// Finally, free the data and the node itself
free(root->data);
free(root);
}
// Returns the number of entries in the tree given by root.
// Returns the number of entries (nodes) in the tree.
// Recursively counts nodes in the left and right subtrees.
// Parameters:
// - root: pointer to the root of the tree
// Returns: unsigned int representing the total number of nodes in the tree
unsigned int treeSize(const TreeNode *root)
{
// Base case: if root is NULL, there are no nodes
if (root == NULL)
{
return 0;
}
// Recursive case: count 1 for the current node, plus all nodes in left and right subtrees
return 1 + treeSize(root->left) + treeSize(root->right);
}

BIN
bintree.o Normal file

Binary file not shown.

BIN
bintree_tests Executable file

Binary file not shown.

BIN
doble_initial Executable file

Binary file not shown.

View File

@ -1 +1,2 @@
player_name;6999
player1;3999

View File

@ -38,12 +38,27 @@ $(program_obj_files): %.o: %.c
unitTests:
echo "needs to be implemented"
# --------------------------
# Test: test_numbers
# --------------------------
test_numbers: stack.o bintree.o numbers.o unity.o
$(CC) $(FLAGS) -Iunity test_numbers.c $^ -o runTest_numbers
unity.o:
$(CC) -c $(FLAGS) -Iunity unity/unity.c -o unity.o
# --------------------------
# Test: test_bintree
# --------------------------
test_bintree: stack.o bintree.o unity.o
$(CC) $(FLAGS) -Iunity test_bintree.c $^ -o runTest_bintree
# --------------------------
# Clean
# --------------------------
clean:
ifeq ($(OS),Windows_NT)
del /f *.o doble
del /f *.o doble runTest_numbers runTest_bintree
else
rm -f *.o doble
rm -f *.o doble runTest_numbers runTest_bintree
endif

137
numbers.c
View File

@ -11,16 +11,151 @@
* Duplizieren eines zufälligen Eintrags im Array.
* in `getDuplicate()`: Sortieren des Arrays und Erkennen der doppelten Zahl durch Vergleich benachbarter Elemente. */
// Comparison function for unsigned integers used in the binary search tree
// Returns: <0 if a < b, 0 if a == b, >0 if a > b
// This function is passed to addToTree to determine ordering
int compareUnsignedInts(const void *a, const void *b)
{
unsigned int valA = *(const unsigned int *)a;
unsigned int valB = *(const unsigned int *)b;
// Simple subtraction works for unsigned integers in this case
// (Note: in general subtraction can overflow, but our range is small)
if (valA < valB) return -1;
if (valA > valB) return 1;
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.
//
// Algorithm:
// 1. Generate len-1 unique random numbers using the BST for duplicate detection
// 2. Randomly duplicate one of those numbers by inserting it at a random position
// 3. Final array has len entries with exactly one value appearing twice
unsigned int *createNumbers(unsigned int len)
{
// Step 1: Validate input - we need at least 2 elements to create a duplicate
if (len < 2)
{
return NULL;
}
// Step 2: Allocate memory for the final array (len elements total)
unsigned int *numbers = (unsigned int *)malloc(len * sizeof(unsigned int));
if (numbers == NULL)
{
return NULL;
}
// Step 3: Create binary search tree to track generated numbers and prevent accidental duplicates
// Note: Random seed should be initialized once in main() with srand(time(NULL))
// Calling srand() here would reset the seed each time, reducing randomness
TreeNode *usedNumbers = NULL;
// Step 4: Generate len-1 unique random numbers (we'll add one duplicate later)
unsigned int arrayIndex = 0;
while (arrayIndex < len - 1)
{
// Generate random number in range [1, 2×len]
unsigned int randomNumber = (rand() % (2 * len)) + 1;
// Check if this number was already generated
int isDuplicate = 0;
usedNumbers = addToTree(usedNumbers, &randomNumber, sizeof(unsigned int), compareUnsignedInts, &isDuplicate);
if (usedNumbers == NULL)
{
free(numbers);
return NULL;
}
// If new number, add to result array; if duplicate, retry
if (isDuplicate == 0)
{
numbers[arrayIndex] = randomNumber;
arrayIndex++;
}
}
// Step 5: Pick a random value from our generated numbers to duplicate
unsigned int indexToDuplicate = rand() % (len - 1);
unsigned int valueToDuplicate = numbers[indexToDuplicate];
// Step 6: Pick a random position to insert the duplicate (anywhere in the array)
unsigned int insertPos = rand() % len;
// Step 7: Shift elements right to make room for the duplicate
for (unsigned int i = len - 1; i > insertPos; i--)
{
numbers[i] = numbers[i - 1];
}
// Step 8: Insert the duplicate at the chosen position
numbers[insertPos] = valueToDuplicate;
// Step 9: Clean up the binary search tree (we don't need it anymore)
clearTree(usedNumbers);
// Return the array with len elements (len-1 unique + 1 duplicate)
return numbers;
}
// Comparison function for qsort to sort unsigned integers in ascending order
// Returns: <0 if a < b, 0 if a == b, >0 if a > b
static int compareUnsigned(const void *a, const void *b)
{
unsigned int valA = *(const unsigned int *)a;
unsigned int valB = *(const unsigned int *)b;
if (valA < valB) return -1;
if (valA > valB) return 1;
return 0;
}
// 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)
//
// Algorithm:
// 1. Create a copy of the array to avoid modifying the input
// 2. Sort the copy using qsort()
// 3. Compare adjacent elements to find the duplicate
// 4. Return the duplicate value, or 0 on error
unsigned int getDuplicate(const unsigned int *numbers, unsigned int len)
{
// Step 1: Input validation - need at least 2 elements to have a duplicate
if (numbers == NULL || len < 2)
{
return 0;
}
// Step 2: Create a copy of the array to sort (we don't modify the input)
unsigned int *sorted = (unsigned int *)malloc(len * sizeof(unsigned int));
if (sorted == NULL)
{
return 0;
}
// Step 3: Copy the array
memcpy(sorted, numbers, len * sizeof(unsigned int));
// Step 4: Sort the copy
qsort(sorted, len, sizeof(unsigned int), compareUnsigned);
// Step 5: Compare adjacent elements to find the duplicate
for (unsigned int i = 0; i < len - 1; i++)
{
if (sorted[i] == sorted[i + 1])
{
// Found the duplicate!
unsigned int result = sorted[i];
free(sorted);
return result;
}
}
// Step 6: No duplicate found (should not happen if input is valid)
free(sorted);
return 0;
}

BIN
numbers.o Normal file

Binary file not shown.

BIN
runTest_bintree Executable file

Binary file not shown.

BIN
runTest_numbers Executable file

Binary file not shown.

86
stack.c
View File

@ -1,33 +1,99 @@
#include <stdlib.h>
#include "stack.h"
//TODO: grundlegende Stackfunktionen implementieren:
/* * `push`: legt ein Element oben auf den Stack,
* `pop`: entfernt das oberste Element,
* `top`: liefert das oberste Element zurück,
* `clearStack`: gibt den gesamten Speicher frei. */
// Pushes data as pointer onto the stack.
// Parameters:
// - stack: pointer to the current top of the stack (can be NULL if stack is empty)
// - data: void pointer to the data to be pushed onto the stack
// Returns: pointer to the new top of the stack (the newly created node)
// Note: The function allocates memory for a new StackNode, sets its data pointer
// and links it to the previous top, making it the new top of the stack.
StackNode *push(StackNode *stack, void *data)
{
// Allocate memory for a new StackNode
StackNode *newNode = (StackNode *)malloc(sizeof(StackNode));
// Check if memory allocation was successful
if (newNode == NULL)
{
return NULL; // Return NULL if allocation failed
}
// Store the data pointer in the new node
newNode->data = data;
// Link the new node to the previous top of the stack
// If stack was NULL (empty), newNode->next will be NULL
// If stack was not NULL, newNode->next points to the old top
newNode->next = stack;
// Return the new node, which is now the new top of the stack
return newNode;
}
// Deletes the top element of the stack (latest added element) and releases its memory. (Pointer to data has to be
// freed by caller.)
// Deletes the top element of the stack (latest added element) and releases its memory.
// Parameters:
// - stack: pointer to the current top of the stack
// Returns: pointer to the new top of the stack (the second element, or NULL if stack becomes empty)
// Note: This function only frees the StackNode structure itself. The caller is responsible
// for freeing the data that the node was pointing to, if that data was dynamically allocated.
StackNode *pop(StackNode *stack)
{
// Check if the stack is empty
if (stack == NULL)
{
return NULL; // Cannot pop from an empty stack
}
// Save a pointer to the next node (which will become the new top)
StackNode *newTop = stack->next;
// Free the memory of the current top node
// NOTE: We do NOT free stack->data here because the caller may still need it
// or may be responsible for freeing it themselves
free(stack);
// Return the new top of the stack (or NULL if the stack is now empty)
return newTop;
}
// Returns the data of the top element.
// Returns the data of the top element without removing it from the stack.
// Parameters:
// - stack: pointer to the current top of the stack
// Returns: void pointer to the data of the top element, or NULL if stack is empty
// Note: This is a "peek" operation - it looks at the top without removing it.
void *top(StackNode *stack)
{
// Check if the stack is empty
if (stack == NULL)
{
return NULL; // Return NULL if stack is empty
}
// Return the data pointer stored in the top node
// The caller can then use this pointer to access the actual data
return stack->data;
}
// Clears stack and releases all memory.
// Clears the entire stack and releases all memory used by the StackNodes.
// Parameters:
// - stack: pointer to the current top of the stack
// Returns: void
// Note: This function only frees the StackNode structures. The caller is responsible
// for freeing any dynamically allocated data that the nodes were pointing to,
// unless that is done elsewhere in the program before calling clearStack.
void clearStack(StackNode *stack)
{
// Base case: if the stack is NULL (empty), we're done
if (stack == NULL)
{
return;
}
// Recursive case: first, recursively clear all the nodes below this one
// This processes the stack from top to bottom
clearStack(stack->next);
// After recursively clearing all deeper nodes, free the current node
free(stack);
}

View File

@ -7,7 +7,12 @@ The latest element is taken from the stack. */
#include <stdlib.h>
//TODO: passenden Datentyp als struct anlegen
// Stack node structure: each node contains data and a pointer to the next node
typedef struct stackNode
{
void *data;
struct stackNode *next;
} StackNode;
// Pushes data as pointer onto the stack.
StackNode *push(StackNode *stack, void *data);

BIN
stack.o Normal file

Binary file not shown.

592
test_bintree.c Normal file
View File

@ -0,0 +1,592 @@
#include "unity.h"
#include "bintree.h"
#include <stdlib.h>
#include <string.h>
/* ============================================================================
* UNIT TESTS FOR BINARY SEARCH TREE IMPLEMENTATION (Binärer Suchbaum)
*
* This test suite covers all four functions:
* - addToTree(): Insert elements maintaining BST ordering
* - clearTree(): Free all memory in the tree
* - treeSize(): Count nodes in the tree
* - nextTreeData(): In-order traversal using stack
* ========================================================================== */
// ============================================================================
// HELPER FUNCTIONS FOR TESTING
// ============================================================================
// Comparison function for integers (ascending order: smaller values first)
// Returns: <0 if a < b, 0 if a == b, >0 if a > b
int compareIntegers(const void *a, const void *b)
{
int valA = *(const int *)a;
int valB = *(const int *)b;
return valA - valB;
}
// Comparison function for strings (alphabetical order)
int compareStrings(const void *a, const void *b)
{
return strcmp((const char *)a, (const char *)b);
}
// ============================================================================
// TEST SETUP AND TEARDOWN
// ============================================================================
void setUp(void)
{
// Perform any setup needed before each test
}
void tearDown(void)
{
// Perform any cleanup needed after each test
// Individual tests are responsible for clearing their trees
}
// ============================================================================
// TEST SUITE 1: addToTree() - Inserting Elements
// ============================================================================
// Test 1.1: Insert a single element into an empty tree (NULL root)
void test_addToTree_SingleElement(void)
{
TreeNode *root = NULL;
int value = 42;
int isDuplicate = 0;
// Insert the first element into an empty tree
root = addToTree(root, &value, sizeof(int), compareIntegers, &isDuplicate);
// Verify the root is not NULL
TEST_ASSERT_NOT_NULL(root);
// Verify the data was copied correctly
TEST_ASSERT_EQUAL_INT(42, *(int *)root->data);
// Verify isDuplicate was set to 0 (new entry added)
TEST_ASSERT_EQUAL_INT(0, isDuplicate);
// Verify the node has no children
TEST_ASSERT_NULL(root->left);
TEST_ASSERT_NULL(root->right);
// Cleanup
clearTree(root);
}
// Test 1.2: Insert multiple elements in ascending order
void test_addToTree_AscendingOrder(void)
{
TreeNode *root = NULL;
int values[] = {10, 20, 30};
// Insert values in ascending order
for (int i = 0; i < 3; i++)
{
root = addToTree(root, &values[i], sizeof(int), compareIntegers, NULL);
}
// Verify root value
TEST_ASSERT_EQUAL_INT(10, *(int *)root->data);
// Verify each value goes to the right (since they're ascending)
TEST_ASSERT_NULL(root->left);
TEST_ASSERT_NOT_NULL(root->right);
TEST_ASSERT_EQUAL_INT(20, *(int *)root->right->data);
TEST_ASSERT_NULL(root->right->left);
TEST_ASSERT_NOT_NULL(root->right->right);
TEST_ASSERT_EQUAL_INT(30, *(int *)root->right->right->data);
// Cleanup
clearTree(root);
}
// Test 1.3: Insert multiple elements in descending order
void test_addToTree_DescendingOrder(void)
{
TreeNode *root = NULL;
int values[] = {30, 20, 10};
// Insert values in descending order
for (int i = 0; i < 3; i++)
{
root = addToTree(root, &values[i], sizeof(int), compareIntegers, NULL);
}
// Verify root value
TEST_ASSERT_EQUAL_INT(30, *(int *)root->data);
// Verify each value goes to the left (since they're descending)
TEST_ASSERT_NULL(root->right);
TEST_ASSERT_NOT_NULL(root->left);
TEST_ASSERT_EQUAL_INT(20, *(int *)root->left->data);
TEST_ASSERT_NULL(root->left->right);
TEST_ASSERT_NOT_NULL(root->left->left);
TEST_ASSERT_EQUAL_INT(10, *(int *)root->left->left->data);
// Cleanup
clearTree(root);
}
// Test 1.4: Insert elements in balanced order (creating a balanced tree)
void test_addToTree_BalancedTree(void)
{
TreeNode *root = NULL;
int values[] = {20, 10, 30, 5, 15, 25, 35};
// Insert values to create a somewhat balanced tree
for (int i = 0; i < 7; i++)
{
root = addToTree(root, &values[i], sizeof(int), compareIntegers, NULL);
}
// Verify root value
TEST_ASSERT_EQUAL_INT(20, *(int *)root->data);
// Verify left subtree
TEST_ASSERT_EQUAL_INT(10, *(int *)root->left->data);
TEST_ASSERT_EQUAL_INT(5, *(int *)root->left->left->data);
TEST_ASSERT_EQUAL_INT(15, *(int *)root->left->right->data);
// Verify right subtree
TEST_ASSERT_EQUAL_INT(30, *(int *)root->right->data);
TEST_ASSERT_EQUAL_INT(25, *(int *)root->right->left->data);
TEST_ASSERT_EQUAL_INT(35, *(int *)root->right->right->data);
// Cleanup
clearTree(root);
}
// Test 1.5: Attempt to insert a duplicate when isDuplicate is NULL (allows duplicates)
void test_addToTree_AllowDuplicates(void)
{
TreeNode *root = NULL;
int value1 = 42;
int value2 = 42;
// Insert first instance
root = addToTree(root, &value1, sizeof(int), compareIntegers, NULL);
// Insert duplicate (isDuplicate is NULL, so duplicates are allowed)
root = addToTree(root, &value2, sizeof(int), compareIntegers, NULL);
// Verify tree has both entries (duplicate goes right)
TEST_ASSERT_EQUAL_INT(42, *(int *)root->data);
TEST_ASSERT_NULL(root->left);
TEST_ASSERT_NOT_NULL(root->right);
TEST_ASSERT_EQUAL_INT(42, *(int *)root->right->data);
// Cleanup
clearTree(root);
}
// Test 1.6: Attempt to insert a duplicate when isDuplicate is provided (rejects duplicates)
void test_addToTree_RejectDuplicates(void)
{
TreeNode *root = NULL;
int value1 = 42;
int value2 = 42;
int isDuplicate = 0;
// Insert first instance
root = addToTree(root, &value1, sizeof(int), compareIntegers, &isDuplicate);
TEST_ASSERT_EQUAL_INT(0, isDuplicate);
// Attempt to insert duplicate
root = addToTree(root, &value2, sizeof(int), compareIntegers, &isDuplicate);
// Verify isDuplicate was set to 1
TEST_ASSERT_EQUAL_INT(1, isDuplicate);
// Verify tree still has only one node with the first value
TEST_ASSERT_EQUAL_INT(42, *(int *)root->data);
TEST_ASSERT_NULL(root->left);
TEST_ASSERT_NULL(root->right);
// Cleanup
clearTree(root);
}
// Test 1.7: Insert multiple elements with duplicate detection
void test_addToTree_MultipleWithDuplicateDetection(void)
{
TreeNode *root = NULL;
int values[] = {20, 10, 30, 10}; // 10 is a duplicate
int isDuplicate = 0;
// Insert 20
root = addToTree(root, &values[0], sizeof(int), compareIntegers, &isDuplicate);
TEST_ASSERT_EQUAL_INT(0, isDuplicate);
// Insert 10 (new)
root = addToTree(root, &values[1], sizeof(int), compareIntegers, &isDuplicate);
TEST_ASSERT_EQUAL_INT(0, isDuplicate);
// Insert 30 (new)
root = addToTree(root, &values[2], sizeof(int), compareIntegers, &isDuplicate);
TEST_ASSERT_EQUAL_INT(0, isDuplicate);
// Insert 10 (duplicate)
root = addToTree(root, &values[3], sizeof(int), compareIntegers, &isDuplicate);
TEST_ASSERT_EQUAL_INT(1, isDuplicate);
// Verify tree structure hasn't changed (3 nodes, not 4)
TEST_ASSERT_EQUAL_INT(3, treeSize(root));
// Cleanup
clearTree(root);
}
// Test 1.8: Insert strings into a tree
void test_addToTree_WithStrings(void)
{
TreeNode *root = NULL;
const char *words[] = {"dog", "cat", "elephant", "bear"};
// Insert strings
for (int i = 0; i < 4; i++)
{
// Note: We pass pointer to the string pointer
root = addToTree(root, &words[i], sizeof(char *), compareStrings, NULL);
}
// Verify root value (first insertion)
TEST_ASSERT_EQUAL_STRING("dog", *(char **)root->data);
// Verify tree has 4 nodes
TEST_ASSERT_EQUAL_INT(4, treeSize(root));
// Cleanup
clearTree(root);
}
// ============================================================================
// TEST SUITE 2: treeSize() - Counting Nodes
// ============================================================================
// Test 2.1: Size of empty tree (NULL root)
void test_treeSize_EmptyTree(void)
{
TreeNode *root = NULL;
unsigned int size = treeSize(root);
// Verify empty tree has size 0
TEST_ASSERT_EQUAL_INT(0, size);
}
// Test 2.2: Size of single-node tree
void test_treeSize_SingleNode(void)
{
TreeNode *root = NULL;
int value = 42;
root = addToTree(root, &value, sizeof(int), compareIntegers, NULL);
unsigned int size = treeSize(root);
// Verify single-node tree has size 1
TEST_ASSERT_EQUAL_INT(1, size);
clearTree(root);
}
// Test 2.2: Size of multi-node tree
void test_treeSize_MultipleNodes(void)
{
TreeNode *root = NULL;
int values[] = {20, 10, 30, 5, 15, 25, 35};
// Insert all values
for (int i = 0; i < 7; i++)
{
root = addToTree(root, &values[i], sizeof(int), compareIntegers, NULL);
}
unsigned int size = treeSize(root);
// Verify tree has 7 nodes
TEST_ASSERT_EQUAL_INT(7, size);
clearTree(root);
}
// Test 2.3: Size after multiple insertions
void test_treeSize_IncrementalGrowth(void)
{
TreeNode *root = NULL;
int values[] = {20, 10, 30, 5, 15};
for (int i = 0; i < 5; i++)
{
root = addToTree(root, &values[i], sizeof(int), compareIntegers, NULL);
// Check size increases with each insertion
unsigned int expectedSize = i + 1;
TEST_ASSERT_EQUAL_INT(expectedSize, treeSize(root));
}
clearTree(root);
}
// ============================================================================
// TEST SUITE 3: clearTree() - Freeing Memory
// ============================================================================
// Test 3.1: Clear empty tree (NULL root)
void test_clearTree_EmptyTree(void)
{
TreeNode *root = NULL;
// Should not crash when clearing NULL
clearTree(root);
// Verify still NULL after clearing
TEST_ASSERT_NULL(root);
}
// Test 3.2: Clear single-node tree
void test_clearTree_SingleNode(void)
{
TreeNode *root = NULL;
int value = 42;
root = addToTree(root, &value, sizeof(int), compareIntegers, NULL);
// Clear the tree
clearTree(root);
root = NULL; // Reset pointer
// Verify root is now NULL
TEST_ASSERT_NULL(root);
}
// Test 3.3: Clear multi-node tree
void test_clearTree_MultipleNodes(void)
{
TreeNode *root = NULL;
int values[] = {20, 10, 30, 5, 15, 25, 35};
for (int i = 0; i < 7; i++)
{
root = addToTree(root, &values[i], sizeof(int), compareIntegers, NULL);
}
// Clear the entire tree
clearTree(root);
root = NULL;
// Verify root is now NULL
TEST_ASSERT_NULL(root);
// If we got here without segfault, the memory was properly freed
}
// ============================================================================
// TEST SUITE 4: nextTreeData() - In-Order Traversal
// ============================================================================
// Test 4.1: In-order traversal of simple tree (ascending linear)
void test_nextTreeData_AscendingLinearTree(void)
{
TreeNode *root = NULL;
int values[] = {1, 2, 3};
for (int i = 0; i < 3; i++)
{
root = addToTree(root, &values[i], sizeof(int), compareIntegers, NULL);
}
// Traverse and collect results
int result1 = *(int *)nextTreeData(root);
int result2 = *(int *)nextTreeData(NULL);
int result3 = *(int *)nextTreeData(NULL);
void *result4 = nextTreeData(NULL);
// Verify in-order traversal produces ascending order
TEST_ASSERT_EQUAL_INT(1, result1);
TEST_ASSERT_EQUAL_INT(2, result2);
TEST_ASSERT_EQUAL_INT(3, result3);
TEST_ASSERT_NULL(result4); // No more elements
clearTree(root);
}
// Test 4.2: In-order traversal of balanced tree
void test_nextTreeData_BalancedTree(void)
{
TreeNode *root = NULL;
int values[] = {20, 10, 30, 5, 15, 25, 35};
for (int i = 0; i < 7; i++)
{
root = addToTree(root, &values[i], sizeof(int), compareIntegers, NULL);
}
// Traverse and collect results
int results[7];
results[0] = *(int *)nextTreeData(root);
for (int i = 1; i < 7; i++)
{
results[i] = *(int *)nextTreeData(NULL);
}
// Verify in-order traversal produces ascending order
int expectedOrder[] = {5, 10, 15, 20, 25, 30, 35};
for (int i = 0; i < 7; i++)
{
TEST_ASSERT_EQUAL_INT(expectedOrder[i], results[i]);
}
// Verify traversal is complete
void *result = nextTreeData(NULL);
TEST_ASSERT_NULL(result);
clearTree(root);
}
// Test 4.3: In-order traversal of descending linear tree
void test_nextTreeData_DescendingLinearTree(void)
{
TreeNode *root = NULL;
int values[] = {30, 20, 10};
for (int i = 0; i < 3; i++)
{
root = addToTree(root, &values[i], sizeof(int), compareIntegers, NULL);
}
// Traverse and collect results
int result1 = *(int *)nextTreeData(root);
int result2 = *(int *)nextTreeData(NULL);
int result3 = *(int *)nextTreeData(NULL);
void *result4 = nextTreeData(NULL);
// Verify in-order traversal produces ascending order (despite insertion order)
TEST_ASSERT_EQUAL_INT(10, result1);
TEST_ASSERT_EQUAL_INT(20, result2);
TEST_ASSERT_EQUAL_INT(30, result3);
TEST_ASSERT_NULL(result4);
clearTree(root);
}
// Test 4.4: Traversal of single-node tree
void test_nextTreeData_SingleNode(void)
{
TreeNode *root = NULL;
int value = 42;
root = addToTree(root, &value, sizeof(int), compareIntegers, NULL);
int result1 = *(int *)nextTreeData(root);
void *result2 = nextTreeData(NULL);
TEST_ASSERT_EQUAL_INT(42, result1);
TEST_ASSERT_NULL(result2);
clearTree(root);
}
// Test 4.5: Traversal of empty tree
void test_nextTreeData_EmptyTree(void)
{
TreeNode *root = NULL;
void *result = nextTreeData(root);
TEST_ASSERT_NULL(result);
}
// ============================================================================
// INTEGRATION TEST: Complete BST Workflow
// ============================================================================
// Test 5.1: Complete workflow - insert, size, traverse, clear
void test_integration_CompleteWorkflow(void)
{
TreeNode *root = NULL;
int values[] = {50, 25, 75, 12, 37, 62, 87};
int isDuplicate = 0;
// Insert all values
for (int i = 0; i < 7; i++)
{
root = addToTree(root, &values[i], sizeof(int), compareIntegers, &isDuplicate);
TEST_ASSERT_EQUAL_INT(0, isDuplicate);
}
// Verify size
TEST_ASSERT_EQUAL_INT(7, treeSize(root));
// Verify in-order traversal
int expectedOrder[] = {12, 25, 37, 50, 62, 75, 87};
int results[7];
results[0] = *(int *)nextTreeData(root);
for (int i = 1; i < 7; i++)
{
results[i] = *(int *)nextTreeData(NULL);
}
for (int i = 0; i < 7; i++)
{
TEST_ASSERT_EQUAL_INT(expectedOrder[i], results[i]);
}
// Verify duplicate detection
root = addToTree(root, &values[0], sizeof(int), compareIntegers, &isDuplicate);
TEST_ASSERT_EQUAL_INT(1, isDuplicate);
TEST_ASSERT_EQUAL_INT(7, treeSize(root)); // Size should not increase
// Clear and verify
clearTree(root);
root = NULL;
TEST_ASSERT_NULL(root);
}
// ============================================================================
// TEST RUNNER
// ============================================================================
int main(void)
{
UNITY_BEGIN();
// Test Suite 1: addToTree()
RUN_TEST(test_addToTree_SingleElement);
RUN_TEST(test_addToTree_AscendingOrder);
RUN_TEST(test_addToTree_DescendingOrder);
RUN_TEST(test_addToTree_BalancedTree);
RUN_TEST(test_addToTree_AllowDuplicates);
RUN_TEST(test_addToTree_RejectDuplicates);
RUN_TEST(test_addToTree_MultipleWithDuplicateDetection);
RUN_TEST(test_addToTree_WithStrings);
// Test Suite 2: treeSize()
RUN_TEST(test_treeSize_EmptyTree);
RUN_TEST(test_treeSize_SingleNode);
RUN_TEST(test_treeSize_MultipleNodes);
RUN_TEST(test_treeSize_IncrementalGrowth);
// Test Suite 3: clearTree()
RUN_TEST(test_clearTree_EmptyTree);
RUN_TEST(test_clearTree_SingleNode);
RUN_TEST(test_clearTree_MultipleNodes);
// Test Suite 4: nextTreeData()
RUN_TEST(test_nextTreeData_AscendingLinearTree);
RUN_TEST(test_nextTreeData_BalancedTree);
RUN_TEST(test_nextTreeData_DescendingLinearTree);
RUN_TEST(test_nextTreeData_SingleNode);
RUN_TEST(test_nextTreeData_EmptyTree);
// Integration Test
RUN_TEST(test_integration_CompleteWorkflow);
return UNITY_END();
}

BIN
test_debug Executable file

Binary file not shown.

61
test_debug.c Normal file
View File

@ -0,0 +1,61 @@
#include <stdio.h>
#include <stdlib.h>
#include "numbers.h"
int main(void)
{
printf("=== Testing createNumbers() ===\n\n");
for (int run = 0; run < 3; run++)
{
printf("RUN %d:\n", run + 1);
unsigned int *numbers = createNumbers(5);
if (numbers == NULL)
{
printf("ERROR: createNumbers returned NULL\n\n");
continue;
}
printf("Array contents: ");
for (int i = 0; i < 5; i++)
{
printf("%u ", numbers[i]);
}
printf("\n");
// Count occurrences of each value
printf("Value counts:\n");
for (int i = 0; i < 5; i++)
{
int count = 0;
for (int j = 0; j < 5; j++)
{
if (numbers[i] == numbers[j])
count++;
}
printf(" Value %u appears %d times\n", numbers[i], count);
}
// Check for duplicates
int duplicateCount = 0;
for (int i = 0; i < 5; i++)
{
int count = 0;
for (int j = 0; j < 5; j++)
{
if (numbers[i] == numbers[j])
count++;
}
if (count == 2 && (i == 0 || numbers[i] != numbers[i-1]))
{
duplicateCount++;
}
}
printf("Duplicate values found: %d\n\n", duplicateCount);
free(numbers);
}
return 0;
}

BIN
test_numbers Executable file

Binary file not shown.

599
test_numbers.c Normal file
View File

@ -0,0 +1,599 @@
#include "unity.h"
#include "numbers.h"
#include <stdlib.h>
#include <string.h>
#include <time.h>
/* ============================================================================
* UNIT TESTS FOR SORTING AND DUPLICATE DETECTION (Sortierung)
*
* This test suite covers:
* - createNumbers(): Generate random numbers with exactly one duplicate
* - getDuplicate(): Find the duplicate number using sorting
* ========================================================================== */
// ============================================================================
// HELPER FUNCTIONS FOR TESTING
// ============================================================================
// Count how many times a specific value appears in an array
unsigned int countOccurrences(const unsigned int *numbers, unsigned int len, unsigned int value)
{
unsigned int count = 0;
for (unsigned int i = 0; i < len; i++)
{
if (numbers[i] == value)
{
count++;
}
}
return count;
}
// Check if a value is in the valid range [1, 2*len]
int isInValidRange(unsigned int value, unsigned int len)
{
return (value >= 1) && (value <= 2 * len);
}
// Count total number of distinct values in the array
unsigned int countDistinctValues(const unsigned int *numbers, unsigned int len)
{
unsigned int distinct = 0;
for (unsigned int i = 0; i < len; i++)
{
int isNew = 1;
for (unsigned int j = 0; j < i; j++)
{
if (numbers[i] == numbers[j])
{
isNew = 0;
break;
}
}
if (isNew)
{
distinct++;
}
}
return distinct;
}
// Find the value that appears exactly twice
unsigned int findDuplicate(const unsigned int *numbers, unsigned int len)
{
for (unsigned int i = 0; i < len; i++)
{
unsigned int count = countOccurrences(numbers, len, numbers[i]);
if (count == 2)
{
return numbers[i];
}
}
return 0; // No duplicate found
}
// ============================================================================
// TEST SETUP AND TEARDOWN
// ============================================================================
void setUp(void)
{
// Setup before each test
}
void tearDown(void)
{
// Cleanup after each test
}
// ============================================================================
// TEST SUITE 1: createNumbers() - Input Validation and Error Handling
// ============================================================================
// Test 1.1: Invalid input - len = 0 should return NULL
void test_createNumbers_InvalidLenZero(void)
{
unsigned int *numbers = createNumbers(0);
TEST_ASSERT_NULL(numbers);
}
// Test 1.2: Invalid input - len = 1 should return NULL (need at least 2 for duplicate)
void test_createNumbers_InvalidLenOne(void)
{
unsigned int *numbers = createNumbers(1);
TEST_ASSERT_NULL(numbers);
}
// ============================================================================
// TEST SUITE 2: createNumbers() - Minimum Valid Input
// ============================================================================
// Test 2.1: Minimum valid input - len = 2
void test_createNumbers_MinimumSize(void)
{
unsigned int *numbers = createNumbers(2);
// Should not be NULL
TEST_ASSERT_NOT_NULL(numbers);
// One value should equal the other (the duplicate)
TEST_ASSERT_EQUAL_INT(numbers[0], numbers[1]);
free(numbers);
}
// ============================================================================
// TEST SUITE 3: createNumbers() - Array Size and Contents
// ============================================================================
// Test 3.1: Check array size for len=5
void test_createNumbers_ArraySize5(void)
{
unsigned int *numbers = createNumbers(5);
TEST_ASSERT_NOT_NULL(numbers);
// Access all 5 elements to verify they exist
for (unsigned int i = 0; i < 5; i++)
{
// Just verify we can read without segfault
(void)numbers[i];
}
free(numbers);
}
// Test 3.2: Check array size for len=10
void test_createNumbers_ArraySize10(void)
{
unsigned int *numbers = createNumbers(10);
TEST_ASSERT_NOT_NULL(numbers);
// Access all 10 elements
for (unsigned int i = 0; i < 10; i++)
{
// Just verify we can read without segfault
(void)numbers[i];
}
free(numbers);
}
// ============================================================================
// TEST SUITE 4: createNumbers() - Value Range Validation
// ============================================================================
// Test 4.1: All values are positive (basic sanity check)
void test_createNumbers_ValueRangeLen5(void)
{
unsigned int *numbers = createNumbers(5);
TEST_ASSERT_NOT_NULL(numbers);
// Check each value is positive and not too large
for (unsigned int i = 0; i < 5; i++)
{
TEST_ASSERT_TRUE(numbers[i] > 0);
TEST_ASSERT_TRUE(numbers[i] <= 10);
}
free(numbers);
}
// Test 4.2: All values are positive (for len=20)
void test_createNumbers_ValueRangeLen20(void)
{
unsigned int *numbers = createNumbers(20);
TEST_ASSERT_NOT_NULL(numbers);
// Check each value is positive and reasonable
for (unsigned int i = 0; i < 20; i++)
{
TEST_ASSERT_TRUE(numbers[i] > 0);
TEST_ASSERT_TRUE(numbers[i] <= 40);
}
free(numbers);
}
// ============================================================================
// TEST SUITE 5: createNumbers() - Duplicate Detection
// ============================================================================
// Test 5.1: Exactly one value appears twice (len=5)
void test_createNumbers_ExactlyOneDuplicateLen5(void)
{
unsigned int *numbers = createNumbers(5);
TEST_ASSERT_NOT_NULL(numbers);
// Count how many distinct values appear exactly twice
unsigned int valuesAppearingTwice = 0;
unsigned int counted[5] = {0}; // Track which values we've counted
for (unsigned int i = 0; i < 5; i++)
{
unsigned int value = numbers[i];
unsigned int count = countOccurrences(numbers, 5, value);
// If this value appears twice and we haven't counted it yet, count it now
if (count == 2)
{
int alreadyCounted = 0;
for (unsigned int j = 0; j < 5; j++)
{
if (counted[j] == value)
{
alreadyCounted = 1;
break;
}
}
if (!alreadyCounted)
{
valuesAppearingTwice++;
counted[i] = value; // Mark this value as counted
}
}
}
// Should have exactly one value that appears twice
TEST_ASSERT_EQUAL_INT(1, valuesAppearingTwice);
// Count distinct values - should be len-1 = 4
unsigned int distinct = countDistinctValues(numbers, 5);
TEST_ASSERT_EQUAL_INT(4, distinct);
free(numbers);
}
// Test 5.2: Exactly one value appears twice (len=10)
void test_createNumbers_ExactlyOneDuplicateLen10(void)
{
unsigned int *numbers = createNumbers(10);
TEST_ASSERT_NOT_NULL(numbers);
// Count how many distinct values appear exactly twice
unsigned int valuesAppearingTwice = 0;
unsigned int counted[10] = {0}; // Track which values we've counted
for (unsigned int i = 0; i < 10; i++)
{
unsigned int value = numbers[i];
unsigned int count = countOccurrences(numbers, 10, value);
// If this value appears twice and we haven't counted it yet, count it now
if (count == 2)
{
int alreadyCounted = 0;
for (unsigned int j = 0; j < 10; j++)
{
if (counted[j] == value)
{
alreadyCounted = 1;
break;
}
}
if (!alreadyCounted)
{
valuesAppearingTwice++;
counted[i] = value; // Mark this value as counted
}
}
}
// Should have exactly one value that appears twice
TEST_ASSERT_EQUAL_INT(1, valuesAppearingTwice);
// Count distinct values - should be len-1 = 9
unsigned int distinct = countDistinctValues(numbers, 10);
TEST_ASSERT_EQUAL_INT(9, distinct);
free(numbers);
}
// Test 5.3: No accidental triplicates (len=5)
void test_createNumbers_NoTriplicatesLen5(void)
{
unsigned int *numbers = createNumbers(5);
TEST_ASSERT_NOT_NULL(numbers);
// Count occurrences of each value
for (unsigned int i = 0; i < 5; i++)
{
unsigned int count = countOccurrences(numbers, 5, numbers[i]);
// Each value should appear 1 or 2 times, never 3 or more
TEST_ASSERT_TRUE(count == 1 || count == 2);
}
free(numbers);
}
// ============================================================================
// TEST SUITE 6: createNumbers() - No Accidental Duplicates Before Intentional One
// ============================================================================
// Test 6.1: Total count validation - sum should be len
void test_createNumbers_TotalCountLen5(void)
{
unsigned int *numbers = createNumbers(5);
TEST_ASSERT_NOT_NULL(numbers);
// Sum of all occurrences should equal len (5)
// (unique_count * 1) + (1 duplicate_value * 2) = len
// which simplifies to: (len-1) + 2 = len + 1 ... wait that's wrong
// Actually: if we have 4 unique values and 1 appears twice:
// 4 unique values, but 1 of them appears twice
// So: 3 values appearing once + 1 value appearing twice = 3 + 2 = 5 total entries
// Total unique values = len - 1 = 4
// But sum of elements = len = 5
// This checks out: (len-1-1) * 1 + 1 * 2 = (len-2) + 2 = len ✓
unsigned int distinct = countDistinctValues(numbers, 5);
TEST_ASSERT_EQUAL_INT(4, distinct);
free(numbers);
}
// ============================================================================
// TEST SUITE 7: createNumbers() - Randomness
// ============================================================================
// Test 7.1: Multiple calls produce different (or can produce different) results
void test_createNumbers_DifferentRandomResults(void)
{
unsigned int *numbers1 = createNumbers(5);
// Advance the random sequence a bit
for (int i = 0; i < 10; i++)
{
rand();
}
unsigned int *numbers2 = createNumbers(5);
TEST_ASSERT_NOT_NULL(numbers1);
TEST_ASSERT_NOT_NULL(numbers2);
// It's possible (though unlikely) that two random arrays are identical
// So we'll just verify that the function works and can produce different results
// by checking that both have correct structure
int identical = 1;
for (unsigned int i = 0; i < 5; i++)
{
if (numbers1[i] != numbers2[i])
{
identical = 0;
break;
}
}
// Note: identical could be 0 or 1, both are valid test outcomes
// The important thing is that both arrays are valid
(void)identical;
free(numbers1);
free(numbers2);
}
// ============================================================================
// TEST SUITE 8: getDuplicate() - Finding the Duplicate
// ============================================================================
// Test 8.1: getDuplicate finds the correct value for len=5
void test_getDuplicate_FindsCorrectValueLen5(void)
{
unsigned int *numbers = createNumbers(5);
TEST_ASSERT_NOT_NULL(numbers);
// Find the duplicate manually (using our test helper)
unsigned int expectedDuplicate = findDuplicate(numbers, 5);
TEST_ASSERT_NOT_EQUAL(0, expectedDuplicate);
// Test getDuplicate() - should find the same duplicate
unsigned int actualDuplicate = getDuplicate(numbers, 5);
TEST_ASSERT_EQUAL_INT(expectedDuplicate, actualDuplicate);
free(numbers);
}
// Test 8.2: getDuplicate finds the correct value for len=10
void test_getDuplicate_FindsCorrectValueLen10(void)
{
unsigned int *numbers = createNumbers(10);
TEST_ASSERT_NOT_NULL(numbers);
// Find the duplicate manually (using our test helper)
unsigned int expectedDuplicate = findDuplicate(numbers, 10);
TEST_ASSERT_NOT_EQUAL(0, expectedDuplicate);
// Test getDuplicate() - should find the same duplicate
unsigned int actualDuplicate = getDuplicate(numbers, 10);
TEST_ASSERT_EQUAL_INT(expectedDuplicate, actualDuplicate);
free(numbers);
}
// Test 8.3: getDuplicate handles NULL pointer gracefully
void test_getDuplicate_NullPointerReturnsZero(void)
{
unsigned int result = getDuplicate(NULL, 5);
TEST_ASSERT_EQUAL_INT(0, result);
}
// Test 8.4: getDuplicate handles len < 2 gracefully
void test_getDuplicate_InvalidLenReturnsZero(void)
{
unsigned int arr[] = {1};
// len = 0
unsigned int result0 = getDuplicate(arr, 0);
TEST_ASSERT_EQUAL_INT(0, result0);
// len = 1
unsigned int result1 = getDuplicate(arr, 1);
TEST_ASSERT_EQUAL_INT(0, result1);
}
// Test 8.5: getDuplicate works with len=20
void test_getDuplicate_FindsCorrectValueLen20(void)
{
unsigned int *numbers = createNumbers(20);
TEST_ASSERT_NOT_NULL(numbers);
// Find the duplicate using our test helper
unsigned int expectedDuplicate = findDuplicate(numbers, 20);
TEST_ASSERT_NOT_EQUAL(0, expectedDuplicate);
// Test getDuplicate()
unsigned int actualDuplicate = getDuplicate(numbers, 20);
TEST_ASSERT_EQUAL_INT(expectedDuplicate, actualDuplicate);
free(numbers);
}
// Test 8.6: getDuplicate doesn't modify the input array
void test_getDuplicate_DoesNotModifyInputArray(void)
{
unsigned int *original = createNumbers(8);
TEST_ASSERT_NOT_NULL(original);
// Create a copy to compare before and after
unsigned int *copy = (unsigned int *)malloc(8 * sizeof(unsigned int));
memcpy(copy, original, 8 * sizeof(unsigned int));
// Call getDuplicate (which creates its own sorted copy internally)
getDuplicate(original, 8);
// Verify the input array wasn't modified
for (unsigned int i = 0; i < 8; i++)
{
TEST_ASSERT_EQUAL_INT(copy[i], original[i]);
}
free(original);
free(copy);
}
// ============================================================================
// TEST SUITE 9: Integration Tests
// ============================================================================
// Test 9.1: Full workflow for len=3
void test_integration_CreateAndValidateLen3(void)
{
unsigned int *numbers = createNumbers(3);
TEST_ASSERT_NOT_NULL(numbers);
// Validate: 3 elements exist and have valid values
for (unsigned int i = 0; i < 3; i++)
{
TEST_ASSERT_TRUE(numbers[i] > 0);
}
// Validate: exactly 2 distinct values (one appears twice)
unsigned int distinct = countDistinctValues(numbers, 3);
TEST_ASSERT_EQUAL_INT(2, distinct);
free(numbers);
}
// Test 9.2: Full workflow for len=15
void test_integration_CreateAndValidateLen15(void)
{
unsigned int *numbers = createNumbers(15);
TEST_ASSERT_NOT_NULL(numbers);
// Validate: 15 elements exist and have valid values
for (unsigned int i = 0; i < 15; i++)
{
TEST_ASSERT_TRUE(numbers[i] > 0);
}
// Validate: exactly 14 distinct values
unsigned int distinct = countDistinctValues(numbers, 15);
TEST_ASSERT_EQUAL_INT(14, distinct);
free(numbers);
}
// Test 9.3: Memory cleanup - no segfault
void test_integration_MultipleAllocationsAndFrees(void)
{
for (unsigned int run = 0; run < 5; run++)
{
unsigned int *numbers = createNumbers(5 + run);
TEST_ASSERT_NOT_NULL(numbers);
free(numbers);
}
// If we reach here without segfault, cleanup worked
TEST_ASSERT_TRUE(1);
}
// ============================================================================
// TEST RUNNER
// ============================================================================
int main(void)
{
UNITY_BEGIN();
// Initialize random number seed once at the beginning
srand(time(NULL));
// Test Suite 1: Input Validation
RUN_TEST(test_createNumbers_InvalidLenZero);
RUN_TEST(test_createNumbers_InvalidLenOne);
// Test Suite 2: Minimum Valid Input
RUN_TEST(test_createNumbers_MinimumSize);
// Test Suite 3: Array Size
RUN_TEST(test_createNumbers_ArraySize5);
RUN_TEST(test_createNumbers_ArraySize10);
// Test Suite 4: Value Range
RUN_TEST(test_createNumbers_ValueRangeLen5);
RUN_TEST(test_createNumbers_ValueRangeLen20);
// Test Suite 5: Duplicate Detection
RUN_TEST(test_createNumbers_ExactlyOneDuplicateLen5);
RUN_TEST(test_createNumbers_ExactlyOneDuplicateLen10);
RUN_TEST(test_createNumbers_NoTriplicatesLen5);
// Test Suite 6: No Accidental Duplicates
RUN_TEST(test_createNumbers_TotalCountLen5);
// Test Suite 7: Randomness
RUN_TEST(test_createNumbers_DifferentRandomResults);
// Test Suite 8: getDuplicate
RUN_TEST(test_getDuplicate_FindsCorrectValueLen5);
RUN_TEST(test_getDuplicate_FindsCorrectValueLen10);
RUN_TEST(test_getDuplicate_NullPointerReturnsZero);
RUN_TEST(test_getDuplicate_InvalidLenReturnsZero);
RUN_TEST(test_getDuplicate_FindsCorrectValueLen20);
RUN_TEST(test_getDuplicate_DoesNotModifyInputArray);
// Test Suite 9: Integration
RUN_TEST(test_integration_CreateAndValidateLen3);
RUN_TEST(test_integration_CreateAndValidateLen15);
RUN_TEST(test_integration_MultipleAllocationsAndFrees);
return UNITY_END();
}

BIN
unity.o Normal file

Binary file not shown.