//- Copyright (c) 2008-2020 James Grenning --- All rights reserved
//- For exclusive use by participants in Wingman Software training courses.
//- Cannot be used by attendees to train others without written permission.
//- www.wingman-sw.com james@wingman-sw.com

#include "CppUTest/TestHarness.h"

extern "C"
{
#include "CircularBuffer.h"
}

#define TEST_CAPACITY 3
#define GET_EMPTY_VALUE (-1)

TEST_GROUP(CircularBuffer)
{
    struct CircularBuffer * buffer;

    void setup()
    {
        buffer = CircularBuffer_Create(TEST_CAPACITY, GET_EMPTY_VALUE);
    }

    void teardown()
    {
        CircularBuffer_Destroy(buffer);
    }

    void fillTheQueue(size_t howMany)
    {
        for (size_t i = 0; i < howMany; i++)
            CircularBuffer_Put(buffer, (int)i);
    }

};

TEST(CircularBuffer, is_empty_after_creation)
{
    CHECK_TRUE(CircularBuffer_IsEmpty(buffer));
}

TEST(CircularBuffer, is_not_full_after_creation)
{
    CHECK_FALSE(CircularBuffer_IsFull(buffer));
}

TEST(CircularBuffer, is_not_empty_after_put)
{
    CircularBuffer_Put(buffer, 42);
    CHECK_FALSE(CircularBuffer_IsEmpty(buffer));
}

TEST(CircularBuffer, is_empty_after_put_then_get)
{
    CircularBuffer_Put(buffer, 42);
    CircularBuffer_Get(buffer);
    CHECK_TRUE(CircularBuffer_IsEmpty(buffer));
}

TEST(CircularBuffer, put_get_one_value)
{
    CircularBuffer_Put(buffer, 42);
    LONGS_EQUAL(42, CircularBuffer_Get(buffer));
}

TEST(CircularBuffer, put_get_is_fifo)
{
    CircularBuffer_Put(buffer, 42);
    CircularBuffer_Put(buffer, 43);
    CircularBuffer_Put(buffer, 44);
    LONGS_EQUAL(42, CircularBuffer_Get(buffer));
    LONGS_EQUAL(43, CircularBuffer_Get(buffer));
    LONGS_EQUAL(44, CircularBuffer_Get(buffer));
}

TEST(CircularBuffer, report_capacity)
{
    LONGS_EQUAL(TEST_CAPACITY, CircularBuffer_Capacity(buffer));
}

TEST(CircularBuffer, create_sets_capacity)
{
    CircularBuffer * buffer = CircularBuffer_Create(2, GET_EMPTY_VALUE);
    LONGS_EQUAL(2, CircularBuffer_Capacity(buffer));
    CircularBuffer_Destroy(buffer);
}

TEST(CircularBuffer, is_full_when_filled_to_capacity)
{
    CircularBuffer_Put(buffer, 1);
    CircularBuffer_Put(buffer, 2);
    CircularBuffer_Put(buffer, 3);
    CHECK_TRUE(CircularBuffer_IsFull(buffer));
}

TEST(CircularBuffer, is_not_empty_when_filled_to_capacity)
{
    CircularBuffer_Put(buffer, 1);
    CircularBuffer_Put(buffer, 2);
    CircularBuffer_Put(buffer, 3);
    CHECK_FALSE(CircularBuffer_IsEmpty(buffer));
}

TEST(CircularBuffer, is_not_full_after_get_from_full_buffer)
{
    CircularBuffer_Put(buffer, 1);
    CircularBuffer_Put(buffer, 2);
    CircularBuffer_Put(buffer, 3);
    CircularBuffer_Get(buffer);
    CHECK_FALSE(CircularBuffer_IsFull(buffer));
}

TEST(CircularBuffer, fill_then_empty)
{
    CircularBuffer_Put(buffer, 1);
    CircularBuffer_Put(buffer, 2);
    CircularBuffer_Put(buffer, 3);
    LONGS_EQUAL(1, CircularBuffer_Get(buffer));
    LONGS_EQUAL(2, CircularBuffer_Get(buffer));
    LONGS_EQUAL(3, CircularBuffer_Get(buffer));
    CHECK_TRUE(CircularBuffer_IsEmpty(buffer));
}

TEST(CircularBuffer, force_a_buffer_wraparound)
{
    CircularBuffer_Put(buffer, 1);
    CircularBuffer_Put(buffer, 2);
    CircularBuffer_Put(buffer, 3);
    CircularBuffer_Get(buffer);
    CircularBuffer_Put(buffer, 1000);
    CHECK_TRUE(CircularBuffer_IsFull(buffer));
    LONGS_EQUAL(2, CircularBuffer_Get(buffer));
    LONGS_EQUAL(3, CircularBuffer_Get(buffer));
    LONGS_EQUAL(1000, CircularBuffer_Get(buffer));
    CHECK_TRUE(CircularBuffer_IsEmpty(buffer));
}

TEST(CircularBuffer, put_to_full_fails)
{
    CircularBuffer_Put(buffer, 1);
    CircularBuffer_Put(buffer, 2);
    CHECK(CircularBuffer_Put(buffer, 3));
    CHECK_FALSE(CircularBuffer_Put(buffer, 4));
}

TEST(CircularBuffer, put_to_full_does_not_damage_contents)
{
    CircularBuffer_Put(buffer, 1);
    CircularBuffer_Put(buffer, 2);
    CircularBuffer_Put(buffer, 3);
    CircularBuffer_Put(buffer, 4);
    CHECK_TRUE(CircularBuffer_IsFull(buffer));
    LONGS_EQUAL(1, CircularBuffer_Get(buffer));
    LONGS_EQUAL(2, CircularBuffer_Get(buffer));
    LONGS_EQUAL(3, CircularBuffer_Get(buffer));
    CHECK_TRUE(CircularBuffer_IsEmpty(buffer));
}

TEST(CircularBuffer, get_from_empty_returns_default_value)
{
    struct CircularBuffer * b = CircularBuffer_Create(100, -9999);
    LONGS_EQUAL(-9999, CircularBuffer_Get(b));
    CircularBuffer_Destroy(b);
}

TEST(CircularBuffer, three_is_not_special)
{
    struct CircularBuffer * b = CircularBuffer_Create(100, GET_EMPTY_VALUE);
    for (int i = 0; i < 100; i++)
        CircularBuffer_Put(b, i);
    CHECK(CircularBuffer_IsFull(b));

    for (int i = 0; i < 99; i++)
        CircularBuffer_Get(b);
    LONGS_EQUAL(99, CircularBuffer_Get(b));
    CHECK(CircularBuffer_IsEmpty(b));

    CircularBuffer_Destroy(b);

}

