Files

188 lines
7.9 KiB
C
Raw Permalink Normal View History

2026-08-10 01:21:15 +08:00
#include "c_MaxPQ.h"
#include <stdlib.h>
#include <stdio.h>
#define EXPECT_EQ(val1, val2, msg) \
do { \
if ((val1) != (val2)) { printf(" [X] Failed: %s (Expected %d, got %d)\n", msg, (int)(val2), (int)(val1)); return false; } \
} while(0)
// Test complex entity
typedef struct {
int thread_id;
int priority_level; // Primary sorting metric for MaxPQ (higher level extract first)
char tag[16];
} ThreadTask;
// Max-Heap comparator: Returns positive if a > b
int compareTasksByPriority(const void* a, const void* b) {
const ThreadTask* t1 = (const ThreadTask*)a;
const ThreadTask* t2 = (const ThreadTask*)b;
return (t1->priority_level - t2->priority_level);
}
// Test Case: Validates API Errors and Basic Operations
bool test_maxpq_lifecycle_and_errors(void) {
c_MaxPQ_t pq;
// 1. Test invalid parameters during initialization
EXPECT_EQ(c_MaxPQ_Init(NULL, 10, sizeof(ThreadTask), compareTasksByPriority), C_ERR_PARAM, "NULL instance handle validation missing");
EXPECT_EQ(c_MaxPQ_Init(&pq, 10, 0, compareTasksByPriority), C_ERR_PARAM, "Zero element size validation missing");
EXPECT_EQ(c_MaxPQ_Init(&pq, 10, sizeof(ThreadTask), NULL), C_ERR_PARAM, "NULL comparator validation missing");
// 2. Correct initialization
EXPECT_EQ(c_MaxPQ_Init(&pq, 2, sizeof(ThreadTask), compareTasksByPriority), C_ERR_OK, "Valid configuration failed init");
// 3. Test empty bounds lookups
EXPECT_EQ(c_MaxPQ_Peek(&pq) == NULL, true, "Empty queue peek did not yield NULL");
ThreadTask output;
EXPECT_EQ(c_MaxPQ_Pop(&pq, &output), C_ERR_EMPTY, "Empty queue extraction did not throw C_ERR_EMPTY");
// Clean up
c_MaxPQ_Destroy(&pq);
return true;
}
// Test Case: Validates Max Extraction and Dynamic Scale Limits
bool test_maxpq_functional_flow(void) {
c_MaxPQ_t pq;
// Initialize with a tiny capacity of 2 to guarantee scaling logic triggers
c_MaxPQ_Init(&pq, 2, sizeof(ThreadTask), compareTasksByPriority);
ThreadTask tasks[] = {
{ 401, 12, "Low Prio" },
{ 402, 99, "Critical" },
{ 403, 50, "High Prio" },
{ 404, 75, "Urgent" }
};
// Push structures
EXPECT_EQ(c_MaxPQ_Push(&pq, &tasks[0]), C_ERR_OK, "Failed pushing task 0");
EXPECT_EQ(c_MaxPQ_Push(&pq, &tasks[1]), C_ERR_OK, "Failed pushing task 1");
EXPECT_EQ(c_MaxPQ_Push(&pq, &tasks[2]), C_ERR_OK, "Failed pushing task 2 (Scale Trigger)");
EXPECT_EQ(c_MaxPQ_Push(&pq, &tasks[3]), C_ERR_OK, "Failed pushing task 3");
// Verify Peak Element maps to highest priority (99)
ThreadTask* peeked = (ThreadTask*)c_MaxPQ_Peek(&pq);
EXPECT_EQ(peeked != NULL && peeked->priority_level == 99, true, "Peek failed to return max item pointer");
ThreadTask extracted;
// Pop 1: Priority 99 ("Critical")
EXPECT_EQ(c_MaxPQ_Pop(&pq, &extracted), C_ERR_OK, "Extraction loop 1 crashed");
EXPECT_EQ(extracted.thread_id, 402, "Extracted sequence misaligned at item 1");
// Pop 2: Priority 75 ("Urgent")
EXPECT_EQ(c_MaxPQ_Pop(&pq, &extracted), C_ERR_OK, "Extraction loop 2 crashed");
EXPECT_EQ(extracted.thread_id, 404, "Extracted sequence misaligned at item 2");
// Pop 3: Priority 50 ("High Prio")
EXPECT_EQ(c_MaxPQ_Pop(&pq, &extracted), C_ERR_OK, "Extraction loop 3 crashed");
EXPECT_EQ(extracted.thread_id, 403, "Extracted sequence misaligned at item 3");
// Pop 4: Priority 12 ("Low Prio")
EXPECT_EQ(c_MaxPQ_Pop(&pq, &extracted), C_ERR_OK, "Extraction loop 4 crashed");
EXPECT_EQ(extracted.thread_id, 401, "Extracted sequence misaligned at item 4");
// Confirm container has completely emptied out
EXPECT_EQ(pq.size, 0, "Active queue tracking counter failed to reach zero index boundary");
c_MaxPQ_Destroy(&pq);
return true;
}
bool test_maxpq_clear_and_reuse(void) {
c_MaxPQ_t pq;
// Initialize with a capacity of 4
c_MaxPQ_Init(&pq, 4, sizeof(ThreadTask), compareTasksByPriority);
ThreadTask t1 = { 101, 10 };
ThreadTask t2 = { 102, 50 };
ThreadTask t3 = { 103, 30 };
// 1. Populate the priority queue
c_MaxPQ_Push(&pq, &t1);
c_MaxPQ_Push(&pq, &t2);
c_MaxPQ_Push(&pq, &t3);
EXPECT_EQ(pq.size, 3, "Queue size should be 3 before clearing");
c_size_t saved_capacity = pq.capacity;
// 2. Execute Clear Protocol
EXPECT_EQ(c_MaxPQ_Clear(NULL), C_ERR_PARAM, "Clearing NULL should yield C_ERR_PARAM");
EXPECT_EQ(c_MaxPQ_Clear(&pq), C_ERR_OK, "Clearing active queue failed");
// 3. Assert structural properties after clearing
EXPECT_EQ(pq.size, 0, "Queue size must be reset to 0 after clear");
EXPECT_EQ(pq.capacity, saved_capacity, "Capacity should remain unchanged after clear");
EXPECT_EQ(c_MaxPQ_Peek(&pq) == NULL, true, "Cleared queue peek should return NULL");
ThreadTask dummy;
EXPECT_EQ(c_MaxPQ_Pop(&pq, &dummy), C_ERR_EMPTY, "Cleared queue pop should return C_ERR_EMPTY");
// 4. Reuse and re-populate the same queue (Verifying memory reuse)
ThreadTask t4 = { 201, 5 };
ThreadTask t5 = { 202, 95 }; // This should become the new max root
EXPECT_EQ(c_MaxPQ_Push(&pq, &t4), C_ERR_OK, "Pushing to cleared queue failed");
EXPECT_EQ(c_MaxPQ_Push(&pq, &t5), C_ERR_OK, "Pushing second item to cleared queue failed");
EXPECT_EQ(pq.size, 2, "Size did not increment properly after reuse");
// Verify extraction works perfectly post-clear
ThreadTask result;
EXPECT_EQ(c_MaxPQ_Pop(&pq, &result), C_ERR_OK, "Pop post-clear failed");
EXPECT_EQ(result.thread_id, 202, "Max-Heap extraction broke after clearing and reusing queue");
c_MaxPQ_Destroy(&pq);
return true;
}
bool test_maxpq_resize_behavior(void) {
c_MaxPQ_t pq;
// Initialize with a capacity of 4
c_MaxPQ_Init(&pq, 4, sizeof(ThreadTask), compareTasksByPriority);
ThreadTask t1 = { 101, 10 };
ThreadTask t2 = { 102, 50 };
c_MaxPQ_Push(&pq, &t1);
c_MaxPQ_Push(&pq, &t2);
EXPECT_EQ(pq.size, 2, "Initial push setup size should be 2");
EXPECT_EQ(pq.capacity, 4, "Initial capacity should be 4");
// 1. Guard Check: Attempting to shrink capacity below the active item count (size=2) must fail
EXPECT_EQ(c_MaxPQ_Resize(&pq, 1), C_ERR_PARAM, "Shrinking below current size did not fail safely");
EXPECT_EQ(pq.capacity, 4, "Invalid resize operation altered internal capacity incorrectly");
// 2. Expansion Check: Expand capacity from 4 to 10
EXPECT_EQ(c_MaxPQ_Resize(&pq, 10), C_ERR_OK, "Expanding valid memory blocks failed");
EXPECT_EQ(pq.capacity, 10, "Capacity tracker failed to update to 10");
EXPECT_EQ(pq.size, 2, "Active structural data sizes mutated during reallocation shift");
// 3. Contraction Check: Tighten memory footprints to fit data perfectly (shrink capacity to size=2)
EXPECT_EQ(c_MaxPQ_Resize(&pq, 2), C_ERR_OK, "Clamping pool capacity limits down to active size failed");
EXPECT_EQ(pq.capacity, 2, "Capacity tracker failed to collapse down to 2");
// 4. Operational Integrity Check: Verify heap extraction still works flawlessly post-resize
ThreadTask result;
EXPECT_EQ(c_MaxPQ_Pop(&pq, &result), C_ERR_OK, "Pop post-resize failed");
EXPECT_EQ(result.thread_id, 102, "Max element tracking corrupted during pointer re-mapping operations");
c_MaxPQ_Destroy(&pq);
return true;
}
int main(void) {
printf("=== Starting Custom Framework Testing for c_MaxPQ ===\n");
if (test_maxpq_lifecycle_and_errors()) printf(" [PASS] Test 1: Lifecycle Management & Error Guard Protocols Verified\n");
if (test_maxpq_functional_flow()) printf(" [PASS] Test 2: Priority Tree Sifting Loops & Data Escalation Verified\n");
if (test_maxpq_clear_and_reuse()) {
printf(" [PASS] Test: Clear, Capacity Preservation, and Queue Reuse Verified Successfully\n");
}
if (test_maxpq_resize_behavior()) {
printf(" [PASS] Test: Manual Resize, Boundary Guard Protection, and Data Persistence Verified\n");
}
printf("=== All Priority Queue Framework Tests Completed ===\n");
return 0;
}