#include "../Tests.hpp"
#include "core/data/Stack.hpp"

template class Core::Internal::BaseStack<int, Core::List<int>>;
template class Core::Internal::BaseStack<int, Core::ArrayList<int, 100>>;

template<typename T>
static void testPushPopPeek() {
    T stack;
    stack.push(1).push(2).push(3);
    CORE_TEST_EQUAL(3, stack.peek());
    CORE_TEST_EQUAL(3, static_cast<const T&>(stack).peek());
    stack.pop();
    CORE_TEST_EQUAL(2, stack.peek());
    CORE_TEST_EQUAL(2, static_cast<const T&>(stack).peek());
    stack.pop();
    CORE_TEST_EQUAL(1, stack.peek());
    CORE_TEST_EQUAL(1, static_cast<const T&>(stack).peek());
    stack.pop();
    CORE_TEST_TRUE(stack.isEmpty());
}

template<typename T>
static void testBigPushPop(int amount) {
    T stack;
    for(int i = 0; i < amount; i++) {
        stack.push(i);
    }
    for(int i = 0; i < amount; i++) {
        stack.pop();
    }
    CORE_TEST_TRUE(stack.isEmpty());
}

template<typename T>
static void testToString() {
    T stack;
    stack.push(1).push(243).push(-423);
    CORE_TEST_STRING("[1, 243, -423]", stack);
    CORE_TEST_STRING("[1]", T().push(1));
    CORE_TEST_STRING("[]", T());
}

template<typename T>
static void testClear() {
    T stack;
    stack.push(1).push(2).push(3);
    stack.clear();
    CORE_TEST_TRUE(stack.isEmpty());
}

template<typename T>
static void testType(int amount) {
    testPushPopPeek<T>();
    testBigPushPop<T>(amount);
    testToString<T>();
    testClear<T>();
}

void Core::testStack(bool light) {
    testType<Core::ListStack<int>>(light ? 10000 : 100000);
    testType<Core::ArrayStack<int, 100>>(100);
}