/*
 * Copyright (c) 2003-2006 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-bdb-0.c,v 1.25 2006/10/05 04:27:38 ca Exp $")

#include "sm/error.h"
#include "sm/heap.h"
#include "sm/memops.h"
#include "sm/string.h"
#include "sm/sysexits.h"
#include "sm/test.h"
#include "sm/maps.h"
#include "sm/mapc.h"
#include "sm/map.h"
#include "sm/mapclasses.h"
#include "sm/bdb.h"
#include "sm/cdb_map.h"

#include "sm/io.h"

int Verbose = 0;

#define MAPC_TYPE	"hash"
#define MAPC_NAME	"bdb0"
#define MAPC_FILE	"./bdb0.db"
#define KEY1	"left1"
#define KEY2	"left2"
#define KEY3	"left3"
#define DATA1	"right1"
#define DATA2	"right2"

static sm_ret_T
init_mapc_test(sm_maps_P *pmaps)
{
	sm_ret_T ret;

	SM_REQUIRE(pmaps != NULL);
	ret = sm_maps_init(pmaps);
	SM_TEST(*pmaps != NULL);
	if (*pmaps == NULL)
		return ret;
	SM_TEST(sm_is_success(ret));
	ret = sm_bdb_class_create(*pmaps);
	SM_TEST(sm_is_success(ret));
#if MTA_USE_TINYCDB
	ret = sm_cdb_class_create(*pmaps);
	SM_TEST(sm_is_success(ret));
#endif
	return ret;
}

static void
testh(const char *mapname, const char *mapfile, const char *maptype)
{
	sm_ret_T ret;
	sm_maps_P maps;
	sm_map_P map;
	sm_cstr_P mtype, mname;
	sm_str_P lhs, rhs;
	sm_map_key_T key;
	sm_map_data_T data;

	maps = NULL;
	mtype = mname = NULL;
	lhs = rhs = NULL;

	mtype = sm_cstr_scpyn0((const uchar *)maptype, strlen(maptype));
	SM_TEST(mtype != NULL);
	if (mtype == NULL)
		goto error;

	mname = sm_cstr_scpyn0((const uchar *)mapname, strlen(mapname));
	SM_TEST(mname != NULL);
	if (mname == NULL)
		goto error;

	lhs = sm_str_new(NULL, 256, 1024);
	SM_TEST(lhs != NULL);
	if (lhs == NULL)
		goto error;

	rhs = sm_str_new(NULL, 256, 1024);
	SM_TEST(rhs != NULL);
	if (rhs == NULL)
		goto error;

	ret = init_mapc_test(&maps);
	SM_TEST(sm_is_success(ret));

	ret = unlink(mapfile);

	map = NULL;
	ret = sm_map_open(maps, mname, mtype, SMAP_MODE_CREATE, mapfile,
			SMAP_MODE_RDWR, &map, SMPO_END);
	SM_TEST(sm_is_success(ret));
	if (!sm_is_success(ret))
		goto error;

	sm_str_assign(key, NULL, (uchar *)KEY1, strlen(KEY1), strlen(KEY1));
	sm_str_assign(data, NULL, (uchar *)DATA1, strlen(DATA1), strlen(DATA1));
	ret = sm_map_add(map, &key, &data, SMMAP_AFL_NONE);
	SM_TEST(sm_is_success(ret));

	sm_str_assign(key, NULL, (uchar *)KEY2, strlen(KEY2), strlen(KEY2));
	sm_str_assign(data, NULL, (uchar *)DATA2, strlen(DATA2), strlen(DATA2));
	ret = sm_map_add(map, &key, &data, SMMAP_AFL_NONE);
	SM_TEST(sm_is_success(ret));

	ret = sm_map_add(map, &key, &data, SMMAP_AFL_NONE);
	SM_TEST(sm_is_success(ret));

	ret = sm_map_close(map, 0);
	SM_TEST(sm_is_success(ret));

	map = NULL;
	ret = sm_map_open(maps, mname, mtype, 0, mapfile, SMAP_MODE_RDONLY,
			&map, SMPO_END);
	SM_TEST(sm_is_success(ret));
	if (!sm_is_success(ret))
		goto error;

	/* perform some operations ... */

	sm_str_clr(rhs);
	sm_str_assign(key, NULL, (uchar *)KEY1, strlen(KEY1), strlen(KEY1));
	ret = sm_map_lookup(map, SMMAP_FL_NONE, &key, rhs);
	SM_TEST(sm_is_success(ret));

	sm_str_assign(key, NULL, (uchar *)KEY2, strlen(KEY2), strlen(KEY2));
	ret = sm_map_lookup(map, SMMAP_FL_NONE, &key, rhs);
	SM_TEST(sm_is_success(ret));

	sm_str_assign(key, NULL, (uchar *)KEY3, strlen(KEY3), strlen(KEY3));
	ret = sm_map_lookup(map, SMMAP_FL_NONE, &key, rhs);
	SM_TEST(!sm_is_success(ret));

	sm_str_clr(lhs);
	sm_str_clr(rhs);
	ret = sm_str_scat(lhs, KEY1);
	SM_TEST(sm_is_success(ret));
	ret = sm_map_rewrite(map, SMMAP_FL_NONE, lhs, rhs);
	SM_TEST(sm_is_success(ret));
	SM_TEST(strncmp(DATA1, (char *) sm_str_data(rhs), sm_str_getlen(rhs))
		== 0);

	sm_str_clr(lhs);
	sm_str_clr(rhs);
	ret = sm_str_scat(lhs, KEY2);
	SM_TEST(sm_is_success(ret));
	ret = sm_map_rewrite(map, SMMAP_FL_NONE, lhs, rhs);
	SM_TEST(sm_is_success(ret));
	SM_TEST(strncmp(DATA2, (char *) sm_str_data(rhs), sm_str_getlen(rhs))
		== 0);

	ret = sm_map_close(map, 0);
	SM_TEST(sm_is_success(ret));

	ret = sm_maps_term(maps);
	SM_TEST(sm_is_success(ret));

	SM_CSTR_FREE(mtype);
	SM_CSTR_FREE(mname);
	SM_STR_FREE(lhs);
	SM_STR_FREE(rhs);
	return;

  error:
	sm_maps_term(maps);
}

