#include <mongoc/mongoc-ts-pool-private.h>

#include "TestSuite.h"
#include "test-libmongoc.h"

static void
test_ts_pool_empty (void)
{
   mongoc_ts_pool *pool = mongoc_ts_pool_new ((mongoc_ts_pool_params){.element_size = sizeof (int)});
   BSON_ASSERT (mongoc_ts_pool_is_empty (pool));
   mongoc_ts_pool_free (pool);
}


static void
test_ts_pool_simple (void)
{
   mongoc_ts_pool *pool = mongoc_ts_pool_new ((mongoc_ts_pool_params){.element_size = sizeof (int)});
   int *item;
   int *item2;

   item = mongoc_ts_pool_get_existing (pool);
   BSON_ASSERT (!item);

   item = mongoc_ts_pool_get (pool, NULL);
   BSON_ASSERT (item);
   ASSERT_CMPINT (*item, ==, 0);
   *item = 42;
   ASSERT_CMPSIZE_T (mongoc_ts_pool_size (pool), ==, 0);
   mongoc_ts_pool_return (pool, item);
   ASSERT_CMPSIZE_T (mongoc_ts_pool_size (pool), ==, 1);

   item2 = mongoc_ts_pool_get_existing (pool);
   BSON_ASSERT (item2);
   ASSERT_CMPINT (*item2, ==, 42);
   ASSERT_CMPSIZE_T (mongoc_ts_pool_size (pool), ==, 0);

   mongoc_ts_pool_drop (pool, item2);
   ASSERT_CMPSIZE_T (mongoc_ts_pool_size (pool), ==, 0);

   mongoc_ts_pool_free (pool);
}

static int
_is_int_42 (const void *v, void *unused)
{
   BSON_UNUSED (unused);
   return *(const int *) v == 42;
}

static void
_set_int_to_7 (void *v, void *unused, bson_error_t *unused2)
{
   BSON_UNUSED (unused);
   BSON_UNUSED (unused2);
   *(int *) v = 7;
}

/* Declare a pool that contains `int`, sets each new int to seven, and drops
 * integers that are equal to 42. */
MONGOC_DECL_SPECIAL_TS_POOL (int, int_pool, void, _set_int_to_7, NULL, _is_int_42)

static void
test_ts_pool_special (void)
{
   int_pool p = int_pool_new (NULL);
   int *item = int_pool_get (p, NULL);

   BSON_ASSERT (item);
   /* Integer items are constructed and set to seven */
   ASSERT_CMPINT (*item, ==, 7);

   ASSERT_CMPSIZE_T (int_pool_size (p), ==, 0);
   int_pool_return (p, item);
   ASSERT_CMPSIZE_T (int_pool_size (p), ==, 1);

   item = int_pool_get_existing (p);
   BSON_ASSERT (item);
   *item = 42;
   int_pool_return (p, item);
   /* The pool will drop integer items that are equal to 42, so the item was not
    * returned to the pool: */
   ASSERT_CMPSIZE_T (int_pool_size (p), ==, 0);

   int_pool_free (p);
}

void
test_ts_pool_install (TestSuite *suite)
{
   TestSuite_Add (suite, "/Util/ts-pool-empty", test_ts_pool_empty);
   TestSuite_Add (suite, "/Util/ts-pool", test_ts_pool_simple);
   TestSuite_Add (suite, "/Util/ts-pool-special", test_ts_pool_special);
}
