/*
 * Copyright (c) 2002, 2004, 2005 Sendmail, Inc. and its suppliers.
 *	All rights reserved.
 *
 * By using this file, you agree to the terms and conditions set
 * forth in the LICENSE file which can be found at the top level of
 * the sendmail distribution.
 *
 */

#include "sm/generic.h"
SM_RCSID("@(#)$Id: t-rsc-0.c,v 1.17 2005/05/31 21:00:28 ca Exp $")

#include <stdio.h>

#include "sm/memops.h"
#include "sm/assert.h"
#include "sm/rpool.h"
#include "sm/rsc.h"
#include "sm/test.h"

#define CSIZE	13
#define HTSIZE	25
#define CHARS	64
#define NH	61	/* must be less than CHARS */
#define HLEN	12
#define KLEN	(HLEN - 2)

int Verbose = 0;
char hashes[NH][HLEN];

static void *
create(const char *key, uint len, void *value, void *ctx)
{
	char *n;
	sm_rpool_P rpool;

	rpool = (sm_rpool_P) ctx;
	n = sm_rpool_strdup(rpool, value);
	if (Verbose > 1)
		fprintf(stderr, "create(%s)=%s\n", key, n == NULL ? "<NULL>" : n);
	return n;
}

static sm_ret_T
delete(void *data, void *ctx)
{
	sm_rpool_P rpool;

	rpool = (sm_rpool_P) ctx;
	if (Verbose > 1)
		fprintf(stderr, "delete(%s)\n", (char *)data);
	sm_rpool_free(rpool, data);
	return SM_SUCCESS;
}

static int cnt = 0;

static void
action(const char *key, const void *value, void *ctx, void *walk_ctx)
{
	if (Verbose > 1)
		fprintf(stderr, "action(%s)=%s\n", key, (char *) value);
	++cnt;
}

static void
testh(uint csize, uint htsize)
{
	int i, j, k;
	rsc_P ct;
	void *ctx;
	char *res;
	sm_ret_T ret;
#if SM_BHTABLE_PERF
	char buf[1024];
#endif /* SM_BHTABLE_PERF */

	ctx = NULL;
	ct = rsc_new(csize, htsize, create, delete, ctx);
	SM_TEST(ct != NULL);
	if (ct == NULL)
		return;
	for (i = 0; i < NH; i++)
	{
		for (j = 0; j < HLEN; j++)
		{
			hashes[i][j] = 'A' + ((i + j) % CHARS);
		}
		hashes[i][HLEN - 1] = '\0';
	}

	for (j = 0; j < CSIZE; j++)
	{
		i = j % NH;
		ret = rsc_add(ct, false, hashes[i], KLEN, hashes[i], (void **)&res);
		SM_TEST(!sm_is_err(ret));
		SM_TEST(strcmp(res, hashes[i]) == 0);
		cnt = 0;
		rsc_walk(ct, action, (void *) 0);
		SM_TEST(cnt == j + 1);
		k = rsc_usage(ct);
		SM_TEST(k == (int) ((j + 1) * 100 / CSIZE));
	}

	for (k = CSIZE; k < NH; k++)
	{
		res = (char *) rsc_lookup(ct, hashes[k], KLEN);
		SM_TEST(res == NULL);
		if (Verbose > 0 && res != NULL)
			fprintf(stderr, "j=%d, k=%d, res=%s\n",
				j, k, res);
		k = rsc_usage(ct);
		SM_TEST(k == 100);
	}

	for (j = 0; j < CSIZE * 3; j++)
	{
		i = j % NH;
		ret = rsc_add(ct, true, hashes[i], KLEN, hashes[i], (void **)&res);
		SM_TEST(!sm_is_err(ret));
		SM_TEST(strcmp(res, hashes[i]) == 0);
		cnt = 0;
		rsc_walk(ct, action, (void *) 0);
		SM_TEST(cnt == CSIZE);

		/* make sure that the other entries are not in the cache */
		if (j > CSIZE)
		{
			for (k = j + 1; k < NH; k++)
			{
				res = (char *) rsc_lookup(ct, hashes[k], KLEN);
				SM_TEST(res == NULL);
				if (Verbose > 0 && res != NULL)
					fprintf(stderr, "j=%d, k=%d, res=%s\n",
						j, k, res);
			}
		}
		k = rsc_usage(ct);
		SM_TEST(k == 100);
	}

	/* XXX need a better test that shows the MRU feature */

#if SM_BHTABLE_PERF
	if (Verbose > 0)
	{
		rsc_stats(ct, buf, sizeof(buf));
		printf("%s", buf);
	}
#endif /* SM_BHTABLE_PERF */
	rsc_free(ct);
}

int
main(int argc, char *argv[])
{
	int c;
	uint csize, htsize;

	csize = CSIZE;
	htsize = HTSIZE;
	while ((c = getopt(argc, argv, "c:h:V")) != -1)
	{
		switch (c)
		{
		  case 'c':
			csize = (uint) atoi(optarg);
			break;
		  case 'h':
			htsize = (uint) atoi(optarg);
			break;
		  case 'V':
			++Verbose;
			break;
		  default:
			return(1);
		}
	}
	sm_test_begin(argc, argv, "test rsc 0");
	testh(csize, htsize);
	return sm_test_end();
}


syntax highlighted by Code2HTML, v. 0.9.1