// Pruebas de IntBuffer: copia, autoasignación, movimiento y cuántas reservas hace cada uno.
#include <cassert>
#include <type_traits>
#include <utility>

#include "alloc_count.h"
#include "check.h"
#include "int_buffer.h"

static_assert(std::is_nothrow_move_constructible_v<IntBuffer>);
static_assert(std::is_nothrow_move_assignable_v<IntBuffer>);

int main() {
    run_test("copia independiente", [] {
        IntBuffer a(3);
        a.at(1) = 5;
        IntBuffer b(a);
        b.at(1) = 6;
        assert(a.at(1) == 5 && b.at(1) == 6);
    });
    run_test("asignación de copia reserva una vez", [] {
        IntBuffer a(3);
        IntBuffer b(8);
        a.at(0) = 1;
        std::size_t before = array_news();
        b = a;
        assert(array_news() == before + 1);
        assert(b.size() == 3 && b.at(0) == 1);
        a.at(0) = 2;
        assert(b.at(0) == 1);
    });
    run_test("autoasignación", [] {
        IntBuffer a(3);
        a.at(2) = 4;
        IntBuffer& same = a;
        a = same;
        assert(a.size() == 3 && a.at(2) == 4);
    });
    run_test("mover no reserva y deja vacío", [] {
        IntBuffer a(3);
        a.at(0) = 8;
        std::size_t before = array_news();
        IntBuffer b(std::move(a));
        assert(array_news() == before);
        assert(a.size() == 0 && b.at(0) == 8);
        a.check_invariants();
        IntBuffer c(1);
        before = array_news();
        c = std::move(b);
        assert(array_news() == before);
        assert(b.size() == 0 && c.size() == 3 && c.at(0) == 8);
        b.check_invariants();
    });
    run_test("automovimiento", [] {
        IntBuffer a(2);
        a.at(1) = 3;
        IntBuffer& same = a;
        a = std::move(same);
        assert(a.size() == 2 && a.at(1) == 3);
        a.check_invariants();
    });
    run_test("un objeto movido se puede volver a usar", [] {
        IntBuffer a(2);
        IntBuffer b(std::move(a));
        a = b;
        assert(a.size() == 2);
        IntBuffer c(std::move(a));
        a = IntBuffer(4);
        assert(a.size() == 4);
    });
    run_test("reservas y liberaciones se emparejan", [] {
        std::size_t news = array_news();
        std::size_t deletes = array_deletes();
        {
            IntBuffer a(3);
            IntBuffer b(a);
            IntBuffer c(std::move(a));
            b = c;
            c = std::move(b);
        }
        assert(array_news() - news == array_deletes() - deletes);
    });
    return 0;
}
