/* Copyright (c) 2026 Jakub Juszczakiewicz
 * All rights reserved.
 */

#include <allocator.h>

#define TEST_BLOCK_SIZE 32
#define TEST_BLOCK_COUNT 16

int test_create_and_dispose(void)
{
  allocator_t a = allocator_create(TEST_BLOCK_SIZE, TEST_BLOCK_COUNT);
  if (!a)
    return 1;

  allocator_dispose(a);
  return 0;
}

int test_alloc_one_block(void)
{
  allocator_t a = allocator_create(TEST_BLOCK_SIZE, TEST_BLOCK_COUNT);
  if (!a)
    return 1;

  void * ptr = allocator_new(a);
  if (!ptr)
    return 1;

  allocator_dispose(a);
  return 0;
}

int test_alloc_and_free_one_block(void)
{
  allocator_t a = allocator_create(TEST_BLOCK_SIZE, TEST_BLOCK_COUNT);
  if (!a)
    return 1;

  void * ptr = allocator_new(a);
  if (!ptr)
    return 1;

  allocator_free(a, ptr);

  allocator_dispose(a);
  return 0;
}

int test_alloc_and_double_free_one_block(void)
{
  allocator_t a = allocator_create(TEST_BLOCK_SIZE, TEST_BLOCK_COUNT);
  if (!a)
    return 1;

  void * ptr = allocator_new(a);
  if (!ptr)
    return 1;

  allocator_free(a, ptr);
  allocator_free(a, ptr);

  allocator_dispose(a);
  return 0;
}

int test_overalloc_blocks(void)
{
  allocator_t a = allocator_create(TEST_BLOCK_SIZE, TEST_BLOCK_COUNT);
  if (!a)
    return 1;

  void * ptrs[TEST_BLOCK_COUNT];
  for (size_t i = 0; i < TEST_BLOCK_COUNT; i++) {
    ptrs[i] = allocator_new(a);
    if (!ptrs[i])
      return 1;
  }
  void * ptr = allocator_new(a);
  if (ptr)
    return 1;

  allocator_dispose(a);
  return 0;
}

int test_alloc_all_blocks_free_and_alloc(void)
{
  allocator_t a = allocator_create(TEST_BLOCK_SIZE, TEST_BLOCK_COUNT);
  if (!a)
    return 1;

  void * ptrs[TEST_BLOCK_COUNT];
  for (size_t i = 0; i < TEST_BLOCK_COUNT; i++) {
    ptrs[i] = allocator_new(a);
    if (!ptrs[i])
      return 1;
  }
  for (size_t i = 0; i < TEST_BLOCK_COUNT; i++) {
    allocator_free(a, ptrs[i]);
  }

  void * ptr = allocator_new(a);
  if (!ptr)
    return 1;

  allocator_free(a, ptr);

  allocator_dispose(a);
  return 0;
}

int main(void)
{
  int r;

  r = test_create_and_dispose();
  if (r)
    return r;

  r = test_alloc_one_block();
  if (r)
    return r;

  r = test_alloc_and_free_one_block();
  if (r)
    return r;

  r = test_alloc_and_double_free_one_block();
  if (r)
    return r;

  r = test_overalloc_blocks();
  if (r)
    return r;

  r = test_alloc_all_blocks_free_and_alloc();
  if (r)
    return r;

  return 0;
}
