#include <stdio.h>
#include "ring_buffer_unit_test.h"
int main()
{
printf("Running ring buffer unit test...\n");
if (true == RingBuffer_UnitTest()) {
return 0;
}
return 1;
}
#ifndef _RING_BUFFER_UNIT_TEST_H_
#define _RING_BUFFER_UNIT_TEST_H_
#include <stdbool.h>
/**
* Runs a unit test of the RingBuffer.
* @return true if the test passed, false if it failed
*/
bool RingBuffer_UnitTest(void);
#endif
#include "ring_buffer.h"
#include "ring_buffer_unit_test.h"
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#ifdef _WIN32
#include <inttypes.h>
#define PASSED "PASSED"
#define FAILED "FAILED"
#ifdef _WIN64
#define PRI_SIZET PRIu64
#else
#define PRI_SIZET PRIu32
#endif
#else
#define PRI_SIZET "zu"
#define PASSED "\x1b[32mPASSED\x1b[0m"
#define FAILED "\x1b[31mFAILED\x1b[0m"
#endif
#define test(expr)(!(expr)) ? (printf(FAILED" at line %u\n", __LINE__), false) : (printf(PASSED"\n"), true)
#define test_quiet(expr)(!(expr)) ? (printf(FAILED" at line %u\n", __LINE__), false) : true
enum {
capacity1 = 10,
capacity2 = 100,
capacity3 = 500,
};
const char guardValue = 0xAB;
static bool RingBuffer_Init_ut();
static bool RingBuffer_PutChar_ut();
static bool RingBuffer_ut(RingBuffer* buffer) {
printf("Test 0: Checking RingBuffer structure...\n");
printf(" - Check if size of ring buffer structure is reasonable: ");
bool result = test(sizeof(*buffer) <= 15 * sizeof(int));
printf("Test 0: %s\n\n", (true == result) ? PASSED : FAILED);
return result;
}
static bool RingBuffer_Init_ut(RingBuffer* buffer, char* data, size_t dataSize) {
printf("Test 1: Checking RingBuffer_Init...\n");
printf(" - Initialize ring buffer with memory region with size %"PRI_SIZET": ", dataSize);
bool result = test(true == RingBuffer_Init(buffer, data, dataSize));
if(true == result) {
printf(" Is empty: ");
result &= test(true == RingBuffer_IsEmpty(buffer));
printf(" Length is 0: ");
result &= test(0 == RingBuffer_GetLen(buffer));
printf(" Capacity is %"PRI_SIZET": ", dataSize);
result &= test(dataSize == RingBuffer_GetCapacity(buffer));
}
printf("Test 1: %s\n\n", (true == result) ? PASSED : FAILED);
return result;
}
static bool RingBuffer_PutChar_ut(RingBuffer* buffer, char* data, size_t dataSize) {
printf("Test 2: Checking RingBuffer_PutChar...\n");
printf(" - Initialize ring buffer with memory region with size %"PRI_SIZET": ", dataSize);
bool result = test(true == RingBuffer_Init(buffer, data, dataSize));
if(true == result) {
printf(" Write data into the buffer...\n");
for(size_t j = 0; true == result && j < dataSize; j++) {
result &= test_quiet(j == RingBuffer_GetLen(buffer));
result &= test_quiet(true == RingBuffer_PutChar(buffer, j % 0x7f));
result &= test_quiet(false == RingBuffer_IsEmpty(buffer));
if(false == result) {
printf(" Writing data no %"PRI_SIZET" produced invalid state (IsEmpty: %c, Length: %"PRI_SIZET", Capacity: %"PRI_SIZET")\n", j, RingBuffer_IsEmpty(buffer) ? 'T' : 'F', RingBuffer_GetLen(buffer), RingBuffer_GetCapacity(buffer));
}
}
if(true == result) {
printf(" Cannot hold more data: ");
result &= test(false == RingBuffer_PutChar(buffer, '0'));
printf(" Capacity is %"PRI_SIZET": ", dataSize);
result &= test(dataSize == RingBuffer_GetCapacity(buffer));
printf(" Length is %"PRI_SIZET": ", dataSize);
result &= test(dataSize == RingBuffer_GetLen(buffer));
printf(" Is not empty: ");
result &= test(false == RingBuffer_IsEmpty(buffer));
}
}
printf("Test 2: %s\n\n", (true == result) ? PASSED : FAILED);
return result;
}
static bool RingBuffer_GetChar_ut(RingBuffer* buffer, char* data, size_t dataSize) {
printf("Test 3: Checking RingBuffer_GetChar...\n");
printf(" - Initialize ring buffer with memory region with size %"PRI_SIZET": ", dataSize);
bool result = test(true == RingBuffer_Init(buffer, data, dataSize));
if(true == result) {
printf(" Write data into the buffer...\n");
for(size_t j = 0; true == result && j < dataSize; j++) {
result &= test_quiet(true == RingBuffer_PutChar(buffer, j % 0x7f));
if(false == result) {
printf(" Writing data no %"PRI_SIZET" produced invalid state (IsEmpty: %c, Length: %"PRI_SIZET", Capacity: %"PRI_SIZET")\n", j, RingBuffer_IsEmpty(buffer) ? 'T' : 'F', RingBuffer_GetLen(buffer), RingBuffer_GetCapacity(buffer));
}
}
if(true == result) {
printf(" Read data from the buffer...\n");
char in ;
for(size_t j = 0; true == result && j < dataSize; ++j) {
result &= test_quiet(true == RingBuffer_GetChar(buffer, &in));
if(true == result) {
result &= test_quiet(j % 0x7f == in);
if(false == result) {
printf(" Data no %"PRI_SIZET" mismatch (%x, but expected %x)\n", j, (int)in, (int)j % 0x7f);
}
} else {
printf(" Failed to read data no %"PRI_SIZET"\n", j);
}
}
if(true == result) {
printf(" Is empty: ");
result &= test(true == RingBuffer_IsEmpty(buffer));
printf(" Length is 0: ");
result &= test(0 == RingBuffer_GetLen(buffer));
printf(" Capacity is %"PRI_SIZET": ", dataSize);
result &= test(dataSize == RingBuffer_GetCapacity(buffer));
printf(" Can be written: ");
result &= test(true == RingBuffer_PutChar(buffer, '0'));
}
}
}
printf("Test 3: %s\n\n", (true == result) ? PASSED : FAILED);
return result;
}
static bool RingBuffer_Clear_ut(RingBuffer* buffer, char* data, size_t dataSize) {
printf("Test 4: Checking RingBuffer_Clear...\n");
printf(" - Initialize ring buffer with memory region with size %"PRI_SIZET": ", dataSize);
bool result = test(true == RingBuffer_Init(buffer, data, dataSize));
if(true == result) {
printf(" Write data into the buffer...\n");
for(size_t j = 0; true == result && j < dataSize; j++) {
result &= test_quiet(true == RingBuffer_PutChar(buffer, j % 0x7f));
if(false == result) {
printf(" Writing data no %"PRI_SIZET" produced invalid state (IsEmpty: %c, Length: %"PRI_SIZET", Capacity: %"PRI_SIZET")\n", j, RingBuffer_IsEmpty(buffer) ? 'T' : 'F', RingBuffer_GetLen(buffer), RingBuffer_GetCapacity(buffer));
}
}
if(true == result) {
printf(" Successful Clear: ");
result &= test(true == RingBuffer_Clear(buffer));
printf(" Is empty: ");
result &= test(true == RingBuffer_IsEmpty(buffer));
printf(" Length is 0: ");
result &= test(0 == RingBuffer_GetLen(buffer));
printf(" Capacity is %"PRI_SIZET": ", dataSize);
result &= test(dataSize == RingBuffer_GetCapacity(buffer));
printf(" Can be written: ");
result &= test(true == RingBuffer_PutChar(buffer, '0'));
}
}
printf("Test 4: %s\n\n", (true == result) ? PASSED : FAILED);
return result;
}
static bool RingBuffer_Interleaved_ut(RingBuffer* buffer, char* data, size_t dataSize) {
printf("Test 5: Checking RingBuffer interleaved read/write...\n");
printf(" - Initialize guard memory region...\n");
data[0] = data[dataSize - 1] = guardValue;
size_t dataSizeWithoutGuard = dataSize -2;
printf(" - Initialize ring buffer with memory region with size %"PRI_SIZET": ", dataSizeWithoutGuard);
bool result = test(true == RingBuffer_Init(buffer, data + 1, dataSizeWithoutGuard));
if(true == result) {
printf(" Write data into the buffer...\n");
for(size_t j = 0; true == result && j < dataSizeWithoutGuard; ++j) {
result &= test_quiet(j == RingBuffer_GetLen(buffer));
result &= test_quiet(true == RingBuffer_PutChar(buffer, 0xFF));
}
if(true == result) {
for(size_t j = 0; true == result && j < 10; ++j) {
printf(" Read data from the buffer...\n");
char in;
for(size_t j = 0; true == result && j < dataSizeWithoutGuard/2; ++j) {
result &= test_quiet(true == RingBuffer_GetChar(buffer, &in));
if(true == result) {
result &= test_quiet((char)0xFF == in);
}
}
if(true == result) {
printf(" Write data into the buffer...\n");
for(size_t j = 0; true == result && j < dataSizeWithoutGuard/2; ++j) {
if(result &= test_quiet(true == RingBuffer_PutChar(buffer, 0xFF))) {
if(false == (result &= test_quiet(guardValue == data[0] && guardValue == data[dataSize - 1]))) {
printf(" Writing data resulted in Buffer Overflow\n");
}
}
}
}
}
}
}
printf("Test 5: %s\n\n", (true == result) ? PASSED : FAILED);
return result;
}
bool RingBuffer_UnitTest(void) {
RingBuffer buffer;
char data1[capacity1], data2[capacity2], data3[capacity3];
char* data[] = {data1, data2, data3};
size_t dataSize[] = { sizeof(data1), sizeof(data2), sizeof(data3)};
bool result = true;
for(int i = 0; true == result && i < sizeof(data)/ sizeof(*data); ++i) {
printf("========== PERFORMING TEST FOR DATA BUFFER WITH SIZE %"PRI_SIZET" ==========\n", dataSize[i]);
do {
if(false == (result &= RingBuffer_ut(&buffer))) break;
if(false == (result &= RingBuffer_Init_ut(&buffer, data[i], dataSize[i]))) break;
if(false == (result &= RingBuffer_PutChar_ut(&buffer, data[i], dataSize[i]))) break;
if(false == (result &= RingBuffer_GetChar_ut(&buffer, data[i], dataSize[i]))) break;
if(false == (result &= RingBuffer_Clear_ut(&buffer, data[i], dataSize[i]))) break;
if(false == (result &= RingBuffer_Interleaved_ut(&buffer, data[i], dataSize[i]))) break;
} while(0);
printf("========== TEST FOR DATA BUFFER WITH SIZE %"PRI_SIZET" FINISHED WITH RESULT %s ==========\n", dataSize[i], (true == result) ? PASSED : FAILED);
}
return result;
}
#ifndef _RING_BUFFER_
#define _RING_BUFFER_
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
char buffer[];
/** Structure describing the ring buffer. */
typedef struct {
char * buf; // pointer
size_t len; // length buffer
uint32_t head; // head pointer value
uint32_t tail; // tail pointer value
size_t size; // tail pointer value
} RingBuffer;
/**
* Initializes the given ring buffer structure.
*
* @param ringBuffer pointer to a \ref RingBuffer structure
* @param dataBuffer pointer to a location in memory, where the ring buffer data will be stored
* @param dataBufferSize size in bytes of the dataBuffer
* @return true if all arguments are valid and the ring buffer is initialized successfully, false otherwise
*/
bool RingBuffer_Init(RingBuffer *ringBuffer, char *dataBuffer, size_t dataBufferSize);
/**
* Clears contents of the given ring buffer.
*
* @param ringBuffer pointer to a \ref RingBuffer structure
* @return true if the ring buffer is cleared successfully, false otherwise
*/
bool RingBuffer_Clear(RingBuffer *ringBuffer);
/**
* Checks if the given ring buffer is empty.
*
* @param ringBuffer pointer to a \ref RingBuffer structure
* @return true if the ring buffer holds no data, false otherwise
*/
bool RingBuffer_IsEmpty(const RingBuffer *ringBuffer);
/**
* Gets the length (in bytes) of the data stored in the given ring buffer.
*
* @param ringBuffer pointer to a \ref RingBuffer structure
* @return length (in bytes) of the data stored in the ring buffer
*/
size_t RingBuffer_GetLen(const RingBuffer *ringBuffer);
/**
* Returns the capacity (in bytes) of the given buffer.
*
* @param ringBuffer pointer to a \ref RingBuffer structure
* @return capacity (in bytes) of the ring buffer (how much characters can it store)
*/
size_t RingBuffer_GetCapacity(const RingBuffer *ringBuffer);
/**
* Appends a single character to the ring buffer. The stored data length will be
* increased by 1.
*
* @param ringBuffer pointer to a \ref RingBuffer structure
* @return true if the character was added successfully, false otherwise
*/
bool RingBuffer_PutChar(RingBuffer *ringBuffer, char c);
/**
* Pulls out a single character from the ring buffer. The stored data length will be
* decreased by 1.
*
* @param ringBuffer pointer to a \ref RingBuffer structure
* @return true if the character was pulled out successfully, false otherwise
*/
bool RingBuffer_GetChar(RingBuffer *ringBuffer, char *c);
#endif //_RING_BUFFER_
/* Includes ------------------------------------------------------------------*/
#include <assert.h>
#include "ring_buffer.h"
bool RingBuffer_Init(RingBuffer *ringBuffer, char *dataBuffer, size_t dataBufferSize)
{
assert(ringBuffer);
assert(dataBuffer);
assert(dataBufferSize > 0);
if ((ringBuffer) && (dataBuffer) && (dataBufferSize > 0))
{
ringBuffer->head = 0;
ringBuffer->tail = 0;
ringBuffer->len = 0;
ringBuffer->size = dataBufferSize;
ringBuffer->buf = dataBuffer;
return true;
}
return false;
}
bool RingBuffer_Clear(RingBuffer *ringBuffer)
{
assert(ringBuffer);
if (ringBuffer) {
memset(ringBuffer->buf, 0, ringBuffer->size);
ringBuffer->head = 0;
ringBuffer->tail = 0;
ringBuffer->len = 0;
return true;
}
return false;
}
bool RingBuffer_IsEmpty(const RingBuffer *ringBuffer)
{
assert(ringBuffer);
// Sprawdzamy czy w buforze jest coś do odczytania
if (ringBuffer->head == ringBuffer->tail)
return true;
else
return false;
}
size_t RingBuffer_GetLen(const RingBuffer *ringBuffer)
{
assert(ringBuffer);
if (ringBuffer) {
// TODO
size_t dataLen = ringBuffer->len;
return dataLen;
}
return 0;
}
size_t RingBuffer_GetCapacity(const RingBuffer *ringBuffer)
{
assert(ringBuffer);
if (ringBuffer) {
// TODO
size_t dataLen = ringBuffer->len;
size_t dataSize = ringBuffer->size;
size_t cap = dataSize-dataLen;
return cap;
}
return 0;
}
bool RingBuffer_PutChar(RingBuffer *ringBuffer, char c)
{
assert(ringBuffer);
if (ringBuffer) {
uint32_t head_temp = ringBuffer->head + 1; // Przypisujemy do zmiennej następny indeks head
size_t cap = RingBuffer_GetCapacity(ringBuffer);
//if(head_temp != ringBuffer->tail) // jesli bufor nie jest pusty
// // Jeśli był to ostatni element tablicy to ustawiamy wskaźnik na jej początek
//if ( head_temp == ringBuffer->size )
// head_temp = 0;
// if ((ringBuffer->len)<(ringBuffer->size)) // jesli bufor nie jest przepelniony
if (cap) // jesli jest miejsce w buforze
{
// Jeśli jest miejsce w buforze to przechodzimy dalej:
ringBuffer->buf[head_temp] = c; // Wpisujemy wartość do bufora
ringBuffer->head = head_temp; // Zapisujemy nowy indeks head
ringBuffer->len++; // = ringBuffer->len + 1;
return true;
}
// Sprawdzamy czy jest miejsce w buforze.
// Jeśli bufor jest pełny to wychodzimy z funkcji i zwracamy błąd.
//if ( head_temp != ringBuffer->tail )
// Można zamiast tego czekać na zwolnienie miejsca: while (head_temp == q->tail);
}
return false;
}
bool RingBuffer_GetChar(RingBuffer *ringBuffer, char *c)
{
assert(ringBuffer);
assert(c);
if ((ringBuffer) && (c)) {
// TODO
// Sprawdzamy czy w buforze jest coś do odczytania
// Jeśli bufor jest pusty to wychodzimy z funkcji i zwracamy błąd.
if (ringBuffer->head == ringBuffer->tail)
return false;
// Jeśli jest coś do odczytania to przechodzimy dalej:
ringBuffer->tail++; // Inkrementujemy indeks tail
// Jeśli był to ostatni element tablicy to ustawiamy wskaźnik na jej początek
if (ringBuffer->tail == ringBuffer->size)
ringBuffer->tail = 0;
*c = ringBuffer->buf[ringBuffer->tail]; // Odczytujemy wartość z bufora
}
return true;
}