// El contrato de la pila, escrito una sola vez, sirve para cualquier implementación.
#include <cassert>
#include <random>
#include <stack>
#include <string>

#include "check.h"
#include "vector_stack.h"

template <typename S>
void last_in_first_out() {
    S stack;
    assert(stack.empty());
    stack.push(1);
    stack.push(2);
    assert(stack.top() == 2);
    stack.pop();
    assert(stack.top() == 1);
    stack.pop();
    assert(stack.empty());
}

template <typename S>
void same_as_library(int seed) {
    std::mt19937 random(seed);
    std::uniform_int_distribution<int> coin(0, 2);
    S stack;
    std::stack<int> reference;
    for (int i = 0; i < 5000; i++) {
        if (coin(random) != 0 || reference.empty()) {
            stack.push(i);
            reference.push(i);
        } else {
            stack.pop();
            reference.pop();
        }
        stack.check_invariants();
        assert(stack.empty() == reference.empty());
        assert(stack.size() == reference.size());
        if (!reference.empty()) {
            assert(stack.top() == reference.top());
        }
    }
}

int main() {
    run_test("último en entrar, primero en salir", [] { last_in_first_out<VectorStack<int>>(); });
    run_test("igual que std::stack", [] { same_as_library<VectorStack<int>>(2026); });
    run_test("con std::string", [] {
        VectorStack<std::string> words;
        words.push("hola");
        words.push("chau");
        assert(words.top() == "chau");
    });
    return 0;
}
