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 [23/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_etchobject.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/test/common/test_etchobject.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/test/common/test_etchobject.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/test/common/test_etchobject.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,1089 @@
+/* $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_etchobject.c.c -- test etch object inheritance and primitives
+ */
+#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 "etchobj.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;
+}
+
+/**
+ * class_a: base class
+ */
+typedef struct class_a
+{
+    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_string* a_string;
+     
+} class_a;
+
+
+/**
+ * class_a destructor
+ */
+int destroy_class_a(class_a* thisp)
+{
+    if (thisp->a_string)
+        thisp->a_string->destroy(thisp->a_string);
+
+    destroy_object((objmask*) thisp);
+    return 0;
+}
+
+/**
+ * class_a copy consttructor
+ */
+class_a* clone_class_a(class_a* origobj)
+{
+    class_a* newobj = (class_a*) new_object(sizeof(class_a), 413, 0);
+    memcpy(newobj, origobj, sizeof(objmask));
+    newobj->a_string = new_string(origobj->a_string->v.valw, ETCH_ENCODING_UTF16);   
+    return newobj; 
+}
+
+
+/**
+ * class_a constructor
+ */
+class_a* new_class_a(const wchar_t* strval)
+{
+    class_a* newobj  = (class_a*) new_object(sizeof(class_a), 403, 0);
+    newobj->destroy  = destroy_class_a;
+    newobj->clone    = clone_class_a;
+    newobj->a_string = new_string(strval, ETCH_ENCODING_UTF16);
+    return newobj;
+}
+
+
+/**
+ * class_b: inherits from class_a
+ */
+typedef struct class_b
+{
+    unsigned int    hashkey;    
+    unsigned short  obj_type; 
+    unsigned short  class_id;
+    struct objmask* vtab;
+    int  (*destroy)(void*);
+    void*(*clone)  (void*);  
+    obj_gethashkey  get_hashkey;           
+    class_a*        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* data; 
+    int   datasize;  
+
+} class_b;
+
+
+/**
+ * class_b destructor
+ */
+int destroy_class_b(class_b* thisp)
+{
+    etch_free(thisp->data);
+    destroy_object((objmask*) thisp);
+    return 0;
+}
+
+
+/**
+ * class_b copy consttructor
+ */
+class_b* clone_class_b(class_b* origobj)
+{
+    class_b* newobj  = (class_b*) new_object(sizeof(class_b), 415, 0);
+    memcpy(newobj, origobj, sizeof(objmask));
+
+    newobj->parent = origobj->parent? 
+        origobj->parent->clone(origobj->parent): 
+        new_class_a(NULL);
+
+    if (origobj->data)
+    {
+        newobj->data     = etch_malloc(origobj->datasize, 412); 
+        newobj->datasize = origobj->datasize;
+        memcpy(newobj->data, origobj->data, origobj->datasize); 
+    }
+ 
+    return newobj;
+}
+
+
+/**
+ * class_b constructor
+ */
+class_b* new_class_b(class_a* parent, const int datalen)
+{
+    class_b* newobj = (class_b*) new_object(sizeof(class_b), 404, 0);
+    newobj->parent  = parent? parent: new_class_a(NULL);
+    newobj->destroy = destroy_class_b;
+    newobj->clone   = clone_class_b;
+    newobj->data    = etch_malloc(datalen, 402);
+    memset(newobj->data, 'x', datalen);
+    newobj->datasize = datalen;
+    return newobj;
+}
+
+
+/**
+ * class_c: inherits from class_b
+ */
+typedef struct class_c
+{
+    unsigned int    hashkey;    
+    unsigned short  obj_type; 
+    unsigned short  class_id;
+    struct objmask* vtab;
+    int  (*destroy)(void*);
+    void*(*clone)  (void*);  
+    obj_gethashkey  get_hashkey;           
+    class_b*        parent;
+    etchresult*     result;
+    unsigned int    refcount;
+    unsigned int    length;
+    unsigned char   is_null;
+    unsigned char   is_copy;
+    unsigned char   is_static;
+    unsigned char   reserved;
+
+    int* intarray;
+    int  numitems;
+
+} class_c;
+
+
+/**
+ * class_c destructor
+ */
+int destroy_class_c(class_c* thisp)
+{
+    etch_free(thisp->intarray);
+    destroy_object((objmask*) thisp);
+    return 0;
+}
+
+
+/**
+ * class_c copy consttructor
+ */
+class_c* clone_class_c(class_c* origobj)
+{
+    class_c* newobj  = (class_c*) new_object(sizeof(class_c), 410, 0);
+    memcpy(newobj, origobj, sizeof(objmask));
+
+    if  (origobj->parent)
+         newobj->parent = origobj->parent->clone(origobj->parent);
+    else newobj->parent = new_class_b(NULL, 0);
+
+    if (origobj->intarray)
+    {
+        newobj->intarray = etch_malloc(origobj->numitems * sizeof(int), 411);
+        newobj->numitems = origobj->numitems;
+        memcpy(newobj->intarray, origobj->intarray, origobj->numitems * sizeof(int)); 
+    }
+
+    return newobj; 
+}
+
+
+/**
+ * class_c constructor
+ */
+class_c* new_class_c(class_b* parent)
+{
+    int i = 0;
+    class_c* newobj  = (class_c*) new_object(sizeof(class_b), 400, 0);
+    newobj->parent   = parent? parent: new_class_b(NULL, 0);
+    newobj->destroy  = destroy_class_c;
+    newobj->clone    = clone_class_c;
+
+    newobj->numitems = 4;
+    newobj->intarray = etch_malloc(4 * sizeof(int), 401);
+    for(; i < 4; i++) newobj->intarray[i] = i;
+
+    return newobj;
+}
+
+
+/**
+ * test_inheritance()
+ * test that in scenario c inherits from b inherits from a,
+ * destroying c destroys b destroys a.
+ */
+void test_inheritance(void)
+{
+    class_a* class_toplevel = NULL;
+    class_b* class_midlevel = NULL;
+    class_c* class_lowlevel = NULL;
+
+    class_toplevel = new_class_a(L"it works!");
+    class_midlevel = new_class_b(class_toplevel, 128);
+    class_lowlevel = new_class_c(class_midlevel);
+ 
+    /* any object destructor should recursively destroy() its superclasses */
+    CU_ASSERT_PTR_NOT_NULL_FATAL(class_lowlevel->parent);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(class_midlevel->parent);
+    CU_ASSERT_PTR_NULL_FATAL(class_toplevel->parent);
+
+    class_lowlevel->destroy(class_lowlevel);
+
+    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_clone()
+ * test validity of cloned objects, also test construction of inherited object
+ * when the parent(s) implementation(s) is/are not specified.
+ * clones must be disposable, i.e. they must own all their memory
+ * including that of their superclasses, such that if c inherits from b 
+ * inherits from a, and I clone c giving c', and I then destroy c, then 
+ * I can subsequently destroy c' via normal channels.
+ */
+void test_clone(void)
+{
+    class_c* class_lowlevel = NULL;
+    class_b* class_midlevel = NULL;
+    class_a* class_toplevel = NULL;
+
+    class_c* clone_lowlevel = NULL;
+    class_b* clone_midlevel = NULL;
+    class_a* clone_toplevel = NULL;
+
+    /* construct class c and all its superclasses */
+    class_lowlevel = new_class_c(NULL);
+
+    /* verify that superclasses were created */
+    class_midlevel = (class_b*) class_lowlevel->parent;
+    CU_ASSERT_PTR_NOT_NULL_FATAL(class_midlevel);
+    class_toplevel = (class_a*) class_midlevel->parent;
+    CU_ASSERT_PTR_NOT_NULL_FATAL(class_toplevel);
+    CU_ASSERT_PTR_NULL_FATAL(class_toplevel->parent);
+
+    /* clone class c and all its superclasses */
+    clone_lowlevel = class_lowlevel->clone(class_lowlevel);
+
+    /* verify that superclasses were created */
+    clone_midlevel = (class_b*) clone_lowlevel->parent;
+    CU_ASSERT_PTR_NOT_NULL_FATAL(clone_midlevel);
+    clone_toplevel = (class_a*) clone_midlevel->parent;
+    CU_ASSERT_PTR_NOT_NULL_FATAL(clone_toplevel);
+    CU_ASSERT_PTR_NULL_FATAL(clone_toplevel->parent);
+
+    /* verify that superclass and data clones are not references to old memory */
+    CU_ASSERT_NOT_EQUAL_FATAL(class_midlevel, clone_midlevel);
+    CU_ASSERT_NOT_EQUAL_FATAL(class_toplevel, clone_toplevel);
+   
+    if (class_midlevel->data != 0 && clone_midlevel->data != 0)
+        CU_ASSERT_NOT_EQUAL_FATAL(class_midlevel->data, clone_midlevel->data);
+    if (class_toplevel->a_string != 0 && clone_toplevel->a_string != 0)
+        CU_ASSERT_NOT_EQUAL_FATAL(class_toplevel->a_string, clone_toplevel->a_string);
+
+    /* we don't need to do this for the test, but here we illustrate   
+     * the etch C way of accessing superclass data from a subclass, 
+     * which is to traverse the parent chain to the class you want, 
+     * and cast the parent* to that class, if it is not so cast already. 
+     */
+    clone_midlevel->datasize = 1024; 
+    clone_midlevel->data = etch_malloc(clone_midlevel->datasize, 419);
+    memset(clone_midlevel->data, '-',  clone_midlevel->datasize);
+ 
+    /* destroy class c with all its superclasses and associated instance data */
+    class_lowlevel->destroy(class_lowlevel);
+
+    /* destroy class c clone and all its superclasses 
+     * if the clone of class_c had not properly cloned all its superclasses and 
+     * data, this would crash on attempt to free dangling pointer.
+     */
+    clone_lowlevel->destroy(clone_lowlevel);
+
+    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 */   
+}
+
+
+void test_primitive_byte(void)
+{
+    signed char v = 255;
+    etch_byte* newobj = new_byte(v);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(newobj); 
+    CU_ASSERT_EQUAL(v, newobj->value);
+
+    newobj->destroy(newobj); 
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);   
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();  
+}
+
+void test_primitive_bool(void)
+{
+    etch_boolean* newobj = new_boolean(100);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(newobj); 
+    CU_ASSERT_EQUAL(newobj->value, TRUE); 
+
+    newobj->destroy(newobj); 
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);   
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();   
+}
+
+void test_primitive_int8(void)
+{
+    signed char v = -1;
+    etch_int8* newobj = new_int8(v);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(newobj); 
+    CU_ASSERT_EQUAL(newobj->value,v); 
+
+    newobj->destroy(newobj); 
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);   
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();   
+}
+
+void test_primitive_int16(void)
+{
+    short v = -1;
+    etch_int16* newobj = new_int16(v);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(newobj); 
+    CU_ASSERT_EQUAL(newobj->value,v); 
+
+    newobj->destroy(newobj); 
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);   
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();   
+}
+
+void test_primitive_int32(void)
+{
+    int v = 1 << 31;
+    etch_int32* newobj = new_int32(v);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(newobj); 
+    CU_ASSERT_EQUAL(newobj->value,v); 
+
+    newobj->destroy(newobj); 
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);   
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();   
+}
+
+void test_primitive_int64(void)
+{
+    int64 v = ((int64)(1)) << 63;
+    etch_int64* newobj = new_int64(v);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(newobj); 
+    CU_ASSERT_EQUAL(newobj->value,v);  
+
+    newobj->destroy(newobj); 
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);   
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();  
+}
+
+void test_primitive_float(void)
+{
+    float v = (float)(3.14159);
+    etch_float* newobj = new_float(v);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(newobj); 
+    CU_ASSERT_EQUAL(newobj->value,v); 
+
+    newobj->destroy(newobj); 
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);   
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();   
+}
+
+void test_primitive_double(void)
+{
+    double v = (1 << 31) + 3.14159;
+    etch_double* newobj = new_double(v);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(newobj); 
+    CU_ASSERT_EQUAL(newobj->value,v); 
+
+    newobj->destroy(newobj); 
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);   
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();  
+}
+
+void test_primitive_string(void)
+{
+    wchar_t* v = L"it works!";
+    etch_string* newobj = new_string(v, ETCH_ENCODING_UTF16);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(newobj); 
+    CU_ASSERT_EQUAL(wcscmp(v, newobj->v.valw), 0);
+    
+    newobj->destroy(newobj); 
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);   
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();    
+}
+
+
+/** 
+ * test_nativearray_ctordtor()
+ * test that we can create and destroy an etch_nativearray with all memory accounted for
+ */
+void test_nativearray_ctordtor(void)
+{
+    etch_nativearray* bytearray_1x4 = new_nativearray(CLASSID_ARRAY_BYTE, sizeof(byte), 1, 4, 0, 0);  
+    CU_ASSERT_PTR_NOT_NULL_FATAL(bytearray_1x4); 
+
+    bytearray_1x4->destroy(bytearray_1x4);
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);   
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();    
+}
+
+
+/** 
+ * test_nativearray_1x1x4()
+ * test that we can populate and access a 1-dimensional array of byte
+ */
+void test_nativearray_1x1x4(void)
+{
+    int   i = 0, result = 0;
+    char  x[4] = {'a','b','c','d'}, thisx = 0;
+    const int numdimensions = 1, itemcount = 4;
+
+    etch_nativearray* a = new_nativearray 
+        (CLASSID_ARRAY_BYTE, sizeof(byte), numdimensions, itemcount, 0, 0);  
+    CU_ASSERT_PTR_NOT_NULL_FATAL(a); 
+
+    for(i = 0; i < itemcount; i++)     /* populate array */
+    {
+        result = a->put1(a, &x[i], i); /* insert value of i to ith slot */
+        CU_ASSERT_EQUAL(result, 0); 
+    }
+
+    for(i = 0; i < itemcount; i++)      /* read values out of array */
+    {
+        result = a->get1(a, &thisx, i); /* get value of ith slot into thisx */
+        CU_ASSERT_EQUAL(result, 0); 
+        CU_ASSERT_EQUAL(x[i], thisx); 
+    }
+
+    a->destroy(a);
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);   
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();    
+}
+
+
+/** 
+ * test_nativearray_1x4x4()
+ * test that we can populate and access a 1-dimensional array of int
+ */
+void test_nativearray_1x4x4(void)
+{
+    int i = 0, j = 0, result = 0;
+    const int numdimensions = 1, itemcount = 4;
+
+    etch_nativearray* a = new_nativearray 
+        (CLASSID_ARRAY_INT32, sizeof(int), numdimensions, itemcount, 0, 0);  
+    CU_ASSERT_PTR_NOT_NULL_FATAL(a); 
+
+    for(i = 0; i < itemcount; i++)  /* populate array */
+    {
+        result = a->put1(a, &i, i); /* insert value of i to ith slot */
+        CU_ASSERT_EQUAL(result, 0); 
+    }
+
+    for(i = 0; i < itemcount; i++)  /* read values out of array */
+    {
+        result = a->get1(a, &j, i); /* get value of ith slot into j */
+        CU_ASSERT_EQUAL(result, 0); 
+        CU_ASSERT_EQUAL(i, j); 
+    }
+
+    a->destroy(a);
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);   
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();    
+}
+
+
+/** 
+ * test_nativearray_1xstruct()
+ * test that we can populate and access a 1-dimensional array of struct
+ */
+void test_nativearray_1xstruct(void)
+{
+    int i = 0, result = 0;
+    const int numdimensions = 1, itemcount = 4;
+    struct x { int n; char c; };
+    struct x xgot  = {-1,'?'};
+    struct x xs[4] = { {0,'a'}, {1,'b'}, {2,'c'}, {3,'d'}, };
+
+    etch_nativearray* a = new_nativearray 
+        (CLASSID_ARRAY_STRUCT, sizeof(struct x), numdimensions, itemcount, 0, 0);  
+    CU_ASSERT_PTR_NOT_NULL_FATAL(a); 
+
+    for(i = 0; i < itemcount; i++)      /* populate array */
+    {
+        result = a->put1(a, &xs[i], i); /* insert xs[i] to ith slot */
+        CU_ASSERT_EQUAL(result, 0); 
+    }
+
+    for(i = 0; i < itemcount; i++)      /* read values out of array */
+    {
+        result = a->get1(a, &xgot, i);  /* get value of ith slot into xgot */
+        CU_ASSERT_EQUAL(result, 0); 
+        result = memcmp(&xgot, &xs[i], sizeof(struct x));
+        CU_ASSERT_EQUAL(result, 0); 
+    }
+
+    a->destroy(a);
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);   
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();    
+}
+
+
+/** 
+ * test_nativearray_2x1x4()
+ * test that we can populate and access a 2-dimensional array of byte
+ */
+void test_nativearray_2x1x4(void)
+{
+    int   i = 0, j = 0, result = 0;
+    char  x[2][4] = { {'a','b','c','d'}, {'e','f','g','h'}, }, thisx = 0;
+    const int numdimensions = 2, dim0count = 4, dim1count = 2;
+
+    /* note when creating arrays, the dimensions are specified in reverse,
+     * low-order dimension (dim0) first, e.g., for x[2][3][4], 
+     * dim0count is 4, dim1count is 3, dim2count is 2.
+     */
+    etch_nativearray* a = new_nativearray 
+        (CLASSID_ARRAY_BYTE, sizeof(byte), numdimensions, dim0count, dim1count, 0);  
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(a); 
+
+    for(i = 0; i < dim1count; i++)         /* populate array */
+    {
+        for(j = 0; j < dim0count; j++)      
+        {                                  /* insert x[i][j] to array[i][j] */
+            result = a->put2(a, &x[i][j], i, j); 
+            CU_ASSERT_EQUAL(result, 0); 
+        }
+    }
+
+    for(i = 0; i < dim1count; i++)         /* read array */
+    {
+        for(j = 0; j < dim0count; j++)     /* read values out of array */
+        {                                  /* get array[i][j] into thisx */
+            result = a->get2(a, &thisx, i, j); 
+            CU_ASSERT_EQUAL(result, 0); 
+            CU_ASSERT_EQUAL(x[i][j], thisx); 
+        }
+    }
+
+    a->destroy(a);
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);   
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();    
+}
+
+
+/** 
+ * test_nativearray_3xstruct()
+ * test that we can populate and access a 3-dimensional array of struct
+ */
+void test_nativearray_3xstruct(void)
+{
+    int i = 0, j = 0, k = 0, result = 0;
+    struct x  { int n; char c; };
+    struct x  xgot  = {-1,'?'};
+    struct x *xthis = 0;
+
+    struct x xs[2][3][4] = 
+    {   
+      {      
+         {  
+            {0,'a'}, {1,'b'}, {2,'c'}, {3,'d'},  
+         },
+         {  
+            {0,'e'}, {1,'f'}, {2,'g'}, {3,'h'},  
+         },
+         {  
+            {0,'i'}, {1,'j'}, {2,'k'}, {3,'l'},  
+         },
+      },
+      {
+         {  
+            {0,'m'}, {1,'n'}, {2,'o'}, {3,'p'},  
+         },
+         {  
+            {0,'q'}, {1,'r'}, {2,'s'}, {3,'t'},  
+         },
+         {  
+            {0,'u'}, {1,'v'}, {2,'w'}, {3,'x'},  
+         },
+      },    
+    };
+
+    const int numdimensions = 3, dim0count = 4, dim1count = 3, dim2count = 2;
+
+    etch_nativearray* a = new_nativearray (CLASSID_ARRAY_STRUCT, sizeof(struct x), 
+        numdimensions, dim0count, dim1count, dim2count);  
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(a); 
+
+    for(i = 0; i < dim2count; i++)   /* write array */       
+    {
+        for(j = 0; j < dim1count; j++)
+        {
+            for(k = 0; k < dim0count; k++)      
+            {                                   
+                result = a->put3(a, &xs[i][j][k], i, j, k); 
+                CU_ASSERT_EQUAL(result, 0); 
+            }
+        }
+    }
+
+    for(i = 0; i < dim2count; i++)     /* read array */
+    {
+        for(j = 0; j < dim1count; j++)
+        {
+            for(k = 0; k < dim0count; k++)      
+            {                                   
+                result = a->get3(a, &xgot, i, j, k);   
+                CU_ASSERT_EQUAL(result, 0); 
+                xthis = &xs[i][j][k];
+                result = memcmp(&xgot, xthis, sizeof(struct x));
+                CU_ASSERT_EQUAL(result, 0); 
+            }
+        }
+    }
+
+    a->destroy(a);
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);   
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();    
+}
+
+
+/** 
+ * test_arrayfrom_2x1x4()
+ * test that we can access a static 2-dimensional array of byte.
+ * also validates that our array subscripting calculations match those of
+ * the C compiler, since we map and access an array mapped by the compiler.
+ * also validates that the etch_nativearray will not attempt to destroy
+ * the byte vector of an array created in this manner. 
+ */
+void test_arrayfrom_2x1x4(void)
+{
+    int   i = 0, j = 0, result = 0;
+    char  x[2][4] = { {'a','b','c','d'}, {'e','f','g','h'}, }, thisx = 0;
+    const int numdimensions = 2, dim0count = 4, dim1count = 2;
+
+    etch_nativearray* a = new_nativearray_from(&x, CLASSID_ARRAY_BYTE,  
+        sizeof(byte), numdimensions, dim0count, dim1count, 0);  
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(a); 
+
+    for(i = 0; i < dim1count; i++)         /* read array */
+    {
+        for(j = 0; j < dim0count; j++)     /* read values out of array */
+        {                                  /* get array[i][j] into thisx */
+            result = a->get2(a, &thisx, i, j); 
+            CU_ASSERT_EQUAL(result, 0); 
+            CU_ASSERT_EQUAL(x[i][j], thisx); 
+        }
+    }
+
+    a->destroy(a);
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);   
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();    
+}
+
+
+/** 
+ * test_subarray()
+ * test that we can create a one-dimensional subarray from a 2-dimensional 
+ * array of byte, and that all memory is accounted for.
+ */
+void test_subarray(void)
+{
+    int   i = 0, j = 0, result = 0;
+    char  x[2][4] = { {'a','b','c','d'}, {'e','f','g','h'}, }, thisx = 0;
+    const int numdimensions = 2, dim0count = 4, dim1count = 2;
+    etch_nativearray *a0 = NULL, *a1 = NULL, *a2 = NULL;
+
+    etch_nativearray* a = new_nativearray_from(&x, CLASSID_ARRAY_BYTE,  
+        sizeof(byte), numdimensions, dim0count, dim1count, 0);  
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(a); 
+    a->content_obj_type = ETCHTYPEB_BYTE;
+    a->content_class_id = CLASSID_NONE; /* unwrapped content */
+
+    a0 = new_subarray(a, 0); /* test index 0 */
+    CU_ASSERT_PTR_NOT_NULL_FATAL(a0); 
+
+    CU_ASSERT_EQUAL(a0->is_content_owned, FALSE);
+    CU_ASSERT_EQUAL(a0->numdims,   a->numdims-1);
+    CU_ASSERT_EQUAL(a0->bytecount, a->bytecount/2);
+    CU_ASSERT_EQUAL(a0->itemsize,  a->itemsize);
+
+    CU_ASSERT_EQUAL(a0->content_obj_type, a->content_obj_type);
+    CU_ASSERT_EQUAL(a0->content_class_id, a->content_class_id);
+
+    /* recall that dimension and dimsize are stored low-order 
+     * dimension first, so dimension[0] and dimsize[0] are 
+     * the same for byte x[2][4] as for x[4] */
+    CU_ASSERT_EQUAL(a0->dimension[0], a->dimension[0]);  
+    CU_ASSERT_EQUAL(a0->dimsize[0],   a->dimsize[0]);  
+
+    for(i = 0; i < dim0count; i++)      
+    {                                  
+        result = a0->get1(a0, &thisx, i); 
+        CU_ASSERT_EQUAL(result, 0); 
+        CU_ASSERT_EQUAL(x[0][i], thisx); 
+    }
+
+    a1 = new_subarray(a, 1); /* test index 1 */
+    CU_ASSERT_PTR_NOT_NULL_FATAL(a1); 
+
+    CU_ASSERT_EQUAL(a1->is_content_owned, FALSE);
+    CU_ASSERT_EQUAL(a1->numdims,   a->numdims-1);
+    CU_ASSERT_EQUAL(a1->bytecount, a->bytecount/2);
+    CU_ASSERT_EQUAL(a1->itemsize,  a->itemsize);
+
+    CU_ASSERT_EQUAL(a1->content_obj_type, a->content_obj_type);
+    CU_ASSERT_EQUAL(a1->content_class_id, a->content_class_id);
+
+    /* recall that dimension and dimsize are stored low-order 
+     * dimension first, so dimension[0] and dimsize[0] are 
+     * the same for byte x[2][4] as for x[4] */
+    CU_ASSERT_EQUAL(a1->dimension[0], a->dimension[0]);
+    CU_ASSERT_EQUAL(a1->dimsize[0],   a->dimsize[0]);
+
+    for(i = 0; i < dim0count; i++)      
+    {                                  
+        result = a1->get1(a1, &thisx, i); 
+        CU_ASSERT_EQUAL(result, 0); 
+        CU_ASSERT_EQUAL(x[1][i], thisx); 
+    }
+
+    a2 = new_subarray(a, 2); /* test nonexistent index 2 */
+    CU_ASSERT_PTR_NULL(a2); 
+
+    a1->destroy(a1);
+    a0->destroy(a0);
+    a->destroy(a);
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);   
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();    
+}
+
+
+/*
+ * test_if_busted_subarray()
+ * this test is here to debug something that was either broken in subarray,
+ * or that was not broken, but rather the validator test using it was broken.
+ * verdict: subarray itemsize was broken, is fixed.
+ */
+void test_if_busted_subarray(void)  
+{
+    short x[2][3][4] = 
+      { { { 1,1,1,1, }, { 1,1,1,1, }, { 1,-1,32767, -32768, }, },
+        { { 1,1,1,1, }, { 1,1,1,1, }, { 1,-1,0xfffe,0xffff, }, },
+      };
+    const int numdimensions = 3, dim0count = 4, dim1count = 3, dim2count = 2;
+    int i=0, j=0, k=0;
+
+    etch_nativearray* a1 = new_nativearray_from(&x, CLASSID_ARRAY_INT16,  
+         sizeof(short), numdimensions, dim0count, dim1count, dim2count);  
+    a1->content_obj_type = ETCHTYPEB_INT16;
+    a1->content_class_id = CLASSID_NONE; /* unwrapped */
+
+    for(i = 0; i < dim2count; i++)
+    {
+        etch_nativearray* a2 = (etch_nativearray*) etch_nativearray_get_element(a1, i); 
+        CU_ASSERT_EQUAL_FATAL(is_etch_nativearray(a2), TRUE);
+        CU_ASSERT_EQUAL_FATAL(a2->bytecount,   a1->bytecount/a1->dimension[2]);
+        CU_ASSERT_EQUAL_FATAL(a2->numdims,     a1->numdims-1);
+        CU_ASSERT_EQUAL_FATAL(a2->dimsize[0],  a1->dimsize[0]);  
+        CU_ASSERT_EQUAL_FATAL(a2->dimsize[1],  a1->dimsize[1]);
+        CU_ASSERT_EQUAL_FATAL(a2->dimension[0],a1->dimension[0]);
+        CU_ASSERT_EQUAL_FATAL(a2->dimension[1],a1->dimension[1]);
+        CU_ASSERT_EQUAL_FATAL(a2->dimension[1],dim1count);
+
+        for(j = 0; j < dim1count; j++)
+        {
+            etch_nativearray* a3 = (etch_nativearray*) etch_nativearray_get_element(a2, j); 
+            CU_ASSERT_EQUAL_FATAL(is_etch_nativearray(a3), TRUE);
+            CU_ASSERT_EQUAL_FATAL(a3->bytecount,   a2->bytecount/a2->dimension[1]);
+            CU_ASSERT_EQUAL_FATAL(a3->numdims,     a2->numdims-1);
+            CU_ASSERT_EQUAL_FATAL(a3->dimsize[0],  a2->dimsize[0]);
+            CU_ASSERT_EQUAL_FATAL(a3->dimension[0],a2->dimension[0]);
+            CU_ASSERT_EQUAL_FATAL(a3->dimension[0],dim0count);
+
+            for(k = 0; k < dim0count; k++)
+            {   
+                short n_expected = 0, n_actual = 0;
+                etch_int16* shortobj  = (etch_int16*) etch_nativearray_get_element(a3, k); 
+                CU_ASSERT_EQUAL_FATAL(is_etch_int16(shortobj), TRUE);
+                n_expected = x[i][j][k];
+                n_actual   = shortobj->value;
+                CU_ASSERT_EQUAL_FATAL(n_expected, n_actual);
+
+                shortobj->destroy(shortobj);
+            }
+
+            a3->destroy(a3);
+        } 
+
+        a2->destroy(a2);   
+    }
+
+    a1->destroy(a1);
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);  
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();  /* start fresh for next test */
+}
+
+
+/** 
+ * test_get_element()
+ * test that we can get element[i] of a native array, and that element
+ * is another native array, or a wrapped etch object the same type as
+ * the array's content_obj_type and possibly content_class_id.
+ */
+void test_get_element(void)
+{
+    int   i = 0, j = 0, result = 0;
+    char  x[2][4] = { {'a','b','c','d'}, {'e','f','g','h'}, }, thisx = 0;
+    const int numdimensions = 2, dim0count = 4, dim1count = 2;
+    etch_nativearray *a1  = NULL;
+    objmask*   returnobj  = NULL;
+    etch_byte* retbyteobj = NULL;
+
+    etch_nativearray* a = new_nativearray_from(&x, CLASSID_ARRAY_BYTE,  
+        sizeof(byte), numdimensions, dim0count, dim1count, 0);  
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(a); 
+    a->content_obj_type = ETCHTYPEB_BYTE;
+    a->content_class_id = CLASSID_NONE; /* unwrapped content */
+
+    /* get element[1] from the array, expecting a byte[4] native array */
+    returnobj = etch_nativearray_get_element(a, 1); 
+
+    CU_ASSERT_EQUAL_FATAL(is_etch_nativearray(returnobj), TRUE);
+
+    a1 = (etch_nativearray*) returnobj;
+
+    CU_ASSERT_EQUAL(a1->is_content_owned, FALSE);
+    CU_ASSERT_EQUAL(a1->numdims,   a->numdims-1);
+    CU_ASSERT_EQUAL(a1->bytecount, a->bytecount/2);
+    CU_ASSERT_EQUAL(a1->itemsize,  a->itemsize);
+
+    CU_ASSERT_EQUAL(a1->content_obj_type, a->content_obj_type);
+    CU_ASSERT_EQUAL(a1->content_class_id, a->content_class_id);
+    CU_ASSERT_EQUAL(a1->dimension[0], a->dimension[0]);
+    CU_ASSERT_EQUAL(a1->dimsize[0],   a->dimsize[0]);
+
+    for(i = 0; i < dim0count; i++)      
+    {   
+        /* get element[i] from the subarray, expecting an etch_byte object */                               
+        returnobj = etch_nativearray_get_element(a1, i); 
+        CU_ASSERT_PTR_NOT_NULL_FATAL(returnobj); 
+        CU_ASSERT_EQUAL_FATAL(returnobj->class_id, CLASSID_PRIMITIVE_BYTE);
+
+        retbyteobj = (etch_byte*) returnobj; /* verify that wrapped byte */
+        thisx = retbyteobj->value;           /* matches original array */
+        CU_ASSERT_EQUAL(x[1][i], thisx); 
+
+        retbyteobj->destroy(retbyteobj);
+    }
+
+    a1->destroy(a1);
+    a->destroy(a);
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);   
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();    
+}
+
+
+/**
+ * main   
+ */
+int _tmain(int argc, _TCHAR* argv[])
+{
+    char c=0;
+    CU_pSuite ps = 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_etchobject");
+    ps = CU_add_suite("etchobject test suite", init_suite, clean_suite);
+    etch_watch_id = 0; 
+
+    CU_add_test(ps, "test primitive byte",    test_primitive_byte); 
+    CU_add_test(ps, "test primitive boolean", test_primitive_bool); 
+    CU_add_test(ps, "test primitive int8",    test_primitive_int8); 
+    CU_add_test(ps, "test primitive int16",   test_primitive_int16); 
+    CU_add_test(ps, "test primitive int32",   test_primitive_int32); 
+    CU_add_test(ps, "test primitive int64",   test_primitive_int64); 
+    CU_add_test(ps, "test primitive float",   test_primitive_float); 
+    CU_add_test(ps, "test primitive double",  test_primitive_double); 
+    CU_add_test(ps, "test primitive string",  test_primitive_string); 
+
+    CU_add_test(ps, "test tri-level inheritance", test_inheritance); 
+    CU_add_test(ps, "test clone and auto-construct superclass", test_clone); 
+
+    CU_add_test(ps, "test native array ctor",  test_nativearray_ctordtor);
+    CU_add_test(ps, "test 1-dim byte array",   test_nativearray_1x1x4);
+    CU_add_test(ps, "test 1-dim int array",    test_nativearray_1x4x4);
+    CU_add_test(ps, "test 1-dim struct array", test_nativearray_1xstruct);
+    CU_add_test(ps, "test 2-dim byte array",   test_nativearray_2x1x4);
+    CU_add_test(ps, "test 3-dim struct array", test_nativearray_3xstruct);
+    CU_add_test(ps, "test static 2-dim byte array", test_arrayfrom_2x1x4);
+    CU_add_test(ps, "test subarray",           test_subarray);
+    CU_add_test(ps, "test get array element",  test_get_element);
+    CU_add_test(ps, "test 3-dim int16 subarray ", test_if_busted_subarray);
+
+    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_flexbuf.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/test/common/test_flexbuf.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/test/common/test_flexbuf.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/test/common/test_flexbuf.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,463 @@
+/* $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_flexbuf.c
+ * test flex buffer
+ */
+#include "apr_time.h" /* some apr must be included first */
+#include "etchthread.h"
+#include <limits.h>
+#include <float.h>
+#include <tchar.h>
+#include <stdio.h>
+#include <conio.h>
+
+#include "cunit.h"
+#include "basic.h"
+#include "automated.h"
+
+#include "etchflexbuf.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;
+}
+
+etch_flexbuffer* fbuf = 0;
+
+
+/**
+ * returns number of errors
+ */
+int check_buf(etch_flexbuffer* buf, const int len, const int ndx, const int avl)
+{
+    int errors = 0, avail = (int) etch_flexbuf_avail(buf);
+    if (buf->datalen != len) errors++;
+    if (buf->index   != ndx) errors++;
+    if (avail        != avl) errors++;
+    return errors;
+}
+
+void testCreateAndDestroy0(void)
+{
+    fbuf = new_flexbuffer(0);
+    CU_ASSERT_PTR_NOT_NULL(fbuf);
+    
+    CU_ASSERT(etch_flexbuf_avail(fbuf) == 0);
+    
+    destroy_etch_flexbuffer(fbuf);
+}
+
+void testCreateAndDestroy1(void)
+{
+    fbuf = new_flexbuffer(-1);
+    CU_ASSERT_PTR_NOT_NULL(fbuf);
+    
+    fbuf = new_flexbuffer(1);
+    CU_ASSERT_PTR_NOT_NULL(fbuf);
+    CU_ASSERT(etch_flexbuf_avail(fbuf) == 0);
+
+    destroy_etch_flexbuffer(fbuf);
+    
+    fbuf = new_flexbuffer(4*1024*1024+1);
+    CU_ASSERT_PTR_NOT_NULL(fbuf);
+    destroy_etch_flexbuffer(fbuf); /* takes NULL */
+}
+
+void testCreateAndDestroy2(void)
+{
+    void *ptr = etch_malloc(1024, 0);
+    fbuf = etch_flexbuf_create_b(ptr, 1024, 0);
+    CU_ASSERT_PTR_NOT_NULL(fbuf);
+    CU_ASSERT(etch_flexbuf_avail(fbuf) == 0);
+
+    destroy_etch_flexbuffer(fbuf);
+}
+
+void testCreateAndDestroy3(void)
+{
+    void *ptr = etch_malloc(1024, 0);
+    fbuf = etch_flexbuf_create_bi(ptr, 1024, 100, 0);
+    CU_ASSERT_PTR_NOT_NULL(fbuf);
+    CU_ASSERT(etch_flexbuf_avail(fbuf) == 100);
+
+    destroy_etch_flexbuffer(fbuf);
+}
+
+void testPutAndGet(void)
+{
+    byte test_bytes[] = "testbytes";
+    void *test_buffer = etch_malloc(128, 0);
+    size_t n;
+    int i;
+    etch_flexbuffer *efb2;
+
+    fbuf = new_flexbuffer(0);
+
+    etch_flexbuf_put(fbuf, test_bytes, 0, strlen(test_bytes));
+
+    /* rewind the buffer */
+    etch_flexbuf_set_index(fbuf, 0);
+    n = etch_flexbuf_get(fbuf, test_buffer, 0, strlen(test_bytes));
+    CU_ASSERT(memcmp(test_buffer, test_bytes, n) == 0);
+
+    /* test put byte */
+    etch_flexbuf_set_index(fbuf, 0);
+    for(i = 0; i < (int) strlen(test_bytes); i++)
+        etch_flexbuf_put_byte(fbuf, test_bytes[i]);    
+
+    etch_flexbuf_set_index(fbuf, 0);
+    n = etch_flexbuf_get(fbuf, test_buffer, 0, strlen(test_bytes));
+    CU_ASSERT(memcmp(test_buffer, test_bytes, n) == 0);
+
+    /* test put from another buffer */
+    efb2 = new_flexbuffer(0);
+    etch_flexbuf_set_index(fbuf, 0);
+    etch_flexbuf_put_from(efb2, fbuf, n);
+
+    etch_flexbuf_set_index(efb2, 0);
+    n = etch_flexbuf_get(efb2, test_buffer, 0, strlen(test_bytes));
+    CU_ASSERT(memcmp(test_buffer, test_bytes, n) == 0);
+
+    etch_free(test_buffer);
+    destroy_etch_flexbuffer(fbuf);
+    destroy_etch_flexbuffer(efb2);
+}
+
+void testPutAndGetFully(void)
+{
+    byte test_bytes[] = "testbytes";
+    void *test_buffer = etch_malloc(128, 0);
+    size_t n;
+
+    fbuf = new_flexbuffer(0);
+
+    etch_flexbuf_put(fbuf, test_bytes, 0, strlen(test_bytes));
+
+    /* rewind the buffer */
+    etch_flexbuf_set_index(fbuf, 0);
+    n = etch_flexbuf_get_fully(fbuf, test_buffer, strlen(test_bytes));
+    CU_ASSERT(memcmp(test_buffer, test_bytes, n) == 0);
+
+    etch_flexbuf_set_index(fbuf, 0);
+    n = etch_flexbuf_get_fully(fbuf, test_buffer, 4);
+    CU_ASSERT(memcmp(test_buffer, test_bytes, 4) == 0);
+
+    etch_flexbuf_set_index(fbuf, 0);
+    n = etch_flexbuf_get_fully(fbuf, test_buffer, 32);
+    CU_ASSERT(memcmp(test_buffer, test_bytes, min(strlen(test_bytes), 32)) == 0);
+
+    etch_free(test_buffer);
+    destroy_etch_flexbuffer(fbuf);
+}
+
+
+void testPutAndGetByte(void)
+{
+    byte test_bytes[] = "testbytes";
+    void *test_buffer = etch_malloc(128, 0);
+    size_t n;
+    int i;
+
+    fbuf = new_flexbuffer(0);
+
+    etch_flexbuf_set_index(fbuf, 0);
+    for(i = 0; i < (int)strlen(test_bytes); i++)
+        etch_flexbuf_put_byte(fbuf, test_bytes[i]);    
+
+    etch_flexbuf_set_index(fbuf, 0);
+    n = etch_flexbuf_get(fbuf, test_buffer, 0, strlen(test_bytes));
+    CU_ASSERT(memcmp(test_buffer, test_bytes, n) == 0);
+
+
+    etch_free(test_buffer);
+    destroy_etch_flexbuffer(fbuf);
+}
+
+void testPutAndGetShort(void)
+{
+    short test_shorts[] = {SHRT_MIN, SHRT_MAX, 0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 0x7FFF, \
+        0xFFFF, 0xFFFE, -8192, -4096, -2048, -1024, -512, -256, -128, -64, -32, -16, -8, -4, -2, -1};
+
+    int i, result; short value = 0;
+
+    fbuf = new_flexbuffer(0);
+
+    for(i = 0; i < sizeof(test_shorts)/sizeof(short); i++)
+        etch_flexbuf_put_short(fbuf, test_shorts[i]);    
+
+    etch_flexbuf_set_index(fbuf, 0);
+
+    for(i = 0; i < sizeof(test_shorts)/sizeof(short); i++)
+    {
+        result = etch_flexbuf_get_short(fbuf, &value);
+        CU_ASSERT_EQUAL(result, 0);
+        CU_ASSERT_EQUAL(test_shorts[i], value); 
+    }   
+
+    destroy_etch_flexbuffer(fbuf);
+}
+
+
+void testPutAndGetInt(void)
+{
+    int test_ints[] = {INT_MIN, INT_MAX, 0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 0x7FFF, \
+        0xFFFF, 0xFFFFF, 0xFFFFFF, 0xFFFFFFF, 0xFFFFFFE,0x7FFFFFFF, 0xFFFFFFFF, 0xF7FFFFFF, 0xF6FFFFFF, \
+        0xF5FFFFFF, 0xF4FFFFFF, 0xF3FFFFFF, 0xF2FFFFFF, 0xF1FFFFFF, 0xF0FFFFFF, 0xFF0FFFFF, \
+        -8192, -4096, -2048, -1024, -512, -256, -128, -64, -32, -16, -8, -4, -2, -1};
+
+    int i;
+
+    fbuf = new_flexbuffer(0);
+
+    for(i = 0; i < sizeof(test_ints)/sizeof(int); i++)
+        etch_flexbuf_put_int(fbuf, test_ints[i]);    
+
+    etch_flexbuf_set_index(fbuf, 0);
+    for(i = 0; i < sizeof(test_ints)/sizeof(int); i++)
+    {   
+        int n = 0, m = test_ints[i], result;
+        result = etch_flexbuf_get_int(fbuf, &n);
+        CU_ASSERT_EQUAL(result, 0);
+        CU_ASSERT_EQUAL(n,m); 
+    }   
+
+    destroy_etch_flexbuffer(fbuf);
+}
+
+
+void testPutAndGetInt64(void)
+{
+    int64 test_int64s[] = {LONG_MIN, LONG_MAX, 0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 0x7FFF, \
+        0xFFFF, 0xFFFFF, 0xFFFFFF, 0xFFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF, 0xF7FFFFFF, 0xF6FFFFFF, 0x7FFFFFFFFFFFFFFF,\
+        0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFF0, 0xFFFFFFFFFFFFFF00, 0xFFFFFFFFFFFFF000, 0xFFFFFFFFFFFFF000, \
+        0xF5FFFFFF, 0xF4FFFFFF, 0xF3FFFFFF, 0xF2FFFFFF, 0xF1FFFFFF, 0xF0FFFFFF, 0xFF0FFFFF, \
+        -8192, -4096, -2048, -1024, -512, -256, -128, -64, -32, -16, -8, -4, -2, -1};
+
+    int i, result;
+
+    fbuf = new_flexbuffer(0);
+
+    for(i = 0; i < sizeof(test_int64s)/sizeof(int64); i++)
+        etch_flexbuf_put_long(fbuf, test_int64s[i]);    
+
+    etch_flexbuf_set_index(fbuf, 0);
+
+    for(i = 0; i < sizeof(test_int64s)/sizeof(int64); i++)
+    {   
+        int64 n = 0, m = test_int64s[i];
+        result = etch_flexbuf_get_long(fbuf, &n);
+        CU_ASSERT_EQUAL(result, 0);
+        CU_ASSERT_EQUAL(n,m); 
+    }   
+
+    destroy_etch_flexbuffer(fbuf);
+}
+
+
+void testPutAndGetFloat(void)
+{
+    float test_floats[] = {FLT_MIN, 0.0f, 1.1f, 2.2f, 4.4f, 8.8f, 16.16f, 32.32f, 64.64f, 128.128f, 256.256f, 512.512f,\
+        1024.1024f, 2048.2048f, 4096.4096f, 8192.8192f, FLT_MAX};
+
+    int i, result;
+
+    fbuf = new_flexbuffer(0);
+
+    for(i = 0; i < sizeof(test_floats)/sizeof(float); i++)
+        etch_flexbuf_put_float(fbuf, test_floats[i]);    
+
+    etch_flexbuf_set_index(fbuf, 0);
+
+    for(i = 0; i < sizeof(test_floats)/sizeof(float); i++)
+    {  
+        float x = 0.0; double diff; int is_equal;
+        const float y = test_floats[i];
+        result = etch_flexbuf_get_float(fbuf, &x);
+        CU_ASSERT_EQUAL(result, 0);
+        diff = (double) (y - x);
+        is_equal = fabs(diff) < 0.00001;
+        CU_ASSERT_EQUAL(is_equal, TRUE);
+    }
+            
+
+    destroy_etch_flexbuffer(fbuf);
+}
+
+void testPutAndGetDouble(void)
+{
+    double test_doubles[] = {DBL_MIN, 0.0, 1.1, 2.2, 4.4, 8.8, 16.16, 32.32, 64.64, 128.128, 256.256, 512.512,\
+        1024.1024, 2048.2048, 4096.4096, 8192.8192, DBL_MAX};
+
+    int i, result;
+
+    fbuf = new_flexbuffer(0);
+
+    for(i = 0; i < sizeof(test_doubles)/sizeof(double); i++)
+        etch_flexbuf_put_double(fbuf, test_doubles[i]);    
+
+    etch_flexbuf_set_index(fbuf, 0);
+
+    for(i = 0; i < sizeof(test_doubles)/sizeof(double); i++)
+    {   
+        double x, y = test_doubles[i];
+        result = etch_flexbuf_get_double(fbuf, &x);
+        CU_ASSERT_EQUAL(result, 0);
+        CU_ASSERT(x == y);  
+    }  
+
+    destroy_etch_flexbuffer(fbuf);
+}
+
+void testSetSize(void)
+{
+    etch_flexbuffer *fbuf = new_flexbuffer(0);
+
+    CU_ASSERT_EQUAL(0, etch_flexbuf_set_length(fbuf, 1024));
+    CU_ASSERT_EQUAL(0, check_buf(fbuf, 1024, 0, 1024));
+   
+    CU_ASSERT_EQUAL(0, etch_flexbuf_set_length(fbuf, 0));
+    CU_ASSERT_EQUAL(0, check_buf(fbuf, 0, 0, 0));
+
+    destroy_etch_flexbuffer(fbuf);
+}
+
+void testCompact(void)
+{
+    int i;
+    etch_flexbuffer *fbuf = new_flexbuffer(128);
+
+    for(i = 0; i < 10; i++)
+        etch_flexbuf_put_short(fbuf, 1);
+
+    etch_flexbuf_set_index(fbuf, 0);
+    etch_flexbuf_compact(fbuf);
+    CU_ASSERT(fbuf->index ==0);
+    CU_ASSERT(etch_flexbuf_avail(fbuf) == (10*sizeof(short)));
+
+    destroy_etch_flexbuffer(fbuf);
+}
+
+
+int _tmain(int argc, _TCHAR* argv[])
+{
+    char c=0;
+    CU_pSuite ps = NULL;
+    g_is_automated_test = argc > 1 && 0 != wcscmp(argv[1], L"-a");
+    if (CUE_SUCCESS != CU_initialize_registry()) return 0;
+    ps = CU_add_suite("suite flexbuffer", init_suite, clean_suite);
+    CU_set_output_filename("../test_flexbuffer");
+    etch_watch_id = 0; 
+
+    CU_add_test(ps, "testCreateAndDestroy0", testCreateAndDestroy0);
+    CU_add_test(ps, "testCreateAndDestroy1", testCreateAndDestroy1);
+    CU_add_test(ps, "testCreateAndDestroy2", testCreateAndDestroy2);
+    CU_add_test(ps, "testCreateAndDestroy3", testCreateAndDestroy3);
+    CU_add_test(ps, "testPutAndGet", testPutAndGet);
+    CU_add_test(ps, "testPutAndGetFully", testPutAndGetFully);
+    CU_add_test(ps, "testPutAndGetByte", testPutAndGetByte);
+    CU_add_test(ps, "testPutAndGetShort", testPutAndGetShort);
+    CU_add_test(ps, "testPutAndGetInt", testPutAndGetInt);
+    CU_add_test(ps, "testPutAndGetInt64", testPutAndGetInt64);
+    CU_add_test(ps, "testPutAndGetFloat", testPutAndGetFloat);
+    CU_add_test(ps, "testPutAndGetFloat", testPutAndGetDouble);
+    CU_add_test(ps, "testSetSize", testSetSize);
+    CU_add_test(ps, "testCompact", testCompact);
+
+    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();  printf("\n"); }     
+    CU_cleanup_registry();
+    return CU_get_error(); 
+}
\ No newline at end of file

