#include <luna/HashMap.h>
#include <luna/HashTable.h>
#include <os/File.h>
#include <test.h>

struct TwoInts
{
    int a;
    int b;

    bool operator==(TwoInts other) const
    {
        return other.a == a;
    }
};

template <> u64 hash(const TwoInts& value, u64 salt)
{
    return hash(value.a, salt);
}

TestResult test_empty_hash_table()
{
    HashTable<int> table;

    validate(table.try_find(0) == nullptr);

    test_success;
}

TestResult test_hash_table_find()
{
    HashTable<int> table;

    validate(TRY(table.try_set(0)));

    validate(table.try_find(0));
    validate(table.try_find(1) == nullptr);

    test_success;
}

TestResult test_hash_table_remove()
{
    HashTable<int> table;

    validate(TRY(table.try_set(0)));

    validate(table.try_find(0));

    validate(table.try_remove(0));

    validate(table.try_find(0) == nullptr);

    test_success;
}

TestResult test_hash_table_duplicates()
{
    HashTable<TwoInts> table;

    validate(TRY(table.try_set(TwoInts { 1, 5 })));
    validate(!TRY(table.try_set(TwoInts { 1, 3 })));

    validate(table.try_find(TwoInts { 1, 0 })->b == 5);

    test_success;
}

TestResult test_hash_map_set_and_get()
{
    HashMap<int, int> map;

    validate(TRY(map.try_set(1, 42)));

    validate(map.try_get(1).release_value() == 42);

    validate(!map.try_get(6).has_value());

    test_success;
}

Result<void> test_main()
{
    test_prelude;

    run_test(test_empty_hash_table);
    run_test(test_hash_table_find);
    run_test(test_hash_table_remove);
    run_test(test_hash_table_duplicates);
    run_test(test_hash_map_set_and_get);

    return {};
}