#include "tile/base/thread/mutex.h"
#include "tile/base/thread/unique_lock.h"
#include "gtest/gtest.h"

#include <thread>

namespace tile {
TEST(UniqueLock, Lock)
{
    Mutex m;
    bool is_set = false;

    {
        UniqueLock<Mutex> lock(m);

        {
            std::thread t1([&] {
                UniqueLock<Mutex> lock(m);
                is_set = true;
            });

            ASSERT_FALSE(is_set);
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
            ASSERT_FALSE(is_set);
            m.Unlock();
            t1.join();
            ASSERT_TRUE(is_set);
            m.Lock();
        }
    }
    ASSERT_TRUE(m.TryLock());
    m.Unlock();
}

TEST(UniqueLock, MultiThread)
{
    constexpr std::size_t kThreadCount = 5;
    constexpr std::size_t kLoopCount   = 10000;

    int x                              = 0;
    Mutex m;
    auto AddOne([&] {
        tile::UniqueLock<Mutex> lock(m);
        int old = x++;
        ASSERT_EQ(old + 1, x);
    });

    std::vector<std::thread> threads;
    threads.resize(kThreadCount);
    for (int i = 0; i < kThreadCount; i++) {
        threads[i] = std::thread([&] {
            for (int i = 0; i < kLoopCount; i++) { AddOne(); }
        });
    }
    while (x != kThreadCount * kLoopCount) { std::this_thread::yield(); }
    for (auto &&t : threads) { t.join(); }
}
}// namespace tile