Added: incubator/etch/trunk/binding-c/runtime/c/src/test/common/test_hashing.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/test/common/test_hashing.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/test/common/test_hashing.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/test/common/test_hashing.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,430 @@
+/* $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_hashing.c 
+ * test hashing of various complex items and associated memory management 
+ */
+#include "apr_time.h" /* some apr must be included first */
+#include "etch_binary_tdi.h"  /* must be included second */
+#include "etch_binary_tdo.h"
+
+#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_id_name.h"
+#include "etch_field.h"
+#include "etch_type.h"
+#include "etchlog.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";
+#define IS_DEBUG_CONSOLE FALSE
+
+
+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;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - 
+ * 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_is_automated_test, g_bytes_allocated;
+
+
+/**
+ * destroy_content_id_name()
+ * passed a content pointer out of the hashtable, interprets pointer as etch_id_name,
+ * frees the name string, and frees the etch_id_name shell.
+ */
+int destroy_content_id_name(void* content)
+{
+    etch_id_name*  idname = (etch_id_name*) content;
+    return idname? idname->destroy(idname): -1;
+    return 0;
+}
+
+
+/**
+ * destroy_content_field()
+ */
+int destroy_content_field(void* content)
+{
+    etch_field* field = (etch_field*) content;
+    return field? field->destroy(field): -1;
+}
+
+
+/**
+ * destroy_content_type()
+ */
+int destroy_content_type(void* content)
+{
+    etch_type* type = (etch_type*) content;
+    return type? type->destroy(type): -1;
+}
+
+
+/**
+ * test_idname_as_key
+ * tests that we can use etch_id_name (and etch_field and etch_type, since they
+ * are etch_id_name typedefs), as hashkeys, and subsequently acccess the original
+ * objects, individually clean up the keys, and ask hashtable to clean up the values.
+ */
+void test_idname_as_key_hashclean_values(void)
+{
+    etch_field*   my_field  = NULL;
+    etch_type*    my_type   = NULL;
+    etch_id_name* my_idname = NULL;
+
+    const int id_name_size = sizeof(etch_id_name);
+    const int field_size   = sizeof(etch_field);
+    const int type_size    = sizeof(etch_type);
+
+    etch_hashtable* myhashtab = NULL;  
+    etch_hashitem   hashbucket;
+    etch_hashitem*  myentry = &hashbucket; 
+
+    wchar_t* name1 = L"name number one";  
+    wchar_t* name2 = L"nombre numero dos";
+    wchar_t* name3 = L"le troisieme nom";
+
+    const size_t numElements1 = wcslen(name1);
+    const size_t numElements2 = wcslen(name2);
+    const size_t numElements3 = wcslen(name3);
+
+    const size_t numBytes1 = sizeof(wchar_t) * numElements1;
+    const size_t numBytes2 = sizeof(wchar_t) * numElements2;
+    const size_t numBytes3 = sizeof(wchar_t) * numElements3;
+
+    void* value1 = NULL, *value2 = NULL, *value3 = NULL;
+
+    int result = 0, result1 = 0, result2 = 0, result3 = 0;
+    unsigned bytes_allocated = 0;
+
+    value1 = etch_malloc(numBytes1 + 2, 0);   
+    value2 = etch_malloc(numBytes2 + 2, 0);  
+    value3 = etch_malloc(numBytes3 + 2, 0);  
+    wcscpy_s(value1, numElements1+1, name1);   
+    wcscpy_s(value2, numElements2+1, name2);   
+    wcscpy_s(value3, numElements3+1, name3);   
+
+    myhashtab = new_hashtable(16);  
+    myhashtab->is_readonly_keys   = TRUE;  /* keys will NOT be freed on destroy */
+    myhashtab->is_readonly_values = FALSE; /* values WILL be freed on destroy */
+    myhashtab->is_tracked_memory  = TRUE;  /* hashtable will use etch_free */
+   
+    my_idname = new_id_name(name1);
+    my_field  = new_field(name2);
+    my_type   = new_type(name3);  
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(my_idname);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(my_field);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(my_type);
+
+    /* ensure constructors populated the hash key */
+    CU_ASSERT_NOT_EQUAL_FATAL(my_idname->hashkey,0);
+    CU_ASSERT_NOT_EQUAL_FATAL(my_field->hashkey,0);
+    CU_ASSERT_NOT_EQUAL_FATAL(my_type->hashkey,0);
+
+    /* ensure constructors populated the wire id */
+    CU_ASSERT_NOT_EQUAL_FATAL(my_idname->id,0);
+    CU_ASSERT_NOT_EQUAL_FATAL(my_field->id,0);
+    CU_ASSERT_NOT_EQUAL_FATAL(my_type->id,0);
+
+    result = myhashtab->vtab->inserth(myhashtab->realtable, my_idname, value1, 0, 0);
+    CU_ASSERT_EQUAL_FATAL(result,0);
+
+    result = myhashtab->vtab->inserth(myhashtab->realtable, my_field, value2, 0, 0);
+    CU_ASSERT_EQUAL_FATAL(result,0);
+
+    result = myhashtab->vtab->inserth(myhashtab->realtable, my_type, value3, 0, 0);
+    CU_ASSERT_EQUAL_FATAL(result,0);
+
+    result = myhashtab->vtab->findh(myhashtab->realtable, my_idname->hashkey, myhashtab, &myentry);
+    CU_ASSERT_EQUAL(result,0);
+    CU_ASSERT_PTR_NOT_NULL(myentry->key);
+    CU_ASSERT_PTR_NOT_NULL(myentry->value);
+    result = destroy_content_id_name(myentry->key);
+    CU_ASSERT_EQUAL(result,0);    
+
+    result = myhashtab->vtab->findh(myhashtab->realtable, my_field->hashkey, myhashtab, &myentry);
+    CU_ASSERT_EQUAL(result,0);
+    CU_ASSERT_PTR_NOT_NULL(myentry->key);
+    CU_ASSERT_PTR_NOT_NULL(myentry->value);
+    result = destroy_content_field(myentry->key);
+    CU_ASSERT_EQUAL(result,0);   
+
+    result = myhashtab->vtab->findh(myhashtab->realtable, my_type->hashkey, myhashtab, &myentry);
+    CU_ASSERT_EQUAL(result,0);
+    CU_ASSERT_PTR_NOT_NULL(myentry->key);
+    CU_ASSERT_PTR_NOT_NULL(myentry->value);
+    result = destroy_content_type(myentry->key);
+    CU_ASSERT_EQUAL(result,0);  
+
+    /** above we looked up each item and freed memory for the id_name, field, and type keys,
+     * but not for their values. when we created the map we specified is_readonly_keys, so the
+     * map destructor will free memory for the value content, but not for the key content. */
+    myhashtab->destroy(myhashtab);
+
+    bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);  /* verify all memory freed */
+    CU_ASSERT_EQUAL(bytes_allocated, 0);  
+    memtable_clear();  /* start fresh for next test */   
+}
+
+
+/**
+ * test_idname_as_key
+ * tests that we can use etch_id_name (and etch_field and etch_type, since they
+ * are etch_id_name typedefs), as hashkeys, and subsequently acccess the original
+ * objects and clean up both the keys and values.
+ */
+void test_idname_as_key_hashclean_none(void)
+{
+    etch_field*   my_field  = NULL;
+    etch_type*    my_type   = NULL;
+    etch_id_name* my_idname = NULL;
+
+    const int id_name_size = sizeof(etch_id_name);
+    const int field_size   = sizeof(etch_field);
+    const int type_size    = sizeof(etch_type);
+
+    etch_hashtable* myhashtab = NULL;  
+    etch_hashitem   hashbucket;
+    etch_hashitem*  myentry = &hashbucket; 
+
+    wchar_t* name1 = L"name number one";  
+    wchar_t* name2 = L"nombre numero dos";
+    wchar_t* name3 = L"le troisieme nom";
+
+    const size_t numElements1 = wcslen(name1);
+    const size_t numElements2 = wcslen(name2);
+    const size_t numElements3 = wcslen(name3);
+
+    const size_t numBytes1 = sizeof(wchar_t) * numElements1;
+    const size_t numBytes2 = sizeof(wchar_t) * numElements2;
+    const size_t numBytes3 = sizeof(wchar_t) * numElements3;
+    void* value1 = NULL, *value2 = NULL, *value3 = NULL;
+
+    size_t actlen1 = 0, actlen2 = 0, actlen3 = 0;
+    int result = 0, result1 = 0, result2 = 0, result3 = 0;
+    unsigned bytes_allocated = 0;
+
+    value1 = etch_malloc(numBytes1 + 2, 0);   
+    value2 = etch_malloc(numBytes2 + 2, 0);  
+    value3 = etch_malloc(numBytes3 + 2, 0);  
+    wcscpy_s(value1, numElements1+1, name1);   
+    wcscpy_s(value2, numElements2+1, name2);   
+    wcscpy_s(value3, numElements3+1, name3);   
+
+    actlen1 = wcslen(name1);  actlen2 = wcslen(name2); actlen3 = wcslen(name3);
+
+    myhashtab = new_hashtable(16);  
+    myhashtab->is_readonly_keys   = TRUE; /* keys will be freed on destroy  */
+    myhashtab->is_readonly_values = TRUE; /* values will be freed on destroy */
+    myhashtab->is_tracked_memory  = TRUE; /* hashtable will etch_free content */
+
+    /* here we are creating id_name, field, and type objects using names allocated
+     * on out local stack. therefore the cleanup parameters must be set to not free 
+     * memory for the name part, or we will crash. note that name is part of the 
+     * key structs, and is also the value of the hashed key/value pair, however 
+     * we etch_malloc'ed memory for the values and copied our stack strings into it,
+     * so we will want to free the value memory. we could ask the hashtable to do
+     * so but we'll do it manually here instead.
+     */
+    my_idname = new_id_name(name1);
+    my_field  = new_field(name2);
+    my_type   = new_type(name3);
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(my_idname);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(my_field);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(my_type);
+
+   /* ensure constructors populated the hash key */
+    CU_ASSERT_NOT_EQUAL_FATAL(my_idname->hashkey,0);
+    CU_ASSERT_NOT_EQUAL_FATAL(my_field->hashkey,0);
+    CU_ASSERT_NOT_EQUAL_FATAL(my_type->hashkey,0);
+
+    /* ensure constructors populated the id (hash of name) */
+    CU_ASSERT_NOT_EQUAL_FATAL(my_idname->id,0);
+    CU_ASSERT_NOT_EQUAL_FATAL(my_field->id,0);
+    CU_ASSERT_NOT_EQUAL_FATAL(my_type->id,0);
+
+    result = myhashtab->vtab->inserth(myhashtab->realtable, my_idname, value1, 0, 0);
+    CU_ASSERT_EQUAL_FATAL(result,0);
+
+    result = myhashtab->vtab->inserth(myhashtab->realtable, my_field, value2, 0, 0);
+    CU_ASSERT_EQUAL_FATAL(result,0);
+
+    result = myhashtab->vtab->inserth(myhashtab->realtable, my_type, value3, 0, 0);
+    CU_ASSERT_EQUAL_FATAL(result,0);
+
+    result = myhashtab->vtab->findh(myhashtab->realtable, my_idname->hashkey, myhashtab, &myentry);
+    CU_ASSERT_EQUAL(result,0);
+    CU_ASSERT_PTR_NOT_NULL(myentry->key);
+    CU_ASSERT_PTR_NOT_NULL(myentry->value);
+    result = destroy_content_id_name(myentry->key);  
+    CU_ASSERT_EQUAL(result,0);  
+    etch_free(myentry->value); 
+
+    result = myhashtab->vtab->findh(myhashtab->realtable, my_field->hashkey, myhashtab, &myentry);
+    CU_ASSERT_EQUAL(result,0);
+    CU_ASSERT_PTR_NOT_NULL(myentry->key);
+    CU_ASSERT_PTR_NOT_NULL(myentry->value);
+    result = destroy_content_field(myentry->key);  
+    CU_ASSERT_EQUAL(result,0); 
+    etch_free(myentry->value);  
+
+    result = myhashtab->vtab->findh(myhashtab->realtable, my_type->hashkey, myhashtab, &myentry);
+    CU_ASSERT_EQUAL(result,0);
+    CU_ASSERT_PTR_NOT_NULL(myentry->key);
+    CU_ASSERT_PTR_NOT_NULL(myentry->value);
+    result = destroy_content_type(myentry->key);  
+    CU_ASSERT_EQUAL(result,0); 
+    etch_free(myentry->value);  
+
+    myhashtab->destroy(myhashtab);  /* hashtable was asked to not free any content */
+
+    bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);  /* verify all memory freed */
+    CU_ASSERT_EQUAL(bytes_allocated, 0);  
+    memtable_clear();  /* start fresh for next test */ 
+}
+
+
+
+int _tmain(int argc, _TCHAR* argv[])
+{
+    CU_pSuite pSuite = 0; char c=0; 
+    if (CUE_SUCCESS != CU_initialize_registry()) return -1;
+    g_is_automated_test = argc > 1 && 0 != wcscmp(argv[1], L"-a");
+    pSuite = CU_add_suite("suite_hashing", init_suite, clean_suite);
+    CU_set_output_filename("../test_hashing");
+    etch_watch_id = 0; 
+
+    CU_add_test(pSuite, "test hash id_name etc - auto-cleanup values", test_idname_as_key_hashclean_values);
+    CU_add_test(pSuite, "test hash id_name etc - no auto-cleanup", test_idname_as_key_hashclean_none);
+
+    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(); 
+}
+