#include "c_MaxPQ.h" #include #include #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; }