You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@etch.apache.org by jd...@apache.org on 2009/04/22 19:25:51 UTC
svn commit: r767594 [27/43] - in /incubator/etch/trunk/binding-c/runtime/c:
./ ext/ ext/hashtab/ ext/lib/ inc/ lib/ project/ project/$etchstop/
project/bin/ project/etch/ project/logcli/ project/logsrv/ project/notes/
project/test/ project/test/logcli/...
Added: incubator/etch/trunk/binding-c/runtime/c/src/test/message/test_idname.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/test/message/test_idname.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/test/message/test_idname.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/test/message/test_idname.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,223 @@
+/* $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_id_name.c
+ * tests the C implementation of the etch_id_name object.
+ */
+#include "apr_time.h" /* some apr must be included first */
+#include "etchthread.h"
+#include <stdio.h>
+#include <conio.h>
+#include "cunit.h"
+#include "basic.h"
+#include "automated.h"
+#include "etch_id_name.h"
+#include "etch_global.h"
+
+
+int apr_setup(void);
+int apr_teardown(void);
+int this_setup();
+int this_teardown();
+apr_pool_t* g_apr_mempool;
+const char* pooltag = "etchpool";
+
+
+/* - - - - - - - - - - - - - -
+ * unit test infrastructure
+ * - - - - - - - - - - - - - -
+ */
+
+int init_suite(void)
+{
+ apr_setup();
+ etch_runtime_init(TRUE);
+ return this_setup();
+}
+
+int clean_suite(void)
+{
+ this_teardown();
+ etch_runtime_cleanup(0,0); /* free memtable and cache etc */
+ apr_teardown();
+ return 0;
+}
+
+int g_is_automated_test, g_bytes_allocated;
+
+#define IS_DEBUG_CONSOLE FALSE
+
+/*
+ * apr_setup()
+ * establish apache portable runtime environment
+ */
+int apr_setup(void)
+{
+ int result = apr_initialize();
+ if (result == 0)
+ { result = etch_apr_init();
+ g_apr_mempool = etch_apr_mempool;
+ }
+ if (g_apr_mempool)
+ apr_pool_tag(g_apr_mempool, pooltag);
+ else result = -1;
+ return result;
+}
+
+/*
+ * apr_teardown()
+ * free apache portable runtime environment
+ */
+int apr_teardown(void)
+{
+ if (g_apr_mempool)
+ apr_pool_destroy(g_apr_mempool);
+ g_apr_mempool = NULL;
+ apr_terminate();
+ return 0;
+}
+
+int this_setup()
+{
+ etch_apr_mempool = g_apr_mempool;
+ return 0;
+}
+
+int this_teardown()
+{
+ return 0;
+}
+
+
+/**
+ * test_id_name
+ */
+void test_id_name(void)
+{
+ int alloc_a = 0, alloc_b = 0, result = 0;
+ etch_id_name *id_name1 = NULL, *id_name2 = NULL;
+
+ const wchar_t* nametext1 = L"abracadabra";
+ const size_t numelts1 = wcslen(nametext1);
+ const size_t numbytes1 = sizeof(wchar_t) * numelts1;
+
+ const wchar_t* nametext2 = L"gilgamesh";
+ const size_t numelts2 = wcslen(nametext2);
+ const size_t numbytes2 = sizeof(wchar_t) * numelts2;
+
+ alloc_a = etch_showmem(0, FALSE);
+ id_name1 = new_id_name(NULL);
+ alloc_b = etch_showmem(0, FALSE);
+ CU_ASSERT_PTR_NULL(id_name1);
+ CU_ASSERT_EQUAL(alloc_a, alloc_b);
+
+ id_name1 = new_id_name(nametext1);
+ CU_ASSERT_PTR_NOT_NULL_FATAL(id_name1);
+ CU_ASSERT_TRUE(is_good_id_name(id_name1));
+
+ id_name2 = new_id_name(nametext1);
+ CU_ASSERT_TRUE(is_equal_id_names(id_name1, id_name2));
+ result = memcmp(id_name1->name, id_name2->name, id_name1->namebytelen);
+ CU_ASSERT_EQUAL(result,0);
+
+ destroy_id_name(id_name1);
+ destroy_id_name(id_name2);
+
+ alloc_a = etch_showmem(0, FALSE);
+ CU_ASSERT_EQUAL(alloc_a, alloc_b);
+
+ id_name1 = new_id_name(nametext1);
+ id_name2 = new_id_name(nametext2);
+
+ CU_ASSERT_FALSE(is_equal_id_names(id_name1, id_name2));
+
+ destroy_id_name(id_name1);
+ destroy_id_name(id_name2);
+
+ g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE); /* verify all memory freed */
+ CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+ memtable_clear(); /* start fresh for next test */
+}
+
+
+/**
+ * test_id_name_hashfunc
+ * Unit test id_name_hashfunc
+ */
+void test_id_name_hashfunc(void)
+{
+ int alloc_a = 0, alloc_b = 0, result = 0;
+ unsigned hash1 = 0, hash2 = 0;
+ etch_id_name *id_name1 = NULL, *id_name2 = NULL;
+
+ const wchar_t* nametext1 = L"abracadabra";
+ const size_t numelts1 = wcslen(nametext1);
+ const size_t numbytes1 = sizeof(wchar_t) * ( numelts1 + 1 );
+
+ const wchar_t* nametext2 = L"gilgamesh";
+ const size_t numelts2 = wcslen(nametext2);
+ const size_t numbytes2 = sizeof(wchar_t) * ( numelts2 + 1 );
+
+ hash1 = compute_id_name_id_from_widename(nametext1);
+ hash2 = compute_id_name_id_from_widename(nametext2);
+
+ CU_ASSERT_NOT_EQUAL(hash1, hash2);
+
+ id_name1 = new_id_name(nametext1);
+ id_name2 = new_id_name(nametext2);
+ CU_ASSERT_EQUAL(id_name1->namebytelen, numbytes1);
+ CU_ASSERT_EQUAL(id_name2->namebytelen, numbytes2);
+ CU_ASSERT_EQUAL(id_name1->id, hash1);
+ CU_ASSERT_EQUAL(id_name2->id, hash2);
+
+ destroy_id_name(id_name1);
+ destroy_id_name(id_name2);
+
+ g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE); /* verify all memory freed */
+ CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+ memtable_clear(); /* start fresh for next test */
+}
+
+
+/**
+ * main
+ */
+int _tmain(int argc, _TCHAR* argv[])
+{
+ char c=0;
+ CU_pSuite pSuite = NULL;
+ g_is_automated_test = argc > 1 && 0 != wcscmp(argv[1], L"-a");
+ if (CUE_SUCCESS != CU_initialize_registry()) return 0;
+ pSuite = CU_add_suite("suite_id_name", init_suite, clean_suite);
+ CU_set_output_filename("../test_id_name");
+
+ CU_add_test(pSuite, "test etch_id_name constructors/destructors", test_id_name);
+ CU_add_test(pSuite, "test etch_id_name hashing", test_id_name_hashfunc);
+
+ if (g_is_automated_test)
+ CU_automated_run_tests();
+ else
+ { CU_basic_set_mode(CU_BRM_VERBOSE);
+ CU_basic_run_tests();
+ }
+
+ if (!g_is_automated_test) { printf("any key ..."); while(!c) c = _getch(); wprintf(L"\n"); }
+ CU_cleanup_registry();
+ return CU_get_error();
+}
\ No newline at end of file
Added: incubator/etch/trunk/binding-c/runtime/c/src/test/message/test_message.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/test/message/test_message.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/test/message/test_message.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/test/message/test_message.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,1380 @@
+/* $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_message.c -- test etch_message object
+ */
+
+#include "apr_time.h" /* some apr must be included first */
+
+#include <tchar.h>
+#include <stdio.h>
+#include <conio.h>
+
+#include "cunit.h"
+#include "basic.h"
+#include "automated.h"
+
+#include "etch_connection.h"
+#include "etch_global.h"
+#include "etch_encoding.h"
+#include "etchthread.h"
+#include "etchlog.h"
+#include "etch_message.h"
+#include "etchexcp.h"
+
+int apr_setup(void);
+int apr_teardown(void);
+int this_setup();
+int this_teardown();
+apr_pool_t* g_apr_mempool;
+const char* pooltag = "etchpool";
+
+
+int init_suite(void)
+{
+ apr_setup();
+ etch_runtime_init(TRUE);
+ return this_setup();
+}
+
+int clean_suite(void)
+{
+ this_teardown();
+ etch_runtime_cleanup(0,0); /* free memtable and cache etc */
+ apr_teardown();
+ return 0;
+}
+
+int g_is_automated_test, g_bytes_allocated;
+#define IS_DEBUG_CONSOLE FALSE
+
+/*
+ * apr_setup()
+ * establish apache portable runtime environment
+ */
+int apr_setup(void)
+{
+ int result = apr_initialize();
+ if (result == 0)
+ { result = etch_apr_init();
+ g_apr_mempool = etch_apr_mempool;
+ }
+ if (g_apr_mempool)
+ apr_pool_tag(g_apr_mempool, pooltag);
+ else result = -1;
+ return result;
+}
+
+/*
+ * apr_teardown()
+ * free apache portable runtime environment
+ */
+int apr_teardown(void)
+{
+ if (g_apr_mempool)
+ apr_pool_destroy(g_apr_mempool);
+ g_apr_mempool = NULL;
+ apr_terminate();
+ return 0;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - -
+ * local declarations
+ * - - - - - - - - - - - - - - - - - - - - - -
+ */
+
+/* - - - - - - - - - - - - - - - - - - - - - -
+ * local setup and teardown
+ * - - - - - - - - - - - - - - - - - - - - - -
+ */
+
+int this_setup()
+{
+ etch_apr_mempool = g_apr_mempool;
+ return 0;
+}
+
+int this_teardown()
+{
+ return 0;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - -
+ * individual setup and teardown
+ * - - - - - - - - - - - - - - - - - - - - - -
+ */
+
+int this_test_setup()
+{
+ int result = -1;
+
+ do
+ {
+ result = 0;
+ } while(0);
+
+ return result;
+}
+
+int this_test_teardown()
+{
+
+ return 0;
+}
+
+int g_bytes_allocated, g_which_exception_test, g_is_automated_test;
+wchar_t* local_excp_text = L"global text";
+
+#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 OBJTYPE_FAKEVF_IMPL ETCHTYPEB_INSTANCEDATA
+#define CLASSID_FAKEVF_IMPL 0xf2
+#define OBJTYPE_FAKEVF_VTABLE 0x90
+#define OBJTYPE_FAKEVF_IMPL ETCHTYPEB_INSTANCEDATA
+#define OBJTYPE_FAKEVF ETCHTYPEB_VALUEFACTORY
+#define CLASSID_FAKEVF 0xf5
+
+#define EXCPTEST_UNCHECKED_STATICTEXT 1
+#define EXCPTEST_CHECKED_COPYTEXT 2
+#define EXCPTEST_CHECKED_STATICTEXT 3
+
+
+typedef struct testitems
+{
+ etch_type* mt1;
+ etch_type* mt2;
+ etch_type* rmt;
+ etch_field* mf1;
+ etch_field* mf2;
+ etch_field* mf3;
+ etch_field* mf4;
+
+ etch_string* s1;
+ etch_string* s2;
+ etch_int32* n1;
+ etch_int32* n2;
+ etch_int64* l1;
+ etch_int64* l2;
+
+ etch_field *mf_bool_d0_1;
+ etch_field *mf_bool_d0_2;
+ etch_field *mf_bool_d1_1;
+ etch_field *mf_bool_d1_2;
+
+ etch_field *mf_int32_d0_1;
+ etch_field *mf_int32_d0_2;
+ etch_field *mf_int32_d1_1;
+ etch_field *mf_int32_d1_2;
+
+ etch_field *mf_str_d0_1;
+ etch_field *mf_str_d0_2;
+ etch_field *mf_str_d1_1;
+ etch_field *mf_str_d1_2;
+
+ etch_field *mf_message_id;
+ etch_field *mf_in_reply_to;
+
+ etch_hashtable* items;
+
+} testitems;
+
+enum objtyp ETCHTYPE_VTABLE_FAKETDI = 0xfa;
+enum objtyp ETCHTYPE_VTABLE_FAKETDO = 0xfb;
+enum objtyp ETCHTYPE_VTABLE_FAKEVF = 0xfc;
+
+
+/* = = = = = = = = = = = = = = =
+ * VALUE FACTORY IMPLEMENTATION
+ * = = = = = = = = = = = = = = =
+ */
+
+/**
+ * fake_vf_impl
+ * instance data for a value factory implementation
+ */
+typedef struct fake_vf_impl
+{
+ unsigned int hashkey;
+ unsigned short obj_type;
+ unsigned short class_id;
+ struct objmask* vtab;
+ int (*destroy)(void*);
+ void*(*clone) (void*);
+ obj_gethashkey get_hashkey;
+ struct objmask* parent;
+ etchresult* result;
+ unsigned int refcount;
+ unsigned int length;
+ unsigned char is_null;
+ unsigned char is_copy;
+ unsigned char is_static;
+ unsigned char reserved;
+
+ etch_field* mf_message_id;
+ etch_field* mf_in_reply_to;
+
+} fake_vf_impl;
+
+
+/**
+ * destroy_fake_vf_impl
+ * destructor for fake_vf_impl
+ */
+int destroy_fake_vf_impl(fake_vf_impl* impl)
+{
+ int result = verify_object((objmask*)impl, OBJTYPE_FAKEVF_IMPL, CLASSID_FAKEVF_IMPL, 0);
+ if (result == -1) return -1; /* object passed was not expected object */
+
+ CU_ASSERT_PTR_NOT_NULL_FATAL(impl->mf_message_id);
+ CU_ASSERT_PTR_NOT_NULL_FATAL(impl->mf_in_reply_to);
+
+ impl->mf_message_id ->destroy(impl->mf_message_id);
+ impl->mf_in_reply_to->destroy(impl->mf_in_reply_to);
+
+ etch_free(impl);
+ return 0;
+}
+
+
+/**
+ * new_fake_vf_impl()
+ * constructor for TDI implementation instance data
+ */
+fake_vf_impl* new_fake_vf_impl(testitems* items)
+{
+ fake_vf_impl* data = etch_malloc(sizeof(fake_vf_impl), ETCHTYPEB_INSTANCEDATA);
+ memset(data, 0, sizeof(fake_vf_impl));
+ data->obj_type = OBJTYPE_FAKEVF_IMPL;
+ data->class_id = CLASSID_FAKEVF_IMPL;
+
+ data->mf_message_id = items->mf_message_id->clone(items->mf_message_id);
+ data->mf_in_reply_to = items->mf_in_reply_to->clone(items->mf_in_reply_to);
+
+ data->destroy = destroy_fake_vf_impl;
+ return data;
+}
+
+
+/*
+ * value factory virtual function overrides
+ */
+
+/**
+ * fvf_get_message_id() -- valuefactory.get_message_id() implementation.
+ * @return non-disposable reference to id object, or null if not found.
+ */
+etch_int64* fvf_get_message_id (etch_value_factory* vf, etch_message* msg)
+{
+ etch_int64* id = NULL;
+ fake_vf_impl* data = (fake_vf_impl*) vf->impl;
+
+ id = (etch_int64*) message_get(msg, data->mf_message_id);
+
+ /* return (etch_int64*) verifyx((objmask*) id, 0,
+ CLASSID_PRIMITIVE_INT64, EXCPTYPE_INTERNALERR); */
+
+ return id;
+}
+
+
+/**
+ * fvf_set_message_id() -- valuefactory.set_message_id() implementation.
+ */
+int fvf_set_message_id (etch_value_factory* vf, etch_message* msg, etch_int64* id)
+{
+ fake_vf_impl* data = (fake_vf_impl*) vf->impl;
+ etch_field* keycopy = data->mf_message_id->clone(data->mf_message_id);
+
+ const int result = message_put(msg, keycopy, (objmask*) id);
+ return result;
+}
+
+
+/**
+ * fvf_get_in_reply_to() -- valuefactory.get_in_reply_to() implementation.
+ */
+etch_int64* fvf_get_in_reply_to (etch_value_factory* vf, etch_message* msg)
+{
+ etch_int64* id = NULL;
+ fake_vf_impl* data = (fake_vf_impl*) vf->impl;
+
+ id = (etch_int64*) message_get(msg, data->mf_in_reply_to);
+
+ return (etch_int64*) verifyx((objmask*) id, 0, CLASSID_PRIMITIVE_INT64, EXCPTYPE_INTERNALERR);
+}
+
+
+/**
+ * fvf_set_in_reply_to() -- valuefactory.set_message_id() implementation.
+ */
+int fvf_set_in_reply_to (etch_value_factory* vf, etch_message* msg, etch_int64* id)
+{
+ fake_vf_impl* data = (fake_vf_impl*) vf->impl;
+ etch_field* keycopy = clone_field(data->mf_in_reply_to);
+
+ /* FYI this copy of the key is put to etch_message* sent message, and gets
+ * freed in msg.destroy(), message owns memory other than vf and type
+ */
+ return message_put(msg, keycopy, (objmask*) id);
+}
+
+/*
+ * value factory constructors/destructors
+ */
+
+
+/**
+ * fakevf_close() ala java test
+ */
+void fakevf_close(etch_value_factory* vf)
+{
+ vf->destroy(vf);
+}
+
+
+#define CLASSID_FAKE_VALUEFACTORY 200
+
+/**
+ * new_fake_value_factory()
+ * constructor for value factory implementation
+ */
+etch_value_factory* new_fake_value_factory(testitems* items)
+{
+ etch_value_factory* fakevf = NULL;
+ i_value_factory* vtab = NULL;
+ const int VTABSIZE = sizeof(i_value_factory);
+ const unsigned short CLASS_ID = CLASSID_FAKE_VALUEFACTORY;
+ int result = 0;
+
+ fakevf = new_value_factory(0);
+
+ vtab = cache_find(get_vtable_cachehkey(CLASS_ID), 0);
+
+ if(!vtab)
+ {
+ vtab = new_vtable(fakevf->vtab, VTABSIZE, CLASS_ID);
+
+ /* override four i_value_factory methods */
+ vtab->get_message_id = fvf_get_message_id;
+ vtab->set_message_id = fvf_set_message_id;
+ vtab->get_in_reply_to = fvf_get_in_reply_to;
+ vtab->set_in_reply_to = fvf_set_in_reply_to;
+
+ vtab->vtab = fakevf->vtab; /* chain vtabs */
+ cache_insert(vtab->hashkey, vtab, 0);
+ }
+
+ CU_ASSERT_EQUAL_FATAL(vtab->class_id, CLASS_ID);
+
+ fakevf->vtab = vtab; /* set override vtab */
+
+ fakevf->impl = (objmask*) new_fake_vf_impl(items); /* create vf instance data */
+
+ switch(g_which_exception_test)
+ { case EXCPTEST_UNCHECKED_STATICTEXT:
+ etch_throw((objmask*) fakevf, EXCPTYPE_NULLPTR, NULL, 0);
+ break;
+ case EXCPTEST_CHECKED_COPYTEXT:
+ etch_throw((objmask*)fakevf, EXCPTYPE_CHECKED_BOGUS, L"copied text", ETCHEXCP_COPYTEXT | ETCHEXCP_FREETEXT);
+ break;
+ case EXCPTEST_CHECKED_STATICTEXT:
+ etch_throw((objmask*)fakevf, EXCPTYPE_CHECKED_BOGUS, local_excp_text, ETCHEXCP_STATICTEXT);
+ break;
+ }
+
+ return fakevf;
+}
+
+
+#if(0)
+
+/* = = = = = = = = = =
+ * TDI IMPLEMENTATION
+ * = = = = = = = = = =
+ */
+
+/**
+ * fake_tdi_impl
+ * instance data for a TDI implementation
+ */
+typedef struct fake_tdi_impl
+{
+ unsigned int hashkey;
+ unsigned short obj_type;
+ unsigned short class_id;
+ struct i_value_factory* vtab;
+ int (*destroy)(void*);
+ void*(*clone) (void*);
+ obj_gethashkey get_hashkey;
+ struct objmask* parent;
+ etchresult* result;
+ unsigned int refcount;
+ unsigned int length;
+ unsigned char is_null;
+ unsigned char is_copy;
+ unsigned char is_static;
+ unsigned char reserved;
+
+ etch_type* tdi_type;
+ etch_message* xmessage;
+ etch_iterator iterator;
+ etch_value_factory* vf;
+ testitems* testdata;
+ byte started, done, ended, is_owned_message;
+
+} fake_tdi_impl;
+
+
+
+/**
+ * destroy_fake_tdi_impl
+ * memory cleanup handler for fake_tdi_impl
+ */
+int destroy_fake_tdi_impl(fake_tdi_impl* impl)
+{
+ etch_destructor destroy = NULL;
+ int result = verify_object((objmask*)impl, OBJTYPE_FAKETDI_IMPL, CLASSID_FAKETDI_IMPL, 0);
+ if (result == -1) return -1; /* object passed was not expected object */
+
+ /* type is a reference, it does not belong to the tdi. message is created
+ * in the tdi, but ownership is assumed to transfer to the caller when
+ * message_read returns. if this is not the case then is_owned_message
+ * must have been set elsewhere.
+ */
+ if (impl->is_owned_message)
+ { /* not the default case, see comment above */
+ CU_ASSERT_PTR_NOT_NULL_FATAL(impl->xmessage);
+ impl->xmessage->destroy(impl->xmessage);
+ }
+
+ etch_free(impl);
+ return 0;
+}
+
+
+/**
+ * new_fake_tdi_impl()
+ * constructor for TDI implementation instance data
+ */
+fake_tdi_impl* new_fake_tdi_impl(etch_value_factory* vf, etch_type* static_type, testitems* testdata)
+{
+ fake_tdi_impl* data = (fake_tdi_impl*)
+ new_object(sizeof(fake_tdi_impl), ETCHTYPEB_INSTANCEDATA, CLASSID_FAKETDI_IMPL);
+
+ /* value factory and type are references, memory not owned by tdi */
+ data->tdi_type = static_type;
+ data->vf = vf;
+ data->testdata = testdata;
+
+ data->destroy = destroy_fake_tdi_impl;
+ return data;
+}
+
+
+/**
+ * faketdi_start_message() overrides tdi_start_message()
+ */
+etch_message* faketdi_start_message(tagged_data_input* tdi)
+{
+ int result = 0;
+ fake_tdi_impl* tdidata = NULL;
+ etch_message* newmessage = NULL;
+ etch_value_factory* vf = NULL;
+ const int READONLY = TRUE, DEFSIZE = 0, DEFDELTA = 0;
+
+ CU_ASSERT_PTR_NOT_NULL_FATAL(tdi);
+ CU_ASSERT_PTR_NOT_NULL_FATAL(tdi->impl);
+
+ tdidata = (fake_tdi_impl*) tdi->impl; /* validate instance data */
+ result = verify_object((objmask*)tdidata, OBJTYPE_FAKETDI_IMPL, 0, 0);
+ CU_ASSERT_EQUAL_FATAL(result,0);
+ CU_ASSERT_PTR_NOT_NULL_FATAL(tdidata->vf);
+
+ result = tdidata->destroy(NULL); /* ensure we can call into instance destructor */
+ CU_ASSERT_EQUAL(result,-1);
+
+ CU_ASSERT_EQUAL(tdidata->started,FALSE);
+ CU_ASSERT_EQUAL(tdidata->done,FALSE);
+ CU_ASSERT_EQUAL(tdidata->ended,FALSE);
+
+ tdidata->started = TRUE;
+
+ /* create a message (struct) to receive the elements read. a message owns all
+ * its memory except the value factory and type (note that the vf might need
+ * to be refcounted for that reason, to ensure that if the service shuts down
+ * while a message is in the pipeline, a vf is not destroyed prior to a message
+ * which references it). the type is passed through to the underlying struct.
+ * a struct owns all its memory except type, so it is assigned a reference to
+ * the tdi's type, which is an object global to the service. ownership of the
+ * struct, and by extension the messsage, memory, is assumed to be passed to
+ * the caller when this function returns. if instead it was desired that the
+ * tdi own the message and hence the struct, an indicator of such and an
+ * associated message dtor call, would need to be coded in the tdi and tdi
+ * destructor implementation.
+ */
+ newmessage = new_message (tdidata->tdi_type, 0, tdidata->vf);
+
+ tdidata->xmessage = newmessage;
+ CU_ASSERT_PTR_NOT_NULL_FATAL(tdidata->xmessage);
+
+ set_iterator(&tdidata->iterator, /* establish iterator on the input data */
+ tdidata->testdata->items, &tdidata->testdata->items->iterable);
+
+ /* while an empty dataset is valid in the general case,
+ * this test assumes that input is non-empty */
+ result = tdidata->iterator.has_next(&tdidata->iterator);
+ CU_ASSERT_EQUAL(result,TRUE);
+
+ return newmessage;
+}
+
+
+/**
+ * faketdi_read_struct_element() overrides tdi_read_struct_element()
+ */
+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;
+ etch_destructor destroy = 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((objmask*)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 = (objmask*) iterator->current_value;
+
+ iterator->next(iterator);
+ return TRUE;
+ }
+
+ data->done = TRUE;
+ return FALSE;
+}
+
+
+/**
+ * faketdi_end_message() overrides tdi_end_struct()
+ */
+etch_message* faketdi_end_message(tagged_data_input* tdi, etch_message* msg)
+{
+ 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((objmask*)data, OBJTYPE_FAKETDI_IMPL, 0, 0);
+ CU_ASSERT_EQUAL_FATAL(result,0);
+ CU_ASSERT_EQUAL_FATAL(data->xmessage, msg);
+
+ CU_ASSERT_EQUAL(data->started,TRUE);
+ CU_ASSERT_EQUAL(data->done,TRUE);
+ CU_ASSERT_EQUAL(data->ended,FALSE);
+
+ data->ended = TRUE;
+ return msg;
+}
+
+
+/**
+ * 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.
+ */
+void faketdi_close(tagged_data_input* tdi)
+{
+ tdi->destroy(tdi);
+}
+
+
+/**
+ * new_fake_tdi()
+ * constructor for TDI implementation
+ */
+tagged_data_input* new_fake_tdi(etch_type* static_type, etch_value_factory* vfobj, testitems* data)
+{
+ 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(faketdi->vtab, sizeof(i_tagged_data_input), CLASS_ID);
+
+ /* override three i_tagged_data_input methods */
+ vtab->start_message = faketdi_start_message;
+ vtab->end_message = faketdi_end_message;
+ vtab->read_struct_element = faketdi_read_struct_element;
+
+ vtab->vtab = faketdi->vtab; /* chain parent vtab to override vtab */
+ cache_insert(vtab->hashkey, vtab, FALSE);
+ }
+
+ CU_ASSERT_EQUAL_FATAL(vtab->class_id, CLASS_ID);
+
+ faketdi->vtab = vtab; /* set override vtab */
+
+ faketdi->impl = (objmask*)
+ new_fake_tdi_impl(vfobj, static_type, data); /* create TDI instance data */
+
+ switch(g_which_exception_test)
+ { case EXCPTEST_UNCHECKED_STATICTEXT:
+ etch_throw((objmask*) faketdi, EXCPTYPE_NULLPTR, NULL, 0);
+ break;
+ case EXCPTEST_CHECKED_COPYTEXT:
+ etch_throw((objmask*) faketdi, EXCPTYPE_CHECKED_BOGUS, L"copied text", ETCHEXCP_COPYTEXT | ETCHEXCP_FREETEXT);
+ break;
+ case EXCPTEST_CHECKED_STATICTEXT:
+ etch_throw((objmask*) faketdi, EXCPTYPE_CHECKED_BOGUS, local_excp_text, ETCHEXCP_STATICTEXT);
+ break;
+ }
+
+ return faketdi;
+}
+
+
+/* = = = = = = = = = =
+ * TDO IMPLEMENTATION
+ * = = = = = = = = = =
+ */
+
+/**
+ * fake_tdo_impl
+ * instance data for a TDO implementation
+ */
+typedef struct fake_tdo_impl
+{
+ unsigned int hashkey;
+ unsigned short obj_type;
+ unsigned short class_id;
+ struct objmask* vtab;
+ int (*destroy)(void*);
+ void*(*clone) (void*);
+ obj_gethashkey get_hashkey;
+ struct objmask* parent;
+ etchresult* result;
+ unsigned int refcount;
+ unsigned int length;
+ unsigned char is_null;
+ unsigned char is_copy;
+ unsigned char is_static;
+ unsigned char reserved;
+
+ byte started, ended, closed;
+ etch_message* xmessage; /* reference */
+ etch_hashtable* fakeout; /* fake output sink */
+
+} fake_tdo_impl;
+
+
+/**
+ * destroy_fake_tdo_impl
+ * memory cleanup handler for fake_tdo_impl
+ * we do not destroy the message and underlying struct, this is a reference.
+ */
+int destroy_fake_tdo_impl(fake_tdo_impl* impl)
+{
+ etch_destructor destroy = NULL;
+ int result = verify_object((objmask*)impl, OBJTYPE_FAKETDO_IMPL, CLASSID_FAKETDO_IMPL, NULL);
+ if (result == -1) return -1; /* object passed was not expected object */
+
+ /* destroy the fake output sink, in this case a map. we do not want the map to
+ * destroy its content because the message owns that content, and we did not
+ * in this case give the output sink copies of that content.
+ */
+ impl->fakeout->destroy(impl->fakeout);
+
+ etch_free(impl);
+ return 0;
+}
+
+
+/**
+ * new_fake_tdo_impl()
+ * constructor for TDO implementation instance data
+ */
+fake_tdo_impl* new_fake_tdo_impl(etch_message* msg)
+{
+ fake_tdo_impl* data = (fake_tdo_impl*)
+ new_object(sizeof(fake_tdo_impl), ETCHTYPEB_INSTANCEDATA, CLASSID_FAKETDO_IMPL);
+
+ data->xmessage = msg; /* reference, not owned */
+
+ data->destroy = destroy_fake_tdo_impl;
+ return data;
+}
+
+
+/**
+ * faketdo_start_message() overrides tdo_start_message()
+ */
+etch_message* faketdo_start_message(tagged_data_output* tdo, etch_message* msg)
+{
+ int result = 0;
+ fake_tdo_impl* data = NULL;
+ etch_destructor destructor = 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((objmask*)data, OBJTYPE_FAKETDO_IMPL, 0, (void**) &destructor);
+ CU_ASSERT_EQUAL_FATAL(result,0);
+
+ result = data->destroy(NULL); /* ensure we can call instance destructor */
+ CU_ASSERT_EQUAL(result,-1);
+
+ CU_ASSERT_EQUAL(data->started,FALSE);
+ CU_ASSERT_EQUAL(data->ended,FALSE);
+
+ CU_ASSERT_EQUAL_FATAL(msg, data->xmessage);
+ CU_ASSERT_PTR_NOT_NULL_FATAL(data->fakeout);
+
+ data->started = TRUE;
+ return msg;
+}
+
+
+/**
+ * faketdo_write_struct_element() overrides tdo_write_struct_element()
+ */
+int faketdo_write_struct_element(tagged_data_output* tdo, etch_field* key, objmask* 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((objmask*)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 = 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 = 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;
+}
+
+
+/**
+ * faketdo_end_message() overrides tdo_end_message()
+ */
+etch_message* faketdo_end_message(tagged_data_output* tdo, etch_message* msg)
+{
+ 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((objmask*)data, OBJTYPE_FAKETDO_IMPL, 0, 0);
+ CU_ASSERT_EQUAL_FATAL(result,0);
+ CU_ASSERT_PTR_NOT_NULL_FATAL(data->xmessage);
+
+ CU_ASSERT_EQUAL(data->started,TRUE);
+ CU_ASSERT_EQUAL(data->ended,FALSE);
+ CU_ASSERT_EQUAL(data->closed,FALSE);
+ CU_ASSERT_EQUAL(data->xmessage, msg);
+
+ data->ended = TRUE;
+ return msg;
+}
+
+
+/**
+ * faketdo_close() ala java test
+ */
+void faketdo_close(tagged_data_output* tdo)
+{
+ tdo->destroy(tdo);
+}
+
+
+/**
+ * new_fake_tdo()
+ * constructor for TDO implementation
+ */
+tagged_data_output* new_fake_tdo(etch_message* msg)
+{
+ 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(msg);
+
+ faketdo = new_tagged_data_output();
+
+ vtab = cache_find(get_vtable_cachehkey(CLASS_ID), 0);
+
+ if(!vtab)
+ {
+ vtab = new_vtable(faketdo->vtab, sizeof(i_tagged_data_output), CLASS_ID);
+
+ /* override three i_tagged_data_output methods */
+ vtab->start_message = faketdo_start_message;
+ vtab->end_message = faketdo_end_message;
+ vtab->write_struct_element = faketdo_write_struct_element;
+
+ vtab->vtab = faketdo->vtab; /* chain parent vtab */
+
+ cache_insert(vtab->hashkey, vtab, FALSE);
+ }
+
+ CU_ASSERT_EQUAL_FATAL(vtab->class_id, CLASS_ID);
+
+ faketdo->vtab = vtab; /* set override vtab */
+
+ impl = new_fake_tdo_impl(msg); /* construct TDO instance data */
+ CU_ASSERT_PTR_NOT_NULL_FATAL(impl);
+
+ impl->fakeout = new_hashtable(16); /* instantiate fake output target */
+ CU_ASSERT_PTR_NOT_NULL_FATAL(impl->fakeout);
+ impl->fakeout->content_type = ETCHHASHTABLE_CONTENT_OBJECT;
+
+ faketdo->impl = (objmask*) impl;
+
+ return faketdo;
+}
+
+#endif /* #if(0) */
+
+
+/* = = = = = = = = = =
+ * TEST DATA
+ * = = = = = = = = = =
+ */
+
+/*
+ * testdata_clear_handler()
+ * memory callback on testdata clear
+ */
+int testdata_clear_handler (etch_field* key, objmask* value)
+{
+ return TRUE; /* indicate free handled */
+}
+
+/*
+ * new_testitems()
+ * instantiate and return types and fields used in tests
+ */
+testitems* new_testitems()
+{
+ testitems* items = etch_malloc(sizeof(struct testitems), 0);
+ items->mt1 = new_type(L"mt1");
+ items->mt2 = new_type(L"mt2");
+ items->rmt = new_type(L"rmt");
+ items->mf1 = new_field(L"x");
+ items->mf2 = new_field(L"y");
+ items->mf3 = new_field(L"s1");
+ items->mf4 = new_field(L"s2");
+
+ items->s1 = new_string(L"string1", ETCH_ENCODING_UTF16);
+ items->s2 = new_string(L"string2", ETCH_ENCODING_UTF16);
+ items->n1 = new_int32(1);
+ items->n2 = new_int32(2);
+ items->l1 = new_int64(12345);
+ items->l2 = new_int64(54321);
+
+ items->mf_bool_d0_1 = new_field(L"f1");
+ items->mf_bool_d0_2 = new_field(L"f2");
+ items->mf_bool_d1_1 = new_field(L"f3");
+ items->mf_bool_d1_2 = new_field(L"f4");
+
+ items->mf_int32_d0_1 = new_field(L"f5");
+ items->mf_int32_d0_2 = new_field(L"f6");
+ items->mf_int32_d1_1 = new_field(L"f7");
+ items->mf_int32_d1_2 = new_field(L"f8");
+
+ items->mf_str_d0_1 = new_field(L"f9");
+ items->mf_str_d0_2 = new_field(L"fa");
+ items->mf_str_d1_1 = new_field(L"fb");
+ items->mf_str_d1_2 = new_field(L"fc");
+
+ items->mf_message_id = new_field(L"_messageId");
+ items->mf_in_reply_to = new_field(L"_inReplyTo");
+
+ etchtype_put_validator(items->mt1, clone_field(items->mf_message_id), (objmask*) etchvtor_int64_get(0));
+ etchtype_put_validator(items->mt1, clone_field(items->mf1), (objmask*) etchvtor_int32_get(0));
+ etchtype_put_validator(items->mt1, clone_field(items->mf2), (objmask*) etchvtor_int32_get(0));
+ etchtype_put_validator(items->mt1, clone_field(items->mf3), (objmask*) etchvtor_string_get(0));
+ etchtype_put_validator(items->mt1, clone_field(items->mf4), (objmask*) etchvtor_string_get(0));
+
+ etchtype_put_validator(items->rmt, clone_field(items->mf_message_id), (objmask*) etchvtor_int64_get(0));
+ etchtype_put_validator(items->rmt, clone_field(items->mf_in_reply_to),(objmask*) etchvtor_int64_get(0));
+
+ #if(0)
+ etchtype_put_validator(items->mt1, items->mf_bool_d0_1->clone(items->mf_bool_d0_1), (objmask*) etchvtor_boolean_get(0));
+ etchtype_put_validator(items->mt1, items->mf_bool_d0_2->clone(items->mf_bool_d0_2), (objmask*) etchvtor_boolean_get(0));
+
+ etchtype_put_validator(items->mt1, items->mf_bool_d1_1->clone(items->mf_bool_d1_1), (objmask*) etchvtor_boolean_get(1));
+ etchtype_put_validator(items->mt1, items->mf_bool_d1_2->clone(items->mf_bool_d1_2), (objmask*) etchvtor_boolean_get(1));
+
+ etchtype_put_validator(items->mt1, items->mf_int32_d0_1->clone(items->mf_int32_d0_1), (objmask*) etchvtor_int32_get(0));
+ etchtype_put_validator(items->mt1, items->mf_int32_d0_2->clone(items->mf_int32_d0_2), (objmask*) etchvtor_int32_get(0));
+
+ etchtype_put_validator(items->mt1, items->mf_int32_d1_1->clone(items->mf_int32_d1_1), (objmask*) etchvtor_int32_get(1));
+ etchtype_put_validator(items->mt1, items->mf_int32_d1_2->clone(items->mf_int32_d1_2), (objmask*) etchvtor_int32_get(1));
+
+ etchtype_put_validator(items->mt1, items->mf_str_d0_1->clone(items->mf_str_d0_1), (objmask*) etchvtor_string_get(0));
+ etchtype_put_validator(items->mt1, items->mf_str_d0_2->clone(items->mf_str_d0_2), (objmask*) etchvtor_string_get(0));
+
+ etchtype_put_validator(items->mt1, items->mf_str_d1_1->clone(items->mf_str_d1_1), (objmask*) etchvtor_string_get(1));
+ etchtype_put_validator(items->mt1, items->mf_str_d1_2->clone(items->mf_str_d1_2), (objmask*) etchvtor_string_get(1));
+ #endif
+
+ items->items = new_hashtable(0);
+ items->items->is_readonly_keys = FALSE;
+ items->items->is_readonly_values = FALSE;
+ items->items->is_tracked_memory = TRUE;
+ items->items->content_type = ETCHHASHTABLE_CONTENT_OBJECT;
+ items->items->freehook = testdata_clear_handler;
+ return items;
+}
+
+/*
+ * destroy_testitems()
+ * free memory for test data
+ */
+void destroy_testitems(testitems* items)
+{
+ items->mt1->destroy(items->mt1);
+ items->mt2->destroy(items->mt2);
+ items->rmt->destroy(items->rmt);
+ items->mf1->destroy(items->mf1);
+ items->mf2->destroy(items->mf2);
+ items->mf3->destroy(items->mf3);
+ items->mf4->destroy(items->mf4);
+
+ items->s1->destroy(items->s1);
+ items->s2->destroy(items->s2);
+ items->n1->destroy(items->n1);
+ items->n2->destroy(items->n2);
+ items->l1->destroy(items->l1);
+ items->l2->destroy(items->l2);
+
+ items->mf_message_id->destroy (items->mf_message_id);
+ items->mf_in_reply_to->destroy(items->mf_in_reply_to);
+
+ items->mf_bool_d0_1->destroy(items->mf_bool_d0_1);
+ items->mf_bool_d0_2->destroy(items->mf_bool_d0_2);
+ items->mf_bool_d1_1->destroy(items->mf_bool_d1_1);
+ items->mf_bool_d1_2->destroy(items->mf_bool_d1_2);
+
+ items->mf_int32_d0_1->destroy(items->mf_int32_d0_1);
+ items->mf_int32_d0_2->destroy(items->mf_int32_d0_2);
+ items->mf_int32_d1_1->destroy(items->mf_int32_d1_1);
+ items->mf_int32_d1_2->destroy(items->mf_int32_d1_2);
+
+ items->mf_str_d0_1->destroy(items->mf_str_d0_1);
+ items->mf_str_d0_2->destroy(items->mf_str_d0_2);
+ items->mf_str_d1_1->destroy(items->mf_str_d1_1);
+ items->mf_str_d1_2->destroy(items->mf_str_d1_2);
+
+ etchvtor_clear_cache(); /* free all cached validators */
+
+ destroy_hashtable(items->items, FALSE, FALSE);
+
+ etch_free(items);
+}
+
+
+/*
+ * compare_lists()
+ * compares specified message content with content of some other map.
+ * returns boolean indicating equal or not.
+ */
+int compare_lists(etch_message* msg, etch_hashtable* otherdata)
+{
+ int thiscount = 0, fakecount = 0, result = 0, i = 0, eqcount = 0;
+ etch_structvalue* svx = NULL;
+ etch_iterator iterator;
+ etch_hashitem hashbucket;
+ etch_hashitem* sventry = &hashbucket;
+
+ svx = msg->sv;
+ CU_ASSERT_PTR_NOT_NULL_FATAL(svx);
+ CU_ASSERT_PTR_NOT_NULL_FATAL(svx->items);
+
+ thiscount = svx->items->vtab->count(svx->items->realtable,0,0);
+ fakecount = otherdata ->vtab->count(otherdata->realtable,0,0);
+ CU_ASSERT_EQUAL(fakecount, thiscount);
+ if (fakecount != thiscount) return FALSE;
+
+ set_iterator(&iterator, otherdata, &otherdata->iterable);
+
+ while(iterator.vtab->has_next(&iterator) && result == 0)
+ {
+ result = svx->items->vtab->findh
+ (svx->items->realtable, ((objmask*)iterator.current_key)->hashkey,
+ otherdata, &sventry);
+ CU_ASSERT_EQUAL(iterator.current_value, sventry->value);
+
+ iterator.vtab->next(&iterator);
+ }
+
+ return TRUE;
+}
+
+
+/*
+ * hashtable_clear_handler()
+ * override callback from hashtable during clear()
+ */
+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 structs always set such a callback on their backing store
+ * in order to free key and value allocations.
+ */
+ return FALSE;
+}
+
+
+/* = = = = = = = = = =
+ * TESTS
+ * = = = = = = = = = =
+ */
+
+/*
+ * run_iterator_test()
+ * iterate over test collection, inserting pairs to specified message.
+ * iterate over message, veriying that content matches test collection.
+ */
+int run_iterator_test(etch_message* msg, testitems* data)
+{
+ etch_iterator* iterator = NULL;
+ int msgcount = 0, testcount = 0, result = 0;
+
+ iterator = new_iterator(data->items, &data->items->iterable);
+
+ CU_ASSERT_PTR_NOT_NULL_FATAL(iterator);
+ CU_ASSERT_EQUAL(iterator->ordinal,1);
+
+ while(iterator->has_next(iterator))
+ {
+ testcount++;
+
+ result = message_put(msg, iterator->current_key, iterator->current_value);
+
+ CU_ASSERT_EQUAL(result,0);
+
+ iterator->next(iterator);
+ }
+
+ set_iterator(iterator, msg->sv->items, &msg->sv->items->iterable);
+ CU_ASSERT_EQUAL(iterator->ordinal,1);
+
+ while(iterator->has_next(iterator))
+ {
+ msgcount++;
+ iterator->next(iterator);
+ }
+
+ CU_ASSERT_EQUAL(testcount, msgcount);
+ iterator->destroy(iterator);
+ return msgcount;
+}
+
+
+/*
+ * iterator_test()
+ */
+void iterator_test(void)
+{
+ int result = 0;
+ testitems* data = NULL;
+ etch_hashtable* map = NULL;
+ etch_message* msg = NULL;
+ etch_value_factory* vf = NULL;
+
+ etch_string *sval1 = NULL, *sval2 = NULL;
+ etch_int32 *ival1 = NULL, *ival2 = NULL;
+ etch_field *skey1 = NULL, *skey2 = NULL;
+ etch_field *ikey1 = NULL, *ikey2 = NULL;
+
+ data = new_testitems();
+ map = data->items;
+
+ /* a message owns all its memory except the value factory and type, so we'll
+ * make copies of all the testdata keys and values to be inserted into it */
+ ikey1 = data->mf1->clone(data->mf1); ikey2 = data->mf2->clone(data->mf2);
+ skey1 = data->mf3->clone(data->mf3); skey2 = data->mf4->clone(data->mf4);
+
+ sval1 = data->s1->clone(data->s1); sval2 = data->s2->clone(data->s2);
+ ival1 = data->n1->clone(data->n1); ival2 = data->n2->clone(data->n2);
+
+ /* insert cloned fields and values to the test input collection */
+ map->vtab->inserth(map->realtable, ikey1, ival1, map, 0);
+ map->vtab->inserth(map->realtable, ikey2, ival2, map, 0);
+ map->vtab->inserth(map->realtable, skey1, sval1, map, 0);
+ map->vtab->inserth(map->realtable, skey2, sval2, map, 0);
+
+ vf = new_fake_value_factory(data);
+
+ CU_ASSERT_PTR_NOT_NULL_FATAL(vf);
+ CU_ASSERT_FALSE_FATAL(is_exception(vf));
+
+ /* a message owns its memory except vf and type, so we give it global type */
+ msg = new_message (data->mt1, 0, vf);
+
+ CU_ASSERT_PTR_NOT_NULL_FATAL(msg);
+ CU_ASSERT_FALSE_FATAL(is_exception(msg));
+
+ result = run_iterator_test(msg, data);
+ CU_ASSERT_EQUAL(result,4); /* 4 items in message */
+
+ msg->destroy(msg);
+ vf ->destroy(vf);
+
+ destroy_testitems(data);
+
+ g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE); /* verify all memory freed */
+ CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+ memtable_clear(); /* start fresh for next test */
+}
+
+/*
+ * reply_test
+ * test message.reply
+ */
+void reply_test(void)
+{
+ int result = 0;
+ etch_message* msg = NULL;
+ etch_message* newmsg = NULL;
+ etch_type* replytype = NULL;
+ etch_value_factory* vf = NULL;
+ etch_int64* id_original = NULL;
+ etch_int64* id_replied_to = NULL;
+ int64 val_origid = 0, val_replyid = 0;
+ testitems* data = new_testitems();
+
+ id_original = data->l1;
+
+ vf = new_fake_value_factory(data);
+
+ msg = new_message (data->mt1, 0, vf); /* message owns neither arg */
+
+ result = message_set_id(msg, id_original->clone(id_original));
+ CU_ASSERT_EQUAL_FATAL(result,0);
+
+ replytype = data->rmt; /* again, a message does not own a type */
+
+ newmsg = message_reply (msg, replytype);
+
+ CU_ASSERT_PTR_NOT_NULL_FATAL(newmsg);
+ CU_ASSERT_FALSE_FATAL(is_exception(newmsg));
+
+ result = is_equal_types(data->rmt, newmsg->sv->struct_type);
+ CU_ASSERT_TRUE(result);
+ CU_ASSERT_EQUAL(vf, newmsg->vf);
+
+ id_replied_to = message_get_in_reply_to(newmsg);
+
+ CU_ASSERT_PTR_NOT_NULL_FATAL(id_replied_to);
+ CU_ASSERT_FALSE_FATAL(is_exception(id_replied_to));
+
+ val_origid = id_original->value;
+ val_replyid = id_replied_to->value;
+ CU_ASSERT_EQUAL(val_origid, val_replyid);
+
+ newmsg->destroy(newmsg);
+ msg->destroy(msg);
+ vf->destroy(vf);
+ destroy_testitems(data);
+
+ g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE); /* verify all memory freed */
+ CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+ memtable_clear(); /* start fresh for next test */
+}
+
+
+/*
+ * run_exception_test
+ * execute an individual exception test
+ */
+void run_exception_test(const int whichtest)
+{
+ int result = 0;
+ tagged_data_input* tdi = NULL;
+ etch_message* msg = NULL;
+ etchexception* excp = NULL;
+ etch_type* static_type = NULL;
+ etch_value_factory* vf = NULL;
+ testitems* data = new_testitems();
+
+ /* global marker asks components to throw exceptions */
+ g_which_exception_test = whichtest;
+ static_type = new_type(L"type1");
+ vf = new_fake_value_factory(data);
+
+ #if(0)
+ /* create a bogus TDI inheriting from tagged data input */
+ tdi = new_fake_tdi(static_type, vf, NULL);
+ 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", tdi->result->exception->excptext);
+ #endif
+ }
+ }
+
+ msg = message_read(NULL); /* pass NULL for TDI */
+ CU_ASSERT_PTR_NOT_NULL_FATAL(msg);
+ CU_ASSERT_TRUE(is_exception(msg));
+ excp = get_exception(msg);
+ CU_ASSERT_EQUAL(excp->excptype, EXCPTYPE_ILLEGALARG);
+ #if IS_DEBUG_CONSOLE
+ wprintf(L"\ncaught %s exception on message\n", msg->result->exception->excptext);
+ #endif
+
+ /* free TDI */
+ faketdi_close(tdi);
+
+ /* free struct, it is just a shell with no content other than the exception */
+ msg->destroy(msg);
+
+ #endif
+
+ vf->destroy(vf);
+
+ destroy_testitems(data);
+ destroy_type(static_type);
+ g_which_exception_test = 0;
+
+ g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE); /* verify all memory freed */
+ CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+ memtable_clear(); /* start fresh for next test */
+}
+
+
+/**
+ * exception_test
+ * all exception tests
+ */
+void exception_test(void)
+{
+ run_exception_test(EXCPTEST_UNCHECKED_STATICTEXT);
+ run_exception_test(EXCPTEST_CHECKED_COPYTEXT);
+ run_exception_test(EXCPTEST_CHECKED_STATICTEXT);
+ g_which_exception_test = 0;
+}
+
+
+
+/**
+ * main
+ */
+int _tmain(int argc, _TCHAR* argv[])
+{
+ char c=0;
+ CU_pSuite pSuite = NULL;
+ g_is_automated_test = argc > 1 && 0 != wcscmp(argv[1], L"-a");
+ if (CUE_SUCCESS != CU_initialize_registry()) return 0;
+ pSuite = CU_add_suite("suite_message", init_suite, clean_suite);
+ CU_set_output_filename("../test_message");
+ etch_watch_id = 0;
+
+ CU_add_test(pSuite, "test iterator over message", iterator_test);
+ CU_add_test(pSuite, "test msg exceptions", exception_test);
+ CU_add_test(pSuite, "message reply test", reply_test);
+
+ if (g_is_automated_test)
+ CU_automated_run_tests();
+ else
+ { CU_basic_set_mode(CU_BRM_VERBOSE);
+ CU_basic_run_tests();
+ }
+
+ if (!g_is_automated_test) { printf("any key ..."); while(!c) c = _getch(); wprintf(L"\n"); }
+ CU_cleanup_registry();
+ return CU_get_error();
+}
+
Added: incubator/etch/trunk/binding-c/runtime/c/src/test/message/test_structvalue.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/test/message/test_structvalue.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/test/message/test_structvalue.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/test/message/test_structvalue.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,1157 @@
+/* $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 "apr_time.h" /* some apr must be included first */
+#include <tchar.h>
+#include <stdio.h>
+#include <conio.h>
+
+#include "cunit.h"
+#include "basic.h"
+#include "automated.h"
+
+#include "etch_connection.h"
+#include "etch_global.h"
+#include "etch_encoding.h"
+#include "etchthread.h"
+#include "etchlog.h"
+#include "etch_structval.h"
+#include "etchexcp.h"
+
+int apr_setup(void);
+int apr_teardown(void);
+int this_setup();
+int this_teardown();
+apr_pool_t* g_apr_mempool;
+const char* pooltag = "etchpool";
+
+
+int init_suite(void)
+{
+ apr_setup();
+ etch_runtime_init(TRUE);
+ return this_setup();
+}
+
+int clean_suite(void)
+{
+ this_teardown();
+ etch_runtime_cleanup(0,0); /* free memtable and cache etc */
+ apr_teardown();
+ return 0;
+}
+
+int g_is_automated_test, g_bytes_allocated;
+
+#define IS_DEBUG_CONSOLE FALSE
+
+/*
+ * apr_setup()
+ * establish apache portable runtime environment
+ */
+int apr_setup(void)
+{
+ int result = apr_initialize();
+ if (result == 0)
+ { result = etch_apr_init();
+ g_apr_mempool = etch_apr_mempool;
+ }
+ if (g_apr_mempool)
+ apr_pool_tag(g_apr_mempool, pooltag);
+ else result = -1;
+ return result;
+}
+
+/*
+ * apr_teardown()
+ * free apache portable runtime environment
+ */
+int apr_teardown(void)
+{
+ if (g_apr_mempool)
+ apr_pool_destroy(g_apr_mempool);
+ g_apr_mempool = NULL;
+ apr_terminate();
+ return 0;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - -
+ * local declarations
+ * - - - - - - - - - - - - - - - - - - - - - -
+ */
+
+/* - - - - - - - - - - - - - - - - - - - - - -
+ * local setup and teardown
+ * - - - - - - - - - - - - - - - - - - - - - -
+ */
+
+int this_setup()
+{
+ etch_apr_mempool = g_apr_mempool;
+ return 0;
+}
+
+int this_teardown()
+{
+ return 0;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - -
+ * individual setup and teardown
+ * - - - - - - - - - - - - - - - - - - - - - -
+ */
+
+int this_test_setup()
+{
+ int result = -1;
+
+ do {
+ result = 0;
+
+ } while(0);
+
+ return result;
+}
+
+int this_test_teardown()
+{
+
+ return 0;
+}
+
+
+etch_type *mt1, *mt2;
+
+etch_field *mf_bool_d0_1;
+etch_field *mf_bool_d0_2;
+etch_field *mf_bool_d1_1;
+etch_field *mf_bool_d1_2;
+
+etch_field *mf_int32_d0_1;
+etch_field *mf_int32_d0_2;
+etch_field *mf_int32_d1_1;
+etch_field *mf_int32_d1_2;
+
+etch_field *mf_str_d0_1;
+etch_field *mf_str_d0_2;
+etch_field *mf_str_d1_1;
+etch_field *mf_str_d1_2;
+
+etch_hashtable* testdata;
+
+int g_bytes_allocated, g_which_exception_test, g_is_automated_test;
+wchar_t* local_excp_text = L"global text";
+
+#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
+{
+ unsigned int hashkey;
+ unsigned short obj_type;
+ unsigned short class_id;
+ struct i_tagged_data_input* vtab;
+ int (*destroy)(void*);
+ void*(*clone) (void*);
+ obj_gethashkey get_hashkey;
+ struct objmask* parent;
+ etchresult* result;
+ unsigned int refcount;
+ unsigned int length;
+ unsigned char is_null;
+ unsigned char is_copy;
+ unsigned char is_static;
+ unsigned char reserved;
+
+ 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
+{
+ unsigned int hashkey;
+ unsigned short obj_type;
+ unsigned short class_id;
+ struct i_tagged_data_output* vtab;
+ int (*destroy)(void*);
+ void*(*clone) (void*);
+ obj_gethashkey get_hashkey;
+ struct objmask* parent;
+ etchresult* result;
+ unsigned int refcount;
+ unsigned int length;
+ unsigned char is_null;
+ unsigned char is_copy;
+ unsigned char is_static;
+ unsigned char reserved;
+
+ 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
+ */
+int destroy_fake_tdi_impl(fake_tdi_impl* impl)
+{
+ etch_destructor destroy = NULL;
+ int result = verify_object((objmask*)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);
+ impl->xstruct->destroy(impl->xstruct);
+ }
+
+ etch_free(impl);
+
+ return 0;
+}
+
+
+/**
+ * fake_tdo_impl_destroy_handler
+ * memory cleanup handler for fake_tdo_impl
+ */
+int destroy_fake_tdo_impl(fake_tdo_impl* impl)
+{
+ etch_destructor destroy = NULL;
+ int result = verify_object((objmask*)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->xstruct->vtab->destroy(impl->xstruct); */
+
+ etch_free(impl);
+ return 0;
+}
+
+
+/**
+ * new_fake_tdi_impl()
+ * constructor for TDI implementation instance data
+ */
+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
+ */
+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()
+ */
+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((objmask*)data, OBJTYPE_FAKETDI_IMPL, 0, 0);
+ CU_ASSERT_EQUAL_FATAL(result,0);
+
+ result = data->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()
+ */
+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((objmask*)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()
+ */
+int faketdo_write_struct_element(tagged_data_output* tdo, etch_field* key, objmask* 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((objmask*)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 = 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 = 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()
+ */
+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((objmask*)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 = (objmask*) iterator->current_value;
+
+ iterator->next(iterator);
+ return TRUE;
+ }
+
+ data->done = TRUE;
+ return FALSE;
+}
+
+
+/**
+ * faketdi_end_struct() overrides tdi_end_struct()
+ */
+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((objmask*)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()
+ */
+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((objmask*)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.
+ */
+void faketdi_close(tagged_data_input* tdi)
+{
+ tdi->destroy(tdi);
+}
+
+
+/**
+ * faketdo_close() ala java test
+ */
+void faketdo_close(tagged_data_output* tdo)
+{
+ tdo->destroy(tdo);
+}
+
+
+/**
+ * new_fake_tdi()
+ * constructor for TDI implementation
+ */
+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(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;
+
+ vtab->vtab = faketdi->vtab; /* chain parent vtab to override vtab */
+ cache_insert(vtab->hashkey, vtab, FALSE);
+ }
+
+ CU_ASSERT_EQUAL_FATAL(vtab->class_id, CLASS_ID);
+
+ faketdi->vtab = vtab; /* set override vtab */
+
+ faketdi->impl = (objmask*)
+ new_fake_tdi_impl(static_type); /* create TDI instance data */
+
+ switch(g_which_exception_test)
+ { case EXCPTEST_UNCHECKED_STATICTEXT:
+ etch_throw((objmask*) faketdi, EXCPTYPE_NULLPTR, NULL, 0);
+ break;
+ case EXCPTEST_CHECKED_COPYTEXT:
+ etch_throw((objmask*) faketdi, EXCPTYPE_CHECKED_BOGUS, L"copied text", ETCHEXCP_COPYTEXT | ETCHEXCP_FREETEXT);
+ break;
+ case EXCPTEST_CHECKED_STATICTEXT:
+ etch_throw((objmask*) faketdi, EXCPTYPE_CHECKED_BOGUS, local_excp_text, ETCHEXCP_STATICTEXT);
+ break;
+ }
+
+ return faketdi;
+}
+
+
+
+/**
+ * new_fake_tdo()
+ * constructor for TDO implementation
+ */
+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(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;
+
+ vtab->vtab = faketdo->vtab; /* chain parent vtab to override vtab */
+
+ cache_insert(vtab->hashkey, vtab, FALSE);
+ }
+
+ CU_ASSERT_EQUAL_FATAL(vtab->class_id, CLASS_ID);
+
+ 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 = (objmask*) impl;
+
+ return faketdo;
+}
+
+#endif /* #if(0) */
+
+
+/*
+ * load_testdata_string()
+ * load testdata map with some ETCH_STRING objects
+ */
+int load_testdata_string()
+{
+ int i = 0, numitems = 4, result = 0;
+ wchar_t* testval = NULL;
+ 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 };
+ const size_t bytelen = (wcslen(str0) + 1) * sizeof(wchar_t);
+
+ for(; i < numitems; i++)
+ {
+ newkey = new_field(strings[i]); /* testdata map CAN free keys */
+ newobj = new_string(strings[i], ETCH_ENCODING_UTF16);
+ result = testdata->vtab->inserth(testdata->realtable, newkey, newobj, 0, 0);
+ }
+
+ return numitems;
+}
+
+
+/*
+ * load_testdata_int()
+ * load testdata array with some ETCH_INT objects
+ */
+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 = testdata->vtab->inserth(testdata->realtable, newkey, newobj, 0, 0);
+ }
+
+ return numitems;
+}
+
+
+/*
+ * testdata_clear_handler()
+ * memory callback on testdata clear
+ */
+int testdata_clear_handler (etch_field* key, objmask* value)
+{
+ key->destroy(key);
+ value->destroy(value);
+ return TRUE;
+}
+
+
+/*
+ * new_testdata()
+ * create testdata map and load it up with data objects
+ */
+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, mf_bool_d0_1->clone(mf_bool_d0_1), (objmask*) etchvtor_boolean_get(0));
+ etchtype_put_validator(mt1, mf_bool_d0_2->clone(mf_bool_d0_2), (objmask*) etchvtor_boolean_get(0));
+
+ etchtype_put_validator(mt1, mf_bool_d1_1->clone(mf_bool_d1_1), (objmask*) etchvtor_boolean_get(1));
+ etchtype_put_validator(mt1, mf_bool_d1_2->clone(mf_bool_d1_2), (objmask*) etchvtor_boolean_get(1));
+
+ etchtype_put_validator(mt1, mf_int32_d0_1->clone(mf_int32_d0_1), (objmask*) etchvtor_int32_get(0));
+ etchtype_put_validator(mt1, mf_int32_d0_2->clone(mf_int32_d0_2), (objmask*) etchvtor_int32_get(0));
+
+ etchtype_put_validator(mt1, mf_int32_d1_1->clone(mf_int32_d1_1), (objmask*) etchvtor_int32_get(1));
+ etchtype_put_validator(mt1, mf_int32_d1_2->clone(mf_int32_d1_2), (objmask*) etchvtor_int32_get(1));
+
+ etchtype_put_validator(mt1, mf_str_d0_1->clone(mf_str_d0_1), (objmask*) etchvtor_string_get(0));
+ etchtype_put_validator(mt1, mf_str_d0_2->clone(mf_str_d0_2), (objmask*) etchvtor_string_get(0));
+
+ etchtype_put_validator(mt1, mf_str_d1_1->clone(mf_str_d1_1), (objmask*) etchvtor_string_get(1));
+ etchtype_put_validator(mt1, mf_str_d1_2->clone(mf_str_d1_2), (objmask*) etchvtor_string_get(1));
+
+ return count;
+}
+
+/*
+ * destroy_testdata()
+ * destroy testdata map and content
+ */
+void destroy_testdata()
+{
+ destroy_hashtable(testdata, TRUE, TRUE);
+
+ destroy_type(mt1);
+ destroy_type(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 */
+}
+
+
+/*
+ * compare_lists()
+ * compares testdata content with specified struct content.
+ * returns boolean indicating equal or not.
+ */
+int compare_lists(etch_structvalue* svx)
+{
+ int thiscount = 0, testcount = 0, result = 0, i = 0, eqcount = 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 = svx->items->vtab->count(svx->items->realtable,0,0);
+ testcount = 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 = svx->items->vtab->findh
+ (svx->items->realtable, ((objmask*)iterator.current_key)->hashkey, testdata, &sventry);
+
+ CU_ASSERT_EQUAL(iterator.current_value, sventry->value);
+
+ iterator.next(&iterator);
+ }
+
+ return TRUE;
+}
+
+
+/*
+ * hashtable_clear_handler()
+ * override callback from hashtable during clear()
+ */
+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.
+ */
+int hashtable_do_nada_handler (void* key, void* value)
+{
+ return TRUE;
+}
+
+
+/*
+ * run_iterator_test
+ * test struct value iterator
+ */
+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_nativearray(CLASSID_ARRAY_INT32, sizeof(int), 1, 3, 0, 0);
+ int_array_2 = new_nativearray(CLASSID_ARRAY_INT32, sizeof(int), 1, 5, 0, 0);
+
+ sv = new_structvalue(mt1, 0);
+
+ CU_ASSERT_PTR_NOT_NULL_FATAL(sv);
+ result = is_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, (objmask*) 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, (objmask*) 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, (objmask*) int_array_1);
+ CU_ASSERT_EQUAL(result, 0);
+
+ fldkey = clone_field(mf_int32_d1_2);
+ result = structvalue_put(sv, fldkey, (objmask*) 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 */
+ sv->destroy(sv);
+ destroy_testdata();
+
+ g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE); /* verify all memory freed */
+ CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+ memtable_clear(); /* start fresh for next test */
+}
+
+
+/*
+ * run_exception_test
+ *
+ */
+void run_exception_test(const int whichtest)
+{
+ int result = 0;
+ tagged_data_input* tdi = NULL;
+ etch_structvalue* sv = NULL;
+ etchexception* excp = NULL;
+ etch_type* static_type = NULL;
+ /* global marker asks components to throw exceptions */
+ g_which_exception_test = whichtest;
+ 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 */
+ sv->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.
+ */
+ static_type->destroy(static_type);
+
+ /* destroy testdata list and content */
+ destroy_testdata();
+
+ g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE); /* verify all memory freed */
+ CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+ memtable_clear(); /* start fresh for next test */
+}
+
+
+/*
+ * test_iterator_over_hashtable
+ */
+void test_iterator_over_hashtable(void)
+{
+ etch_iterator* iterator = NULL;
+ int testcount = 0, thiscount = 0;
+ new_testdata(1);
+ CU_ASSERT_PTR_NOT_NULL_FATAL(testdata);
+ testcount = 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;
+
+ while(iterator->vtab->has_next(iterator))
+ thiscount += (iterator->vtab->next(iterator) == 0);
+
+ CU_ASSERT_EQUAL(testcount, thiscount);
+
+ destroy_iterator(iterator);
+ destroy_testdata();
+
+ g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE); /* verify all memory freed */
+ CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+ memtable_clear(); /* start fresh for next test */
+}
+
+
+/*
+ * exception_test_1
+ */
+void exception_test_1(void)
+{
+ int itemcount = 0;
+ if ((itemcount = new_testdata(1)) > 0)
+ run_exception_test(EXCPTEST_UNCHECKED_STATICTEXT);
+}
+
+
+/*
+ * exception_test_2
+ */
+void exception_test_2(void)
+{
+ int itemcount = 0;
+ if ((itemcount = new_testdata(1)) > 0)
+ run_exception_test(EXCPTEST_CHECKED_COPYTEXT);
+}
+
+
+/*
+ * exception_test_3
+ */
+void exception_test_3(void)
+{
+ int itemcount = 0;
+ if ((itemcount = new_testdata(1)) > 0)
+ run_exception_test(EXCPTEST_CHECKED_STATICTEXT);
+}
+
+
+/**
+ * main
+ */
+int _tmain(int argc, _TCHAR* argv[])
+{
+ char c=0;
+ CU_pSuite pSuite = NULL;
+ g_is_automated_test = argc > 1 && 0 != wcscmp(argv[1], L"-a");
+ if (CUE_SUCCESS != CU_initialize_registry()) return 0;
+ pSuite = CU_add_suite("suite_structvalue", init_suite, clean_suite);
+ CU_set_output_filename("../test_structvalue");
+ etch_watch_id = 0;
+
+ 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);
+
+ if (g_is_automated_test)
+ CU_automated_run_tests();
+ else
+ { CU_basic_set_mode(CU_BRM_VERBOSE);
+ CU_basic_run_tests();
+ }
+
+ if (!g_is_automated_test) { printf("any key ..."); while(!c) c = _getch(); wprintf(L"\n"); }
+ CU_cleanup_registry();
+ return CU_get_error();
+}
+