/*
    SPDX-FileCopyrightText: 2021 Valentin Boettcher <hiro at protagon.space; @hiro98:tchncs.de>

    SPDX-License-Identifier: GPL-2.0-or-later
*/

#include <QtGlobal>
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
#include <QtTest/QTest>
#include <QtTest/qtestcase.h>>
#else
#include <QTest>
#include <qtestcase.h>
#endif

#include <QtConcurrent/QtConcurrentRun>

#include "trixelcache.h"

using TestCache = TrixelCache<std::vector<int>>;
class TestTrixelCache : public QObject
{
    Q_OBJECT
  private:
    TestCache m_cache{ 10, 5 };
  private slots:
    void init()
    {
        // a fresh cache for each test
        m_cache = { 10, 5 };
    };

    void noop()
    {
        m_cache = { 10, 10 };
        QVERIFY2(m_cache.noop(), "Is the constructed trixel cache a noop?");

        m_cache.set_size(5);
        QVERIFY2(!m_cache.noop(), "Is the cache no noop after resize?");

        m_cache.set_size(10);
        QVERIFY2(m_cache.noop(), "Is the cache no noop again after resize?");
    }

    void resize()
    {
        QVERIFY_EXCEPTION_THROWN(m_cache.set_size(20), std::range_error);
        m_cache.set_size(1);
        QCOMPARE(m_cache.size(), 1);

        m_cache.set_size(2);
        QCOMPARE(m_cache.size(), 2);
    };

    void setting()
    {
        QCOMPARE(m_cache.current_usage(), 0);

        m_cache[0] = { 1, 2, 3 };
        QCOMPARE(m_cache.current_usage(), 1);
        QCOMPARE(m_cache.primed_indices(), std::list<size_t>{ 0 });
        QVERIFY(m_cache[0].is_set());

        m_cache[2] = { 1, 2, 3 };
        QCOMPARE(m_cache.current_usage(), 2);
        QCOMPARE(m_cache.primed_indices(), (std::list<size_t>{ 2, 0 }));
        QVERIFY(m_cache[2].is_set());
    };

    void pruning()
    {
        m_cache    = { 10, 1 };
        m_cache[1] = { 4, 5, 6 };
        m_cache[0] = { 1, 2, 3 };

        QVERIFY2(m_cache[1].is_set(), "Index 1 should be set.");
        QVERIFY2(m_cache[0].is_set(), "Index 0 should be set.");

        m_cache.prune();

        QVERIFY2(!m_cache[1].is_set(), "Index 1 should be cleared.");
        QCOMPARE(m_cache[1].data(), std::vector<int>{});
        QVERIFY2(m_cache[0].is_set(), "Index 0 should be set.");
        QCOMPARE(m_cache[0].data(), (std::vector<int>{ 1, 2, 3 }));

        m_cache[0] = { 1, 2, 3 };
        m_cache[1] = { 4, 5, 6 };
        m_cache.prune(2);

        QVERIFY2(m_cache[1].is_set(), "Index 1 should be set.");
        QVERIFY2(m_cache[0].is_set(), "Index 0 should be set.");
    };

    void clear()
    {
        m_cache    = { 2, 1 };
        m_cache[1] = { 4, 5, 6 };
        m_cache[0] = { 1, 2, 3 };

        QVERIFY2(m_cache[1].is_set(), "Index 1 should be set.");
        QVERIFY2(m_cache[0].is_set(), "Index 0 should be set.");

        m_cache.clear();

        QCOMPARE(m_cache.current_usage(), 0);
        QCOMPARE(m_cache.primed_indices(), {});

        QVERIFY2(!m_cache[1].is_set(), "Index 1 should be cleared.");
        QCOMPARE(m_cache[1].data(), std::vector<int>{});
        QVERIFY2(!m_cache[0].is_set(), "Index 0 should be cleared.");
        QCOMPARE(m_cache[0].data(), std::vector<int>{});
    };
};

QTEST_GUILESS_MAIN(TestTrixelCache);
