//- Copyright (c) 2008-2020 James Grenning
//- All rights reserved
//- For use by participants in Wingman Software training courses.

#include "CircularBuffer.h"
#include "CppUTest/TestHarness.h"

using namespace std;

TEST_GROUP(CircularBuffer)
{
    CircularBuffer buffer;

    void setup()
    {
    }

    void teardown()
    {
    }
};

TEST(CircularBuffer, start_here)
{
//    FAIL("Start here");
}

/*
 * TDD Exercise
 *
 *   Please read the instructions file.
 *
 *   - Move the #if down the page one test at a time.
 *   - Incrementally develop the circular buffer
 *   - Open the course notes to see some sketches
 *     of interesting CircularBuffer states.
 *   - Delete the conversation comments as you
 *     finish each test.
 *
*/

/* PLEASE DELETE CONVERSATION COMMENTS AS YOU GET TESTS TO PASS */


#ifdef Move_this_line_down_one_test_at_a_time
/*
 * Discussion with James about next test:
 * How do we choose the first test? Let's test initialization.
 * What should the state of the CircularBuffer be after creation?
 * It should be empty.  Let's write a test that defines
 * that interface an assures buffers start out empty.
 *
 * You'll have to add the isEmpty member function.
 * --- remember small steps (Compile, Link, Fail, Pass)
 */

TEST(CircularBuffer, empty_after_create)
{
    CHECK_TRUE(buffer.isEmpty());
}

/* PLEASE DELETE CONVERSATION COMMENTS AS YOU GET TESTS TO PASS */

/*
 * Discussion with James about next test:
 * While the buffer is empty, it can't also be full.
 * Let's write that test.
 */

TEST(CircularBuffer, not_full_after_create)
{
    CHECK_FALSE(buffer.isFull());
}

/* PLEASE DELETE CONVERSATION COMMENTS AS YOU GET TESTS TO PASS */
/*
 * Retrospective:
 * To get the prior two tests passing
 * all you need are the function declarations in
 * the header with hard coded return results in
 * the implementation.  Please delete any other
 * code you don't need yet.
 *
 * Did you remember to fail the test before making it pass?
 */

/*
 * Discussion with James about next test:
 * If we put a value into the buffer, it should no
 * longer be empty. Let's define the Put interface
 * and write a test for the empty to not empty boundary
 * condition.
 */

TEST(CircularBuffer, not_empty_after_put)
{
    buffer.put(42);
    CHECK_FALSE(buffer.isEmpty());
}


/* PLEASE DELETE CONVERSATION COMMENTS AS YOU GET TESTS TO PASS */

/*
 * Discussion with James about next test:
 * While we are at it, let's transition back to empty
 * after putting in one value.  We're testing another
 * boundary condition.
 */

TEST(CircularBuffer, transition_to_empty)
{
    buffer.put(42);
    buffer.get();
    CHECK_TRUE(buffer.isEmpty());
}

/* PLEASE DELETE CONVERSATION COMMENTS AS YOU GET TESTS TO PASS */

/*
 * Retrospective:
 * To get the prior two tests passing
 * all you needed to do was to add an input-index
 * and an output-index to the class, incrementing them
 * in put() and get() and using them to decide if the queue
 * is empty.  You don't need to store anything yet!
 */

/*
 * Discussion with James about next test:
 * Now, lets write a test that checks that a single
 * number put in the queue can be recalled.
 */

TEST(CircularBuffer, get_put_one_value)
{
    buffer.put(42);
    LONGS_EQUAL(42, buffer.get());
}

/* PLEASE DELETE CONVERSATION COMMENTS AS YOU GET TESTS TO PASS */

/*
 * Retrospective:
 * You still do not need to store anything.
 * You can hard code the return value for get()
 *
 * If you have more, it is not tested, delete it! You
 * are supposed to be doing TDD!
 */

/*
 * Discussion with James about next test:
 * With this test it will be more trouble to fake several values
 * than to introduce an array to hold the values.  Make the
 * array a fixed size for now. We can customize the size next.
 */

