/** * @file test_mutex.c * @brief Unit tests for mutex */ #include "unity.h" #include "kernel.h" #include "mutex.h" #include "task.h" #include /* Test mutexes */ static Mutex_t test_mutex; static Mutex_t recursive_mutex; /* Test task for mutex contention */ static TaskHandle_t contention_task; static volatile bool task_got_mutex = false; static void mutex_contention_task(void* params) { (void)params; /* Try to lock mutex */ if (mutex_lock(&test_mutex, 1000) == KERNEL_OK) { task_got_mutex = true; mutex_unlock(&test_mutex); } while (1) { kernel_delay(1000); } } /* Setup */ void setUp(void) { kernel_init(); /* Create test mutexes */ mutex_create(&test_mutex, false); mutex_create(&recursive_mutex, true); task_got_mutex = false; } /* Teardown */ void tearDown(void) { kernel_stop(); } /* ============================================================================ * Test Cases * ============================================================================ */ /** * @brief Test mutex creation */ void test_mutex_create(void) { TEST_ASSERT_NULL(mutex_get_owner(&test_mutex)); } /** * @brief Test mutex lock and unlock */ void test_mutex_lock_unlock(void) { TEST_ASSERT_EQUAL(KERNEL_OK, mutex_lock(&test_mutex, 100)); TEST_ASSERT_NOT_NULL(mutex_get_owner(&test_mutex)); TEST_ASSERT_EQUAL(KERNEL_OK, mutex_unlock(&test_mutex)); TEST_ASSERT_NULL(mutex_get_owner(&test_mutex)); } /** * @brief Test recursive mutex */ void test_recursive_mutex(void) { /* Lock recursive mutex multiple times */ TEST_ASSERT_EQUAL(KERNEL_OK, mutex_lock(&recursive_mutex, 100)); TEST_ASSERT_EQUAL(KERNEL_OK, mutex_lock(&recursive_mutex, 100)); TEST_ASSERT_EQUAL(KERNEL_OK, mutex_lock(&recursive_mutex, 100)); /* Unlock same number of times */ TEST_ASSERT_EQUAL(KERNEL_OK, mutex_unlock(&recursive_mutex)); TEST_ASSERT_EQUAL(KERNEL_OK, mutex_unlock(&recursive_mutex)); TEST_ASSERT_EQUAL(KERNEL_OK, mutex_unlock(&recursive_mutex)); } /** * @brief Test non-recursive mutex */ void test_non_recursive_mutex(void) { /* Lock mutex */ TEST_ASSERT_EQUAL(KERNEL_OK, mutex_lock(&test_mutex, 100)); /* Try to lock again */ TEST_ASSERT_EQUAL(KERNEL_RESOURCE_BUSY, mutex_lock(&test_mutex, 0)); /* Unlock */ TEST_ASSERT_EQUAL(KERNEL_OK, mutex_unlock(&test_mutex)); } /** * @brief Test mutex timeout */ void test_mutex_timeout(void) { /* Lock mutex */ TEST_ASSERT_EQUAL(KERNEL_OK, mutex_lock(&test_mutex, 0)); /* Create contention task */ TaskConfig_t config = { .name = "contention", .function = mutex_contention_task, .parameters = NULL, .stack_size = 1024, .priority = 1, .period_ticks = 0 }; contention_task = task_create(&config); kernel_start(); kernel_delay(100); /* Task should not have gotten mutex yet */ TEST_ASSERT_FALSE(task_got_mutex); /* Unlock mutex */ mutex_unlock(&test_mutex); kernel_delay(100); /* Task should have gotten mutex */ TEST_ASSERT_TRUE(task_got_mutex); } /** * @brief Test mutex deletion */ void test_mutex_delete(void) { TEST_ASSERT_EQUAL(KERNEL_OK, mutex_delete(&test_mutex)); } /* ============================================================================ * Test Runner * ============================================================================ */ int main(void) { UNITY_BEGIN(); RUN_TEST(test_mutex_create); RUN_TEST(test_mutex_lock_unlock); RUN_TEST(test_recursive_mutex); RUN_TEST(test_non_recursive_mutex); RUN_TEST(test_mutex_timeout); RUN_TEST(test_mutex_delete); return UNITY_END(); }