text: /*
   * FreeRTOS V202111.00
   * Copyright (C) 2020 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
   *
   * Permission is hereby granted, free of charge, to any person obtaining a copy of
   * this software and associated documentation files (the "Software"), to deal in
   * the Software without restriction, including without limitation the rights to
   * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
   * the Software, and to permit persons to whom the Software is furnished to do so,
   * subject to the following conditions:
   *
   * The above copyright notice and this permission notice shall be included in all
   * copies or substantial portions of the Software.
   *
   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
   * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
   * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
   *
   * https://www.FreeRTOS.org
   * https://github.com/FreeRTOS
   *
   */
  /*! @file recursive_mutex_utest.c */
  
  #include "../queue_utest_common.h"
  
  /* Queue includes */
  #include "FreeRTOS.h"
  #include "FreeRTOSConfig.h"
  #include "semphr.h"
  #include "mock_fake_port.h"
  
  /* ============================  GLOBAL VARIABLES =========================== */
  
  /* ==========================  CALLBACK FUNCTIONS =========================== */
  
  /* ============================= Unity Fixtures ============================= */
  
  void setUp( void )
  {
      commonSetUp();
      xTaskPriorityDisinherit_IgnoreAndReturn( pdFALSE );
  }
  
  void tearDown( void )
  {
      commonTearDown();
  }
  
  void suiteSetUp()
  {
      commonSuiteSetUp();
  }
  
  int suiteTearDown( int numFailures )
  {
      return commonSuiteTearDown( numFailures );
  }
  
  /* ==========================  Helper functions =========================== */
  
  /* =============================  Test Cases ============================== */
  
  /**
   * @brief Test xSemaphoreCreateRecursiveMutex where the call to malloc fails
   * @coverage xQueueCreateMutex
   */
  void test_macro_xSemaphoreCreateRecursiveMutex_malloc_fail( void )
  {
      UnityMalloc_MakeMallocFailAfterCount( 0 );
  
      SemaphoreHandle_t xSemaphore = INVALID_PTR;
  
      xSemaphore = xSemaphoreCreateRecursiveMutex();
  
      /* validate returned semaphore handle */
      TEST_ASSERT_EQUAL( NULL, xSemaphore );
  }
  
  /**
   * @brief Test xSemaphoreCreateRecursiveMutex
   * @details Create a mutex using xSemaphoreCreateRecursiveMutex
   * @coverage xQueueCreateMutex
   */
  void test_macro_xSemaphoreCreateRecursiveMutex_success( void )
  {
      SemaphoreHandle_t xSemaphore = xSemaphoreCreateRecursiveMutex();
  
      /* validate returned semaphore handle */
      TEST_ASSERT_NOT_EQUAL( NULL, xSemaphore );
  
      TEST_ASSERT_EQUAL( QUEUE_T_SIZE, getLastMallocSize() );
  
      TEST_ASSERT_EQUAL( B_SEMPHR_AVAILABLE, uxSemaphoreGetCount( xSemaphore ) );
  
      vSemaphoreDelete( xSemaphore );
  }
  
  /**
   * @brief Test xSemaphoreCreateRecursiveMutexStatic with a null buffer
   * @coverage xQueueCreateMutexStatic
   */
  void test_macro_xSemaphoreCreateRecursiveMutexStatic_nullptr( void )
  {
      SemaphoreHandle_t xSemaphore = INVALID_PTR;
  
      /* Expect that xQueueCreate will assert due to the NULL buffer */
      fakeAssertExpectFail();
  
      xSemaphore = xSemaphoreCreateRecursiveMutexStatic( NULL );
  
      /* Check that configASSERT was called twice */
      fakeAssertVerifyNumAssertsAndClear( 2 );
  
      TEST_ASSERT_EQUAL( NULL, xSemaphore );
      TEST_ASSERT_EQUAL( 0, getLastMallocSize() );
  }
  
  /**
   * @brief Verify that calling xSemaphoreTakeRecursive with a NULL mutex handle causes a configASSERT failure.
   * @coverage xQueueTakeMutexRecursive
   */
  void test_macro_xSemaphoreTakeRecursive_null_handle( void )
  {
      EXPECT_ASSERT_BREAK( xSemaphoreTakeRecursive( NULL, 0 ) );
  }
  
  /**
   * @brief Test xSemaphoreTakeRecursive with a mutex that is not owned by any task.
   * @coverage xQueueTakeMutexRecursive
   */
  void test_macro_xSemaphoreTakeRecursive_not_owned_once( void )
  {
      TaskHandle_t xMutexHolder = ( void * ) ( BaseType_t ) getNextMonotonicTestValue();
  
      SemaphoreHandle_t xSemaphore = xSemaphoreCreateRecursiveMutex();
  
      TEST_ASSERT_EQUAL( B_SEMPHR_AVAILABLE, uxSemaphoreGetCount( xSemaphore ) );
  
      xTaskGetCurrentTaskHandle_ExpectAndReturn( xMutexHolder );
      pvTaskIncrementMutexHeldCount_ExpectAndReturn( xMutexHolder );
  
      TEST_ASSERT_EQUAL( pdTRUE, xSemaphoreTakeRecursive( xSemaphore, 0 ) );
  
      TEST_ASSERT_EQUAL( B_SEMPHR_TAKEN, uxSemaphoreGetCount( xSemaphore ) );
  
      vSemaphoreDelete( xSemaphore );
  }
  
  /**
   * @brief Test xSemaphoreTakeRecursive with a mutex that is already owned by the current task
   * @coverage xQueueTakeMutexRecursive
   */
  void test_macro_xSemaphoreTakeRecursive_self_owned_twice( void )
  {
      TaskHandle_t xMutexHolder = ( void * ) ( BaseType_t ) getNextMonotonicTestValue();
  
      SemaphoreHandle_t xSemaphore = xSemaphoreCreateRecursiveMutex();
  
      TEST_ASSERT_EQUAL( B_SEMPHR_AVAILABLE, uxSemaphoreGetCount( xSemaphore ) );
  
      xTaskGetCurrentTaskHandle_ExpectAndReturn( xMutexHolder );
      pvTaskIncrementMutexHeldCount_ExpectAndReturn( xMutexHolder );
  
      TEST_ASSERT_EQUAL( pdTRUE, xSemaphoreTakeRecursive( xSemaphore, 0 ) );
  
      TEST_ASSERT_EQUAL( B_SEMPHR_TAKEN, uxSemaphoreGetCount( xSemaphore ) );
  
      xTaskGetCurrentTaskHandle_ExpectAndReturn( xMutexHolder );
  
      TEST_ASSERT_EQUAL( pdTRUE, xSemaphoreTakeRecursive( xSemaphore, 0 ) );
  
      TEST_ASSERT_EQUAL( B_SEMPHR_TAKEN, uxSemaphoreGetCount( xSemaphore ) );
  
      vSemaphoreDelete( xSemaphore );
  }
  
  /**
   * @brief Test xSemaphoreTakeRecursive on a mutex that is already owned by a different task
   * @coverage xQueueTakeMutexRecursive
   */
  void test_macro_xSemaphoreTakeRecursive_owned_other_task( void )
  {
      TaskHandle_t xMutexHolder1 = ( void * ) ( BaseType_t ) getNextMonotonicTestValue();
      TaskHandle_t xMutexHolder2 = ( void * ) ( BaseType_t ) getNextMonotonicTestValue();
  
      SemaphoreHandle_t xSemaphore = xSemaphoreCreateRecursiveMutex();
  
      /* Take the recursive mutex with task handle == xMutexHolder1 */
      xTaskGetCurrentTaskHandle_ExpectAndReturn( xMutexHolder1 );
      pvTaskIncrementMutexHeldCount_ExpectAndReturn( xMutexHolder1 );
      TEST_ASSERT_EQUAL( pdTRUE, xSemaphoreTakeRecursive( xSemaphore, 0 ) );
  
      /* Attempt to take the recursive mutex with task handle == xMutexHolder2 */
      xTaskGetCurrentTaskHandle_ExpectAndReturn( xMutexHolder2 );
      TEST_ASSERT_EQUAL( pdFALSE, xSemaphoreTakeRecursive( xSemaphore, 0 ) );
  
      vSemaphoreDelete( xSemaphore );
  }
  
  /**
   * @brief Verify that calling xSemaphoreGiveRecursive with a NULL mutex handle causes a configASSERT failure.
   * @coverage xQueueGiveMutexRecursive
   */
  void test_macro_xSemaphoreGiveRecursive_null_handle( void )
  {
      EXPECT_ASSERT_BREAK( xSemaphoreGiveRecursive( NULL ) );
  }
  
  /**
   * @brief Test xSemaphoreGiveRecursive with a mutex that is not already owned by any task.
   * @coverage xQueueGiveMutexRecursive
   */
  void test_macro_xSemaphoreGiveRecursive_unowned( void )
  {
      TaskHandle_t xMutexHolder = ( void * ) ( BaseType_t ) getNextMonotonicTestValue();
  
      SemaphoreHandle_t xSemaphore = xSemaphoreCreateRecursiveMutex();
  
      TEST_ASSERT_EQUAL( B_SEMPHR_AVAILABLE, uxSemaphoreGetCount( xSemaphore ) );
  
      xTaskGetCurrentTaskHandle_ExpectAndReturn( xMutexHolder );
  
      TEST_ASSERT_EQUAL( pdFALSE, xSemaphoreGiveRecursive( xSemaphore ) );
  
      TEST_ASSERT_EQUAL( B_SEMPHR_AVAILABLE, uxSemaphoreGetCount( xSemaphore ) );
  
      vSemaphoreDelete( xSemaphore );
  }
  
  /**
   * @brief Test xSemaphoreGiveRecursive with a mutex that is not owned by any task with a NULL TaskHandle returned by calls to xTaskGetCurrentTaskHandle.
   * @coverage xQueueGiveMutexRecursive
   */
  void test_macro_xSemaphoreGiveRecursive_unowned_null_taskhandle( void )
  {
      SemaphoreHandle_t xSemaphore = xSemaphoreCreateRecursiveMutex();
  
      TEST_ASSERT_EQUAL( B_SEMPHR_AVAILABLE, uxSemaphoreGetCount( xSemaphore ) );
  
      xTaskGetCurrentTaskHandle_ExpectAndReturn( NULL );
  
      TEST_ASSERT_EQUAL( pdTRUE, xSemaphoreGiveRecursive( xSemaphore ) );
  
      TEST_ASSERT_EQUAL( B_SEMPHR_AVAILABLE, uxSemaphoreGetCount( xSemaphore ) );
  
      vSemaphoreDelete( xSemaphore );
  }
  
  /**
   * @brief Test xSemaphoreGiveRecursive with a mutex that is already owned by the current task
   * @coverage xQueueGiveMutexRecursive
   */
  void test_macro_xSemaphoreGiveRecursive_self_owned( void )
  {
      TaskHandle_t xMutexHolder = ( void * ) ( BaseType_t ) getNextMonotonicTestValue();
  
      SemaphoreHandle_t xSemaphore = xSemaphoreCreateRecursiveMutex();
  
      /* Take the Recursive Mutex from taskHandle == xMutexHolder */
      xTaskGetCurrentTaskHandle_ExpectAndReturn( xMutexHolder );
      pvTaskIncrementMutexHeldCount_ExpectAndReturn( xMutexHolder );
  
      xSemaphoreTakeRecursive( xSemaphore, 0 );
  
      /* Verify that the Recursive Mutex is in the taken state */
      TEST_ASSERT_EQUAL( B_SEMPHR_TAKEN, uxSemaphoreGetCount( xSemaphore ) );
  
      /* call xSemaphoreGiveRecursive to release the Recursive Mutex */
      xTaskGetCurrentTaskHandle_ExpectAndReturn( xMutexHolder );
  
      TEST_ASSERT_EQUAL( pdTRUE, xSemaphoreGiveRecursive( xSemaphore ) );
  
      /* Verify that the Recursive Mutex is now in the available state */
      TEST_ASSERT_EQUAL( B_SEMPHR_AVAILABLE, uxSemaphoreGetCount( xSemaphore ) );
  
      vSemaphoreDelete( xSemaphore );
  }
  
  /**
   * @brief Test xSemaphoreGiveRecursive on a mutex that is already owned by a different task
   * @coverage xQueueGiveMutexRecursive
   */
  void test_macro_xSemaphoreGiveRecursive_owned_other_task( void )
  {
      TaskHandle_t xMutexHolder1 = ( void * ) ( BaseType_t ) getNextMonotonicTestValue();
      TaskHandle_t xMutexHolder2 = ( void * ) ( BaseType_t ) getNextMonotonicTestValue();
  
      SemaphoreHandle_t xSemaphore = xSemaphoreCreateRecursiveMutex();
  
      /* Take the Recursive Mutex from taskHandle == xMutexHolder */
      xTaskGetCurrentTaskHandle_ExpectAndReturn( xMutexHolder1 );
      pvTaskIncrementMutexHeldCount_ExpectAndReturn( xMutexHolder1 );
  
      xSemaphoreTakeRecursive( xSemaphore, 0 );
  
      /* Verify that the Recursive Mutex is in the taken state */
      TEST_ASSERT_EQUAL( B_SEMPHR_TAKEN, uxSemaphoreGetCount( xSemaphore ) );
  
      /* call xSemaphoreGiveRecursive to release the Recursive Mutex */
      xTaskGetCurrentTaskHandle_ExpectAndReturn( xMutexHolder2 );
  
      TEST_ASSERT_EQUAL( pdFALSE, xSemaphoreGiveRecursive( xSemaphore ) );
  
      /* Verify that the Recursive Mutex remains in the taken state */
      TEST_ASSERT_EQUAL( B_SEMPHR_TAKEN, uxSemaphoreGetCount( xSemaphore ) );
  
      vSemaphoreDelete( xSemaphore );
  }
  
  
  /**
   * @brief Call xSemaphoreTakeRecursive and xSemaphoreGiveRecursive each multiple times
   * @coverage xQueueTakeMutexRecursive xQueueGiveMutexRecursive
   */
  void test_macro_xSemaphoreTakeRecursive_xSemaphoreGiveRecursive_recursive( void )
  {
      TaskHandle_t xMutexHolder = ( void * ) ( BaseType_t ) getNextMonotonicTestValue();
  
      SemaphoreHandle_t xSemaphore = xSemaphoreCreateRecursiveMutex();
  
      /* Take the Recursive Mutex */
      xTaskGetCurrentTaskHandle_ExpectAndReturn( xMutexHolder );
      pvTaskIncrementMutexHeldCount_ExpectAndReturn( xMutexHolder );
      xSemaphoreTakeRecursive( xSemaphore, 0 );
  
      /* Verify that the Recursive Mutex is in the taken state */
      TEST_ASSERT_EQUAL( B_SEMPHR_TAKEN, uxSemaphoreGetCount( xSemaphore ) );
  
      /* Take the Recursive Mutex a second time */
      xTaskGetCurrentTaskHandle_ExpectAndReturn( xMutexHolder );
      xSemaphoreTakeRecursive( xSemaphore, 0 );
  
      /* Verify that the Recursive Mutex remains in the taken state */
      TEST_ASSERT_EQUAL( B_SEMPHR_TAKEN, uxSemaphoreGetCount( xSemaphore ) );
  
      /* call xSemaphoreGiveRecursive to release the Recursive Mutex (first time) */
      xTaskGetCurrentTaskHandle_ExpectAndReturn( xMutexHolder );
      TEST_ASSERT_EQUAL( pdTRUE, xSemaphoreGiveRecursive( xSemaphore ) );
  
      /* Verify that the Recursive Mutex remains in the taken state */
      TEST_ASSERT_EQUAL( B_SEMPHR_TAKEN, uxSemaphoreGetCount( xSemaphore ) );
  
      /* call xSemaphoreGiveRecursive to release the Recursive Mutex (second time) */
      xTaskGetCurrentTaskHandle_ExpectAndReturn( xMutexHolder );
      TEST_ASSERT_EQUAL( pdTRUE, xSemaphoreGiveRecursive( xSemaphore ) );
  
      /* Verify that the Recursive Mutex is now in the available state */
      TEST_ASSERT_EQUAL( B_SEMPHR_AVAILABLE, uxSemaphoreGetCount( xSemaphore ) );
  
      vSemaphoreDelete( xSemaphore );
  }
  