TEST(CircularBuffer, get_put_a_few_is_fifo)
{
    buffer.put(41);
    buffer.put(42);
    buffer.put(43);
    LONGS_EQUAL(41, buffer.get());
    LONGS_EQUAL(42, buffer.get());
    LONGS_EQUAL(43, buffer.get());
}

/* PLEASE DELETE CONVERSATION COMMENTS AS YOU GET TESTS TO PASS */

/*
 * Retrospective:
 * The previous test has driven you to have a simple internal
 * array in the structure with fixed size, an input-index and
 * an output-index.
 *
 * There should be no circular buffer logic yet!
 *
 * Why?  Your tests do not require it.
 * Please, delete untested code now!
 */

/*
 * Discussion with James about next test:
 * We know a hard-coded buffer length is not going to work
 * in production.  The user of the buffer should provide the
 * capacity when the buffer is created.
 *
 * Let's create a Capacity function, so we can
 * query the capacity.  This brings us one step closer to
 * dynamically sizing the values array.
 * When you get around to passing the capacity to the constructor
 * you'll need to make this test match setup() for the TEST_GROUP.
 *
 */

TEST(CircularBuffer, query_capacity)
{
    LONGS_EQUAL(10, buffer.capacity());
}

/* PLEASE DELETE CONVERSATION COMMENTS AS YOU GET TESTS TO PASS */

/*
 * Now, let's write a test that show how to
 * customize the size.
 *
 * Should you parameterize the existing constructor, or add
 * a second constructor?  You decide.  Be ready to justify
 * you decision.
 *
 * Get this API change in place before actually sizing the
 * internal stored values array.
 *
 * Once the code passes this test you have everything
 * you need to dynamically allocate the values array.
 *
 */

TEST(CircularBuffer, capacity_set_by_constructor)
{
    CircularBuffer buffer1(2);
    CircularBuffer buffer2(10);
    LONGS_EQUAL(2, buffer1.capacity());
    LONGS_EQUAL(10, buffer2.capacity());
}

/* PLEASE DELETE CONVERSATION COMMENTS AS YOU GET TESTS TO PASS */

/*
 ***** NOTICE *****
 * Before you move on, you should modify your implementation
 * to dynamically allocate the values array.
 *
 * (There is no test to make you add dynamic allocation)
 *
 * The tests provide a safety net to support converting
 * your fixed size array to a pointer to allocated memory.
 *
 * YOU SHOULD NOW CONVERT YOUR CircularBuffer TO USE
 * ALLOCATED MEMORY!
 *
 * Convert int values[] to int * values.
 * In your constructor: values = new int[capacity]
 *
 * Later watch the video that demonstrates cpputest's
 * additional safety net for dynamic memory allocation.
 *
 */

/*********************************************************
 *
 * DO NOT CONTINUE UNTIL YOU CONVERT YOUR CircularBuffer 
 * TO USE DYNAMIC ALLCATION
 *
 *********************************************************/


/*
 * Discussion with James about next test:
 * Now let's fill the queue all the way and add the
 * IsFull implementation.
 *
 * 1) Write the test and watch it fail.
 * 2) Then consider the implementation.  You might want
 * to draw the diagram for the full scenario.
 * 3) Before you implement IsFull, look at the comment
 *    near the bottom of the file labeled:
 *        Empty/Full Design Problem and Considerations
 */


TEST(CircularBuffer, is_full_when_filled_to_capacity)
{
    /*
    * Write the test that fills the buffer
    * Then confirms the buffer is full
    */
}

/* PLEASE DELETE CONVERSATION COMMENTS AS YOU GET TESTS TO PASS */

/*
 * There is no need for the wrap around logic yet.
 * That test scenario has not been written.
 *
 * If you have wrap around logic already, delete it.
 */

/*
 * Discussion with James about next test:
 * I kind of expect this test to pass right away.
 */

TEST(CircularBuffer, fill_to_capacity_then_empty)
{
    /*
    * Write the test that fills the buffer
    * Then takes all the items out and checks them
    * Then confirms the buffer is empty
    */
}

/* PLEASE DELETE CONVERSATION COMMENTS AS YOU GET TESTS TO PASS */

