#include "tests/StackTests.h"
#include "tests/Test.h"
#include "utils/StringBuffer.h"
#include "utils/Stack.h"

typedef Stack<int, 10> IntStack;
typedef StringBuffer<50> String;

static void testPushPopPeek(Test& test) {
    IntStack stack;
    stack.push(1);
    stack.push(2);
    stack.push(3);
    test.checkEqual(3, stack.peek(), "push pop peek 1");
    test.checkEqual(false, stack.pop(), "pop without error 1");
    test.checkEqual(2, stack.peek(), "push pop peek 2");
    test.checkEqual(false, stack.pop(), "pop without error 2");
    test.checkEqual(1, stack.peek(), "push pop peek 3");
    test.checkEqual(false, stack.pop(), "pop without error 3");
    test.checkEqual(true, stack.isEmpty(), "empty after popping all");
}

static void testOverflow(Test& test) {
    IntStack stack;
    for(int i = 0; i < 10; i++) {
        test.checkEqual(false, stack.push(i), "push returns false without overflow");
    }
    for(int i = 0; i < 1000000; i++) {
        test.checkEqual(true, stack.push(i), "push returns true with overflow");
    }
    test.checkEqual(true, true, "survives overflow");
}

static void testToString1(Test& test) {
    IntStack stack;
    stack.push(1);
    stack.push(243);
    stack.push(-423);
    test.checkEqual(String("[1, 243, -423]"), String(stack), "to string 1");
}

static void testToString2(Test& test) {
    IntStack stack;
    stack.push(1);
    test.checkEqual(String("[1]"), String(stack), "to string 2");
}

static void testToString3(Test& test) {
    IntStack stack;
    test.checkEqual(String("[]"), String(stack), "to string 3");
}

static void testPop(Test& test) {
    IntStack stack;
    for(int i = 0; i < 1000000; i++) {
        test.checkEqual(true, stack.pop(), "popping empty stack is safe");
    }
}

void StackTests::test() {
    Test test("Stack");
    testPushPopPeek(test);
    testOverflow(test);
    testToString1(test);
    testToString2(test);
    testToString3(test);
    testPop(test);
    test.finalize();
}