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 [24/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/common/test_hashtable.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/test/common/test_hashtable.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/test/common/test_hashtable.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/test/common/test_hashtable.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,1192 @@
+/* $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_hashtable.c 
+ * tests the C implementation of etch hashtable.
+ * this hashtable implementation uses the public domain jenkins hashtable.
+ */
+
+#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_global.h"
+
+#define TESTDATAPATH "./jenktest.txt"
+#define MAXLINELEN 64
+#define DATASIZE    4
+#define DATAVALUE  "foo" 
+#define INITIAL_TABLE_SIZE 64
+
+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 g_is_automated_test, g_bytes_allocated;
+
+#define IS_DEBUG_CONSOLE FALSE
+
+
+/* - - - - - - - - - - - - - - 
+ * 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;
+}
+
+/*
+ * 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_new_hashtable
+ * unit test for new_hashtable
+ */
+void test_new_hashtable(void)
+{
+    /* new_hashtable always returns mimimal initial size if the input value is too small */
+    etch_hashtable* eht = new_hashtable(-1);
+    CU_ASSERT_PTR_NOT_NULL(eht);
+    CU_ASSERT_EQUAL(jenkins_size(eht->realtable, 0, 0), ETCH_DEFAULT_HASHTABLE_SIZE);
+    eht->destroy(eht);
+
+    /* the hashtable size will be modified to previous power of 2 */
+    eht = new_hashtable(63);
+    CU_ASSERT_PTR_NOT_NULL(eht);
+    CU_ASSERT_EQUAL(jenkins_size(eht->realtable, 0, 0), 32);  /* size will be 3 2instead of 64 */
+    eht->destroy(eht);
+
+    /* good input case, the size is within boundary and power of 2 */
+    eht = new_hashtable(32);
+    CU_ASSERT_PTR_NOT_NULL(eht);
+    CU_ASSERT_EQUAL(jenkins_size(eht->realtable, 0, 0), 32);
+    eht->destroy(eht);
+
+    /* the maximum initial size is MAX_INITIAL_HASHTABLE_SIZE */
+    eht = new_hashtable(MAX_INITIAL_HASHTABLE_SIZE+1);
+    CU_ASSERT_PTR_NOT_NULL(eht);
+    CU_ASSERT_EQUAL(jenkins_size(eht->realtable, 0, 0), MAX_INITIAL_HASHTABLE_SIZE);
+    eht->destroy(eht);
+
+    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_new_etch_hashtable
+ * unit test for new_etch_hashtable
+ */
+void test_new_etch_hashtable(void)
+{
+    /* new_etch_hashtable does not have meat in it */
+    etch_hashtable* eht = new_etch_hashtable();
+    CU_ASSERT_PTR_NOT_NULL_FATAL(eht);
+    CU_ASSERT_PTR_NULL(eht->realtable);
+    CU_ASSERT_PTR_NULL(eht->vtab);
+    etch_free(eht);
+}
+
+/**
+ * test_destroy_hashtable
+ * unit test for destroy_hashtable
+ */
+void test_destroy_hashtable(void)
+{
+    wchar_t *key = NULL, *val = NULL;
+
+    /* try to delete key and value but nothing in it */
+    etch_hashtable* eht = new_etch_hashtable();
+    destroy_hashtable(eht, TRUE, TRUE);
+
+    /* negative test with NULL hash table */
+    destroy_hashtable(NULL, TRUE, TRUE);
+
+    /* TODO: add more cases to verify key/value deletion */
+}
+
+/**
+ * test_jenkins_insert
+ * unit test for jenkins_insert
+ */
+void test_jenkins_insert(void)
+{
+    int keylen = 0;
+    wchar_t key[100];
+
+    etch_hashtable* eht = new_hashtable(16);
+    
+    CU_ASSERT_PTR_NOT_NULL(eht);
+    CU_ASSERT_EQUAL(jenkins_size(eht->realtable, 0, 0), 16);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 0);
+
+    swprintf(key, 100, L"key%d", 0);
+    keylen = (int)wcslen(key);
+    jenkins_insert(eht->realtable, key, keylen*2+2, L"val", 8, 0, 0);
+    CU_ASSERT_EQUAL(jenkins_size(eht->realtable, 0, 0), 16);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 1);
+    /* insert the same key value pair */
+    jenkins_insert(eht->realtable, key, keylen*2+2, L"val", 8, 0, 0);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 1);
+
+    /* insert the same key but different value */
+    jenkins_insert(eht->realtable, key, keylen*2+2, L"va1", 8, 0, 0);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 1);
+
+    /* insert different key but the same value */
+    swprintf(key, 100, L"key%d", 1);
+    jenkins_insert(eht->realtable, key, keylen*2+2, L"val", 8, 0, 0);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 2);
+
+    /* insert different key value pair */
+    swprintf(key, 100, L"key%d", 2);
+    jenkins_insert(eht->realtable, key, keylen*2+2, L"va1", 8, 0, 0);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 3);
+
+    /* insert NULL key and value */
+    jenkins_insert(eht->realtable, NULL, 0, NULL, 0, 0, 0);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 3);
+
+    eht->destroy(eht);
+}
+
+/**
+ * test_jenkins_find
+ * unit test for jenkins_find
+ */
+void test_jenkins_find(void)
+{
+    int result = 0, keylen = 0, vallen = 0;
+    wchar_t* key1 = 0;
+    wchar_t* key2 = 0;
+    wchar_t* val1 = 0;
+    wchar_t* val2 = 0;
+    etch_hashitem* outentry;
+    etch_hashtable* eht = 0;
+
+    eht = new_hashtable(32);
+    CU_ASSERT_PTR_NOT_NULL(eht);
+    CU_ASSERT_EQUAL(jenkins_size(eht->realtable, 0, 0), 32);
+
+    outentry = (etch_hashitem*)malloc(sizeof(etch_hashitem)); 
+    outentry->key = malloc(sizeof(wchar_t) * 100);
+    outentry->value = malloc(sizeof(wchar_t) * 100);
+
+    key1 = malloc(sizeof(wchar_t) * 100);
+    key2 = malloc(sizeof(wchar_t) * 100);
+    swprintf(key1, 100, L"key%d", 1);
+    swprintf(key2, 100, L"key%d", 2);
+    keylen = (int)wcslen(key1);
+
+    val1 = malloc(sizeof(wchar_t) * 100);
+    val2 = malloc(sizeof(wchar_t) * 100);
+    swprintf(val1, 100, L"val%d", 1);
+    swprintf(val2, 100, L"val%d", 2);
+    vallen = (int)wcslen(val1);
+
+    jenkins_insert(eht->realtable, key1, keylen*2+2, val1, vallen*2+2, 0, 0);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 1);
+
+    /* get first, first key = first key */
+    result = jenkins_find(eht->realtable, key2, keylen*2+2, 0, &outentry);
+    CU_ASSERT_EQUAL(result, -1);
+
+    jenkins_insert(eht->realtable, key2, keylen*2+2, val2, vallen*2+2, 0, 0);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 2);
+
+    /* get first, first key = first key */
+    result = jenkins_find(eht->realtable, key2, keylen*2+2, 0, &outentry);
+    CU_ASSERT_EQUAL(result, 0);
+    CU_ASSERT_PTR_EQUAL(key2, outentry->key);
+
+    eht->destroy(eht);
+
+    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_jenkins_findh
+ * unit test for jenkins_findh
+ */
+void test_jenkins_findh(void)
+{
+    int result = 0, keylen = 0, vallen = 0, hash = 0, bytes_allocated = 0;
+    wchar_t* key1 = 0;
+    wchar_t* key2 = 0;
+    wchar_t* val1 = 0;
+    wchar_t* val2 = 0;
+    etch_hashitem* outentry;
+
+    etch_hashtable* eht = new_hashtable(32);
+    CU_ASSERT_PTR_NOT_NULL(eht);
+    CU_ASSERT_EQUAL(jenkins_size(eht->realtable, 0, 0), 32);
+
+    outentry = (etch_hashitem*)malloc(sizeof(etch_hashitem)); 
+    outentry->key   = malloc(sizeof(wchar_t) * 100);
+    outentry->value = malloc(sizeof(wchar_t) * 100);
+
+    key1 = malloc(sizeof(wchar_t) * 100);
+    key2 = malloc(sizeof(wchar_t) * 100);
+    swprintf(key1, 100, L"key%d", 1);
+    swprintf(key2, 100, L"key%d", 2);
+    keylen = (int)wcslen(key1);
+
+    val1 = malloc(sizeof(wchar_t) * 100);
+    val2 = malloc(sizeof(wchar_t) * 100);
+    swprintf(val1, 100, L"val%d", 1);
+    swprintf(val2, 100, L"val%d", 2);
+    vallen = (int)wcslen(val1);
+
+    jenkins_insert(eht->realtable, key1, keylen*2+2, val1, vallen*2+2, 0, 0);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 1);
+    jenkins_insert(eht->realtable, key2, keylen*2+2, val2, vallen*2+2, 0, 0);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 2);
+
+    /* Find the second key */
+    result = jenkins_find(eht->realtable, key2, keylen*2+2, 0, &outentry);
+    CU_ASSERT_EQUAL(result, 0);
+    CU_ASSERT_PTR_EQUAL(key2, outentry->key);
+
+    eht->destroy(eht);
+
+    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 */ 
+}
+
+
+/**
+ * etch_testobject  
+ * test object for test_jenkins_inserth
+ */
+typedef struct etch_testobject
+{
+    unsigned int     hashkey;    
+    unsigned short   obj_type;  
+    unsigned short   class_id;   
+    struct vtabmask* 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;
+
+    char* hashvalue; 
+
+} etch_testobject; 
+
+
+ 
+/**
+ * test_inserth_get_hashkey
+ * object hashkey computation virtual for test_jenkins_inserth
+ * attempts to compute and set hashkey in object, returning hashkey so set, or zero.
+ */
+int test_inserth_get_hashkey(objmask* obj)
+{
+    char* hashitem = ((etch_testobject*)obj)->hashvalue;
+    if (NULL == hashitem) return 0;
+    return obj->hashkey = jenkins_hashx(hashitem, (int) strlen(hashitem), 0);
+}
+
+
+/**
+ * new_testobject  
+ * construct test object for test_jenkins_inserth
+ * illustrates that constructor should set the get_hashkey virtual.
+ */
+etch_testobject* new_testobject(char* hashsource)
+{
+   etch_testobject* newobj = (etch_testobject*) new_object
+        (sizeof(etch_testobject), ETCHTYPEB_NONE, CLASSID_NONE);
+
+   newobj->hashvalue = hashsource;
+
+   newobj->get_hashkey = test_inserth_get_hashkey;
+
+   newobj->get_hashkey((objmask*)newobj);
+
+   return newobj;
+}
+
+
+
+/**
+ * test_inserth_freehandler
+ * hashtable content memory management callback for test_jenkins_inserth
+ */
+int test_inserth_freehandler(objmask* key, objmask* val)
+{
+    if (key) key->destroy(key);
+    if (val) val->destroy(val);
+    return 0;
+}
+
+
+/**
+ * test_jenkins_inserth
+ * unit test for jenkins_inserth
+ * this test was written before the etch objmask* included a get_hashkey virtual
+ */
+void test_jenkins_inserth(void)
+{
+    int result = 0; 
+    unsigned hash1 = 0, hash2 = 0;
+    etch_hashitem outentry, *outitem = &outentry; 
+    char *s1 = "abracadabra", *s2 =  "gilgamesh";
+    etch_testobject *key1, *key2;
+    objmask *val1, *val2;
+    etch_hashtable* eht;
+    memset(outitem, 0, sizeof(etch_hashitem));   
+
+    key1 = new_testobject(s1);
+    key2 = new_testobject(s2);
+
+    val1 = new_object(sizeof(objmask), ETCHTYPEB_NONE, CLASSID_NONE);
+    val2 = new_object(sizeof(objmask), ETCHTYPEB_NONE, CLASSID_NONE);
+
+    eht = new_hashtable(32);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(eht);
+
+    /* set hook to free all hashtable content when we destroy hashtable */
+    eht->freehook = test_inserth_freehandler;
+
+    CU_ASSERT_NOT_EQUAL_FATAL(key1->hashkey, 0); /* ensure test object ctor set hashkey */
+    CU_ASSERT_NOT_EQUAL_FATAL(key2->hashkey, 0);
+    /* recompute expected hashkeys and compare to effective hashkeys */
+    hash1 = jenkins_hashx(s1, (int) strlen(s1), 0);
+    hash2 = jenkins_hashx(s2, (int) strlen(s2), 0);
+    CU_ASSERT_EQUAL(hash1,key1->hashkey);
+    CU_ASSERT_EQUAL(hash2,key2->hashkey);
+
+    /* insert pairs to map using the pre-computed hashkeys */
+    result = jenkins_inserth(eht->realtable, key1, val1, NULL, NULL);
+    CU_ASSERT_EQUAL(result,0);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 1);
+
+    result = jenkins_inserth(eht->realtable, key2, val2, NULL, NULL);
+    CU_ASSERT_EQUAL(result,0);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 2);
+
+    /* look them up using expected hashkeys */
+    result = jenkins_findh(eht->realtable, hash1, 0, &outitem);
+    CU_ASSERT_EQUAL(result, 0);
+    CU_ASSERT_PTR_EQUAL(key1, outentry.key);
+
+    result = jenkins_findh(eht->realtable, hash2, 0, &outitem);
+    CU_ASSERT_EQUAL(result, 0);
+    CU_ASSERT_PTR_EQUAL(key2, outentry.key);
+
+    eht->destroy(eht);
+
+    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 */ 
+}
+
+ 
+/**
+ * default_get_hashkey
+ * object hashkey computation virtual for test_default_hashkey
+ * attempts to compute and set a hashkey in object, 
+ * for use when no dedicated override is supplied.
+ */
+int default_get_hashkey(objmask* obj)
+{
+    void* hashitem = obj;  /* we use the object address as hash source */
+    return obj->hashkey = jenkins_hashx((char*)&hashitem, sizeof(void*), 0);
+}
+
+
+/**
+ * new_default_object
+ * test object constructor for test_default_hashkey
+ * sets a default hashkey function and invokes it
+ */
+etch_testobject* new_default_object()
+{
+   etch_testobject* newobj = (etch_testobject*) new_object
+        (sizeof(etch_testobject), ETCHTYPEB_NONE, CLASSID_NONE);
+
+   newobj->get_hashkey = default_get_hashkey;
+
+   newobj->get_hashkey((objmask*)newobj);
+
+   return newobj;
+}
+
+
+/**
+ * test_default_hashkey
+ * unit test for hashing using the default hashkey function
+ * this test was written before the etch objmask* included a get_hashkey virtual
+ */
+void test_default_hashkey(void)
+{
+    int result = 0; 
+    unsigned hash1 = 0, hash2 = 0;
+    etch_hashitem outentry, *outitem = &outentry; 
+    etch_testobject *key1, *key2, *val1, *val2;
+    etch_hashtable* eht;
+    memset(outitem, 0, sizeof(etch_hashitem));   
+
+    key1 = new_default_object();
+    key2 = new_default_object();
+    CU_ASSERT_NOT_EQUAL_FATAL(key1->hashkey, 0); /* ensure test object ctor set hashkey */
+    CU_ASSERT_NOT_EQUAL_FATAL(key2->hashkey, 0);
+    val1 = new_default_object();
+    val2 = new_default_object();
+    eht = new_hashtable(32);
+    /* set hook to free all hashtable content when we destroy hashtable */
+    eht->freehook = test_inserth_freehandler;
+
+    /* insert pairs to map using the pre-computed hashkeys */
+    result = jenkins_inserth(eht->realtable, key1, val1, NULL, NULL);
+    CU_ASSERT_EQUAL(result,0);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 1);
+
+    result = jenkins_inserth(eht->realtable, key2, val2, NULL, NULL);
+    CU_ASSERT_EQUAL(result,0);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 2);
+
+    /* look them up using effective hashkeys */
+    result = jenkins_findh(eht->realtable, key1->hashkey, 0, &outitem);
+    CU_ASSERT_EQUAL(result, 0);
+    CU_ASSERT_PTR_EQUAL(key1, outentry.key);
+
+    result = jenkins_findh(eht->realtable, key2->hashkey, 0, &outitem);
+    CU_ASSERT_EQUAL(result, 0);
+    CU_ASSERT_PTR_EQUAL(key2, outentry.key);
+
+    /* compute expected hashkeys from addresses of key objects */
+    hash1 = jenkins_hashx((char*)&key1, sizeof(void*), 0);
+    hash2 = jenkins_hashx((char*)&key2, sizeof(void*), 0);
+
+    /* look them up using computed hashkeys */
+    result = jenkins_findh(eht->realtable, hash1, 0, &outitem);
+    CU_ASSERT_EQUAL(result, 0);
+    CU_ASSERT_PTR_EQUAL(key1, outentry.key);
+
+    result = jenkins_findh(eht->realtable, hash2, 0, &outitem);
+    CU_ASSERT_EQUAL(result, 0);
+    CU_ASSERT_PTR_EQUAL(key2, outentry.key);
+
+    eht->destroy(eht);
+
+    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_jenkins_first
+ * unit test for jenkins_first
+ */
+void test_jenkins_first(void)
+{
+    int result = 0, keylen = 0, vallen = 0;
+    wchar_t* key1 = 0;
+    wchar_t* key2 = 0;
+    wchar_t* val1 = 0;
+    wchar_t* val2 = 0;
+    etch_hashitem* outentry;
+
+    etch_hashtable* eht = new_hashtable(32);
+    CU_ASSERT_PTR_NOT_NULL(eht);
+    CU_ASSERT_EQUAL(jenkins_size(eht->realtable, 0, 0), 32);
+
+    outentry = (etch_hashitem*)malloc(sizeof(etch_hashitem)); 
+    outentry->key = malloc(sizeof(wchar_t) * 100);
+    outentry->value = malloc(sizeof(wchar_t) * 100);
+
+    key1 = malloc(sizeof(wchar_t) * 100);
+    key2 = malloc(sizeof(wchar_t) * 100);
+    swprintf(key1, 100, L"key%d", 1);
+    swprintf(key2, 100, L"key%d", 2);
+    keylen = (int)wcslen(key1);
+
+    val1 = malloc(sizeof(wchar_t) * 100);
+    val2 = malloc(sizeof(wchar_t) * 100);
+    swprintf(val1, 100, L"val%d", 1);
+    swprintf(val2, 100, L"val%d", 2);
+    vallen = (int)wcslen(val1);
+
+    jenkins_insert(eht->realtable, key1, keylen*2+2, val1, vallen*2+2, 0, 0);
+    jenkins_insert(eht->realtable, key2, keylen*2+2, val2, vallen*2+2, 0, 0);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 2);
+
+    /* get first, first key = first key */
+    result = jenkins_first(eht->realtable, 0, &outentry);
+    CU_ASSERT_EQUAL(result, 0);
+    CU_ASSERT_PTR_EQUAL(key1, outentry->key);
+
+    /* next is key2 */
+    result = jenkins_next(eht->realtable, 0, &outentry);
+    CU_ASSERT_EQUAL(result, 0);
+    CU_ASSERT_PTR_EQUAL(key2, outentry->key);
+
+    eht->destroy(eht);
+}
+
+
+/**
+ * test_jenkins_next
+ * unit test for jenkins_next
+ */
+void test_jenkins_next(void)
+{
+    int result = 0, keylen = 0, vallen = 0;
+    wchar_t* key1 = 0;
+    wchar_t* key2 = 0;
+    wchar_t* key3 = 0;
+    wchar_t* val1 = 0;
+    wchar_t* val2 = 0;
+    wchar_t* val3 = 0;
+    etch_hashitem* outentry;
+
+    etch_hashtable* eht = new_hashtable(32);
+    CU_ASSERT_PTR_NOT_NULL(eht);
+    CU_ASSERT_EQUAL(jenkins_size(eht->realtable, 0, 0), 32);
+
+    outentry = (etch_hashitem*)malloc(sizeof(etch_hashitem)); 
+    outentry->key = malloc(sizeof(wchar_t) * 100);
+    outentry->value = malloc(sizeof(wchar_t) * 100);
+
+    key1 = malloc(sizeof(wchar_t) * 100);
+    key2 = malloc(sizeof(wchar_t) * 100);
+    key3 = malloc(sizeof(wchar_t) * 100);
+    swprintf(key1, 100, L"key%d", 1);
+    swprintf(key2, 100, L"key%d", 2);
+    swprintf(key3, 100, L"key%d", 3);
+    keylen = (int)wcslen(key1);
+
+    val1 = malloc(sizeof(wchar_t) * 100);
+    val2 = malloc(sizeof(wchar_t) * 100);
+    val3 = malloc(sizeof(wchar_t) * 100);
+    swprintf(val1, 100, L"val%d", 1);
+    swprintf(val2, 100, L"val%d", 2);
+    swprintf(val3, 100, L"val%d", 3);
+    vallen = (int)wcslen(val1);
+
+    jenkins_insert(eht->realtable, key1, keylen*2+2, val1, vallen*2+2, 0, 0);
+    jenkins_insert(eht->realtable, key2, keylen*2+2, val2, vallen*2+2, 0, 0);
+    jenkins_insert(eht->realtable, key3, keylen*2+2, val3, vallen*2+2, 0, 0);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 3);
+
+    result = jenkins_first(eht->realtable, 0, &outentry);
+    CU_ASSERT_EQUAL(result, 0);
+
+    result = jenkins_next(eht->realtable, 0, &outentry);
+    CU_ASSERT_EQUAL(result, 0);
+
+    result = jenkins_next(eht->realtable, 0, &outentry);
+    CU_ASSERT_EQUAL(result, 0);
+
+    result = jenkins_next(eht->realtable, 0, &outentry);
+    CU_ASSERT_EQUAL(result, -1);
+
+    eht->destroy(eht);
+}
+
+
+/**
+ * test_jenkins_current
+ * unit test for jenkins_current
+ */
+void test_jenkins_current(void)
+{
+    int result = 0, keylen = 0, vallen = 0;
+    wchar_t* key1 = 0;
+    wchar_t* key2 = 0;
+    wchar_t* val1 = 0;
+    wchar_t* val2 = 0;
+    etch_hashitem* outentry;
+
+    etch_hashtable* eht = new_hashtable(32);
+    CU_ASSERT_PTR_NOT_NULL(eht);
+    CU_ASSERT_EQUAL(jenkins_size(eht->realtable, 0, 0), 32);
+
+    /* get current, no key */
+    outentry = (etch_hashitem*)malloc(sizeof(etch_hashitem)); 
+    outentry->key = malloc(sizeof(wchar_t) * 100);
+    outentry->value = malloc(sizeof(wchar_t) * 100);
+    result = jenkins_current(eht->realtable, 0, &outentry);
+    CU_ASSERT_EQUAL(result, -1);
+
+    key1 = malloc(sizeof(wchar_t) * 100);
+    key2 = malloc(sizeof(wchar_t) * 100);
+    swprintf(key1, 100, L"key%d", 1);
+    swprintf(key2, 100, L"key%d", 2);
+    keylen = (int)wcslen(key1);
+
+    val1 = malloc(sizeof(wchar_t) * 100);
+    val2 = malloc(sizeof(wchar_t) * 100);
+    swprintf(val1, 100, L"val%d", 1);
+    swprintf(val2, 100, L"val%d", 2);
+    vallen = (int)wcslen(val1);
+
+    jenkins_insert(eht->realtable, key1, keylen*2+2, val1, vallen*2+2, 0, 0);
+    jenkins_insert(eht->realtable, key2, keylen*2+2, val2, vallen*2+2, 0, 0);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 2);
+
+    /* get current, current key = key2 */
+    result = jenkins_current(eht->realtable, 0, &outentry);
+    CU_ASSERT_EQUAL(result, 0);
+    CU_ASSERT_PTR_EQUAL(key2, outentry->key);
+
+    /* remove second entry */
+    result = jenkins_remove(eht->realtable, key2, keylen*2+2, 0, &outentry);
+    CU_ASSERT_EQUAL(result, 0);
+    CU_ASSERT_PTR_EQUAL(key2, outentry->key);
+
+    /* get current, current key = key1 */
+    result = jenkins_current(eht->realtable, 0, &outentry);
+    CU_ASSERT_EQUAL(result, 0);
+    CU_ASSERT_PTR_EQUAL(key1, outentry->key);
+
+    eht->destroy(eht);
+}
+
+/**
+ * test_jenkins_remove
+ * unit test for jenkins_remove
+ */
+void test_jenkins_remove(void)
+{
+    int count = 0, keylen = 0, vallen = 0;
+    wchar_t* key1 = 0;
+    wchar_t* key2 = 0;
+    wchar_t* val1 = 0;
+    //wchar_t* val2 = 0;
+    etch_hashitem* outentry;
+
+    etch_hashtable* eht = new_hashtable(32);
+    CU_ASSERT_PTR_NOT_NULL(eht);
+    CU_ASSERT_EQUAL(jenkins_size(eht->realtable, 0, 0), 32);
+
+    key1 = malloc(sizeof(wchar_t) * 100);
+    key2 = malloc(sizeof(wchar_t) * 100);
+    swprintf(key1, 100, L"key%d", 1);
+    swprintf(key2, 100, L"key%d", 2);
+    keylen = (int)wcslen(key1);
+
+    val1 = malloc(sizeof(wchar_t) * 100);
+    //val2 = malloc(sizeof(wchar_t) * 100);
+    swprintf(val1, 100, L"val%d", 1);
+    //swprintf(val2, 100, L"val%d", 2);
+    vallen = (int)wcslen(val1);
+
+    outentry = (etch_hashitem*)malloc(sizeof(etch_hashitem)); 
+    outentry->key   = malloc(sizeof(wchar_t) * 100);
+    outentry->value = malloc(sizeof(wchar_t) * 100);
+
+    jenkins_insert(eht->realtable, key1, keylen*2+2, val1, vallen*2+2, 0, 0);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 1);
+
+    /* remove wrong entry */
+    count = jenkins_remove(eht->realtable, key2, keylen*2+2, 0, &outentry);
+    CU_ASSERT_EQUAL(count, -1);
+
+    /* remove the entry */
+    count = jenkins_remove(eht->realtable, key1, keylen*2+2, 0, &outentry);
+    CU_ASSERT_EQUAL(count, 0);
+    CU_ASSERT_PTR_EQUAL(key1, outentry->key);
+
+    eht->destroy(eht);
+}
+
+
+/**
+ * test_jenkins_clear
+ * unit test for jenkins_clear
+ */
+void test_jenkins_clear(void)
+{
+    int count = 0, keylen = 0, vallen = 0;
+    wchar_t* key1 = 0;
+    wchar_t* key2 = 0;
+    wchar_t* val1 = 0;
+    wchar_t* val2 = 0;
+
+    etch_hashtable* eht = new_hashtable(32);
+    CU_ASSERT_PTR_NOT_NULL(eht);
+    CU_ASSERT_EQUAL(jenkins_size(eht->realtable, 0, 0), 32);
+
+    key1 = malloc(sizeof(wchar_t) * 100);
+    key2 = malloc(sizeof(wchar_t) * 100);
+    swprintf(key1, 100, L"key%d", 1);
+    swprintf(key2, 100, L"key%d", 2);
+    keylen = (int)wcslen(key1);
+
+    val1 = malloc(sizeof(wchar_t) * 100);
+    val2 = malloc(sizeof(wchar_t) * 100);
+    swprintf(val1, 100, L"val%d", 1);
+    swprintf(val2, 100, L"val%d", 2);
+    vallen = (int)wcslen(val1);
+
+    jenkins_insert(eht->realtable, key1, keylen*2+2, val1, vallen*2+2, 0, 0);
+    jenkins_insert(eht->realtable, key2, keylen*2+2, val2, vallen*2+2, 0, 0);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 2);
+    count = jenkins_clear(eht->realtable, TRUE, TRUE, 0, 0);
+    /* clear 2 key/val pair */
+    CU_ASSERT_EQUAL(count, 2);
+    CU_ASSERT_PTR_NOT_NULL(eht->realtable);
+
+    eht->destroy(eht);
+}
+
+
+/**
+ * test_jenkins_count
+ * unit test for jenkins_count
+ */
+void test_jenkins_count(void)
+{
+    etch_hashtable* eht = new_hashtable(32);
+    CU_ASSERT_PTR_NOT_NULL(eht);
+    CU_ASSERT_EQUAL(jenkins_size(eht->realtable, 0, 0), 32);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 0);
+    jenkins_insert(eht->realtable, L"key", 8, L"val", 8, 0, 0);
+    CU_ASSERT_EQUAL(jenkins_size(eht->realtable, 0, 0), 32);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 1);
+    eht->destroy(eht);
+}
+
+/**
+ * test_jenkins_size
+ * unit test for jenkins_size
+ */
+void test_jenkins_size(void)
+{
+    int i = 0;
+    int keylen = 0;
+    wchar_t key[100];
+
+    etch_hashtable* eht = new_hashtable(16);
+    CU_ASSERT_PTR_NOT_NULL(eht);
+    CU_ASSERT_EQUAL(jenkins_size(eht->realtable, 0, 0), 16);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 0);
+    for (i=0; i<17; i++)
+    {
+        swprintf(key, 100, L"key%d", i);
+        keylen = (int)wcslen(key);
+        jenkins_insert(eht->realtable, key, keylen*2+2, L"val", 8, 0, 0);
+    }
+    CU_ASSERT_EQUAL(jenkins_size(eht->realtable, 0, 0), 32);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 17);
+    eht->destroy(eht);
+}
+
+/**
+ * test_jenkins_stats
+ * unit test for jenkins_stats
+ */
+void test_jenkins_stats(void)
+{
+    
+}
+
+/**
+ * test_jenkins_hash
+ * unit test for jenkins_hash
+ */
+void test_jenkins_hash(void)
+{
+    int hash = 0;
+
+    etch_hashtable* eht = new_etch_hashtable();
+    CU_ASSERT_PTR_NOT_NULL(eht);
+    CU_ASSERT_PTR_NULL(eht->realtable);
+    /* realtable is NULL */
+    hash = jenkins_hash(eht->realtable, "key", 3, 0, 0, 0);
+    CU_ASSERT_EQUAL(hash, 0);
+    destroy_hashtable(eht, TRUE, TRUE);
+
+    eht = new_hashtable(16);
+    CU_ASSERT_PTR_NOT_NULL(eht);
+    CU_ASSERT_EQUAL(jenkins_size(eht->realtable, 0, 0), 16);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 0);
+    /* key is NULL */
+    hash = jenkins_hash(eht->realtable, 0, 0, 0, 0, 0);
+    CU_ASSERT_EQUAL(hash, 0);
+    /* key length is 0 */
+    hash = jenkins_hash(eht->realtable, "key", 0, 0, 0, 0);
+    CU_ASSERT_EQUAL(hash, 0);
+    /* key length is MAX_ETCHHASHKEY + 1 */
+    hash = jenkins_hash(eht->realtable, "key", MAX_ETCHHASHKEY+1, 0, 0, 0);
+    CU_ASSERT_EQUAL(hash, 0);
+    /* get a good hash */
+    hash = jenkins_hash(eht->realtable, "key", 3, 0, 0, 0);
+    CU_ASSERT_NOT_EQUAL(hash, 0);
+    /* hash should be the same is input arguments are the same */
+    CU_ASSERT_EQUAL(hash, jenkins_hash(eht->realtable, "key", 3, 0, 0, 0));
+    /* hash should be different if input arguments are different */
+    CU_ASSERT_NOT_EQUAL(hash, jenkins_hash(eht->realtable, "kee", 3, 0, 0, 0));
+    eht->destroy(eht);
+}
+
+
+/**
+ * test_intkey
+ * test using a 32 bit int as a key
+ */
+#pragma warning (disable:4996)
+void test_intkey(void)
+{
+  	etch_hashitem   hashbucket;
+    etch_hashitem*  myentry = &hashbucket;
+    char* test_string = "it works"; 
+    unsigned int key = 12345, key2 = 11111, key3 = 11111;
+    int value_len = (int)strlen(test_string)+1; /* string length of value */
+   
+    etch_hashtable* ht = new_hashtable(4);
+
+    /* our hash key is a 4-byte item, which we will use to contain the 
+       value of a 32 bit int.
+     */
+	char* pkey = malloc(sizeof(int));
+
+    /*  the string pval is our hash value */
+    char* pval = malloc(value_len);  
+    strcpy(pval, test_string); 
+
+    /* copy the int into our hash key.
+     */
+    memcpy(pkey, &key, sizeof(int));
+    CU_ASSERT_EQUAL(ht->vtab->insert(ht->realtable, pkey, sizeof(int), pval, value_len, 0, 0), 0);
+    CU_ASSERT_EQUAL(ht->vtab->find  (ht->realtable, pkey, sizeof(int), NULL, &myentry), 0);
+    CU_ASSERT_EQUAL(ht->vtab->find  (ht->realtable, &key, sizeof(int), NULL, &myentry), 0);
+
+    /* test two pointers to the same value.
+     */
+    CU_ASSERT_EQUAL(ht->vtab->insert(ht->realtable, &key2, sizeof(int), pval, value_len, 0, 0), 0);
+    CU_ASSERT_EQUAL(ht->vtab->find  (ht->realtable, &key3, sizeof(int), NULL, &myentry), 0);
+
+    destroy_hashtable(ht, FALSE, FALSE);
+    free(pkey);
+    free(pval);
+}
+
+
+/**
+ * test_jenkins_destroy
+ * unit test for jenkins_destroy
+ */
+void test_jenkins_destroy(void)
+{
+    int result = 0;
+
+    etch_hashtable* eht = new_etch_hashtable();
+    CU_ASSERT_PTR_NOT_NULL(eht);
+    CU_ASSERT_PTR_NULL(eht->realtable);
+    /* realtable is NULL */
+    result = jenkins_destroy(eht->realtable, 0, 0);
+    CU_ASSERT_EQUAL(result, -1);
+
+    eht = new_hashtable(16);
+    CU_ASSERT_PTR_NOT_NULL(eht);
+    CU_ASSERT_EQUAL(jenkins_size(eht->realtable, 0, 0), 16);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 0);
+    /* realtable is not NULL */
+    result = jenkins_destroy(eht->realtable, 0, 0);
+    CU_ASSERT_EQUAL(result, 0);
+}
+
+/**
+ * test_jenkins_create
+ * unit test for jenkins_create
+ */
+void test_jenkins_create(void)
+{
+    int result = 0;
+
+    etch_hashtable* eht = new_etch_hashtable();
+    CU_ASSERT_PTR_NOT_NULL(eht);
+    CU_ASSERT_PTR_NULL(eht->realtable);
+    /* realtable is NULL */
+    result = jenkins_create(16, 0, eht->realtable);
+    CU_ASSERT_EQUAL(result, -1);
+    destroy_hashtable(eht, FALSE, FALSE);
+
+    eht = new_hashtable(16);
+    CU_ASSERT_PTR_NOT_NULL(eht);
+    CU_ASSERT_PTR_NOT_NULL(eht->realtable);
+    /* realtable is NULL */
+    result = jenkins_create(16, 0, eht->realtable);
+    CU_ASSERT_EQUAL(result, 0);
+    CU_ASSERT_EQUAL(jenkins_size(eht->realtable, 0, 0), 16);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 0);
+    destroy_hashtable(eht, FALSE, FALSE);
+}
+
+/**
+ * test_ctor_jenkins_hashtable
+ * unit test for ctor_jenkins_hashtable
+ */
+void test_ctor_jenkins_hashtable(void)
+{
+    etch_hashtable* eht = ctor_jenkins_hashtable(16);
+    CU_ASSERT_PTR_NOT_NULL(eht);
+    CU_ASSERT_PTR_NOT_NULL(eht->realtable);
+    CU_ASSERT_PTR_NOT_NULL(eht->vtab);
+    CU_ASSERT_EQUAL(jenkins_size(eht->realtable, 0, 0), 16);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 0);
+
+    destroy_hashtable(eht, FALSE, FALSE);
+}
+
+
+#pragma warning (disable:4996)
+
+/*
+ * test_key_pointer: test using a memory address as a hash key.
+ * return 1 if OK, zero if failed.
+ */
+int test_key_pointer(etch_hashtable* ht)
+{
+	etch_hashitem   hashbucket;
+    etch_hashitem*  myentry = &hashbucket;
+    char* test_string = "it works"; 
+    const int value_len = (int)strlen(test_string)+1; /* string length of value */
+    const int key_len = sizeof(char*); 
+
+    /* our hash key is a 4-byte item, which we will use to contain the 
+       value of a memory address.
+     */
+	char* pkey = malloc(key_len);
+
+    /* the value of the pval memory address is our hash key.
+     * the string pval is our hash value. Of course, our hash table stores pointers,
+     * not values, so the key is &pval, and the value is pval.
+     */
+    char* pval = malloc(value_len);  
+    strcpy(pval, test_string); 
+
+    /* copy the memory address into our hash key.
+     */
+    memcpy(pkey, &pval, sizeof(char*));
+
+    CU_ASSERT_EQUAL(ht->vtab->insert(ht->realtable, pkey, key_len, pval, value_len, 0, 0), 0);
+
+    CU_ASSERT_EQUAL(ht->vtab->find(ht->realtable, pkey, key_len, NULL, &myentry), 0);
+
+    CU_ASSERT_PTR_NOT_NULL(myentry->value);
+
+    /* This code demonstrates what we've done here. The key is the value of a
+     * char*, and the value is that same char*. So, indirectly dereferencing  
+     * the key must elicit the same result as dereferencing the value. 
+     */
+    CU_ASSERT_EQUAL(memcmp(myentry->key, &myentry->value, sizeof(char*)), 0);
+    
+    CU_ASSERT_EQUAL(strcmp(*(char**)myentry->key, (char*)myentry->value), 0);
+
+	return 1;
+}
+
+/**
+ * test_all
+ * unit test for various functions strung together
+ */
+void test_combo(void)
+{
+    char  buf[MAXLINELEN];
+    char* pkey; void* pdata;
+    int   n, keylen, myincount=0, myhashcount=0, myfreecount=0;
+    etch_hashtable* myhash;
+    etch_hashitem   hashbucket;
+    etch_hashitem*  myentry = &hashbucket;
+    unsigned hashed;
+    char  c = 0, *p;
+    FILE* f = 0;
+    p = "abracadabra"; n = (int)strlen(p); // Test the hash function
+    hashed = etchhash(p, n, 0);
+
+    f = fopen(TESTDATAPATH,"r");
+    CU_ASSERT_PTR_NOT_NULL_FATAL(f);
+
+    myhash = new_hashtable(INITIAL_TABLE_SIZE);  /* create hash table */
+    CU_ASSERT_PTR_NOT_NULL_FATAL(myhash);
+
+    myhash->vtab->stats(myhash->realtable, 0, 0); /* show table stats */
+    n = myhash->vtab->size(myhash->realtable, 0, 0);
+    CU_ASSERT_EQUAL(n, INITIAL_TABLE_SIZE);
+  
+    while (fgets((char*)buf, MAXLINELEN, f))   /* read the testdata file line by line */ 
+    {
+        unsigned char* p = buf; while(*p++) if (*p <= 0x0d) *p = 0;       /* strip crlf */
+        keylen = (int)strlen(buf);   /* we use null termed key, but it is not necessary */ 
+        pkey   = malloc(keylen+1); strcpy(pkey, buf);    
+        pdata  = malloc(DATASIZE);  /* note that user allocates memory for key and data */
+        strcpy(pdata, DATAVALUE);   /* hashtable does not make copies of key or of data */
+                                    /* insert the new hashtable entry */          
+        if  (0 == myhash->vtab->insert(myhash->realtable, pkey, keylen, pdata, DATASIZE, 0, 0))         
+        {    myincount++;           /* point at current entry in hashtable */
+             myhash->vtab->current(myhash->realtable, 0, &myentry);  
+             CU_ASSERT_PTR_EQUAL(myentry->key, pkey); /* ensure items just inserted are there */
+             CU_ASSERT_PTR_EQUAL(myentry->value, pdata);
+        }
+        else                        /* insert failure - probably duplicate */
+        {    free(pkey);  
+             free(pdata);
+        }
+    }
+
+    fclose(f); f = 0;
+    myhash->vtab->stats(myhash->realtable, 0, 0); /* show table stats */ 
+
+    pkey = "banana";  /* test a hashtable lookup */
+
+    CU_ASSERT_EQUAL(myhash->vtab->find(myhash->realtable, pkey, (int)strlen(pkey), NULL, &myentry), 0);
+    CU_ASSERT_EQUAL(strcmp(pkey, myentry->key), 0);
+
+    CU_ASSERT_EQUAL(myhash->vtab->first(myhash->realtable, NULL, &myentry), 0);
+    myhashcount = 1;
+
+    while(0 == myhash->vtab->next(myhash->realtable, NULL, &myentry))          
+    {    
+        myhashcount++;
+    }
+
+    /* test using pointer as key, adding 0 or 1 to myhashcount */
+    myhashcount += test_key_pointer(myhash);
+
+    /* destroy hash table and all its contents (free key and data memory) */
+    myfreecount = myhash->vtab->clear(myhash->realtable, TRUE, TRUE, 0, 0);
+
+    CU_ASSERT_EQUAL(myfreecount, myhashcount);
+}
+
+
+/**
+ * _tmain
+ * unit test entry point
+ */
+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;
+    CU_set_output_filename("../test_etchhash");
+    etch_watch_id = 0; 
+     
+    pSuite = CU_add_suite("suite_etchhash", init_suite, clean_suite);
+   
+    CU_add_test(pSuite, "new_hashtable", test_new_hashtable);
+    CU_add_test(pSuite, "new_etch_hashtable", test_new_etch_hashtable);
+    CU_add_test(pSuite, "destroy_hashtable", test_destroy_hashtable);
+    CU_add_test(pSuite, "jenkins_hash", test_jenkins_hash);  
+    CU_add_test(pSuite, "jenkins_find", test_jenkins_find);
+    CU_add_test(pSuite, "jenkins_findh", test_jenkins_findh);
+    CU_add_test(pSuite, "jenkins default key", test_default_hashkey);
+    CU_add_test(pSuite, "jenkins_first", test_jenkins_first);
+    CU_add_test(pSuite, "jenkins_next", test_jenkins_next);
+    CU_add_test(pSuite, "jenkins_current", test_jenkins_current);  
+    CU_add_test(pSuite, "jenkins_remove", test_jenkins_remove);  
+    CU_add_test(pSuite, "jenkins_clear", test_jenkins_clear);  
+    CU_add_test(pSuite, "jenkins_count", test_jenkins_count);  
+    CU_add_test(pSuite, "jenkins_size", test_jenkins_size);  
+    CU_add_test(pSuite, "jenkins_insert", test_jenkins_insert);  
+    CU_add_test(pSuite, "jenkins_inserth", test_jenkins_inserth);  
+    CU_add_test(pSuite, "jenkins_stats", test_jenkins_stats);  
+    CU_add_test(pSuite, "jenkins_destroy", test_jenkins_destroy);  
+    CU_add_test(pSuite, "jenkins_create", test_jenkins_create);  
+    CU_add_test(pSuite, "ctor_jenkins_hashtable", test_ctor_jenkins_hashtable);   
+    CU_add_test(pSuite, "test integer key", test_intkey);  
+    CU_add_test(pSuite, "test combinations", test_combo);    
+
+    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/common/test_iterator.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/test/common/test_iterator.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/test/common/test_iterator.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/test/common/test_iterator.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,385 @@
+/* $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_iterator.c -- test etch_iterator over i_iterable classes
+ */
+
+#include "apr_time.h" /* some apr must be included first */
+#include "etchthread.h"
+#include <tchar.h>
+#include <stdio.h>
+#include <conio.h>
+
+#include "cunit.h"
+#include "basic.h"
+#include "automated.h"
+
+#include "etch_global.h"
+#include "etch_arraylist.h"
+#include "etchhash.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;
+}
+
+
+etch_arraylist* testlist;
+etch_hashtable* testhash;
+
+/* 
+ * load_listdata_int()
+ * load testlist array with some etch_int32 objects
+ */
+int load_listdata_int()
+{
+    int i = 0, numitems = 4;
+    etch_int32* newobj = NULL;
+    int ints[4] = { 1, 2, 3, 4 };
+
+    for(; i < numitems; i++)
+    {
+        newobj = new_int32(ints[i]);
+        arraylist_add(testlist, newobj);
+    }
+
+    return numitems;
+}
+
+
+/* 
+ * new_listdata()
+ * create testlist array and load it up with data objects
+ */
+int new_listdata(const int datatype)
+{
+    int count = 0;
+    testlist = new_arraylist(0,0);  
+    testlist->content_type = ETCHARRAYLIST_CONTENT_OBJECT;
+    count = load_listdata_int(); 
+    return count;
+}
+
+
+/* 
+ * destroy_listdata()
+ * destroy testlist array and content
+ */
+void destroy_listdata()
+{
+    arraylist_destroy(testlist, TRUE);
+}
+
+
+/* 
+ * load_hashdata_string()
+ * load testhash hashtable with some etch_string objects
+ */
+int load_hashdata_string()
+{
+    int i = 0, numitems = 4, result = 0;
+    //wchar_t* testval = NULL;
+    void* key = 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++)
+    {
+        //testval = etch_malloc(bytelen, 0);
+        //memcpy(testval, strings[i], bytelen);
+        newobj = new_string(strings[i], ETCH_ENCODING_UTF16); 
+
+        key  = etch_malloc(bytelen, 0);
+        memcpy(key, strings[i], bytelen);
+
+        result = testhash->vtab->insert(testhash->realtable, 
+                 key, (int)bytelen, newobj, 0, NULL, NULL);
+    }
+
+    return numitems;
+}
+
+
+/* 
+ * new_hashdata()
+ * create testhash hashtable and load it up with data objects
+ */
+int new_hashdata(const int datatype)
+{
+    int count = 0;
+    testhash = new_hashtable(16);  
+    count = load_hashdata_string();
+    return count;
+}
+
+
+/* 
+ * destroy_hashdata()
+ * destroy testhash hashtable and content
+ */
+void destroy_hashdata()
+{
+    destroy_hashtable(testhash, TRUE, TRUE);
+}
+
+
+/* 
+ * test_iterator_over_arraylist
+ */
+void test_iterator_over_arraylist(void)
+{
+    etch_iterator* iterator = NULL; 
+    int testcount = 0, thiscount = 0;
+    testcount = new_listdata(0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(testlist);
+    CU_ASSERT_NOT_EQUAL(testlist->count, 0);
+
+    iterator = new_iterator(testlist, &testlist->iterable);
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(iterator);
+    CU_ASSERT_EQUAL_FATAL(iterator->ordinal,1);
+
+    while(iterator->has_next(iterator))
+          thiscount += (iterator->next(iterator) == 0);  
+        
+    CU_ASSERT_EQUAL(thiscount, testcount-1);
+
+    iterator->destroy(iterator);
+    destroy_listdata();
+
+    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 result = 0, thiscount = 0, testcount = 0, startbytes = 0;
+    testcount = new_hashdata(1);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(testhash);
+    CU_ASSERT_NOT_EQUAL(testhash->vtab->count(testhash->realtable,0,0),0);
+    startbytes = etch_showmem(0, FALSE); /* note testdata bytes */
+
+    iterator = new_iterator(testhash, &testhash->iterable);
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(iterator);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(iterator->current_key);
+    CU_ASSERT_EQUAL_FATAL(iterator->ordinal,1);
+    thiscount = 1;
+
+    while(iterator->has_next(iterator))
+    {
+        if (0 != (result = iterator->next(iterator))) break;  
+         
+        thiscount++;
+        CU_ASSERT_PTR_NOT_NULL(iterator->current_key);
+        CU_ASSERT_PTR_NOT_NULL(iterator->current_value);
+
+        #if IS_DEBUG_CONSOLE       
+        if  (iterator->current_value)
+             wprintf(L"value is %s\n",(wchar_t*)iterator->current_value);
+        else wprintf(L"value is null\n");           
+        #endif       
+    } 
+        
+    CU_ASSERT_EQUAL(testcount, thiscount);
+
+    iterator->destroy(iterator);
+    destroy_hashdata();
+
+    /* we are etch_malloc'ing testdata but hashtable frees content, not etch_free */
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);  
+    g_bytes_allocated -= startbytes;
+    CU_ASSERT_TRUE(g_bytes_allocated <= 0);  
+    memtable_clear();  /* start fresh for next test */ 
+}
+
+
+/* 
+ * test_stack_allocated_iterator
+ * iterator as automatic variable
+ */
+void test_stack_allocated_iterator(void)
+{
+    etch_iterator iterator;
+    int testcount = 0, thiscount = 0;
+    testcount = new_listdata(0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(testlist);
+    CU_ASSERT_NOT_EQUAL(testlist->count, 0);
+
+    set_iterator(&iterator, testlist, &testlist->iterable);
+
+    CU_ASSERT_EQUAL_FATAL(iterator.ordinal,1);
+
+    while(iterator.vtab->has_next(&iterator))
+          thiscount += (iterator.vtab->next(&iterator) == 0);  
+        
+    CU_ASSERT_EQUAL(thiscount, testcount-1);
+
+    destroy_listdata();
+
+    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_reset_iterator
+ * test reinitalizing and reusing iterator
+ */
+void test_reset_iterator(void)
+{
+    etch_iterator iterator;
+    int testcount = 0, thiscount1 = 0, thiscount2 = 0;
+    testcount = new_listdata(0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(testlist);
+    CU_ASSERT_NOT_EQUAL(testlist->count, 0);
+
+    set_iterator(&iterator, testlist, &testlist->iterable);
+
+    CU_ASSERT_EQUAL(iterator.ordinal,1);
+
+    while(iterator.vtab->has_next(&iterator))
+          thiscount1 += (iterator.vtab->next(&iterator) == 0);  
+        
+    CU_ASSERT_EQUAL(thiscount1, testcount-1);
+
+    set_iterator(&iterator, testlist, &testlist->iterable);
+
+    CU_ASSERT_EQUAL(iterator.ordinal,1);
+
+    while(iterator.vtab->has_next(&iterator))
+          thiscount2 += (iterator.vtab->next(&iterator) == 0); 
+ 
+    CU_ASSERT_EQUAL(thiscount2, thiscount1);    
+
+    destroy_listdata();
+
+    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_iterator", init_suite, clean_suite);
+    CU_set_output_filename("../test_iterator");  
+
+    CU_add_test(pSuite, "test forward iterator over arraylist",   test_iterator_over_arraylist);
+    CU_add_test(pSuite, "test forward iterator over hashtable",   test_iterator_over_hashtable);
+    CU_add_test(pSuite, "test stack allocated iterator",   test_stack_allocated_iterator);
+    CU_add_test(pSuite, "test reset iterator",   test_reset_iterator);
+
+    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/common/test_objects.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/test/common/test_objects.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/test/common/test_objects.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/test/common/test_objects.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,426 @@
+/**
+ * test_objects.c -- test etch_objects
+ */
+
+#include <tchar.h>
+#include <stdio.h>
+#include <conio.h>
+
+#include "cunit.h"
+#include "basic.h"
+#include "automated.h"
+
+#include "etch_global.h"
+#include "etch_objects.h"
+#include "etch_arraylist.h"
+
+#ifndef TESTSUITEDEFS
+#define TESTSUITEDEFS
+
+int init_suite(void)
+{
+    return etch_runtime_init();
+}
+
+int clean_suite(void)
+{
+    return etch_runtime_cleanup(0,0); /* free memtable and cache etc */
+}
+
+int g_is_automated_test, g_bytes_allocated;
+
+#define IS_DEBUG_CONSOLE FALSE
+
+#endif /* TESTSUITEDEFS */
+
+#define OBJSIG 0xbadf00d
+#define NUMITEMS 3
+#define ETCHTYPEA_TESTOBJ 0xff
+
+
+/**
+ * globals, test objects to stuff into arraylists, etc
+ */
+int bytes_allocated, bytes_prior;
+
+typedef struct TESTOBJ
+{   int id;
+    int signature;
+} TESTOBJ;
+
+TESTOBJ* objfactory(const int id)
+{ 
+   TESTOBJ* obj = etch_malloc(sizeof(TESTOBJ), ETCHTYPEA_TESTOBJ);
+   obj->id = id; obj->signature = OBJSIG;
+   return obj;
+}
+
+/**
+ * comparator callback for contains(), indexof(), functions
+ * typedef int (*etch_comparator) (void* myobj, void* otherobj);
+ */
+int al_comparator(void* p, void* q)
+{   
+    int result = 0;
+    TESTOBJ* myobj = (TESTOBJ*)p, *othobj = (TESTOBJ*)q;
+    if (!myobj || !othobj) result = -2;
+    else if (myobj->signature != OBJSIG || othobj->signature != OBJSIG) result = -2;
+    else if (myobj->id < othobj->id) result = -1;
+    else if (myobj->id > othobj->id) result = 1;
+    else result = 0; /* equality */
+    return result;
+}
+
+
+/* 
+ * test ETCH_INT32 object 
+ */
+void test_int32(void)
+{   
+    void* pvtbl = NULL;
+    const int testval = -1;
+
+    ETCH_INT32* newobj = new_etch_int32(testval);
+
+    /* ensure the etchobject and its interface were created */
+    CU_ASSERT_PTR_NOT_NULL_FATAL(newobj);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(newobj->vtab);
+
+    /* ensure the i_etchobject vtable is cached and is correct */
+    pvtbl = cache_find(ETCHTYPE_VTABLE_ETCHOBJECT, 0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(pvtbl);
+    CU_ASSERT_EQUAL_FATAL(newobj->vtab, pvtbl);
+    CU_ASSERT_EQUAL_FATAL(newobj->vtab->destroy, destroy_etchobject); 
+
+    /* ensure object instance data is as expected */
+    CU_ASSERT_EQUAL(newobj->size, sizeof(int));
+    CU_ASSERT_EQUAL(newobj->value_int32, testval);
+    CU_ASSERT_EQUAL(newobj->type, ETCHTYPE_BOXED_INT32);
+    CU_ASSERT_PTR_NULL(newobj->result);
+
+    /* ensure object memory is destroyed as expected */
+    newobj->vtab->destroy(newobj);
+    bytes_allocated = etch_showmem(TRUE,FALSE);
+    CU_ASSERT_EQUAL(bytes_allocated, 0);
+    memtable_clear(); /* start fresh for next test */
+}
+
+/* 
+ * test ETCH_INT64 object 
+ */
+void test_int64(void)
+{   
+    void* pvtbl = NULL;
+    const short testval = -1;
+
+    ETCH_INT64* newobj = new_etch_int64(testval);
+
+    /* ensure the etchobject and its interface were created */
+    CU_ASSERT_PTR_NOT_NULL_FATAL(newobj);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(newobj->vtab);
+
+    /* ensure the i_etchobject vtable is cached and is correct */
+    pvtbl = cache_find(ETCHTYPE_VTABLE_ETCHOBJECT, 0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(pvtbl);
+    CU_ASSERT_EQUAL_FATAL(newobj->vtab, pvtbl);
+    CU_ASSERT_EQUAL_FATAL(newobj->vtab->destroy, destroy_etchobject); 
+
+    /* ensure object instance data is as expected */
+    CU_ASSERT_EQUAL(newobj->size, sizeof(int64));
+    CU_ASSERT_EQUAL(newobj->value_int64, -1);
+    CU_ASSERT_EQUAL(newobj->type, ETCHTYPE_BOXED_INT64);
+
+    /* ensure object memory is destroyed as expected */
+    newobj->vtab->destroy(newobj);
+    bytes_allocated = etch_showmem(TRUE,FALSE);
+    CU_ASSERT_EQUAL(bytes_allocated, 0);
+    memtable_clear(); /* start fresh for next test */
+}
+
+/* 
+ * test ETCH_INT16 object 
+ */
+void test_int16(void)
+{   
+    void* pvtbl = NULL;
+    const short testval = -1;
+
+    ETCH_INT16* newobj = new_etch_int16(testval);
+
+    /* ensure the etchobject and its interface were created */
+    CU_ASSERT_PTR_NOT_NULL_FATAL(newobj);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(newobj->vtab);
+
+    /* ensure the i_etchobject vtable is cached and is correct */
+    pvtbl = cache_find(ETCHTYPE_VTABLE_ETCHOBJECT, 0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(pvtbl);
+    CU_ASSERT_EQUAL_FATAL(newobj->vtab, pvtbl);
+    CU_ASSERT_EQUAL_FATAL(newobj->vtab->destroy, destroy_etchobject); 
+
+    /* ensure object instance data is as expected */
+    CU_ASSERT_EQUAL(newobj->size, sizeof(short));
+    CU_ASSERT_EQUAL(newobj->value_int16, -1);
+    CU_ASSERT_EQUAL(newobj->type, ETCHTYPE_BOXED_INT16);
+
+    /* ensure object memory is destroyed as expected */
+    newobj->vtab->destroy(newobj);
+    bytes_allocated = etch_showmem(TRUE,FALSE);
+    CU_ASSERT_EQUAL(bytes_allocated, 0);
+    memtable_clear(); /* start fresh for next test */
+}
+
+/* 
+ * test ETCH_INT8 object 
+ */
+void test_int8(void)
+{   
+    void* pvtbl = NULL;
+    const signed char testval = -1;
+
+    ETCH_INT8* newobj = new_etch_int8(testval);
+
+    /* ensure the etchobject and its interface were created */
+    CU_ASSERT_PTR_NOT_NULL_FATAL(newobj);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(newobj->vtab);
+
+    /* ensure the i_etchobject vtable is cached and is correct */
+    pvtbl = cache_find(ETCHTYPE_VTABLE_ETCHOBJECT, 0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(pvtbl);
+    CU_ASSERT_EQUAL_FATAL(newobj->vtab, pvtbl);
+    CU_ASSERT_EQUAL_FATAL(newobj->vtab->destroy, destroy_etchobject); 
+
+    /* ensure object instance data is as expected */
+    CU_ASSERT_EQUAL(newobj->size, sizeof(char));
+    CU_ASSERT_EQUAL(newobj->value_int8, -1);
+    CU_ASSERT_EQUAL(newobj->type, ETCHTYPE_BOXED_INT8);
+
+    /* ensure object memory is destroyed as expected */
+    newobj->vtab->destroy(newobj);
+    bytes_allocated = etch_showmem(TRUE,FALSE);
+    CU_ASSERT_EQUAL(bytes_allocated, 0);
+    memtable_clear(); /* start fresh for next test */
+}
+
+/* 
+ * test ETCH_BOOL object 
+ */
+void test_bool(void)
+{   
+    void* pvtbl = NULL;
+    const unsigned char testval = 0x11;
+
+    ETCH_BOOL* newobj = new_etch_bool(testval);
+
+    /* ensure the etchobject and its interface were created */
+    CU_ASSERT_PTR_NOT_NULL_FATAL(newobj);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(newobj->vtab);
+
+    /* ensure the i_etchobject vtable is cached and is correct */
+    pvtbl = cache_find(ETCHTYPE_VTABLE_ETCHOBJECT, 0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(pvtbl);
+    CU_ASSERT_EQUAL_FATAL(newobj->vtab, pvtbl);
+    CU_ASSERT_EQUAL_FATAL(newobj->vtab->destroy, destroy_etchobject); 
+
+    /* ensure object instance data is as expected */
+    CU_ASSERT_EQUAL(newobj->size, sizeof(char));
+    CU_ASSERT_EQUAL(newobj->value_int8, TRUE);
+    CU_ASSERT_EQUAL(newobj->type, ETCHTYPE_BOXED_BOOL);
+
+    /* ensure object memory is destroyed as expected */
+    newobj->vtab->destroy(newobj);
+    bytes_allocated = etch_showmem(TRUE,FALSE);
+    CU_ASSERT_EQUAL(bytes_allocated, 0);
+    memtable_clear(); /* start fresh for next test */
+}
+
+
+/* 
+ * test ETCH_IEEE64 object 
+ */
+void test_ieee64(void)
+{   
+    void* pvtbl = NULL;
+    const double testval = 3.14159;
+
+    ETCH_IEEE64* newobj = new_etch_ieee64(testval);
+
+    /* ensure the etchobject and its interface were created */
+    CU_ASSERT_PTR_NOT_NULL_FATAL(newobj);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(newobj->vtab);
+
+    /* ensure the i_etchobject vtable is cached and is correct */
+    pvtbl = cache_find(ETCHTYPE_VTABLE_ETCHOBJECT, 0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(pvtbl);
+    CU_ASSERT_EQUAL_FATAL(newobj->vtab, pvtbl);
+    CU_ASSERT_EQUAL_FATAL(newobj->vtab->destroy, destroy_etchobject); 
+
+    /* ensure object instance data is as expected */
+    CU_ASSERT_EQUAL(newobj->size, sizeof(double));
+    CU_ASSERT_DOUBLE_EQUAL(newobj->value_ieee64, testval, (double)0.00001);
+    CU_ASSERT_EQUAL(newobj->type, ETCHTYPE_BOXED_IEEE64);
+
+    /* ensure object memory is destroyed as expected */
+    newobj->vtab->destroy(newobj);
+    bytes_allocated = etch_showmem(TRUE,FALSE);
+    CU_ASSERT_EQUAL(bytes_allocated, 0);
+    memtable_clear(); /* start fresh for next test */
+}
+
+/* 
+ * test ETCH_IEEE32 object 
+ */
+void test_ieee32(void)
+{   
+    void* pvtbl = NULL;
+    const float testval = (float)3.14159;
+
+    ETCH_IEEE32* newobj = new_etch_ieee32(testval);
+
+    /* ensure the etchobject and its interface were created */
+    CU_ASSERT_PTR_NOT_NULL_FATAL(newobj);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(newobj->vtab);
+
+    /* ensure the i_etchobject vtable is cached and is correct */
+    pvtbl = cache_find(ETCHTYPE_VTABLE_ETCHOBJECT, 0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(pvtbl);
+    CU_ASSERT_EQUAL_FATAL(newobj->vtab, pvtbl);
+    CU_ASSERT_EQUAL_FATAL(newobj->vtab->destroy, destroy_etchobject); 
+
+    /* ensure object instance data is as expected */
+    CU_ASSERT_EQUAL(newobj->size, sizeof(float));
+    CU_ASSERT_DOUBLE_EQUAL(newobj->value_ieee32, testval, (float)0.00001);
+    CU_ASSERT_EQUAL(newobj->type, ETCHTYPE_BOXED_IEEE32);
+
+    /* ensure object memory is destroyed as expected */
+    newobj->vtab->destroy(newobj);
+    bytes_allocated = etch_showmem(TRUE,FALSE);
+    CU_ASSERT_EQUAL(bytes_allocated, 0);
+    memtable_clear(); /* start fresh for next test */
+}
+
+/* 
+ * test ETCH_STRING object
+ */
+void test_string(void)
+{   
+    void* pvtbl = NULL;
+    ETCH_STRING* newobj = NULL;
+    const wchar_t* teststr = L"it works!";
+    size_t testlen = (wcslen(teststr) + 1) * sizeof(wchar_t);
+    wchar_t* testval = etch_malloc(testlen, 0);
+    memcpy(testval, teststr, testlen);
+    /* cache_dump(); */
+
+    /* note that cache is not clear, should not re-cache here - check cache.find() */
+    newobj = new_etch_string(testval);
+
+    /* ensure the etchobject and its interface were created */
+    CU_ASSERT_PTR_NOT_NULL_FATAL(newobj);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(newobj->vtab);
+
+    /* ensure the i_etchobject vtable is cached and is correct */
+    pvtbl = cache_find(ETCHTYPE_VTABLE_ETCHOBJECT, 0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(pvtbl);
+    /* TODO: figure out what's wrong with these tests. we know the vtable is OK
+     * since desttroy() works fine thru the vtable, below.
+     * CU_ASSERT_EQUAL_FATAL(newobj->vtab, pvtbl);
+     * CU_ASSERT_EQUAL_FATAL(newobj->vtab->destroy, destroy_etchobject); 
+     */
+
+    /* ensure object instance data is as expected */
+    CU_ASSERT_EQUAL(newobj->size, testlen);
+    CU_ASSERT_EQUAL(memcmp(newobj->value_ptr_to, teststr, testlen), 0);
+    CU_ASSERT_EQUAL(newobj->type, ETCHTYPE_BOXED_STRING);
+    CU_ASSERT_PTR_NULL(newobj->result);
+
+    /* ensure object memory is destroyed as expected */
+    newobj->vtab->destroy(newobj);
+    bytes_allocated = etch_showmem(TRUE,FALSE);
+    CU_ASSERT_EQUAL(bytes_allocated, 0);
+    memtable_clear(); /* start fresh for next test */
+}
+
+
+/* 
+ * test ETCH_ARRAYLIST object
+ * TODO: much more comprehensive test of boxed arraylists: clone, etc.
+ * TODO: write custom ctor with dedicated vtable for this object type 
+ * that permits the object to be destroyed with or without freeing
+ * memory for the list contents. when we do this, remove the code
+ * in etchobject destroy and clone methods which do this.
+ */
+void test_arraylist(void)
+{   
+    void* pvtbl = NULL;
+    etch_arraylist* list = NULL;
+    TESTOBJ* t1 = NULL, *t2 = NULL;
+    const int initsize = 8, deltsize = 4, NOTREADONLY = FALSE;
+    ETCH_ARRAYLIST* newobj = NULL;
+
+    newobj = new_etch_arraylist(initsize,deltsize,NOTREADONLY);
+
+    /* ensure the etchobject and its interface were created */
+    CU_ASSERT_PTR_NOT_NULL_FATAL(newobj);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(newobj->vtab);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(newobj->value_ptr_to);
+
+    /* ensure the i_etchobject vtable is cached and is correct */
+    pvtbl = cache_find(ETCHTYPE_VTABLE_ETCHOBJECT, 0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(pvtbl);
+
+    /* ensure object instance data is as expected */
+    CU_ASSERT_EQUAL(newobj->type, ETCHTYPE_BOXED_ARRAYLIST);
+
+    /* allocate content memory and add content to arraylist */
+    list = newobj->value_ptr_to;
+    arraylist_add(list, t1 = objfactory(1));
+    arraylist_add(list, t2 = objfactory(2));
+    CU_ASSERT_EQUAL(list->count, 2);
+
+    /* ensure object memory is destroyed as expected. since we specified
+     * false for is_readonly in the new_etch_arraylist constructor, any
+     * memory allocated for arraylist content *will* be freed in destroy(). 
+     * of course we should eventually test with is_readonly true, and
+     * ensuring memory remains allocated.
+     */
+    newobj->vtab->destroy(newobj);
+    bytes_allocated = etch_showmem(TRUE,FALSE);
+    CU_ASSERT_EQUAL(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;
+    CU_set_output_filename("../test_etchobjects");
+    pSuite = CU_add_suite("suite_etchobjects", init_suite, clean_suite);
+
+    CU_add_test(pSuite, "test ETCH_INT32",  test_int32);
+    CU_add_test(pSuite, "test ETCH_INT64",  test_int64);
+    CU_add_test(pSuite, "test ETCH_INT16",  test_int16);
+    CU_add_test(pSuite, "test ETCH_INT8",   test_int8);
+    CU_add_test(pSuite, "test ETCH_BOOL",   test_bool);
+    CU_add_test(pSuite, "test ETCH_IEEE64", test_ieee64);
+    CU_add_test(pSuite, "test ETCH_IEEE32", test_ieee32);
+    CU_add_test(pSuite, "test ETCH_STRING", test_string);
+    CU_add_test(pSuite, "test ETCH_ARRAYLIST", test_arraylist);
+
+    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(); 
+}
+