/*
 * If you have wrap around logic already, you still
 * do not need it.
 */

/*
 * Discussion with James about next test:
 * Finally, the wrap around test. Sometimes this test will crash the
 * tests when your buffer boundary is violated.
 */

TEST(CircularBuffer, full_after_buffer_wrap_around)
{
    //Write the test
}

TEST(CircularBuffer, values_are_correct_after_wrap_around)
{
    //Write the test
}

TEST(CircularBuffer, empty_after_buffer_wrap_around)
{
    //Write the test
}

/* PLEASE DELETE CONVERSATION COMMENTS AS YOU GET TESTS TO PASS */

/*
 *  If you are using a loop to fill the buffer, you are
 *  overdue for refactoring your tests.
 *
 *  Refactor the loop into a fillTheBuffer helper
 *  function, add it as a helper function to the TEST_GROUP.
 *  Get rid of all the duplication.
 *
 *  BTW: At this point in the exercise you should not have
 *  any production code that is worried about doing a Get
 *  from an empty buffer, or putting to a full buffer.
 *  You will worry about that in the next test.
 *  TDD, remember?
 *
 */

/*
 * Do you plan on using exceptions in your code?
 *
 * If so, let your instructor know.
 */

TEST(CircularBuffer, put_to_full_does_no_harm)
{
    //Write the test
}

TEST(CircularBuffer, get_from_empty_does_no_harm)
{
    //Write the test
}

TEST(CircularBuffer, get_from_empty_returns_a_default_value)
{
    /* Write the test.  You need to modify your constructor
     * to take a custom default value.
     */
}

/*
 * Did you refactor your CircularBuffer implementation,
 * getting rid of duplicate code and fixing bad names?
 */

/*
 * Do you need any other tests?
 */

#endif

/**********************************************************
 *
 * Empty/Full Design Problem and Considerations
 *
 * We earlier looked at the diagram for several
 * CircularBuffer scenarios.  But we did not draw
 * the scenario for the full CircularBuffer.
 *
 * If you followed my lead and used input_index and
 * output_index to determine empty, you have a
 * problem. Empty and full scenarios look the same!
 *
 *
 * Empty
 *
 *       -------------------
 *       |  |  |  |  |  |  |
 *       -------------------
 *           ^^
 *           ||
 *           / \
 *          /   input_index
 *         output_index
 *
 *
 * Full
 *       -------------------
 *       |22|17|33|64|00|14|
 *       -------------------
 *              ^^
 *              ||
 *              / \
 *             /   \
 *            /     output_index
 *      input_index
 *
 * Not empty/full and not wrapped
 *
 *       -------------------
 *       |  |53|12|19|  |  |
 *       -------------------
 *           ^        ^
 *           |        |
 *           /         \
 *          /           input_index
 *         output_index
 *
 *
 * Not empty/full and is wrapped
 *
 *       -------------------
 *       |  |  |12|19|42|86|
 *       -------------------
 *        ^      ^
 *        |      |
 *        /       \
 *       /         output_index
 *      input_index
 *
 *
 *
 * Have you ever started down a path programming and
 * then discovered a critical flaw?
 *
 * I'd like you now to consider WTSTTCPW!
 *
 * (What's The Simplest Thing That Could Possibly Work.)
 *
 * I've seen many complex solution attempts that won't work.
 * Keep it simple. If you are aware of the 'extra-cell'
 * design, do not use it now. There are simpler designs.
 * We'll consider the extra-cell design in the next exercise.
 *
 * If you are not sure how to continue, there are a
 * couple hints in the next comment block.
 *
 *********************************************************/


/*********************************************************
 *
 * Hints for Empty/Full Detection.
 *
 * There are a couple simple approaches. Each hint refers
 * to a specific approach.
 *
 * 1) How many items are in an empty CircualrBuffer?
 *
 * 2) How can you differentiate the two scenarios where
 *    input_index == output_index?
 *
 * 3) If you are familar with the extra cell design, don't
 *    use it now.  The next exercise we'll convert the
 *    CircularBuffer to that design.
 *
 *********************************************************/