static void
usage(const char *prg)
{
	sm_io_fprintf(smioerr, "usage: %s [options]\n"
		"-F file   name of db file [%s]\n"
		"-l n      list available map classes (n: verbosity)\n"
		"-n name   name of map [%s]\n"
		"-T type   map type [%s]\n"
		, prg
		, MAPC_FILE
		, MAPC_NAME
		, MAPC_TYPE
		);
	exit(EX_USAGE);
}

int
main(int argc, char *argv[])
{
	int c, list_mapc;
	char *mapname, *mapfile, *maptype, *prg;

	prg = argv[0];
	mapname = MAPC_NAME;
	mapfile = MAPC_FILE;
	maptype = MAPC_TYPE;
	list_mapc = -1;
#if SM_HEAP_CHECK
	SmHeapCheck = 0;
#endif
	while ((c = getopt(argc, argv, "F:H:l:n:T:V")) != -1)
	{
		switch (c)
		{
		  case 'F':
			SM_STRDUP_OPT(mapfile, optarg);
			break;
		  case 'H':
#if SM_HEAP_CHECK
			SmHeapCheck = atoi(optarg);
#endif
			break;
		  case 'l':
			list_mapc = (int) strtol(optarg, NULL, 0);
			break;
		  case 'n':
			SM_STRDUP_OPT(mapname, optarg);
			break;
		  case 'T':
			SM_STRDUP_OPT(maptype, optarg);
			break;

		  default:
			usage(prg);
			/* NOTREACHED */
			return EX_USAGE;
		}
	}
	sm_test_begin(argc, argv, "test map 0");
	if (list_mapc >= 0)
	{
		sm_ret_T ret;
		sm_maps_P maps;

		maps = NULL;
		ret = init_mapc_test(&maps);
		if (sm_is_err(ret))
			exit(EX_SOFTWARE);
		c = sm_mapc_list(smioout, maps, list_mapc, 0);
	}
	else
		testh(mapname, mapfile, maptype);
#if SM_HEAP_CHECK
	if (SmHeapCheck > 0)
		sm_heap_report(smioerr, 3);
#endif
	return sm_test_end();
}


syntax highlighted by Code2HTML, v. 0.9.1