2021-11-30 14:51:24 +01:00

1382 lines
56 KiB
C

/*
* 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 stream_buffer_utest.c */
/* C runtime includes. */
#include <stdlib.h>
#include <stdbool.h>
/* Stream Buffer includes */
#include "FreeRTOS.h"
#include "FreeRTOSConfig.h"
#include "stream_buffer.h"
/* Test includes. */
#include "unity.h"
#include "unity_memory.h"
#include "CException.h"
/* Mock includes. */
#include "mock_task.h"
#include "mock_fake_assert.h"
#include "mock_fake_port.h"
/**
* @brief Sample size in bytes of the stream buffer used for test.
* The size is kept short enough so that the buffer can be allocated on stack.
*/
#define TEST_STREAM_BUFFER_SIZE ( 64U )
/**
* @brief Sample trigger level in bytes used for stream buffer tests.
* When a receiver task is blocked waiting for data, trigger level determines how much bytes should
* be available before which receiver task can be unblocked.
*/
#define TEST_STREAM_BUFFER_TRIGGER_LEVEL ( 32U )
/**
* @brief Maximum unsigned long value that can be passed as a stream buffer size so as to
* trigger an integer overflow.
*/
#define TEST_STREAM_BUFFER_MAX_UINT_SIZE ( ~( size_t ) ( 0UL ) )
/**
* @brief A value used to test setting and getting stream buffer number.
*/
#define TEST_STREAM_BUFFER_NUMBER ( 0xFFU )
/**
* @brief Wait ticks passed into from tests if the stream buffer is full while sending data or
* empty while receiving data.
*/
#define TEST_STREAM_BUFFER_WAIT_TICKS ( 1000U )
/**
* @brief CException code for when a configASSERT should be intercepted.
*/
#define configASSERT_E 0xAA101
/**
* @brief Expect a configASSERT from the function called.
* Break out of the called function when this occurs.
* @details Use this macro when the call passed in as a parameter is expected
* to cause invalid memory access.
*/
#define EXPECT_ASSERT_BREAK( call ) \
do \
{ \
shouldAbortOnAssertion = true; \
CEXCEPTION_T e = CEXCEPTION_NONE; \
Try \
{ \
call; \
TEST_FAIL(); \
} \
Catch( e ) \
{ \
TEST_ASSERT_EQUAL( configASSERT_E, e ); \
} \
} while( 0 )
/* ============================ GLOBAL VARIABLES =========================== */
/**
* @brief Global counter for the number of assertions in code.
*/
static int assertionFailed = 0;
/**
* @brief Global counter to keep track of how many times a sender task was woken up by a task receiving from the stream buffer.
*/
static int senderTaskWoken = 0;
/**
* @brief Global counter to keep track of how many times a receiver task was woken up by a task sending to the buffer.
*/
static int receiverTaskWoken = 0;
/**
* @brief Dummy sender task handle to which the stream buffer receive APIs will send notification.
*/
static TaskHandle_t senderTask = ( TaskHandle_t ) ( 0xAABBCCDD );
/**
* @brief Dummy receiver task handle to which the stream buffer send APIs will send notifications.
*/
static TaskHandle_t receiverTask = ( TaskHandle_t ) ( 0xABCDEEFF );
/**
* @brief Global Stream buffer handle used for tests.
*/
static StreamBufferHandle_t xStreamBuffer;
/**
* @brief Flag which denotes if test need to abort on assertion.
*/
static BaseType_t shouldAbortOnAssertion;
/**
* @brief Variable used to record the total dynamic size allocated in a test.
*/
static size_t dynamicMemoryAllocated = 0;
/* ========================== CALLBACK FUNCTIONS =========================== */
void * pvPortMalloc( size_t xSize )
{
dynamicMemoryAllocated += xSize;
return unity_malloc( xSize );
}
void vPortFree( void * pv )
{
return unity_free( pv );
}
static void vFakeAssertStub( bool x,
char * file,
int line,
int cmock_num_calls )
{
if( !x )
{
assertionFailed++;
if( shouldAbortOnAssertion == pdTRUE )
{
Throw( configASSERT_E );
}
}
}
static BaseType_t streamBufferReceiveCallback( UBaseType_t uxIndexToWaitOn,
uint32_t ulBitsToClearOnEntry,
uint32_t ulBitsToClearOnExit,
uint32_t * pulNotificationValue,
TickType_t xTicksToWait,
int cmock_num_calls )
{
uint8_t data[ TEST_STREAM_BUFFER_SIZE ] = { 0 };
size_t dataReceived = 0;
/* Receive enough bytes (full size) from stream buffer to wake up sender task. */
dataReceived = xStreamBufferReceive( xStreamBuffer, data, TEST_STREAM_BUFFER_SIZE, 0 );
TEST_ASSERT_EQUAL( TEST_STREAM_BUFFER_SIZE, dataReceived );
return pdTRUE;
}
static BaseType_t streamBufferReceiveFromISRCallback( UBaseType_t uxIndexToWaitOn,
uint32_t ulBitsToClearOnEntry,
uint32_t ulBitsToClearOnExit,
uint32_t * pulNotificationValue,
TickType_t xTicksToWait,
int cmock_num_calls )
{
uint8_t data[ TEST_STREAM_BUFFER_SIZE ] = { 0 };
size_t dataReceived = 0;
BaseType_t senderTaskWokenFromISR = pdFALSE;
/* Receive enough bytes (full size) from stream buffer to wake up sender task. */
dataReceived = xStreamBufferReceiveFromISR( xStreamBuffer, data, TEST_STREAM_BUFFER_SIZE, &senderTaskWokenFromISR );
TEST_ASSERT_EQUAL( pdTRUE, senderTaskWokenFromISR );
TEST_ASSERT_EQUAL( TEST_STREAM_BUFFER_SIZE, dataReceived );
return pdTRUE;
}
static BaseType_t resetWhenBlockedCallback( UBaseType_t uxIndexToWaitOn,
uint32_t ulBitsToClearOnEntry,
uint32_t ulBitsToClearOnExit,
uint32_t * pulNotificationValue,
TickType_t xTicksToWait,
int cmock_num_calls )
{
BaseType_t status;
/* Reset when the task is blocked on stream buffer, should fail and return pdFAIL. */
status = xStreamBufferReset( xStreamBuffer );
TEST_ASSERT_EQUAL( pdFAIL, status );
return pdTRUE;
}
static BaseType_t sendCompletedFromISRCallback( UBaseType_t uxIndexToWaitOn,
uint32_t ulBitsToClearOnEntry,
uint32_t ulBitsToClearOnExit,
uint32_t * pulNotificationValue,
TickType_t xTicksToWait,
int cmock_num_calls )
{
BaseType_t status = pdFALSE, highPriorityTaskWoken = pdFALSE;
/* Executing the send completed API from ISR should unblock a high priority task waiting to receive from stream buffer. */
status = xStreamBufferSendCompletedFromISR( xStreamBuffer, &highPriorityTaskWoken );
TEST_ASSERT_EQUAL( pdTRUE, status );
TEST_ASSERT_EQUAL( pdTRUE, highPriorityTaskWoken );
return pdTRUE;
}
static BaseType_t receiveCompletedFromISRCallback( UBaseType_t uxIndexToWaitOn,
uint32_t ulBitsToClearOnEntry,
uint32_t ulBitsToClearOnExit,
uint32_t * pulNotificationValue,
TickType_t xTicksToWait,
int cmock_num_calls )
{
BaseType_t status = pdFALSE, highPriorityTaskWoken = pdFALSE;
/* Executing the receive completed API from ISR should unblock a high priority task waiting to send to stream buffer. */
status = xStreamBufferReceiveCompletedFromISR( xStreamBuffer, &highPriorityTaskWoken );
TEST_ASSERT_EQUAL( pdTRUE, status );
TEST_ASSERT_EQUAL( pdTRUE, highPriorityTaskWoken );
return pdTRUE;
}
static BaseType_t senderTaskNotificationCallback( TaskHandle_t xTaskToNotify,
UBaseType_t uxIndexToNotify,
uint32_t ulValue,
eNotifyAction eAction,
uint32_t * pulPreviousNotificationValue,
int cmock_num_calls )
{
TEST_ASSERT_EQUAL( senderTask, xTaskToNotify );
senderTaskWoken++;
return pdTRUE;
}
static BaseType_t senderTaskNotificationFromISRCallback( TaskHandle_t xTaskToNotify,
UBaseType_t uxIndexToNotify,
uint32_t ulValue,
eNotifyAction eAction,
uint32_t * pulPreviousNotificationValue,
BaseType_t * pxHigherPriorityTaskWoken,
int cmock_num_calls )
{
TEST_ASSERT_EQUAL( senderTask, xTaskToNotify );
senderTaskWoken++;
*pxHigherPriorityTaskWoken = pdTRUE;
return pdTRUE;
}
static BaseType_t streamBufferSendCallback( UBaseType_t uxIndexToWaitOn,
uint32_t ulBitsToClearOnEntry,
uint32_t ulBitsToClearOnExit,
uint32_t * pulNotificationValue,
TickType_t xTicksToWait,
int cmock_num_calls )
{
uint8_t data[ TEST_STREAM_BUFFER_TRIGGER_LEVEL ] = { 0 };
size_t dataSent = 0;
/* Send enough (trigger level) bytes to stream buffer to wake up the receiver Task. */
dataSent = xStreamBufferSend( xStreamBuffer, data, TEST_STREAM_BUFFER_TRIGGER_LEVEL, 0 );
TEST_ASSERT_EQUAL( TEST_STREAM_BUFFER_TRIGGER_LEVEL, dataSent );
return pdTRUE;
}
static BaseType_t streamBufferSendFromISRCallback( UBaseType_t uxIndexToWaitOn,
uint32_t ulBitsToClearOnEntry,
uint32_t ulBitsToClearOnExit,
uint32_t * pulNotificationValue,
TickType_t xTicksToWait,
int cmock_num_calls )
{
uint8_t data[ TEST_STREAM_BUFFER_TRIGGER_LEVEL ] = { 0 };
size_t dataSent = 0;
BaseType_t receiverTaskWokenFromISR = pdFALSE;
/* Send enough (trigger level) bytes to stream buffer to wake up the receiver Task. */
dataSent = xStreamBufferSendFromISR( xStreamBuffer, data, TEST_STREAM_BUFFER_TRIGGER_LEVEL, &receiverTaskWokenFromISR );
TEST_ASSERT_EQUAL( pdTRUE, receiverTaskWokenFromISR );
TEST_ASSERT_EQUAL( TEST_STREAM_BUFFER_TRIGGER_LEVEL, dataSent );
return pdTRUE;
}
static BaseType_t sendLessThanTriggerLevelBytesCallback( UBaseType_t uxIndexToWaitOn,
uint32_t ulBitsToClearOnEntry,
uint32_t ulBitsToClearOnExit,
uint32_t * pulNotificationValue,
TickType_t xTicksToWait,
int cmock_num_calls )
{
uint8_t data[ TEST_STREAM_BUFFER_TRIGGER_LEVEL ] = { 0 };
size_t dataSent = 0;
/* Sending less than trigger level bytes should not wake up the receiver Task. */
dataSent = xStreamBufferSend( xStreamBuffer, data, TEST_STREAM_BUFFER_TRIGGER_LEVEL - 1, 0 );
TEST_ASSERT_EQUAL( TEST_STREAM_BUFFER_TRIGGER_LEVEL - 1, dataSent );
return pdTRUE;
}
static BaseType_t sendLessThanTriggerLevelBytesFromISRCallback( UBaseType_t uxIndexToWaitOn,
uint32_t ulBitsToClearOnEntry,
uint32_t ulBitsToClearOnExit,
uint32_t * pulNotificationValue,
TickType_t xTicksToWait,
int cmock_num_calls )
{
uint8_t data[ TEST_STREAM_BUFFER_TRIGGER_LEVEL ] = { 0 };
size_t dataSent = 0;
BaseType_t receiverTaskWokenFromISR = pdFALSE;
/* Sending less than trigger level bytes should not wake up the receiver Task. */
dataSent = xStreamBufferSendFromISR( xStreamBuffer, data, TEST_STREAM_BUFFER_TRIGGER_LEVEL - 1, &receiverTaskWokenFromISR );
TEST_ASSERT_EQUAL( pdFALSE, receiverTaskWokenFromISR );
TEST_ASSERT_EQUAL( TEST_STREAM_BUFFER_TRIGGER_LEVEL - 1, dataSent );
return pdTRUE;
}
static BaseType_t receiverTaskNotificationFromISRCallback( TaskHandle_t xTaskToNotify,
UBaseType_t uxIndexToNotify,
uint32_t ulValue,
eNotifyAction eAction,
uint32_t * pulPreviousNotificationValue,
BaseType_t * pxHigherPriorityTaskWoken,
int cmock_num_calls )
{
TEST_ASSERT_EQUAL( receiverTask, xTaskToNotify );
receiverTaskWoken++;
*pxHigherPriorityTaskWoken = pdTRUE;
return pdTRUE;
}
static BaseType_t receiverTaskNotificationCallback( TaskHandle_t xTaskToNotify,
UBaseType_t uxIndexToNotify,
uint32_t ulValue,
eNotifyAction eAction,
uint32_t * pulPreviousNotificationValue,
int cmock_num_calls )
{
TEST_ASSERT_EQUAL( receiverTask, xTaskToNotify );
receiverTaskWoken++;
return pdTRUE;
}
/*******************************************************************************
* Unity fixtures
******************************************************************************/
void setUp( void )
{
assertionFailed = 0;
xStreamBuffer = NULL;
senderTaskWoken = 0;
receiverTaskWoken = 0;
shouldAbortOnAssertion = pdTRUE;
dynamicMemoryAllocated = 0;
mock_task_Init();
mock_fake_assert_Init();
mock_fake_port_Init();
vFakePortEnterCriticalSection_Ignore();
vFakePortExitCriticalSection_Ignore();
ulFakePortSetInterruptMaskFromISR_IgnoreAndReturn( 0U );
vFakePortClearInterruptMaskFromISR_Ignore();
vFakeAssert_StubWithCallback( vFakeAssertStub );
/* Track calls to malloc / free */
UnityMalloc_StartTest();
}
/*! called before each test case */
void tearDown( void )
{
TEST_ASSERT_EQUAL_MESSAGE( 0, assertionFailed, "Assertion check failed in code." );
UnityMalloc_EndTest();
mock_task_Verify();
mock_task_Destroy();
mock_fake_assert_Verify();
mock_fake_assert_Destroy();
mock_fake_port_Verify();
mock_fake_port_Destroy();
}
/*! called at the beginning of the whole suite */
void suiteSetUp()
{
}
/*! called at the end of the whole suite */
int suiteTearDown( int numFailures )
{
return numFailures;
}
static void validate_stream_buffer_init_state( StreamBufferHandle_t xStreamBuffer,
size_t bufferSize )
{
TEST_ASSERT_TRUE( xStreamBufferIsEmpty( xStreamBuffer ) );
TEST_ASSERT_FALSE( xStreamBufferIsFull( xStreamBuffer ) );
TEST_ASSERT_EQUAL( bufferSize, xStreamBufferSpacesAvailable( xStreamBuffer ) );
TEST_ASSERT_EQUAL( 0U, xStreamBufferBytesAvailable( xStreamBuffer ) );
TEST_ASSERT_EQUAL( 0U, xStreamBufferNextMessageLengthBytes( xStreamBuffer ) );
TEST_ASSERT_EQUAL( 0, ucStreamBufferGetStreamBufferType( xStreamBuffer ) );
}
static void validate_and_clear_assertions( void )
{
TEST_ASSERT_EQUAL( 1, assertionFailed );
assertionFailed = 0;
}
/* ============================== Test Cases ============================== */
/**
* @brief Validates that stream buffer of sample size is created successfully.
*/
void test_xStreamBufferCreate_success( void )
{
xStreamBuffer = xStreamBufferCreate( TEST_STREAM_BUFFER_SIZE, TEST_STREAM_BUFFER_TRIGGER_LEVEL );
TEST_ASSERT_NOT_EQUAL( NULL, xStreamBuffer );
validate_stream_buffer_init_state( xStreamBuffer, TEST_STREAM_BUFFER_SIZE );
/* Verify internal memory allocated is equal to size of the struct + buffer size + 1. */
TEST_ASSERT_EQUAL( TEST_STREAM_BUFFER_SIZE + 1U + sizeof( StaticStreamBuffer_t ), dynamicMemoryAllocated );
/* Set a stream buffer number and get it. */
vStreamBufferSetStreamBufferNumber( xStreamBuffer, TEST_STREAM_BUFFER_NUMBER );
TEST_ASSERT_EQUAL( TEST_STREAM_BUFFER_NUMBER, uxStreamBufferGetStreamBufferNumber( xStreamBuffer ) );
vStreamBufferDelete( xStreamBuffer );
}
/**
* Returns NULL if there is an integer overflow in the buffer size.
*/
void test_xStreamBufferCreate_integer_overflow( void )
{
xStreamBuffer = xStreamBufferCreate( TEST_STREAM_BUFFER_MAX_UINT_SIZE, TEST_STREAM_BUFFER_TRIGGER_LEVEL );
TEST_ASSERT_EQUAL( NULL, xStreamBuffer );
}
/**
* @brief Returns NULL if internal memory allocation of the stream buffer fails.
*/
void test_xStreamBufferCreate_malloc_fail( void )
{
UnityMalloc_MakeMallocFailAfterCount( 0 );
xStreamBuffer = xStreamBufferCreate( TEST_STREAM_BUFFER_SIZE, TEST_STREAM_BUFFER_TRIGGER_LEVEL );
TEST_ASSERT_EQUAL( NULL, xStreamBuffer );
}
/**
* @brief Assertion fails if a zero buffer size is passed as the parameter.
*/
void test_xStreamBufferCreate_zero_buffer_size( void )
{
EXPECT_ASSERT_BREAK( ( void ) xStreamBufferCreate( 0, TEST_STREAM_BUFFER_TRIGGER_LEVEL ) );
validate_and_clear_assertions();
}
/**
* @brief Assertion fails if trigger level is greater than the stream buffer size.
*/
void test_xStreamBufferCreate_invalid_trigger_level( void )
{
EXPECT_ASSERT_BREAK( ( void ) xStreamBufferCreate( TEST_STREAM_BUFFER_SIZE, ( TEST_STREAM_BUFFER_SIZE + 1 ) ) );
validate_and_clear_assertions();
}
/**
* @brief Assertion fails while trying to delete a null stream buffer.
*/
void test_xStreamBufferDelete_null_stream_buffer( void )
{
EXPECT_ASSERT_BREAK( vStreamBufferDelete( NULL ) );
validate_and_clear_assertions();
}
/**
* @brief Validates stream buffer create using a static buffer is successful.
*/
void test_xStreamBufferCreateStatic_success( void )
{
StaticStreamBuffer_t streamBufferStruct;
/* The size of stream buffer array should be one greater than the required size of stream buffer. */
uint8_t streamBufferArray[ TEST_STREAM_BUFFER_SIZE + 1 ] = { 0 };
xStreamBuffer = xStreamBufferCreateStatic( sizeof( streamBufferArray ), TEST_STREAM_BUFFER_TRIGGER_LEVEL, streamBufferArray, &streamBufferStruct );
TEST_ASSERT_NOT_NULL( xStreamBuffer );
validate_stream_buffer_init_state( xStreamBuffer, TEST_STREAM_BUFFER_SIZE );
vStreamBufferDelete( xStreamBuffer );
}
/**
* @brief Validates stream buffer static create fails if NULL array is passed.
*/
void test_xStreamBufferCreateStatic_null_array( void )
{
StaticStreamBuffer_t streamBufferStruct;
/* The size of stream buffer array should be one greater than the required size of stream buffer. */
uint8_t streamBufferArray[ TEST_STREAM_BUFFER_SIZE + 1 ] = { 0 };
/* Tests should abort if assertion is enabled or return NULL. */
shouldAbortOnAssertion = pdFALSE;
/* Returns NULL if a NULL pointer is passed as the stream buffer storage area. */
xStreamBuffer = xStreamBufferCreateStatic( sizeof( streamBufferArray ), TEST_STREAM_BUFFER_TRIGGER_LEVEL, NULL, &streamBufferStruct );
TEST_ASSERT_NULL( xStreamBuffer );
validate_and_clear_assertions();
}
/**
* @brief Validates stream buffer static create fails if NULL struct is passed.
*/
void test_xStreamBufferCreateStatic_invalid_null_struct( void )
{
/* The size of stream buffer array should be one greater than the required size of stream buffer. */
uint8_t streamBufferArray[ TEST_STREAM_BUFFER_SIZE + 1 ] = { 0 };
/* Tests should abort if assertion is enabled or return NULL. */
shouldAbortOnAssertion = pdFALSE;
/* Returns NULL if a NULL struct is passed as a parameter. */
xStreamBuffer = xStreamBufferCreateStatic( sizeof( streamBufferArray ), TEST_STREAM_BUFFER_TRIGGER_LEVEL, streamBufferArray, NULL );
TEST_ASSERT_NULL( xStreamBuffer );
validate_and_clear_assertions();
}
/**
* @brief Validates stream buffer static create fails on passing invalid trigger level
*/
void test_xStreamBufferCreateStatic_invalid_trigger_level( void )
{
StaticStreamBuffer_t streamBufferStruct;
/* The size of stream buffer array should be one greater than the required size of stream buffer. */
uint8_t streamBufferArray[ TEST_STREAM_BUFFER_SIZE + 1 ] = { 0 };
EXPECT_ASSERT_BREAK( ( void ) xStreamBufferCreateStatic( sizeof( streamBufferArray ), TEST_STREAM_BUFFER_SIZE + 2, streamBufferArray, &streamBufferStruct ) );
validate_and_clear_assertions();
}
/**
* @brief Validates a task is able to send upto buffer space available without blocking.
*/
void test_xStreamBufferSend_success( void )
{
uint8_t data[ TEST_STREAM_BUFFER_SIZE ] = { 0 };
size_t sent = 0;
vTaskSetTimeOutState_Ignore();
vTaskSuspendAll_Ignore();
xTaskResumeAll_IgnoreAndReturn( pdTRUE );
/* Create a stream buffer of the default test sample size. */
xStreamBuffer = xStreamBufferCreate( TEST_STREAM_BUFFER_SIZE, TEST_STREAM_BUFFER_TRIGGER_LEVEL );
TEST_ASSERT_NOT_NULL( xStreamBuffer );
TEST_ASSERT_EQUAL( TEST_STREAM_BUFFER_SIZE, xStreamBufferSpacesAvailable( xStreamBuffer ) );
/* Sending bytes of size upto to available size should succeed without blocking. */
sent = xStreamBufferSend( xStreamBuffer, data, TEST_STREAM_BUFFER_SIZE, TEST_STREAM_BUFFER_WAIT_TICKS );
TEST_ASSERT_EQUAL( TEST_STREAM_BUFFER_SIZE, sent );
TEST_ASSERT_EQUAL( TEST_STREAM_BUFFER_SIZE, xStreamBufferBytesAvailable( xStreamBuffer ) );
TEST_ASSERT_EQUAL( pdFALSE, xStreamBufferIsEmpty( xStreamBuffer ) );
vStreamBufferDelete( xStreamBuffer );
}
/**
* @brief Validates that sending data more than stream buffer size will cap it to the size of stream buffer without blocking.
*/
void test_xStreamBufferSend_more_than_buffer_size( void )
{
uint8_t data[ TEST_STREAM_BUFFER_SIZE + 1 ] = { 0 };
size_t sent = 0;
vTaskSetTimeOutState_Ignore();
vTaskSuspendAll_Ignore();
xTaskResumeAll_IgnoreAndReturn( pdTRUE );
/* Create a stream buffer of the default test sample size. */
xStreamBuffer = xStreamBufferCreate( TEST_STREAM_BUFFER_SIZE, TEST_STREAM_BUFFER_TRIGGER_LEVEL );
TEST_ASSERT_NOT_NULL( xStreamBuffer );
TEST_ASSERT_EQUAL( TEST_STREAM_BUFFER_SIZE, xStreamBufferSpacesAvailable( xStreamBuffer ) );
/* Sending bytes more than stream buffer size caps its to the size of stream buffer. */
sent = xStreamBufferSend( xStreamBuffer, data, TEST_STREAM_BUFFER_SIZE + 1, TEST_STREAM_BUFFER_WAIT_TICKS );
TEST_ASSERT_EQUAL( TEST_STREAM_BUFFER_SIZE, sent );
TEST_ASSERT_EQUAL( TEST_STREAM_BUFFER_SIZE, xStreamBufferBytesAvailable( xStreamBuffer ) );
vStreamBufferDelete( xStreamBuffer );
}
/**
* @brief Sending zero bytes to stream buffer should return write nothing to the
* buffer and return 0.
*/
void test_xStreamBufferSend_zero_bytes( void )
{
uint8_t data[ TEST_STREAM_BUFFER_SIZE + 1 ] = { 0 };
vTaskSetTimeOutState_Ignore();
vTaskSuspendAll_Ignore();
xTaskResumeAll_IgnoreAndReturn( pdTRUE );
/* Create a stream buffer of the default test sample size. */
xStreamBuffer = xStreamBufferCreate( TEST_STREAM_BUFFER_SIZE, TEST_STREAM_BUFFER_TRIGGER_LEVEL );
TEST_ASSERT_NOT_NULL( xStreamBuffer );
TEST_ASSERT_EQUAL( TEST_STREAM_BUFFER_SIZE, xStreamBufferSpacesAvailable( xStreamBuffer ) );
TEST_ASSERT_EQUAL( pdFALSE, xStreamBufferSend( xStreamBuffer, data, 0U, TEST_STREAM_BUFFER_WAIT_TICKS ) );
vStreamBufferDelete( xStreamBuffer );
}
/**
* @brief Validates cases where stream buffer has insufficient space to send the data and sender has to block.
*/
void test_xStreamBufferSend_blocking( void )
{
uint8_t data[ TEST_STREAM_BUFFER_SIZE ] = { 0 };
size_t sent = 0;
vTaskSetTimeOutState_Ignore();
xTaskGenericNotifyStateClear_IgnoreAndReturn( pdTRUE );
xTaskGetCurrentTaskHandle_IgnoreAndReturn( senderTask );
vTaskSuspendAll_Ignore();
xTaskResumeAll_IgnoreAndReturn( pdTRUE );
/* Create a stream buffer of test sample size. */
xStreamBuffer = xStreamBufferCreate( TEST_STREAM_BUFFER_SIZE, TEST_STREAM_BUFFER_TRIGGER_LEVEL );
TEST_ASSERT_NOT_NULL( xStreamBuffer );
TEST_ASSERT_EQUAL( TEST_STREAM_BUFFER_SIZE, xStreamBufferSpacesAvailable( xStreamBuffer ) );
/* Sending upto size of stream buffer should not block. */
sent = xStreamBufferSend( xStreamBuffer, data, TEST_STREAM_BUFFER_SIZE - 1, TEST_STREAM_BUFFER_WAIT_TICKS );
TEST_ASSERT_EQUAL( TEST_STREAM_BUFFER_SIZE - 1, sent );
TEST_ASSERT_EQUAL( 1, xStreamBufferSpacesAvailable( xStreamBuffer ) );
/*
* Sending beyond the stream buffer size should make task wait for upto TEST_STREAM_BUFFER_WAIT_TICKS. After the timeout
* elapses, task should return with partial bytes sent.
*/
xTaskGenericNotifyWait_ExpectAndReturn( 0, 0, 0, NULL, TEST_STREAM_BUFFER_WAIT_TICKS, pdTRUE );
xTaskCheckForTimeOut_IgnoreAndReturn( pdTRUE );
sent = xStreamBufferSend( xStreamBuffer, data, TEST_STREAM_BUFFER_SIZE, TEST_STREAM_BUFFER_WAIT_TICKS );
TEST_ASSERT_EQUAL( 1, sent );
TEST_ASSERT_EQUAL( pdTRUE, xStreamBufferIsFull( xStreamBuffer ) );
/*
* A task trying to send to a stream buffer without any space available should block for upto TEST_STREAM_BUFFER_WAIT_TICKS.
* Sender task should be notified and woken up when bytes are consumed by a receiver task during the wait period.
*/
xTaskGenericNotifyWait_StubWithCallback( streamBufferReceiveCallback );
xTaskGenericNotify_StubWithCallback( senderTaskNotificationCallback );
xTaskCheckForTimeOut_IgnoreAndReturn( pdFALSE );
sent = xStreamBufferSend( xStreamBuffer, data, TEST_STREAM_BUFFER_SIZE, TEST_STREAM_BUFFER_WAIT_TICKS );
TEST_ASSERT_EQUAL( TEST_STREAM_BUFFER_SIZE, sent );
TEST_ASSERT_EQUAL( TEST_STREAM_BUFFER_SIZE, xStreamBufferBytesAvailable( xStreamBuffer ) );
TEST_ASSERT_EQUAL( 1, senderTaskWoken );
/*
* A task trying to send to a stream buffer without any space available should block for upto TEST_STREAM_BUFFER_WAIT_TICKS.
* Sender task should be notified and woken up when bytes are consumed by an ISR during the wait period.
*/
xTaskGenericNotifyWait_StubWithCallback( streamBufferReceiveFromISRCallback );
xTaskGenericNotifyFromISR_StubWithCallback( senderTaskNotificationFromISRCallback );
xTaskCheckForTimeOut_IgnoreAndReturn( pdFALSE );
sent = xStreamBufferSend( xStreamBuffer, data, TEST_STREAM_BUFFER_SIZE, TEST_STREAM_BUFFER_WAIT_TICKS );
TEST_ASSERT_EQUAL( TEST_STREAM_BUFFER_SIZE, sent );
TEST_ASSERT_EQUAL( TEST_STREAM_BUFFER_SIZE, xStreamBufferBytesAvailable( xStreamBuffer ) );
TEST_ASSERT_EQUAL( 2, senderTaskWoken );
vStreamBufferDelete( xStreamBuffer );
}
/**
* @brief Validates that stream buffer does not block if zero wait time is passed.
*/
void test_xStreamBufferSend_zero_wait_ticks( void )
{
uint8_t data[ TEST_STREAM_BUFFER_SIZE ] = { 0 };
size_t dataSent = 0;
vTaskSetTimeOutState_Ignore();
vTaskSuspendAll_Ignore();
xTaskResumeAll_IgnoreAndReturn( pdTRUE );
/* Create a stream buffer of sample size. */
xStreamBuffer = xStreamBufferCreate( TEST_STREAM_BUFFER_SIZE, TEST_STREAM_BUFFER_TRIGGER_LEVEL );
TEST_ASSERT_NOT_NULL( xStreamBuffer );
TEST_ASSERT_EQUAL( TEST_STREAM_BUFFER_SIZE, xStreamBufferSpacesAvailable( xStreamBuffer ) );
/* Sending data of upto stream buffer size should not block. */
dataSent = xStreamBufferSend( xStreamBuffer, data, TEST_STREAM_BUFFER_SIZE, TEST_STREAM_BUFFER_WAIT_TICKS );
TEST_ASSERT_EQUAL( TEST_STREAM_BUFFER_SIZE, dataSent );
TEST_ASSERT_EQUAL( 0, xStreamBufferSpacesAvailable( xStreamBuffer ) );
/* Sending data beyond stream buffer size but with zero wait ticks should not block and return zero bytes sent. */
dataSent = xStreamBufferSend( xStreamBuffer, data, TEST_STREAM_BUFFER_SIZE, 0 );
TEST_ASSERT_EQUAL( 0, dataSent );
vStreamBufferDelete( xStreamBuffer );
}
/**
* @brief Validates that a task is able to receive from a non empty stream buffer without blocking.
*/
void test_xStreamBufferReceive_success( void )
{
uint8_t data[ TEST_STREAM_BUFFER_SIZE ] = { 0xAA };
uint8_t dataReceived[ TEST_STREAM_BUFFER_SIZE ] = { 0x00 };
size_t sentBytes = 0, receivedBytes = 0;
vTaskSetTimeOutState_Ignore();
vTaskSuspendAll_Ignore();
xTaskResumeAll_IgnoreAndReturn( pdTRUE );
/* Create a stream buffer of sample size. */
xStreamBuffer = xStreamBufferCreate( TEST_STREAM_BUFFER_SIZE, TEST_STREAM_BUFFER_TRIGGER_LEVEL );
TEST_ASSERT_NOT_NULL( xStreamBuffer );
TEST_ASSERT_EQUAL( TEST_STREAM_BUFFER_SIZE, xStreamBufferSpacesAvailable( xStreamBuffer ) );
/* Send TEST_STREAM_BUFFER_SIZE data to the stream buffer. */
sentBytes = xStreamBufferSend( xStreamBuffer, &data, TEST_STREAM_BUFFER_SIZE, TEST_STREAM_BUFFER_WAIT_TICKS );
TEST_ASSERT_EQUAL( TEST_STREAM_BUFFER_SIZE, sentBytes );
/* Receive the partial data from stream Buffer without blocking. */
receivedBytes = xStreamBufferReceive( xStreamBuffer, &dataReceived, TEST_STREAM_BUFFER_SIZE - 1, TEST_STREAM_BUFFER_WAIT_TICKS );
TEST_ASSERT_EQUAL( TEST_STREAM_BUFFER_SIZE - 1, receivedBytes );
TEST_ASSERT_EQUAL_HEX8_ARRAY( data, dataReceived, receivedBytes );
TEST_ASSERT_EQUAL( 1, xStreamBufferBytesAvailable( xStreamBuffer ) );
/* Request for full TEST_STREAM_BUFFER_SIZE bytes, but only receive what's available without blocking. */
receivedBytes = xStreamBufferReceive( xStreamBuffer, &dataReceived, TEST_STREAM_BUFFER_SIZE, TEST_STREAM_BUFFER_WAIT_TICKS );
TEST_ASSERT_EQUAL( 1, receivedBytes );
TEST_ASSERT_EQUAL( 0, xStreamBufferBytesAvailable( xStreamBuffer ) );
vStreamBufferDelete( xStreamBuffer );
}
/**
* @brief Validates receiving from an empty stream buffer will block until at least trigger level bytes are
* sent to the buffer.
*/
void test_xStreamBufferReceive_blocking( void )
{
uint8_t data[ TEST_STREAM_BUFFER_SIZE ] = { 0xAA };
size_t receivedBytes = 0;
vTaskSetTimeOutState_Ignore();
xTaskGenericNotifyStateClear_IgnoreAndReturn( pdTRUE );
xTaskGetCurrentTaskHandle_IgnoreAndReturn( receiverTask );
xTaskGenericNotify_StubWithCallback( receiverTaskNotificationCallback );
xTaskCheckForTimeOut_IgnoreAndReturn( pdFALSE );
vTaskSuspendAll_Ignore();
xTaskResumeAll_IgnoreAndReturn( pdTRUE );
/* Create a stream buffer of sample size. */
xStreamBuffer = xStreamBufferCreate( TEST_STREAM_BUFFER_SIZE, TEST_STREAM_BUFFER_TRIGGER_LEVEL );
TEST_ASSERT_NOT_NULL( xStreamBuffer );
TEST_ASSERT_EQUAL( 0, xStreamBufferBytesAvailable( xStreamBuffer ) );
/*
* Receiving from an empty buffer causes the task to wait for TEST_STREAM_BUFFER_WAIT_TICKS period.
* After the timeout elapses, task returns with zero bytes received.
*/
xTaskGenericNotifyWait_ExpectAndReturn( 0, 0, 0, NULL, TEST_STREAM_BUFFER_WAIT_TICKS, pdTRUE );
xTaskCheckForTimeOut_IgnoreAndReturn( pdTRUE );
receivedBytes = xStreamBufferReceive( xStreamBuffer, data, TEST_STREAM_BUFFER_SIZE, TEST_STREAM_BUFFER_WAIT_TICKS );
TEST_ASSERT_EQUAL( 0, receivedBytes );
/*
* Sending at least trigger level bytes, should notify and wake up the receiver task.
*/
xTaskGenericNotifyWait_StubWithCallback( streamBufferSendCallback );
xTaskCheckForTimeOut_IgnoreAndReturn( pdFALSE );
receivedBytes = xStreamBufferReceive( xStreamBuffer, data, TEST_STREAM_BUFFER_SIZE, TEST_STREAM_BUFFER_WAIT_TICKS );
TEST_ASSERT_EQUAL( TEST_STREAM_BUFFER_TRIGGER_LEVEL, receivedBytes );
TEST_ASSERT_EQUAL( 1, receiverTaskWoken );
TEST_ASSERT_EQUAL( 0, xStreamBufferBytesAvailable( xStreamBuffer ) );
/*
* Sending at least trigger level bytes from ISR, should notify and wake up the receiver task.
*/
xTaskGenericNotifyWait_StubWithCallback( streamBufferSendFromISRCallback );
xTaskGenericNotifyFromISR_StubWithCallback( receiverTaskNotificationFromISRCallback );
xTaskCheckForTimeOut_IgnoreAndReturn( pdFALSE );
receivedBytes = xStreamBufferReceive( xStreamBuffer, data, TEST_STREAM_BUFFER_SIZE, TEST_STREAM_BUFFER_WAIT_TICKS );
TEST_ASSERT_EQUAL( TEST_STREAM_BUFFER_TRIGGER_LEVEL, receivedBytes );
TEST_ASSERT_EQUAL( 2, receiverTaskWoken );
TEST_ASSERT_EQUAL( 0, xStreamBufferBytesAvailable( xStreamBuffer ) );
/* Sending less than trigger level bytes should not wake up the task. */
xTaskGenericNotifyWait_StubWithCallback( sendLessThanTriggerLevelBytesCallback );
xTaskGenericNotifyFromISR_StubWithCallback( receiverTaskNotificationFromISRCallback );
xTaskCheckForTimeOut_IgnoreAndReturn( pdTRUE );
receivedBytes = xStreamBufferReceive( xStreamBuffer, data, TEST_STREAM_BUFFER_SIZE, TEST_STREAM_BUFFER_WAIT_TICKS );
TEST_ASSERT_EQUAL( 2, receiverTaskWoken );
/* Sending less than trigger level bytes from ISR should not wake up the task. */
xTaskGenericNotifyWait_StubWithCallback( sendLessThanTriggerLevelBytesFromISRCallback );
xTaskGenericNotifyFromISR_StubWithCallback( receiverTaskNotificationFromISRCallback );
xTaskCheckForTimeOut_IgnoreAndReturn( pdTRUE );
receivedBytes = xStreamBufferReceive( xStreamBuffer, data, TEST_STREAM_BUFFER_SIZE, TEST_STREAM_BUFFER_WAIT_TICKS );
TEST_ASSERT_EQUAL( 2, receiverTaskWoken );
vStreamBufferDelete( xStreamBuffer );
}
/**
* @brief Validates that receiver task does not block if zero wait ticks are passed.
*/
void test_xStreamBufferReceive_zero_wait_ticks( void )
{
uint8_t data[ TEST_STREAM_BUFFER_SIZE ] = { 0xAA };
size_t receivedBytes = 0;
vTaskSetTimeOutState_Ignore();
vTaskSuspendAll_Ignore();
xTaskResumeAll_IgnoreAndReturn( pdTRUE );
/* Create a stream buffer of sample size. */
xStreamBuffer = xStreamBufferCreate( TEST_STREAM_BUFFER_SIZE, TEST_STREAM_BUFFER_TRIGGER_LEVEL );
TEST_ASSERT_NOT_NULL( xStreamBuffer );
TEST_ASSERT_EQUAL( TEST_STREAM_BUFFER_SIZE, xStreamBufferSpacesAvailable( xStreamBuffer ) );
/* Task does not block on an empty stream buffer if zero wait ticks are passed. */
receivedBytes = xStreamBufferReceive( xStreamBuffer, data, TEST_STREAM_BUFFER_SIZE, 0 );
TEST_ASSERT_EQUAL( 0, receivedBytes );
vStreamBufferDelete( xStreamBuffer );
}
/**
* @brief Validates that an interrupt service routine is able to read data from stream
* buffer without blocking.
*/
void test_xStreamBufferReceiveFromISR_success( void )
{
uint8_t data[ TEST_STREAM_BUFFER_SIZE ] = { 0xAA };
uint8_t dataReceived[ TEST_STREAM_BUFFER_SIZE ] = { 0x00 };
size_t receivedBytes = 0, sentBytes = 0;
BaseType_t xHighPriorityTaskWoken = pdFALSE;
vTaskSetTimeOutState_Ignore();
vTaskSuspendAll_Ignore();
xTaskResumeAll_IgnoreAndReturn( pdTRUE );
/* Create a stream buffer of sample size. */
xStreamBuffer = xStreamBufferCreate( TEST_STREAM_BUFFER_SIZE, TEST_STREAM_BUFFER_TRIGGER_LEVEL );
TEST_ASSERT_NOT_NULL( xStreamBuffer );
TEST_ASSERT_EQUAL( TEST_STREAM_BUFFER_SIZE, xStreamBufferSpacesAvailable( xStreamBuffer ) );
/* Send data to fill the stream buffer to maximum capacity. */
sentBytes = xStreamBufferSend( xStreamBuffer, data, TEST_STREAM_BUFFER_SIZE, TEST_STREAM_BUFFER_WAIT_TICKS );
TEST_ASSERT_EQUAL( TEST_STREAM_BUFFER_SIZE, sentBytes );
TEST_ASSERT_EQUAL( TEST_STREAM_BUFFER_SIZE, xStreamBufferBytesAvailable( xStreamBuffer ) );
/* Receive partial data from stream buffer without blocking. */
receivedBytes = xStreamBufferReceiveFromISR( xStreamBuffer, &dataReceived, ( TEST_STREAM_BUFFER_SIZE - 1U ), &xHighPriorityTaskWoken );
TEST_ASSERT_EQUAL( ( TEST_STREAM_BUFFER_SIZE - 1U ), receivedBytes );
TEST_ASSERT_EQUAL_HEX8_ARRAY( data, dataReceived, receivedBytes );
TEST_ASSERT_EQUAL( pdFALSE, xHighPriorityTaskWoken );
/* Try to receive full capacity from stream buffer but only remaining data is received. */
receivedBytes = xStreamBufferReceiveFromISR( xStreamBuffer, &dataReceived, TEST_STREAM_BUFFER_SIZE, &xHighPriorityTaskWoken );
TEST_ASSERT_EQUAL( 1U, receivedBytes );
TEST_ASSERT_EQUAL( 0, xStreamBufferBytesAvailable( xStreamBuffer ) );
vStreamBufferDelete( xStreamBuffer );
}
/**
* @brief Assertion fails if a null stream buffer is passed.
*/
void test_xStreamBufferReceiveFromISR_null_stream_buffer( void )
{
uint8_t data[ TEST_STREAM_BUFFER_SIZE ] = { 0xAA };
BaseType_t xHighPriorityTaskWoken = pdFALSE;
EXPECT_ASSERT_BREAK( ( void ) xStreamBufferReceiveFromISR( NULL, data, TEST_STREAM_BUFFER_SIZE, &xHighPriorityTaskWoken ) );
validate_and_clear_assertions();
}
/**
* @brief Assertion fails if a null message is passed.
*/
void test_xStreamBufferReceiveFromISR_null_buffer( void )
{
BaseType_t xHighPriorityTaskWoken = pdFALSE;
/* Create a stream buffer of sample size. */
xStreamBuffer = xStreamBufferCreate( TEST_STREAM_BUFFER_SIZE, TEST_STREAM_BUFFER_TRIGGER_LEVEL );
TEST_ASSERT_NOT_NULL( xStreamBuffer );
TEST_ASSERT_EQUAL( TEST_STREAM_BUFFER_SIZE, xStreamBufferSpacesAvailable( xStreamBuffer ) );
EXPECT_ASSERT_BREAK( ( void ) xStreamBufferReceiveFromISR( xStreamBuffer, NULL, TEST_STREAM_BUFFER_SIZE, &xHighPriorityTaskWoken ) );
validate_and_clear_assertions();
vStreamBufferDelete( xStreamBuffer );
}
/**
* @brief Validates that an interrupt service routine is able to send data upto the size of stream buffer without blocking.
*/
void test_xStreamBufferSendFromISR_success( void )
{
uint8_t data[ TEST_STREAM_BUFFER_SIZE ] = { 0xAA };
size_t sentBytes = 0;
BaseType_t xHighPriorityTaskWoken = pdFALSE;
vTaskSetTimeOutState_Ignore();
vTaskSuspendAll_Ignore();
xTaskResumeAll_IgnoreAndReturn( pdTRUE );
/* Create a stream buffer of sample size. */
xStreamBuffer = xStreamBufferCreate( TEST_STREAM_BUFFER_SIZE, TEST_STREAM_BUFFER_TRIGGER_LEVEL );
TEST_ASSERT_NOT_NULL( xStreamBuffer );
TEST_ASSERT_EQUAL( TEST_STREAM_BUFFER_SIZE, xStreamBufferSpacesAvailable( xStreamBuffer ) );
/* Send data to an empty buffer should succeed without blocking. */
sentBytes = xStreamBufferSendFromISR( xStreamBuffer, data, TEST_STREAM_BUFFER_SIZE - 1U, &xHighPriorityTaskWoken );
TEST_ASSERT_EQUAL( TEST_STREAM_BUFFER_SIZE - 1U, sentBytes );
TEST_ASSERT_EQUAL( 1U, xStreamBufferSpacesAvailable( xStreamBuffer ) );
TEST_ASSERT_EQUAL( pdFALSE, xHighPriorityTaskWoken );
/* Send full capacity from ISR again should send partial bytes without blocking. */
sentBytes = xStreamBufferSendFromISR( xStreamBuffer, data, TEST_STREAM_BUFFER_SIZE, &xHighPriorityTaskWoken );
TEST_ASSERT_EQUAL( 1U, sentBytes );
TEST_ASSERT_EQUAL( 0, xStreamBufferSpacesAvailable( xStreamBuffer ) );
TEST_ASSERT_EQUAL( pdFALSE, xHighPriorityTaskWoken );
/* Send to full stream buffer should return 0 bytes sent without blocking. */
sentBytes = xStreamBufferSendFromISR( xStreamBuffer, data, TEST_STREAM_BUFFER_SIZE, &xHighPriorityTaskWoken );
TEST_ASSERT_EQUAL( 0U, sentBytes );
TEST_ASSERT_EQUAL( pdFALSE, xHighPriorityTaskWoken );
vStreamBufferDelete( xStreamBuffer );
}
/**
* @brief Assertion fails if a null stream buffer is passed.
*/
void test_xStreamBufferSendFromISR_null_stream_buffer( void )
{
uint8_t data[ TEST_STREAM_BUFFER_SIZE ] = { 0xAA };
BaseType_t xHighPriorityTaskWoken = pdFALSE;
EXPECT_ASSERT_BREAK( ( void ) xStreamBufferSendFromISR( NULL, data, TEST_STREAM_BUFFER_SIZE, &xHighPriorityTaskWoken ) );
validate_and_clear_assertions();
}
/**
* @brief Assertion fails if a null message is passed.
*/
void test_xStreamBufferSendFromISR_null_message( void )
{
BaseType_t xHighPriorityTaskWoken = pdFALSE;
/* Create a stream buffer of sample size. */
xStreamBuffer = xStreamBufferCreate( TEST_STREAM_BUFFER_SIZE, TEST_STREAM_BUFFER_TRIGGER_LEVEL );
TEST_ASSERT_NOT_NULL( xStreamBuffer );
TEST_ASSERT_EQUAL( TEST_STREAM_BUFFER_SIZE, xStreamBufferSpacesAvailable( xStreamBuffer ) );
EXPECT_ASSERT_BREAK( ( void ) xStreamBufferSendFromISR( xStreamBuffer, NULL, TEST_STREAM_BUFFER_SIZE, &xHighPriorityTaskWoken ) );
validate_and_clear_assertions();
vStreamBufferDelete( xStreamBuffer );
}
/**
* @brief Validates user is able to reset the stream buffer back to empty state.
*/
void test_xStreamBufferReset_success( void )
{
uint8_t data[ TEST_STREAM_BUFFER_SIZE ] = { 0 };
size_t dataSent = 0;
BaseType_t status = pdFALSE;
vTaskSetTimeOutState_Ignore();
vTaskSuspendAll_Ignore();
xTaskResumeAll_IgnoreAndReturn( pdTRUE );
/* Create a stream buffer of the default test sample size. */
xStreamBuffer = xStreamBufferCreate( TEST_STREAM_BUFFER_SIZE, TEST_STREAM_BUFFER_TRIGGER_LEVEL );
TEST_ASSERT_NOT_NULL( xStreamBuffer );
/* Validate stream buffer is empty initially. */
validate_stream_buffer_init_state( xStreamBuffer, TEST_STREAM_BUFFER_SIZE );
/* Send full capacity to stream buffer. */
dataSent = xStreamBufferSend( xStreamBuffer, data, sizeof( data ), TEST_STREAM_BUFFER_WAIT_TICKS );
TEST_ASSERT_EQUAL( TEST_STREAM_BUFFER_SIZE, dataSent );
/* Verify that all bytes are available. */
TEST_ASSERT_EQUAL( TEST_STREAM_BUFFER_SIZE, xStreamBufferBytesAvailable( xStreamBuffer ) );
/* Reset the stream buffer back to empty state. */
status = xStreamBufferReset( xStreamBuffer );
TEST_ASSERT_EQUAL( pdTRUE, status );
/* Validate that stream buffer is empty. */
validate_stream_buffer_init_state( xStreamBuffer, TEST_STREAM_BUFFER_SIZE );
vStreamBufferDelete( xStreamBuffer );
}
/**
* @brief Resetting a null stream buffer should fail assertion.
*/
void test_xStreamBufferReset_null_stream_buffer( void )
{
vTaskSetTimeOutState_Ignore();
vTaskSuspendAll_Ignore();
xTaskResumeAll_IgnoreAndReturn( pdTRUE );
EXPECT_ASSERT_BREAK( ( void ) xStreamBufferReset( NULL ) );
validate_and_clear_assertions();
}
/**
* @brief Validates that stream buffer reset fails if a sender or receiver task is blocked on it.
*/
void test_xStreamBufferReset_while_blocked( void )
{
uint8_t data[ TEST_STREAM_BUFFER_SIZE ] = { 0xAA };
size_t sentBytes = 0, receivedBytes = 0;
vTaskSetTimeOutState_Ignore();
xTaskGenericNotifyStateClear_IgnoreAndReturn( pdTRUE );
xTaskGetCurrentTaskHandle_IgnoreAndReturn( senderTask );
xTaskGenericNotifyWait_StubWithCallback( resetWhenBlockedCallback );
xTaskCheckForTimeOut_IgnoreAndReturn( pdTRUE );
vTaskSuspendAll_Ignore();
xTaskResumeAll_IgnoreAndReturn( pdTRUE );
/* Create a stream buffer of sample size. */
xStreamBuffer = xStreamBufferCreate( TEST_STREAM_BUFFER_SIZE, TEST_STREAM_BUFFER_TRIGGER_LEVEL );
TEST_ASSERT_NOT_NULL( xStreamBuffer );
TEST_ASSERT_EQUAL( TEST_STREAM_BUFFER_SIZE, xStreamBufferSpacesAvailable( xStreamBuffer ) );
/*
* Perform a blocking operation to receive from an empty stream buffer. Reset stream buffer within receiver task notify
* wait callback should fail.
*/
receivedBytes = xStreamBufferReceive( xStreamBuffer, data, TEST_STREAM_BUFFER_SIZE, TEST_STREAM_BUFFER_WAIT_TICKS );
TEST_ASSERT_EQUAL( 0, receivedBytes );
/*
* Send full size data to stream buffer.
*/
sentBytes = xStreamBufferSend( xStreamBuffer, data, TEST_STREAM_BUFFER_SIZE, TEST_STREAM_BUFFER_WAIT_TICKS );
TEST_ASSERT_EQUAL( TEST_STREAM_BUFFER_SIZE, sentBytes );
TEST_ASSERT_EQUAL( pdTRUE, xStreamBufferIsFull( xStreamBuffer ) );
/*
* Sending data to full stream buffer causes task to be blocked. Reset stream buffer within sender task notify
* wait callback should fail.
*/
sentBytes = xStreamBufferSend( xStreamBuffer, data, TEST_STREAM_BUFFER_SIZE, TEST_STREAM_BUFFER_WAIT_TICKS );
TEST_ASSERT_EQUAL( 0, sentBytes );
vStreamBufferDelete( xStreamBuffer );
}
/**
* @brief Validates that a receiver task is able to receive data after lowering the stream buffer trigger level.
*/
void test_xStreamBufferSetTrigerLevel_success( void )
{
uint8_t data[ TEST_STREAM_BUFFER_SIZE ] = { 0xAA };
BaseType_t status;
vTaskSetTimeOutState_Ignore();
xTaskGenericNotifyStateClear_IgnoreAndReturn( pdTRUE );
xTaskGetCurrentTaskHandle_IgnoreAndReturn( receiverTask );
xTaskGenericNotify_StubWithCallback( receiverTaskNotificationCallback );
xTaskGenericNotifyWait_StubWithCallback( streamBufferSendCallback );
xTaskCheckForTimeOut_IgnoreAndReturn( pdTRUE );
vTaskSuspendAll_Ignore();
xTaskResumeAll_IgnoreAndReturn( pdTRUE );
/* Create stream buffer with trigger level equal to maximum stream buffer size. */
xStreamBuffer = xStreamBufferCreate( TEST_STREAM_BUFFER_SIZE, TEST_STREAM_BUFFER_SIZE );
TEST_ASSERT_NOT_NULL( xStreamBuffer );
/* Set the trigger level to TEST_STREAM_BUFFER_TRIGGER_LEVEL. */
status = xStreamBufferSetTriggerLevel( xStreamBuffer, TEST_STREAM_BUFFER_TRIGGER_LEVEL );
TEST_ASSERT_EQUAL( pdTRUE, status );
/*
* Receive data from empty stream buffer, with trigger level bytes send from the callback. This should unblock
* the task.
*/
( void ) xStreamBufferReceive( xStreamBuffer, data, TEST_STREAM_BUFFER_SIZE, TEST_STREAM_BUFFER_WAIT_TICKS );
TEST_ASSERT_EQUAL( 1, receiverTaskWoken );
vStreamBufferDelete( xStreamBuffer );
}
/**
* @brief Validate setting trigger level with invalid parameters fails.
*/
void test_xStreamBufferSetTrigerLevel_larger_than_buffer_size( void )
{
BaseType_t status;
/* Create stream buffer. */
xStreamBuffer = xStreamBufferCreate( TEST_STREAM_BUFFER_SIZE, TEST_STREAM_BUFFER_TRIGGER_LEVEL );
TEST_ASSERT_NOT_NULL( xStreamBuffer );
/* Set the trigger level to ( TEST_STREAM_BUFFER_SIZE + 1) should fail. */
status = xStreamBufferSetTriggerLevel( xStreamBuffer, ( TEST_STREAM_BUFFER_SIZE + 1 ) );
TEST_ASSERT_EQUAL( pdFALSE, status );
vStreamBufferDelete( xStreamBuffer );
}
/**
* @brief Set the trigger level to 0 should pass but internally set trigger level to 1.
*/
void test_xStreamBufferSetTrigerLevel_zero( void )
{
BaseType_t status;
xStreamBuffer = xStreamBufferCreate( TEST_STREAM_BUFFER_SIZE, TEST_STREAM_BUFFER_TRIGGER_LEVEL );
TEST_ASSERT_NOT_NULL( xStreamBuffer );
status = xStreamBufferSetTriggerLevel( xStreamBuffer, 0 );
TEST_ASSERT_EQUAL( pdTRUE, status );
vStreamBufferDelete( xStreamBuffer );
}
/**
* @brief Setting trigger level for a null stream buffer should fail assertion.
*/
void test_xStreamBufferSetTriggerLevel_null_stream_buffer( void )
{
EXPECT_ASSERT_BREAK( ( void ) xStreamBufferSetTriggerLevel( NULL, TEST_STREAM_BUFFER_TRIGGER_LEVEL ) );
validate_and_clear_assertions();
}
/**
* @brief Checking bytes available for a null stream buffer should fail assertion.
*/
void test_xStreamBufferBytesAvailable_null_stream_buffer( void )
{
EXPECT_ASSERT_BREAK( ( void ) xStreamBufferBytesAvailable( NULL ) );
validate_and_clear_assertions();
}
/**
* @brief Checking if stream buffer is full for a null stream buffer should fail assertion.
*/
void test_xStreamBufferIsFull_null_stream_buffer( void )
{
EXPECT_ASSERT_BREAK( ( void ) xStreamBufferIsFull( NULL ) );
validate_and_clear_assertions();
}
/**
* @brief Checking if stream buffer is empty for a null stream buffer should fail assertion.
*/
void test_xStreamBufferIsEmpty_null_stream_buffer( void )
{
EXPECT_ASSERT_BREAK( ( void ) xStreamBufferIsEmpty( NULL ) );
validate_and_clear_assertions();
}
/**
* @brief Checking buffer size for a null stream buffer should fail assertion.
*/
void test_xStreamBufferSpacesAvailable_null_stream_buffer( void )
{
EXPECT_ASSERT_BREAK( ( void ) xStreamBufferSpacesAvailable( NULL ) );
validate_and_clear_assertions();
}
/**
* @brief Checking Next message length available for a null stream buffer fails
* assertion.
*/
void test_xStreamBufferNextMessageLengthBytes_null_stream_buffer( void )
{
EXPECT_ASSERT_BREAK( ( void ) xStreamBufferNextMessageLengthBytes( NULL ) );
validate_and_clear_assertions();
}
/**
* @brief Validates xStreamBufferSendCompletedFromISR function unblocks a receive task.
*/
void test_xStreamBufferSendCompletedFromISR_success( void )
{
BaseType_t status = pdFALSE;
BaseType_t highPriorityTaskWoken = pdFALSE;
uint8_t data[ TEST_STREAM_BUFFER_SIZE ];
size_t receiveBytes = 0;
/* Create a stream buffer of the default test sample size. */
xStreamBuffer = xStreamBufferCreate( TEST_STREAM_BUFFER_SIZE, TEST_STREAM_BUFFER_TRIGGER_LEVEL );
TEST_ASSERT_NOT_NULL( xStreamBuffer );
/* Send completed from ISR without receiver task waiting. */
status = xStreamBufferSendCompletedFromISR( xStreamBuffer, &highPriorityTaskWoken );
TEST_ASSERT_EQUAL( pdFALSE, status );
TEST_ASSERT_EQUAL( pdFALSE, highPriorityTaskWoken );
/* Send completed from ISR with receiver task waiting. */
vTaskSetTimeOutState_Ignore();
xTaskGenericNotifyStateClear_IgnoreAndReturn( pdTRUE );
xTaskGetCurrentTaskHandle_IgnoreAndReturn( receiverTask );
xTaskGenericNotifyWait_StubWithCallback( sendCompletedFromISRCallback );
xTaskGenericNotifyFromISR_StubWithCallback( receiverTaskNotificationFromISRCallback );
xTaskCheckForTimeOut_IgnoreAndReturn( pdTRUE );
vTaskSuspendAll_Ignore();
xTaskResumeAll_IgnoreAndReturn( pdTRUE );
receiveBytes = xStreamBufferReceive( xStreamBuffer, data, TEST_STREAM_BUFFER_SIZE, TEST_STREAM_BUFFER_WAIT_TICKS );
TEST_ASSERT_EQUAL( 0, receiveBytes );
TEST_ASSERT_EQUAL( 1, receiverTaskWoken );
vStreamBufferDelete( xStreamBuffer );
}
/**
* @brief Validates xStreamBufferSendCompletedFromISR fails assertion if a null stream buffer is passed.
*/
void test_xStreamBufferSendCompletedFromISR_null_stream_buffer( void )
{
BaseType_t highPriorityTaskWoken = pdFALSE;
/* Send completed from ISR without receiver task waiting. */
EXPECT_ASSERT_BREAK( ( void ) xStreamBufferSendCompletedFromISR( NULL, &highPriorityTaskWoken ) );
validate_and_clear_assertions();
}
/**
* @brief Validates xStreamBufferReceiveCompletedFromISR unblocks a sender task.
*/
void test_xStreamBufferReceiveCompletedFromISR_success( void )
{
BaseType_t status = pdFALSE;
BaseType_t highPriorityTaskWoken = pdFALSE;
uint8_t data[ TEST_STREAM_BUFFER_SIZE ] = { 0xAA };
size_t sentBytes = 0;
vTaskSetTimeOutState_Ignore();
vTaskSuspendAll_Ignore();
xTaskResumeAll_IgnoreAndReturn( pdTRUE );
/* Create a stream buffer of the default test sample size. */
xStreamBuffer = xStreamBufferCreate( TEST_STREAM_BUFFER_SIZE, TEST_STREAM_BUFFER_TRIGGER_LEVEL );
TEST_ASSERT_NOT_NULL( xStreamBuffer );
/* Receive completed from ISR without a sender task waiting. */
status = xStreamBufferReceiveCompletedFromISR( xStreamBuffer, &highPriorityTaskWoken );
TEST_ASSERT_EQUAL( pdFALSE, status );
TEST_ASSERT_EQUAL( pdFALSE, highPriorityTaskWoken );
/* Send full capacity to a stream buffer so that sender task blocks. */
sentBytes = xStreamBufferSend( xStreamBuffer, data, TEST_STREAM_BUFFER_SIZE, TEST_STREAM_BUFFER_WAIT_TICKS );
TEST_ASSERT_EQUAL( TEST_STREAM_BUFFER_SIZE, sentBytes );
TEST_ASSERT_EQUAL( TEST_STREAM_BUFFER_SIZE, xStreamBufferBytesAvailable( xStreamBuffer ) );
/* Receive completed from ISR when a sender task is waiting. */
xTaskGenericNotifyStateClear_IgnoreAndReturn( pdTRUE );
xTaskGetCurrentTaskHandle_IgnoreAndReturn( senderTask );
xTaskGenericNotifyWait_StubWithCallback( receiveCompletedFromISRCallback );
xTaskGenericNotifyFromISR_StubWithCallback( senderTaskNotificationFromISRCallback );
xTaskCheckForTimeOut_IgnoreAndReturn( pdTRUE );
sentBytes = xStreamBufferSend( xStreamBuffer, data, TEST_STREAM_BUFFER_SIZE, TEST_STREAM_BUFFER_WAIT_TICKS );
TEST_ASSERT_EQUAL( 0, sentBytes );
TEST_ASSERT_EQUAL( 1, senderTaskWoken );
vStreamBufferDelete( xStreamBuffer );
}
/**
* @brief Validates xStreamBufferReceiveCompletedFromISR fails assertion if a null stream buffer is passed.
*/
void test_xStreamBufferReceiveCompletedFromISR_null_stream_buffer( void )
{
BaseType_t highPriorityTaskWoken = pdFALSE;
/* Send completed from ISR without receiver task waiting. */
EXPECT_ASSERT_BREAK( ( void ) xStreamBufferReceiveCompletedFromISR( NULL, &highPriorityTaskWoken ) );
validate_and_clear_assertions();
}
/**
* @brief Validates scenario where stream buffer head and tail pointer wraps over.
*/
void test_xStreamBufferSend_WrapOver( void )
{
uint8_t data[ TEST_STREAM_BUFFER_SIZE ] = { 0xAA };
size_t sent = 0, received = 0;
vTaskSetTimeOutState_Ignore();
vTaskSuspendAll_Ignore();
xTaskResumeAll_IgnoreAndReturn( pdTRUE );
/* Create a stream buffer of the default test sample size. */
xStreamBuffer = xStreamBufferCreate( TEST_STREAM_BUFFER_SIZE, TEST_STREAM_BUFFER_TRIGGER_LEVEL );
TEST_ASSERT_NOT_NULL( xStreamBuffer );
TEST_ASSERT_EQUAL( TEST_STREAM_BUFFER_SIZE, xStreamBufferSpacesAvailable( xStreamBuffer ) );
/* Sending bytes upto max stream buffer size. */
sent = xStreamBufferSend( xStreamBuffer, data, TEST_STREAM_BUFFER_SIZE, TEST_STREAM_BUFFER_WAIT_TICKS );
TEST_ASSERT_EQUAL( TEST_STREAM_BUFFER_SIZE, sent );
TEST_ASSERT_EQUAL( TEST_STREAM_BUFFER_SIZE, xStreamBufferBytesAvailable( xStreamBuffer ) );
TEST_ASSERT_EQUAL( 0, xStreamBufferSpacesAvailable( xStreamBuffer ) );
/* Read upto max buffer size - 1 */
received = xStreamBufferReceive( xStreamBuffer, data, TEST_STREAM_BUFFER_SIZE - 1, TEST_STREAM_BUFFER_WAIT_TICKS );
TEST_ASSERT_EQUAL( TEST_STREAM_BUFFER_SIZE - 1, received );
TEST_ASSERT_EQUAL( 1, xStreamBufferBytesAvailable( xStreamBuffer ) );
TEST_ASSERT_EQUAL( TEST_STREAM_BUFFER_SIZE - 1, xStreamBufferSpacesAvailable( xStreamBuffer ) );
/* Send upto max buffer size - 1 so that head wraps over. */
sent = xStreamBufferSend( xStreamBuffer, data, TEST_STREAM_BUFFER_SIZE - 1, TEST_STREAM_BUFFER_WAIT_TICKS );
TEST_ASSERT_EQUAL( TEST_STREAM_BUFFER_SIZE - 1, sent );
TEST_ASSERT_EQUAL( TEST_STREAM_BUFFER_SIZE, xStreamBufferBytesAvailable( xStreamBuffer ) );
TEST_ASSERT_EQUAL( 0U, xStreamBufferSpacesAvailable( xStreamBuffer ) );
/* Read all bytes and verify that tail wraps over as well. */
received = xStreamBufferReceive( xStreamBuffer, data, TEST_STREAM_BUFFER_SIZE, TEST_STREAM_BUFFER_WAIT_TICKS );
TEST_ASSERT_EQUAL( TEST_STREAM_BUFFER_SIZE, received );
TEST_ASSERT_EQUAL( 0, xStreamBufferBytesAvailable( xStreamBuffer ) );
TEST_ASSERT_EQUAL( TEST_STREAM_BUFFER_SIZE, xStreamBufferSpacesAvailable( xStreamBuffer ) );
vStreamBufferDelete( xStreamBuffer );
}