/*
 * 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-bhtable.c,v 1.20 2005/04/14 17:14:02 ca Exp $")

#include <stdio.h>

#include "sm/error.h"
#include "sm/heap.h"
#include "sm/bhtable.h"
#include "sm/memops.h"
#include "sm/test.h"

#include "sm/io.h"
#if SM_HEAP_CHECK
extern SM_DEBUG_T SmHeapCheck;
# define HEAP_CHECK (SmHeapCheck > 0)
#else /* SM_HEAP_CHECK */
static int SmHeapCheck;
# define HEAP_CHECK false
#endif /* SM_HEAP_CHECK */

#define T_BHT_SIZE	1023
#define NH	255
#define HLEN	128
#define KLEN	(HLEN - 2)

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

/* ARGSUSED1 */
static sm_ret_T
action(bht_entry_P info, void *ctx)
{
	int i;

	(void) ctx;
	for (i = 0; i < NH; i++)
	{
		if (sm_memeq(info->bhe_value, hashes[i], KLEN))
			return SM_SUCCESS;
	}
	SM_TEST(i < NH);
	return SM_FAILURE;
}

static void
stats(bht_P tn)
{
#if SM_BHT_PERF
	char buf[1024];

	if (Verbose > 0)
	{
		bht_stats(tn, buf, sizeof(buf));
		printf("%s", buf);
	}
#else /* SM_BHT_PERF */
	(void) tn;
#endif /* SM_BHT_PERF */
}

static void
testh(uint bhtsize)
{
	int i, j;
	char *str;
	bht_P tn;
	bht_entry_P bi;
	sm_ret_T ret;

	tn = NULL;
	tn = bht_new(bhtsize, bhtsize * 2);
	SM_TEST(tn != NULL);
	if (tn == NULL)
		return;
	for (i = 0; i < NH; i++)
	{
		for (j = 0; j < HLEN; j++)
		{
			hashes[i][j] = ' ' + (i + j) % 96;
		}
		hashes[i][HLEN - 1] = '\0';
	}

	for (i = 0; i < NH; i++)
	{
		ret = bht_add(tn, hashes[i], KLEN, hashes[i], &bi);
		SM_TEST(ret == SM_SUCCESS);
		SM_TEST(bi != NULL);
	}

	for (i = 0; i < NH; i++)
	{
		str = bht_find(tn, hashes[i], KLEN);
		SM_TEST(str != NULL);
		if (str == NULL)
			goto error;
		SM_TEST(sm_memeq(str, hashes[i], KLEN));
	}

	bht_walk(tn, action, NULL);

	for (i = 0; i < NH; i++)
	{
		str = bht_find(tn, hashes[i], HLEN - 1);
		SM_TEST(str == NULL);
	}
	for (i = 0; i < NH; i++)
	{
		bht_rm(tn, hashes[i], KLEN, NULL, NULL);
		for (j = i + 1; j < NH; j++)
		{
			str = bht_find(tn, hashes[j], KLEN);
			SM_TEST(str != NULL);
			if (str == NULL)
				goto error;
			SM_TEST(sm_memeq(str, hashes[j], KLEN));
		}
	}
  error:
	stats(tn);
	bht_destroy(tn, NULL, NULL);
}

static void
testd(uint bhtsize)
{
	int i, j;
	char *str;
	bht_P tn;
	bht_entry_P bi;
	sm_ret_T ret;

	tn = NULL;
	tn = bht_new(bhtsize, bhtsize * 2);
	SM_TEST(tn != NULL);
	if (tn == NULL)
		return;
	for (i = 0; i < NH; i++)
	{
		for (j = 0; j < HLEN; j++)
		{
			hashes[i][j] = ' ' + (i + j) % 96;
		}
		hashes[i][HLEN - 1] = '\0';
	}

	i = 0;
	ret = bht_add(tn, hashes[i], KLEN, hashes[i], &bi);
	SM_TEST(ret == SM_SUCCESS);
	SM_TEST(bi != NULL);
	for (i = 0; i < NH; i++)
	{
		ret = bht_add(tn, hashes[i], KLEN, hashes[i], &bi);
		SM_TEST(ret == SM_SUCCESS);
		SM_TEST(bi != NULL);
	}

	i = 0;
	bht_rm_all(tn, hashes[i], KLEN, NULL, NULL);

	for (i = 1; i < NH; i++)
	{
		bht_rm(tn, hashes[i], KLEN, NULL, NULL);
		for (j = i + 1; j < NH; j++)
		{
			if (sm_memeq(hashes[0], hashes[j], KLEN))
				continue;
			str = bht_find(tn, hashes[j], KLEN);
			SM_TEST(str != NULL);
			if (str == NULL)
				goto error;
			SM_TEST(sm_memeq(str, hashes[j], KLEN));
		}
	}
  error:
	stats(tn);
	bht_destroy(tn, NULL, NULL);
}


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

	bhtsize = T_BHT_SIZE;
	SmHeapCheck = 0;
	while ((c = getopt(argc, argv, "H:s:V")) != -1)
	{
		switch (c)
		{
		  case 'H':
			SmHeapCheck = atoi(optarg);
			break;
		  case 's':
			bhtsize = (uint) atoi(optarg);
			break;
		  case 'V':
			++Verbose;
			break;
		  default:
			return(1);
		}
	}
	sm_test_begin(argc, argv, "test bhtable");
	if (HEAP_CHECK)
	{
		sm_io_fprintf(smioout, "Heap report before testh(NULL)\n");
		sm_heap_report(smioout, 3);
	}
	testh(bhtsize);
	if (HEAP_CHECK)
	{
		sm_io_fprintf(smioout, "Heap report after testh(NULL)\n");
		sm_heap_report(smioout, 3);
	}
	testd(bhtsize);
	return sm_test_end();
}


syntax highlighted by Code2HTML, v. 0.9.1