/*
 * Copyright (c) 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-seq-2.c,v 1.7 2005/10/12 18:08:24 ca Exp $")

#include "sm/error.h"
#include "sm/heap.h"
#include "sm/memops.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/io.h"

int Verbose = 0;

#define MAPC_TYPE1	"bhtable"
#define MAPC_NAME1	"bht1"
#define KEY1_1	"left1_1"
#define KEY1_2	"left1_2"
#define KEY1_3	"left1_3"
#define DATA1_1	"right1_1"
#define DATA1_2	"right1_2"

#define MAPC_TYPE2	"hash"
#define MAPC_NAME2	"bdb2"
#define MAPC_FILE2	"./bdb2.db"
#define KEY2_1	"left2_1"
#define KEY2_2	"left2_2"
#define KEY2_3	"left2_3"
#define DATA2_1	"right2_1"
#define DATA2_2	"right2_2"

#define MAPC_TYPE3	"sequence"
#define MAPC_NAME3	"seq1"

static sm_ret_T
crt_bdb_map(sm_maps_P maps, sm_map_P *pmap, const char *name, const char *type)
{
	sm_ret_T ret;
	sm_map_P map;
	sm_cstr_P mtype, mname;

	SM_REQUIRE(maps != NULL);
	SM_REQUIRE(pmap != NULL);
	SM_REQUIRE(name != NULL);
	SM_REQUIRE(type != NULL);

	mtype = mname = NULL;
	mtype = sm_cstr_scpyn0((const uchar *)type, strlen(type));
	ret = sm_error_temp(SM_EM_MAP, ENOMEM);
	SM_TEST(mtype != NULL);
	if (mtype == NULL)
		goto error;
	mname = sm_cstr_scpyn0((const uchar *)name, strlen(name));
	SM_TEST(mname != NULL);
	if (mname == NULL)
		goto error;
	ret = sm_bdb_class_create(maps);
	SM_TEST(sm_is_success(ret));
	(void) unlink(MAPC_FILE2);

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

	*pmap = map;
	return ret;

  error:
	return ret;
}

static sm_ret_T
crt_map(sm_maps_P maps, sm_map_P *pmap, const char *name, const char *type)
{
	sm_ret_T ret;
	sm_cstr_P mtype, mname;
	sm_map_P map;

	SM_REQUIRE(maps != NULL);
	SM_REQUIRE(pmap != NULL);
	SM_REQUIRE(name != NULL);
	SM_REQUIRE(type != NULL);

	mtype = mname = NULL;
	mtype = sm_cstr_scpyn0((const uchar *)type, strlen(type));
	ret = sm_error_temp(SM_EM_MAP, ENOMEM);
	SM_TEST(mtype != NULL);
	if (mtype == NULL)
		goto error;
	mname = sm_cstr_scpyn0((const uchar *)name, strlen(name));
	SM_TEST(mname != NULL);
	if (mname == NULL)
		goto error;
	map = NULL;
	ret = sm_map_create(maps, mtype, 0, &map);
	SM_TEST(sm_is_success(ret));
	if (!sm_is_success(ret))
		goto error;
	ret = sm_map_setopt(map, SMPO_HASH_NELEM, 23, SMPO_MAX_ELEM, 51,
			SMPO_END);
	SM_TEST(sm_is_success(ret));
	if (!sm_is_success(ret))
		goto error;
	ret = sm_map_open(maps, mname, mtype, 0, NULL, SMAP_MODE_RDWR, &map,
			SMPO_END);
	SM_TEST(sm_is_success(ret));
	if (!sm_is_success(ret))
		goto error;
	SM_CSTR_FREE(mtype);
	SM_CSTR_FREE(mname);

	*pmap = map;
	return SM_SUCCESS;

  error:
	*pmap = NULL;
	return ret;
}

static void
testh(void)
{
	sm_ret_T ret;
	sm_maps_P maps;
	sm_map_P map1, map2, map3;
	sm_cstr_P mname1, mname2;
	sm_cstr_P mtype, mname;
	sm_str_P lhs, rhs;
	sm_str_T key, data;

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

	ret = sm_maps_init(&maps);
	SM_TEST(maps != NULL);
	if (maps == NULL)
		return;
	SM_TEST(sm_is_success(ret));

	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 = sm_bht_class_create(maps);
	SM_TEST(sm_is_success(ret));
	if (!sm_is_success(ret))
		goto error;
	ret = sm_seq_class_create(maps);
	SM_TEST(sm_is_success(ret));
	if (!sm_is_success(ret))
		goto error;

	ret = crt_map(maps, &map1, MAPC_NAME1, MAPC_TYPE1);
	SM_TEST(sm_is_success(ret));
	if (!sm_is_success(ret))
		goto error;

	ret = crt_bdb_map(maps, &map2, MAPC_NAME2, MAPC_TYPE2);
	SM_TEST(sm_is_success(ret));
	if (!sm_is_success(ret))
		goto error;

	mname1 = sm_cstr_scpyn0((const uchar *)MAPC_NAME1, strlen(MAPC_NAME1));
	ret = sm_error_temp(SM_EM_MAP, ENOMEM);
	SM_TEST(mname1 != NULL);
	if (mname1 == NULL)
		goto error;

	mname2 = sm_cstr_scpyn0((const uchar *)MAPC_NAME2, strlen(MAPC_NAME2));
	ret = sm_error_temp(SM_EM_MAP, ENOMEM);
	SM_TEST(mname2 != NULL);
	if (mname2 == NULL)
		goto error;

	/* populate map */
	sm_str_assign(key, NULL, (uchar *)KEY1_1, strlen(KEY1_1),
			strlen(KEY1_1));
	sm_str_assign(data, NULL, (uchar *)DATA1_1, strlen(DATA1_1),
			strlen(DATA1_1));
	ret = sm_map_add(map1, &key, &data, SMMAP_AFL_NONE);
	SM_TEST(sm_is_success(ret));
	sm_str_assign(key, NULL, (uchar *)KEY1_2, strlen(KEY1_2),
			strlen(KEY1_2));
	sm_str_assign(data, NULL, (uchar *)DATA1_2, strlen(DATA1_2),
			strlen(DATA1_2));
	ret = sm_map_add(map1, &key, &data, SMMAP_AFL_NONE);
	SM_TEST(sm_is_success(ret));

	/* populate map */
	sm_str_assign(key, NULL, (uchar *)KEY2_1, strlen(KEY2_1),
			strlen(KEY2_1));
	sm_str_assign(data, NULL, (uchar *)DATA2_1, strlen(DATA2_1),
			strlen(DATA2_1));
	ret = sm_map_add(map2, &key, &data, SMMAP_AFL_NONE);
	SM_TEST(sm_is_success(ret));
	sm_str_assign(key, NULL, (uchar *)KEY2_2, strlen(KEY2_2),
			strlen(KEY2_2));
	sm_str_assign(data, NULL, (uchar *)DATA2_2, strlen(DATA2_2),
			strlen(DATA2_2));
	ret = sm_map_add(map2, &key, &data, SMMAP_AFL_NONE);
	SM_TEST(sm_is_success(ret));


	/* perform some operations ... */
	sm_str_clr(rhs);
	sm_str_assign(key, NULL, (uchar *)KEY1_1, strlen(KEY1_1),
			strlen(KEY1_1));
	ret = sm_map_lookup(map1, SMMAP_FL_NONE, &key, rhs);
	SM_TEST(sm_is_success(ret));
	sm_str_assign(key, NULL, (uchar *)KEY1_2, strlen(KEY1_2),
			strlen(KEY1_2));
	ret = sm_map_lookup(map1, SMMAP_FL_NONE, &key, rhs);
	SM_TEST(sm_is_success(ret));
	sm_str_assign(key, NULL, (uchar *)KEY1_3, strlen(KEY1_3),
			strlen(KEY1_3));
	ret = sm_map_lookup(map1, SMMAP_FL_NONE, &key, rhs);
	SM_TEST(!sm_is_success(ret));

	/* perform some operations ... */
	sm_str_clr(rhs);
	sm_str_assign(key, NULL, (uchar *)KEY2_1, strlen(KEY2_1),
			strlen(KEY2_1));
	ret = sm_map_lookup(map2, SMMAP_FL_NONE, &key, rhs);
	SM_TEST(sm_is_success(ret));
	sm_str_assign(key, NULL, (uchar *)KEY2_2, strlen(KEY2_2),
			strlen(KEY2_2));
	ret = sm_map_lookup(map2, SMMAP_FL_NONE, &key, rhs);
	SM_TEST(sm_is_success(ret));
	sm_str_assign(key, NULL, (uchar *)KEY2_3, strlen(KEY2_3),
			strlen(KEY2_3));
	ret = sm_map_lookup(map2, 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_1);
	SM_TEST(sm_is_success(ret));
	ret = sm_map_rewrite(map1, SMMAP_FL_NONE, lhs, rhs);
	SM_TEST(sm_is_success(ret));
	SM_TEST(strncmp(DATA1_1, (char *) sm_str_data(rhs), sm_str_getlen(rhs))
		== 0);
	sm_str_clr(lhs);
	sm_str_clr(rhs);
	ret = sm_str_scat(lhs, KEY1_2);
	SM_TEST(sm_is_success(ret));
	ret = sm_map_rewrite(map1, SMMAP_FL_NONE, lhs, rhs);
	SM_TEST(sm_is_success(ret));
	SM_TEST(strncmp(DATA1_2, (char *) sm_str_data(rhs), sm_str_getlen(rhs))
		== 0);


	/* create sequence map */
	mtype = mname = NULL;
	mtype = sm_cstr_scpyn0((const uchar *)MAPC_TYPE3, strlen(MAPC_TYPE3));
	ret = sm_error_temp(SM_EM_MAP, ENOMEM);
	SM_TEST(mtype != NULL);
	if (mtype == NULL)
		goto error;
	mname = sm_cstr_scpyn0((const uchar *)MAPC_NAME3, strlen(MAPC_NAME3));
	SM_TEST(mname != NULL);
	if (mname == NULL)
		goto error;
	map3 = NULL;
	ret = sm_map_create(maps, mtype, 0, &map3);
	SM_TEST(sm_is_success(ret));
	if (!sm_is_success(ret))
		goto error;
	ret = sm_map_setopt(map3,
			SMPO_MAPNAME, mname1,
			SMPO_MAPNAME, mname2,
			SMPO_END);
	SM_TEST(sm_is_success(ret));
	if (!sm_is_success(ret))
		goto error;
	ret = sm_map_open(maps, mname, mtype, 0, NULL, SMAP_MODE_RDWR, &map3,
			SMPO_END);
	SM_TEST(sm_is_success(ret));
	if (!sm_is_success(ret))
		goto error;
	SM_CSTR_FREE(mtype);
	SM_CSTR_FREE(mname);


	/* perform some operations ... */
	sm_str_clr(rhs);
	sm_str_assign(key, NULL, (uchar *)KEY1_1, strlen(KEY1_1),
			strlen(KEY1_1));
	ret = sm_map_lookup(map3, SMMAP_FL_NONE, &key, rhs);
	SM_TEST(sm_is_success(ret));
	sm_str_assign(key, NULL, (uchar *)KEY1_2, strlen(KEY1_2),
			strlen(KEY1_2));
	ret = sm_map_lookup(map3, SMMAP_FL_NONE, &key, rhs);
	SM_TEST(sm_is_success(ret));
	sm_str_assign(key, NULL, (uchar *)KEY1_3, strlen(KEY1_3),
			strlen(KEY1_3));
	ret = sm_map_lookup(map3, SMMAP_FL_NONE, &key, rhs);
	SM_TEST(!sm_is_success(ret));

	/* perform some operations ... */
	sm_str_clr(rhs);
	sm_str_assign(key, NULL, (uchar *)KEY2_1, strlen(KEY2_1),
			strlen(KEY2_1));
	ret = sm_map_lookup(map3, SMMAP_FL_NONE, &key, rhs);
	SM_TEST(sm_is_success(ret));
	sm_str_assign(key, NULL, (uchar *)KEY2_2, strlen(KEY2_2),
			strlen(KEY2_2));
	ret = sm_map_lookup(map3, SMMAP_FL_NONE, &key, rhs);
	SM_TEST(sm_is_success(ret));
	sm_str_assign(key, NULL, (uchar *)KEY2_3, strlen(KEY2_3),
			strlen(KEY2_3));
	ret = sm_map_lookup(map3, SMMAP_FL_NONE, &key, rhs);
	SM_TEST(!sm_is_success(ret));


	ret = sm_map_close(map3, 0);
	SM_TEST(sm_is_success(ret));
	ret = sm_map_close(map2, 0);
	SM_TEST(sm_is_success(ret));
	ret = sm_map_close(map1, 0);
	SM_TEST(sm_is_success(ret));

	ret = sm_maps_term(maps);
	SM_TEST(sm_is_success(ret));
	SM_STR_FREE(lhs);
	SM_STR_FREE(rhs);
	return;

  error:
	sm_maps_term(maps);
}


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

	while ((c = getopt(argc, argv, "H:s:V")) != -1)
	{
		switch (c)
		{
		  default:
			return 1;
		}
	}
	sm_test_begin(argc, argv, "test sequence map 0");
	testh();
	return sm_test_end();
}


syntax highlighted by Code2HTML, v. 0.9.1