blob: 6a1cac1581ca6fd7bde3e9ca82f7dc989f4ad4d7 [file] [log] [blame]
/* $Id$
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to you under the Apache License, Version
* 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* test_structvalue.c -- test etch_structvalue object
*/
#include "etch_runtime.h"
#include "etch_connection.h"
#include "etch_encoding.h"
#include "etch_log.h"
#include "etch_structval.h"
#include "etch_nativearray.h"
#include "etch_objecttypes.h"
#include "etch_exception.h"
#include <stdio.h>
#include "CUnit.h"
#define IS_DEBUG_CONSOLE FALSE
// extern types
extern apr_pool_t* g_etch_main_pool;
/* - - - - - - - - - - - - - -
* unit test infrastructure
* - - - - - - - - - - - - - -
*/
static int init_suite(void)
{
etch_status_t etch_status = ETCH_SUCCESS;
etch_status = etch_runtime_initialize(NULL);
if(etch_status != NULL) {
// error
}
return 0;
}
static int clean_suite(void)
{
//this_teardown();
etch_runtime_shutdown();
return 0;
}
/* - - - - - - - - - - - - - - - - - - - - - -
* individual setup and teardown
* - - - - - - - - - - - - - - - - - - - - - -
*/
static etch_type *mt1, *mt2;
static etch_field *mf_bool_d0_1;
static etch_field *mf_bool_d0_2;
static etch_field *mf_bool_d1_1;
static etch_field *mf_bool_d1_2;
static etch_field *mf_int32_d0_1;
static etch_field *mf_int32_d0_2;
static etch_field *mf_int32_d1_1;
static etch_field *mf_int32_d1_2;
static etch_field *mf_str_d0_1;
static etch_field *mf_str_d0_2;
static etch_field *mf_str_d1_1;
static etch_field *mf_str_d1_2;
static etch_hashtable* testdata;
static int g_which_exception_test;
#if(0)
#define OBJTYPE_FAKETDI_IMPL ETCHTYPEB_INSTANCEDATA
#define CLASSID_FAKETDI_IMPL 0xf0
#define OBJTYPE_FAKETDO_IMPL ETCHTYPEB_INSTANCEDATA
#define CLASSID_FAKETDO_IMPL 0xf1
#define OBJTYPE_FAKETDI_VTABLE 0x88
#define OBJTYPE_FAKETDO_VTABLE 0x89
#define CLASSID_FAKETDI 0xf6
#define CLASSID_FAKETDO 0xf7
#endif
#define EXCPTEST_UNCHECKED_STATICTEXT 1
#define EXCPTEST_CHECKED_COPYTEXT 2
#define EXCPTEST_CHECKED_STATICTEXT 3
#if(0)
/**
* fake_tdi_impl
* instance data for a TDI implementation
*/
typedef struct fake_tdi_impl
{
etch_object object;
etch_type* tdi_type;
byte started, done, ended, is_owned_struct;
etch_structvalue* xstruct;
etch_iterator iterator;
} fake_tdi_impl;
/**
* fake_tdo_impl
* instance data for a TDO implementation
*/
typedef struct fake_tdo_impl
{
etch_object object;
byte started, ended, closed;
etch_structvalue* xstruct;
etch_hashtable* fakeout; /* fake output stream */
} fake_tdo_impl;
/**
* fake_tdi_impl_destroy_handler
* memory cleanup handler for fake_tdi_impl
*/
static int destroy_fake_tdi_impl(fake_tdi_impl* impl)
{
etch_destructor destroy = NULL;
int result = verify_object((etch_object*)impl, OBJTYPE_FAKETDI_IMPL, CLASSID_FAKETDI_IMPL, NULL);
if (result == -1) return -1; /* object passed was not expected object */
/* type is a refrence, it does not belong to the tdi. struct is created
* in the tdi, but ownership is assumed to transfer to the caller when
* structvalue_read returns. if this is not the case then is_owned_struct
* must have been set elsewhere
*/
if (impl->is_owned_struct)
{ /* not the default case, see comment above */
CU_ASSERT_PTR_NOT_NULL_FATAL(impl->xstruct);
etch_object_destroy(impl->xstruct);
}
etch_free(impl);
return 0;
}
/**
* fake_tdo_impl_destroy_handler
* memory cleanup handler for fake_tdo_impl
*/
static int destroy_fake_tdo_impl(fake_tdo_impl* impl)
{
etch_destructor destroy = NULL;
int result = verify_object((etch_object*)impl, OBJTYPE_FAKETDO_IMPL, CLASSID_FAKETDO_IMPL, NULL);
if (result == -1) return -1; /* object passed was not expected object */
/* destroy the fake output receptor, in this case a hashtable. we don't want the
* hashtable to destroy its content because its content is references to someone
* else's content, in this case the host struct value.
*/
destroy_hashtable(impl->fakeout, FALSE, FALSE);
/* we do not destroy the struct value, this is merely a reference */
/* impl->((etch_object*)xstruct)->vtab->destroy(impl->xstruct); */
etch_free(impl);
return 0;
}
/**
* new_fake_tdi_impl()
* constructor for TDI implementation instance data
*/
static fake_tdi_impl* new_fake_tdi_impl(etch_type* static_type)
{
fake_tdi_impl* data = (fake_tdi_impl*)
new_object(sizeof(fake_tdi_impl), ETCHTYPEB_INSTANCEDATA, CLASSID_FAKETDI_IMPL);
/* assign type - this is a reference, it is not our memory */
data->tdi_type = static_type;
/* set destructor */
data->destroy = destroy_fake_tdi_impl;
return data;
}
/**
* new_fake_tdo_impl()
* constructor for TDO implementation instance data
*/
static fake_tdo_impl* new_fake_tdo_impl(etch_structvalue* sv)
{
fake_tdo_impl* data = (fake_tdo_impl*)
new_object(sizeof(fake_tdo_impl), ETCHTYPEB_INSTANCEDATA, CLASSID_FAKETDO_IMPL);
data->xstruct = sv;
/* set destructor */
data->destroy = destroy_fake_tdo_impl;
return data;
}
enum objtyp ETCHTYPE_VTABLE_FAKETDI = 0xf0;
enum objtyp ETCHTYPE_VTABLE_FAKETDO = 0xf1;
/**
* faketdi_start_struct() overrides tdi_start_struct()
*/
static etch_structvalue* faketdi_start_struct(tagged_data_input* tdi)
{
int result = 0;
fake_tdi_impl* data = NULL;
etch_structvalue* newstructval = NULL;
const int READONLY = TRUE, DEFSIZE = 0, DEFDELTA = 0;
CU_ASSERT_PTR_NOT_NULL_FATAL(tdi);
CU_ASSERT_PTR_NOT_NULL_FATAL(tdi->impl);
data = (fake_tdi_impl*) tdi->impl; /* validate instance data */
result = verify_object((etch_object*)data, OBJTYPE_FAKETDI_IMPL, 0, 0);
CU_ASSERT_EQUAL_FATAL(result,0);
result = etch_object_destroy(NULL); /* ensure we can call into instance data destructor */
CU_ASSERT_EQUAL(result,-1);
CU_ASSERT_EQUAL(data->started,FALSE);
CU_ASSERT_EQUAL(data->done,FALSE);
CU_ASSERT_EQUAL(data->ended,FALSE);
data->started = TRUE;
/* create a struct to receive the elements read. a struct owns all its memory
* so we give it a copy of the tdi's type. ownership of the struct is assumed
* to be passed to the caller when this function returns. if instead it was
* desired that the tdi own the struct, data.is_owned_struct would have to
* be set subsequently elsewhere.
* note that sv no longer owns type, so we no longer clone the type
*/
newstructval = new_structvalue (data->tdi_type, 0);
data->xstruct = newstructval;
CU_ASSERT_PTR_NOT_NULL_FATAL(data->xstruct);
/* establish iterator on the fake input data */
set_iterator(&data->iterator, testdata, &testdata->iterable);
/* while an empty dataset is valid in the general case,
* this test assumes that input is non-empty */
result = data->iterator.vtab->has_next(&data->iterator);
CU_ASSERT_EQUAL(result,TRUE);
return data->xstruct;
}
/**
* faketdo_start_struct() overrides tdo_start_struct()
*/
static int faketdo_start_struct(tagged_data_output* tdo, etch_structvalue* structval)
{
int result = 0;
fake_tdo_impl* data = NULL;
CU_ASSERT_PTR_NOT_NULL_FATAL(tdo);
CU_ASSERT_PTR_NOT_NULL_FATAL(tdo->impl);
data = (fake_tdo_impl*) tdo->impl; /* validate instance data */
result = verify_object((etch_object*)data, OBJTYPE_FAKETDO_IMPL, 0, 0);
CU_ASSERT_EQUAL_FATAL(result,0);
result = data->destroy(NULL); /* ensure we can call instance data destructor */
CU_ASSERT_EQUAL(result,-1);
CU_ASSERT_EQUAL(data->started,FALSE);
CU_ASSERT_EQUAL(data->ended,FALSE);
CU_ASSERT_EQUAL_FATAL(structval, data->xstruct);
CU_ASSERT_PTR_NOT_NULL_FATAL(data->fakeout);
data->started = TRUE;
return 0;
}
/**
* faketdo_write_struct_element() overrides tdo_write_struct_element()
*/
static int faketdo_write_struct_element(tagged_data_output* tdo, etch_field* key, etch_object* val)
{
int result = 0;
fake_tdo_impl* data = NULL;
etch_hashtable* fakeout = NULL;
etch_hashitem hashbucket;
etch_hashitem* myentry = &hashbucket;
CU_ASSERT_PTR_NOT_NULL_FATAL(tdo); /* validate parameters */
CU_ASSERT_PTR_NOT_NULL_FATAL(tdo->impl);
CU_ASSERT_PTR_NOT_NULL_FATAL(val);
result = is_good_field(key);
CU_ASSERT_EQUAL_FATAL(result,TRUE);
data = (fake_tdo_impl*) tdo->impl; /* validate instance data */
result = verify_object((etch_object*)data, OBJTYPE_FAKETDO_IMPL, 0, 0);
CU_ASSERT_EQUAL_FATAL(result,0);
fakeout = data->fakeout;
CU_ASSERT_PTR_NOT_NULL_FATAL(fakeout);
CU_ASSERT_PTR_NOT_NULL_FATAL(fakeout->realtable);
CU_ASSERT_EQUAL(data->started,TRUE);
CU_ASSERT_EQUAL(data->ended, FALSE);
CU_ASSERT_EQUAL(data->closed,FALSE);
/* do the write to the fake output */
result = ((etch_object*)fakeout)->vtab->insert(fakeout->realtable, key, HASHSIZE_FIELD, val, 0, 0, 0);
CU_ASSERT_EQUAL_FATAL(result,0);
/* verify the write by accessing the item just written */
result = ((etch_object*)fakeout)->vtab->find(fakeout->realtable, key, HASHSIZE_FIELD, 0, &myentry);
CU_ASSERT_EQUAL_FATAL(result,0);
CU_ASSERT_EQUAL_FATAL(myentry->key, (void*)key);
CU_ASSERT_EQUAL_FATAL(myentry->value, val);
return 0;
}
/**
* faketdi_read_struct_element() overrides tdi_read_struct_element()
*/
static int faketdi_read_struct_element(tagged_data_input* tdi, etch_struct_element* out_se)
{
int result = 0;
fake_tdi_impl* data = NULL;
etch_iterator* iterator = NULL;
CU_ASSERT_PTR_NOT_NULL_FATAL(tdi);
CU_ASSERT_PTR_NOT_NULL_FATAL(tdi->impl);
CU_ASSERT_PTR_NOT_NULL_FATAL(out_se);
data = (fake_tdi_impl*) tdi->impl; /* validate instance data */
result = verify_object((etch_object*)data, OBJTYPE_FAKETDI_IMPL, 0, 0);
CU_ASSERT_EQUAL_FATAL(result,0);
CU_ASSERT_EQUAL(data->started,TRUE);
CU_ASSERT_EQUAL(data->done,FALSE);
CU_ASSERT_EQUAL(data->ended,FALSE);
iterator = &data->iterator;
if (iterator->has_next(iterator))
{
CU_ASSERT_EQUAL_FATAL(result,0);
CU_ASSERT_PTR_NOT_NULL_FATAL(iterator->current_key);
CU_ASSERT_PTR_NOT_NULL_FATAL(iterator->current_value);
out_se->key = (etch_field*) iterator->current_key;
out_se->value = (etch_object*) iterator->current_value;
iterator->next(iterator);
return TRUE;
}
data->done = TRUE;
return FALSE;
}
/**
* faketdi_end_struct() overrides tdi_end_struct()
*/
static int faketdi_end_struct(tagged_data_input* tdi, etch_structvalue* sv)
{
int result = 0;
fake_tdi_impl* data = NULL;
CU_ASSERT_PTR_NOT_NULL_FATAL(tdi);
CU_ASSERT_PTR_NOT_NULL_FATAL(tdi->impl);
data = (fake_tdi_impl*) tdi->impl; /* validate instance data */
result = verify_object((etch_object*)data, OBJTYPE_FAKETDI_IMPL, 0, 0);
CU_ASSERT_EQUAL_FATAL(result,0);
CU_ASSERT_PTR_NOT_NULL_FATAL(data->xstruct);
CU_ASSERT_EQUAL(data->started,TRUE);
CU_ASSERT_EQUAL(data->done,TRUE);
CU_ASSERT_EQUAL(data->ended,FALSE);
CU_ASSERT_EQUAL(data->xstruct,sv);
data->ended = TRUE;
return 0;
}
/**
* faketdo_end_struct() overrides tdo_end_struct()
*/
static int faketdo_end_struct(tagged_data_output* tdo, struct etch_structvalue* sv)
{
int result = 0;
fake_tdo_impl* data = NULL;
CU_ASSERT_PTR_NOT_NULL_FATAL(tdo);
CU_ASSERT_PTR_NOT_NULL_FATAL(tdo->impl);
data = (fake_tdo_impl*) tdo->impl; /* validate instance data */
result = verify_object((etch_object*)data, OBJTYPE_FAKETDO_IMPL, 0, 0);
CU_ASSERT_EQUAL_FATAL(result,0);
CU_ASSERT_PTR_NOT_NULL_FATAL(data->xstruct);
CU_ASSERT_EQUAL(data->started,TRUE);
CU_ASSERT_EQUAL(data->ended,FALSE);
CU_ASSERT_EQUAL(data->closed,FALSE);
CU_ASSERT_EQUAL(data->xstruct, sv);
data->ended = TRUE;
return 0;
}
/**
* faketdi_close() ala java test
* also tested here is that we can call base methods on a derived object. we invoke
* the TDI destructor here, which is an overide of the etchobject destructor.
* the TDI destructor walks the vtable chain to its parent, and invokes the parent
* destructor to destroy etchobject content such as any exception, and finally
* the object itself.
*/
static void faketdi_close(tagged_data_input* tdi)
{
tdi->destroy(tdi);
}
/**
* faketdo_close() ala java test
*/
static void faketdo_close(tagged_data_output* tdo)
{
tdo->destroy(tdo);
}
/**
* new_fake_tdi()
* constructor for TDI implementation
*/
static tagged_data_input* new_fake_tdi(etch_type* static_type)
{
tagged_data_input* faketdi = NULL;
i_tagged_data_input* vtab = NULL;
const unsigned short CLASS_ID = CLASSID_FAKETDI;
CU_ASSERT_EQUAL_FATAL(is_good_type(static_type),TRUE);
faketdi = new_tagged_data_input();
vtab = cache_find(get_vtable_cachehkey(CLASS_ID), 0);
if(!vtab)
{
vtab = new_vtable(((etch_object*)faketdi)->vtab, sizeof(i_tagged_data_input), CLASS_ID);
/* override three i_tagged_data_input methods */
vtab->start_struct = faketdi_start_struct;
vtab->end_struct = faketdi_end_struct;
vtab->read_struct_element = faketdi_read_struct_element;
((etch_object*)vtab)->vtab = faketdi->vtab; /* chain parent vtab to override vtab */
cache_insert(vtab->hashkey, vtab, FALSE);
}
CU_ASSERT_EQUAL_FATAL(((etch_object*)vtab)->class_id, CLASS_ID);
((etch_object*)faketdi)->vtab = vtab; /* set override vtab */
faketdi->impl = (etch_object*)
new_fake_tdi_impl(static_type); /* create TDI instance data */
switch(g_which_exception_test)
{ case EXCPTEST_UNCHECKED_STATICTEXT:
etch_throw((etch_object*) faketdi, EXCPTYPE_NULLPTR, NULL, 0);
break;
case EXCPTEST_CHECKED_COPYTEXT:
etch_throw((etch_object*) faketdi, EXCPTYPE_CHECKED_BOGUS, L"copied text", ETCHEXCP_COPYTEXT | ETCHEXCP_FREETEXT);
break;
case EXCPTEST_CHECKED_STATICTEXT:
etch_throw((etch_object*) faketdi, EXCPTYPE_CHECKED_BOGUS, local_excp_text, ETCHEXCP_STATICTEXT);
break;
}
return faketdi;
}
/**
* new_fake_tdo()
* constructor for TDO implementation
*/
static tagged_data_output* new_fake_tdo(etch_structvalue* sv)
{
tagged_data_output* faketdo = NULL;
i_tagged_data_output* vtab = NULL;
fake_tdo_impl* impl = NULL;
const unsigned short CLASS_ID = CLASSID_FAKETDO;
CU_ASSERT_PTR_NOT_NULL_FATAL(sv);
faketdo = new_tagged_data_output();
vtab = cache_find(get_vtable_cachehkey(CLASS_ID), 0);
if(!vtab)
{
vtab = new_vtable(((etch_object*)faketdo)->vtab, sizeof(i_tagged_data_output), CLASS_ID);
/* override three i_tagged_data_output methods */
vtab->start_struct = faketdo_start_struct;
vtab->end_struct = faketdo_end_struct;
vtab->write_struct_element = faketdo_write_struct_element;
((etch_object*)vtab)->vtab = faketdo->vtab; /* chain parent vtab to override vtab */
cache_insert(vtab->hashkey, vtab, FALSE);
}
CU_ASSERT_EQUAL_FATAL(((etch_object*)vtab)->class_id, CLASS_ID);
((etch_object*)faketdo)->vtab = vtab; /* set override vtab */
impl = new_fake_tdo_impl(sv); /* set TDO instance data */
CU_ASSERT_PTR_NOT_NULL_FATAL(impl);
impl->fakeout = new_hashtable(16);
CU_ASSERT_PTR_NOT_NULL_FATAL(impl->fakeout);
impl->fakeout->is_readonly_keys = impl->fakeout->is_readonly_values = FALSE;
impl->fakeout->is_tracked_memory = TRUE;
impl->fakeout->content_type = ETCHHASHTABLE_CONTENT_OBJECT;
faketdo->impl = (etch_object*) impl;
return faketdo;
}
#endif /* #if(0) */
/*
* load_testdata_string()
* load testdata map with some ETCH_STRING objects
*/
static int load_testdata_string()
{
int i = 0, numitems = 4, result = 0;
etch_field* newkey = NULL;
etch_string* newobj = NULL;
wchar_t* str0 = L"now ", *str1 = L"is ", *str2 = L"the ", *str3 = L"time";
wchar_t* strings[4] = { str0, str1, str2, str3 };
for(; i < numitems; i++)
{
newkey = new_field(strings[i]); /* testdata map CAN free keys */
newobj = new_stringw(strings[i]);
result = ((struct i_hashtable*)((etch_object*)testdata)->vtab)->inserth(testdata->realtable, newkey, newobj, 0, 0);
}
return numitems;
}
/*
* load_testdata_int()
* load testdata array with some ETCH_INT objects
*/
static int load_testdata_int()
{
const int numitems = 4;
int i = 0, result = 0;
etch_field* newkey = NULL;
etch_int32* newobj = NULL;
wchar_t* str0 = L"fld1", *str1 = L"fld2", *str2 = L"fld3", *str3 = L"fld4";
wchar_t* keys[4] = { str0, str1, str2, str3 };
int ints[4] = { 1, 2, 3, 4 };
for(; i < numitems; i++)
{
newkey = new_field(keys[i]);
newobj = new_int32(ints[i]); /* testdata table can free both keys and values */
result = ((struct i_hashtable*)((etch_object*)testdata)->vtab)->inserth(testdata->realtable, newkey, newobj, 0, 0);
}
return numitems;
}
/*
* testdata_clear_handler()
* memory callback on testdata clear
*/
static int testdata_clear_handler (void* keyData, void* valueData)
{
etch_object_destroy((etch_object*)keyData);
etch_object_destroy((etch_object*)valueData);
return TRUE;
}
/*
* new_testdata()
* create testdata map and load it up with data objects
*/
static int new_testdata(const int datatype)
{
int count = 0;
#if IS_DEBUG_CONSOLE
etch_iterator iterator;
#endif
g_which_exception_test = 0;
testdata = new_hashtable(0);
testdata->is_readonly_keys = FALSE;
testdata->is_readonly_values = FALSE;
testdata->is_tracked_memory = TRUE;
testdata->content_type = ETCHHASHTABLE_CONTENT_OBJECT;
testdata->freehook = testdata_clear_handler;
switch(datatype)
{ case 1: count = load_testdata_int(); break;
case 2: count = load_testdata_string(); break;
default: return -1;
}
#if IS_DEBUG_CONSOLE
printf("\n");
#pragma warning (disable:4313)
set_iterator(&iterator, testdata, &testdata->iterable);
while(iterator.vtab->has_next(&iterator))
{
printf("testdata %08x %08x\n", iterator.current_key, iterator.current_value);
iterator.vtab->next(&iterator);
}
printf("\n");
#endif
mt1 = new_type(L"one");
mt2 = new_type(L"two");
mf_bool_d0_1 = new_field(L"f1");
mf_bool_d0_2 = new_field(L"f2");
mf_bool_d1_1 = new_field(L"f3");
mf_bool_d1_2 = new_field(L"f4");
mf_int32_d0_1 = new_field(L"f5");
mf_int32_d0_2 = new_field(L"f6");
mf_int32_d1_1 = new_field(L"f7");
mf_int32_d1_2 = new_field(L"f8");
mf_str_d0_1 = new_field(L"f9");
mf_str_d0_2 = new_field(L"fa");
mf_str_d1_1 = new_field(L"fb");
mf_str_d1_2 = new_field(L"fc");
etchtype_put_validator(mt1, (etch_field*)etch_object_clone_func(mf_bool_d0_1), (etch_object*) etchvtor_boolean_get(0));
etchtype_put_validator(mt1, (etch_field*)etch_object_clone_func(mf_bool_d0_2), (etch_object*) etchvtor_boolean_get(0));
etchtype_put_validator(mt1, (etch_field*)etch_object_clone_func(mf_bool_d1_1), (etch_object*) etchvtor_boolean_get(1));
etchtype_put_validator(mt1, (etch_field*)etch_object_clone_func(mf_bool_d1_2), (etch_object*) etchvtor_boolean_get(1));
etchtype_put_validator(mt1, (etch_field*)etch_object_clone_func(mf_int32_d0_1), (etch_object*) etchvtor_int32_get(0));
etchtype_put_validator(mt1, (etch_field*)etch_object_clone_func(mf_int32_d0_2), (etch_object*) etchvtor_int32_get(0));
etchtype_put_validator(mt1, (etch_field*)etch_object_clone_func(mf_int32_d1_1), (etch_object*) etchvtor_int32_get(1));
etchtype_put_validator(mt1, (etch_field*)etch_object_clone_func(mf_int32_d1_2), (etch_object*) etchvtor_int32_get(1));
etchtype_put_validator(mt1, (etch_field*)etch_object_clone_func(mf_str_d0_1), (etch_object*) etchvtor_string_get(0));
etchtype_put_validator(mt1, (etch_field*)etch_object_clone_func(mf_str_d0_2), (etch_object*) etchvtor_string_get(0));
etchtype_put_validator(mt1, (etch_field*)etch_object_clone_func(mf_str_d1_1), (etch_object*) etchvtor_string_get(1));
etchtype_put_validator(mt1, (etch_field*)etch_object_clone_func(mf_str_d1_2), (etch_object*) etchvtor_string_get(1));
return count;
}
/*
* destroy_testdata()
* destroy testdata map and content
*/
static void destroy_testdata()
{
destroy_hashtable(testdata, TRUE, TRUE);
etch_object_destroy(mt1);
etch_object_destroy(mt2);
destroy_field(mf_bool_d0_1);
destroy_field(mf_bool_d0_2);
destroy_field(mf_bool_d1_1);
destroy_field(mf_bool_d1_2);
destroy_field(mf_int32_d0_1);
destroy_field(mf_int32_d0_2);
destroy_field(mf_int32_d1_1);
destroy_field(mf_int32_d1_2);
destroy_field(mf_str_d0_1);
destroy_field(mf_str_d0_2);
destroy_field(mf_str_d1_1);
destroy_field(mf_str_d1_2);
etchvtor_clear_cache(); /* free all cached validators */
}
#if 0
/*
* compare_lists()
* compares testdata content with specified struct content.
* returns boolean indicating equal or not.
*/
static int compare_lists(etch_structvalue* svx)
{
int thiscount = 0, testcount = 0, result = 0;
etch_iterator iterator;
etch_hashitem hashbucket;
etch_hashitem* sventry = &hashbucket;
CU_ASSERT_PTR_NOT_NULL_FATAL(svx);
CU_ASSERT_PTR_NOT_NULL_FATAL(svx->items);
thiscount = ((struct i_hashtable*)((etch_object*)svx->items)->vtab)->count(svx->items->realtable,0,0);
testcount = ((struct i_hashtable*)((etch_object*)testdata)->vtab)->count(testdata->realtable,0,0);
CU_ASSERT_EQUAL(testcount, thiscount);
if (testcount != thiscount) return FALSE;
set_iterator(&iterator, testdata, &testdata->iterable);
while(iterator.has_next(&iterator) && result == 0)
{
result = ((struct i_hashtable*)((etch_object*)svx->items)->vtab)->findh
(svx->items->realtable, ((etch_object*)iterator.current_key)->hashkey, testdata, (void**)&sventry);
CU_ASSERT_EQUAL(iterator.current_value, sventry->value);
iterator.next(&iterator);
}
return TRUE;
}
/*
* hashtable_clear_handler()
* override callback from hashtable during clear()
*/
static int hashtable_clear_handler (void* key, void* value)
{
/* prior to calling clear() on any hashtable htab, set:
* htab.callback = hashtable_clear_handler;
* and the hashtable will call back here for each item in the table,
* replacing any such handler installed. return FALSE to have the hashtable
* proceed as it would with a handler. save off the existing handler and call
* it, to proceed as if you had not replaced the handler. return TRUE to
* indicate you handled the free and the hashtable should not attempt to free
* memory for key and/or value, if in fact it would have done so otherwise.
* note that structvalue always sets such a callback on its backing store
* in order to free key and value allocations.
*/
return FALSE;
}
/*
* hashtable_do_nada_handler()
* override callback from hashtable during clear()
* this callback does nothing and returns TRUE, so no content memory is freed.
*/
static int hashtable_do_nada_handler (void* key, void* value)
{
return TRUE;
}
#endif
/*
* run_iterator_test
* test struct value iterator
*/
static void run_iterator_test(void)
{
int result = 0, count = 0;
etch_iterator iterator;
etch_int32* int_obj_1 = NULL;
etch_int32* int_obj_2 = NULL;
etch_nativearray* int_array_1 = NULL;
etch_nativearray* int_array_2 = NULL;
etch_structvalue* sv = NULL;
etch_field* fldkey = NULL;
new_testdata(1); /* instantiate types and fields we use here */
/* memory for field keys and object values is given to the struct to manage.
* once a key and value are "put" to the struct, we give up responsibility
* for freeing them. therefore when we put an object to the struct, we clone
* a type to use as the key. note that when we assign the struct a type,
* however, we do not relinquish ownership of the memory for that etch_type.
* this is because types are global to the service in the binding,
* and are freed only at service shutdown.
*/
int_obj_1 = new_int32(123);
int_obj_2 = new_int32(234);
int_array_1 = new_etch_nativearray(CLASSID_ARRAY_INT32, sizeof(int), 1, 3, 0, 0);
int_array_2 = new_etch_nativearray(CLASSID_ARRAY_INT32, sizeof(int), 1, 5, 0, 0);
sv = new_structvalue(mt1, 0);
CU_ASSERT_PTR_NOT_NULL_FATAL(sv);
result = is_etch_exception(sv);
CU_ASSERT_EQUAL(result, FALSE);
CU_ASSERT_PTR_NOT_NULL_FATAL(sv->items);
/* if structvalue has ETCH_STRUCTVAL_VALIDATE_ON_PUT compiled,
* these structvalue.put()s will be validated. */
fldkey = clone_field(mf_int32_d0_1);
result = structvalue_put(sv, fldkey, (etch_object*) int_obj_1);
CU_ASSERT_EQUAL(result, 0);
set_iterator(&iterator, sv->items, &sv->items->iterable);
CU_ASSERT_EQUAL(iterator.has_next(&iterator), TRUE);
fldkey = clone_field(mf_int32_d0_2);
result = structvalue_put(sv, fldkey, (etch_object*) int_obj_2);
CU_ASSERT_EQUAL(result, 0);
set_iterator(&iterator, sv->items, &sv->items->iterable);
CU_ASSERT_TRUE(iterator.has_next(&iterator));
iterator.next(&iterator);
CU_ASSERT_TRUE(iterator.has_next(&iterator));
iterator.next(&iterator);
CU_ASSERT_FALSE(iterator.has_next(&iterator));
fldkey = clone_field(mf_int32_d1_1);
result = structvalue_put(sv, fldkey, (etch_object*) int_array_1);
CU_ASSERT_EQUAL(result, 0);
fldkey = clone_field(mf_int32_d1_2);
result = structvalue_put(sv, fldkey, (etch_object*) int_array_2);
CU_ASSERT_EQUAL(result, 0);
set_iterator(&iterator, sv->items, &sv->items->iterable);
while(iterator.has_next(&iterator))
{ count++;
iterator.next(&iterator);
}
CU_ASSERT_EQUAL(count,4);
/* free memory for struct and its instance data and content */
etch_object_destroy(sv);
destroy_testdata();
#ifdef ETCH_DEBUGALLOC
g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE); /* verify all memory freed */
CU_ASSERT_EQUAL(g_bytes_allocated, 0);
// start fresh for next test
memtable_clear();
#endif
}
/*
* run_exception_test
*
*/
static void run_exception_test(const int whichtest)
{
etch_type* static_type = NULL;
static_type = new_type(L"type1");
#if(0)
/* create a bogus TDI inheriting from tagged data input */
tdi = new_fake_tdi(static_type);
CU_ASSERT_PTR_NOT_NULL_FATAL(tdi);
switch(whichtest)
{ case EXCPTEST_UNCHECKED_STATICTEXT:
case EXCPTEST_CHECKED_COPYTEXT:
case EXCPTEST_CHECKED_STATICTEXT:
{ CU_ASSERT_TRUE_FATAL(is_exception(tdi));
#if IS_DEBUG_CONSOLE
wprintf(L"\ncaught %s exception on tdi\n", tdiobj->result->exception->excptext);
#endif
}
}
sv = structvalue_read(NULL); /* pass NULL for TDI */
CU_ASSERT_PTR_NOT_NULL_FATAL(sv);
CU_ASSERT_TRUE(is_exception(tdi));
excp = get_exception(sv);
CU_ASSERT_EQUAL(excp->excptype, EXCPTYPE_ILLEGALARG);
#if IS_DEBUG_CONSOLE
wprintf(L"\ncaught %s exception on sv\n", svobj->result->exception->excptext);
#endif
/* free TDI */
faketdi_close(tdi);
/* free struct, it is just a shell with no content other than the exception */
etch_object_destroy(sv);
#endif
/* destroy the type allocated above.
* in most tests we would NOT do this since the struct would own it after we
* created the struct. however we passed a null tdi parameter above to the
* method which would have created the struct. the type which would have
* been assigned to the struct was in the tdi that we did not pass. The tdi
* will not destroy its type. however note that in the real world this
* situation would not occur. all types would be global, and we will always
* create a copy of the type for the struct. see faketdi_start_struct() for
* an example, note that it clones the type for the new struct.
*/
etch_object_destroy(static_type);
/* destroy testdata list and content */
destroy_testdata();
#ifdef ETCH_DEBUGALLOC
g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE); /* verify all memory freed */
CU_ASSERT_EQUAL(g_bytes_allocated, 0);
// start fresh for next test
memtable_clear();
#endif
}
/*
* test_iterator_over_hashtable
*/
static void test_iterator_over_hashtable(void)
{
etch_iterator* iterator = NULL;
int testcount = 0, thiscount = 0;
struct i_iterable* vtab = NULL;
new_testdata(1);
CU_ASSERT_PTR_NOT_NULL_FATAL(testdata);
testcount = ((struct i_hashtable*)((etch_object*)testdata)->vtab)->count(testdata->realtable, 0, 0);
CU_ASSERT_NOT_EQUAL(testcount, 0);
iterator = new_iterator(testdata, &testdata->iterable);
CU_ASSERT_PTR_NOT_NULL_FATAL(iterator);
CU_ASSERT_EQUAL_FATAL(iterator->ordinal,1);
thiscount = 1;
vtab = (i_iterable*)((etch_object*)iterator)->vtab;
while(vtab->has_next(iterator))
thiscount += (vtab->next(iterator) == 0);
CU_ASSERT_EQUAL(testcount, thiscount);
destroy_iterator(iterator);
destroy_testdata();
#ifdef ETCH_DEBUGALLOC
g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE); /* verify all memory freed */
CU_ASSERT_EQUAL(g_bytes_allocated, 0);
// start fresh for next test
memtable_clear();
#endif
}
#if 0
/*
* exception_test_1
*/
static void exception_test_1(void)
{
int itemcount = 0;
if ((itemcount = new_testdata(1)) > 0)
run_exception_test(EXCPTEST_UNCHECKED_STATICTEXT);
}
#endif
/*
* exception_test_2
*/
static void exception_test_2(void)
{
int itemcount = 0;
if ((itemcount = new_testdata(1)) > 0)
run_exception_test(EXCPTEST_CHECKED_COPYTEXT);
}
#if 0
/*
* exception_test_3
*/
static void exception_test_3(void)
{
int itemcount = 0;
if ((itemcount = new_testdata(1)) > 0)
run_exception_test(EXCPTEST_CHECKED_STATICTEXT);
}
#endif
/**
* main
*/
//int wmain( int argc, wchar_t* argv[], wchar_t* envp[])
CU_pSuite test_etch_structvalue_suite()
{
CU_pSuite pSuite = CU_add_suite("suite_structvalue", init_suite, clean_suite);
CU_add_test(pSuite, "test iterator over hashtable", test_iterator_over_hashtable);
CU_add_test(pSuite, "test structvalue iterator", run_iterator_test);
CU_add_test(pSuite, "test sv exceptions", exception_test_2);
return pSuite;
}