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 [22/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_arraylist.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/test/common/test_arraylist.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/test/common/test_arraylist.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/test/common/test_arraylist.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,693 @@
+/* $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_arraylist.c -- test etch_arraylist
+ */
+#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"
+
+#define OBJSIG 0xbadf00d
+#define NUMITEMS 3
+#define ETCHTYPEA_TESTOBJ 0xff
+
+
+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;
+}
+
+int 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 new_arraylist()
+ */
+void test_new_arraylist(void)
+{
+    const int TESTSIZE = 2048, TESTDELTA = 1024;
+
+    etch_arraylist* list = new_arraylist(0, 0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(list);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(list->base);
+    CU_ASSERT_EQUAL(list->count,0);
+    CU_ASSERT_EQUAL(list->size,  ETCHARRAYLIST_DEFSIZE * sizeof(void**));
+    CU_ASSERT_EQUAL(list->delta, ETCHARRAYLIST_DEFSIZE * sizeof(void**));
+
+    arraylist_destroy(list,TRUE); /* free memory and ensure nothing remains allocated */
+    g_bytes_allocated = etch_showmem(TRUE,FALSE);
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+
+    list = new_arraylist(TESTSIZE, TESTDELTA);
+    CU_ASSERT_EQUAL(list->count,0);
+    CU_ASSERT_EQUAL(list->size,  TESTSIZE  * sizeof(void**));
+    CU_ASSERT_EQUAL(list->delta, TESTDELTA * sizeof(void**));
+    memset(list->base, 0xff, list->size); /* try write to entire buffer */
+
+    arraylist_destroy(list,TRUE); /* free memory; ensure nothing remains allocated */
+    g_bytes_allocated = etch_showmem(TRUE,FALSE);
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+    memtable_clear(); /* start fresh for next test */
+}
+
+
+/* 
+ * test arraylist_add()
+ */
+void test_add(void)
+{
+   TESTOBJ *x1, *x2;
+   etch_arraylist* list = new_arraylist(8,0); 
+   CU_ASSERT_EQUAL(list->base[0],NULL);
+   CU_ASSERT_EQUAL(list->base[1],NULL);
+
+   arraylist_add(list, x1 = objfactory(1));
+   CU_ASSERT_EQUAL(list->count,1);
+   CU_ASSERT_EQUAL(list->base[0], x1); /* ensure item's buffer slot OK */
+
+   arraylist_add(list, x2 = objfactory(2));
+   CU_ASSERT_EQUAL(list->count,2);
+   CU_ASSERT_EQUAL(list->base[1], x2); /* ensure item's buffer slot OK */
+
+   arraylist_destroy(list,TRUE); /* free memory including test objects */
+   g_bytes_allocated = etch_showmem(TRUE,FALSE);
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+   memtable_clear(); /* start fresh for next test */
+}
+
+
+/* 
+ * test arraylist_destroy()
+ */
+void test_destroy(void)
+{
+    CU_PASS("tested in all previous and subsequent tests"); 
+}
+
+
+/* 
+ * test arraylist_remove()
+ */
+void test_remove_firstitem(void)
+{
+   TESTOBJ *x1, *x2;
+   etch_arraylist* list = new_arraylist(8,0); 
+
+   arraylist_add(list, x1 = objfactory(1));   /* allocate and add test obj x1 */
+   arraylist_add(list, x2 = objfactory(2));   /* allocate and add test obj x2 */
+
+   CU_ASSERT_EQUAL_FATAL(list->count,2);
+   CU_ASSERT_EQUAL(list->base[0], x1);  
+   CU_ASSERT_EQUAL(list->base[1], x2);  
+   bytes_prior = etch_showmem(0,0);
+
+   arraylist_remove(list,0,TRUE);    /* remove list[0] and free its x1 memory */
+
+   CU_ASSERT_EQUAL_FATAL(list->count,1); 
+   g_bytes_allocated = etch_showmem(0,0);  /* ensure TESTBOJ bytes were freed */
+   CU_ASSERT_EQUAL(bytes_prior - g_bytes_allocated, sizeof(TESTOBJ));
+   CU_ASSERT_EQUAL(list->base[1], NULL); /* ensure item's buffer slot cleared */
+
+   CU_ASSERT_EQUAL_FATAL(list->base[0], x2);   /* ensure item 1 is now item 0 */
+   
+   arraylist_remove(list,0,FALSE); /* remove list[0] but don't free x2 memory */
+
+   bytes_prior = etch_showmem(0,0);  
+   CU_ASSERT_EQUAL(list->count,0); /* ensure no bytes were freed */
+   CU_ASSERT_EQUAL(bytes_prior, g_bytes_allocated);
+   CU_ASSERT_EQUAL(list->base[0], NULL); /* ensure item's buffer slot cleared */
+
+   /* finally free the last test object, which would have been freed in the
+    * prior arraylist_remove() had we not specified to not do so. Also if we
+    * did not free it here it would be freed in the memtable_clear() below.
+    */
+   etch_free(x2);  
+
+   arraylist_destroy(list,TRUE); /* destroy the arraylist */
+
+   g_bytes_allocated = etch_showmem(0,0);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+   memtable_clear();  /* start fresh for next test */   
+}
+
+
+/* 
+ * test arraylist_remove()
+ */
+void test_remove_lastitem(void)
+{
+   TESTOBJ *x1, *x2, *x3;
+   etch_arraylist* list = new_arraylist(8,0); 
+
+   arraylist_add(list, x1 = objfactory(1));   /* allocate and add test obj x1 */
+   arraylist_add(list, x2 = objfactory(2));   /* allocate and add test obj x2 */
+   arraylist_add(list, x3 = objfactory(3));   /* allocate and add test obj x3 */
+   CU_ASSERT_EQUAL_FATAL(list->count,3);
+
+   CU_ASSERT_EQUAL(list->base[2], x3);
+
+   arraylist_remove(list,2,TRUE);    /* remove list[2] and free its x1 memory */
+
+   CU_ASSERT_EQUAL(list->base[2], NULL); /* ensure item's buffer slot cleared */
+
+   CU_ASSERT_EQUAL_FATAL(list->base[0], x1);    
+   CU_ASSERT_EQUAL_FATAL(list->base[1], x2); 
+   
+   /* destroy the arraylist freeing the test object content as well */
+   arraylist_destroy(list,TRUE); 
+
+   g_bytes_allocated = etch_showmem(0,0);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+   memtable_clear();  /* start fresh for next test */   
+}
+
+
+void dumplist(etch_arraylist* list)
+{
+    int i=0; char c=0;
+    const int n = list->count;
+    printf("\ndumping list ...\n"); fflush(stdout);
+    for(; i < n; i++)
+    {   TESTOBJ* item = list->base[i];
+        printf("\n list[%d] %d\n", i, item->id); fflush(stdout);
+    }
+    
+    printf("\nany key ..."); while(!c) c = _getch(); printf("\n"); 
+}
+
+
+/* 
+ * removetest_comparator()
+ * comparator for test_remove() arraylist_indexof
+ * note that the test value is passed as an int not an object
+ */
+int removetest_comparator(void* testvalue, void* listcontent)
+{
+    const int ivalue  = (int) (size_t) testvalue;
+    TESTOBJ*  listobj = (TESTOBJ*) listcontent;
+    int jvalue = listobj->id;
+    return ivalue < jvalue? -1: ivalue > jvalue? 1: 0;
+} 
+
+
+/* 
+ * test_remove()
+ * remove items 
+ */
+void test_remove(void)
+{
+    const int numitems = 10;
+    int i=0, curritems = numitems;
+    etch_arraylist* list = new_arraylist(64,0); 
+
+    for(; i < numitems; i++)        
+        arraylist_add(list, objfactory(i));
+        
+    #if IS_DEBUG_CONSOLE
+    dumplist(list);
+    #endif
+
+    for(i=2; i < numitems; i+=2)
+    {
+        /* remove the list content whose value is i */
+        const int index = arraylist_indexof(list, (void*)(size_t) i, 0, removetest_comparator);
+        CU_ASSERT_NOT_EQUAL(index, -1);
+
+        if (index >= 0)
+        {
+            if (0 == arraylist_remove(list, index, TRUE))
+                curritems--;
+            
+            #if IS_DEBUG_CONSOLE
+            dumplist(list);
+            #endif
+        }
+        else
+        {
+            #if IS_DEBUG_CONSOLE
+            printf("could not remove list content %d\n", i);
+            #endif
+        }
+
+        CU_ASSERT_EQUAL(list->count, curritems);
+    }
+
+    /* destroy the arraylist freeing the test object content as well */
+    arraylist_destroy(list,TRUE); 
+
+    g_bytes_allocated = etch_showmem(0,0);  /* verify all memory freed */
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();  /* start fresh for next test */   
+}
+
+
+/* 
+ * test arraylist_insert()
+ */
+void test_insert_first(void)
+{
+   TESTOBJ *x1, *x2, *x3;
+   etch_arraylist* list = new_arraylist(8,0); 
+
+   arraylist_add(list, x2 = objfactory(2));   /* allocate and add test obj x2 */
+   arraylist_add(list, x3 = objfactory(3));   /* allocate and add test obj x3 */
+
+   /* insert test obj x1 into slot 0 */
+   arraylist_insert(list, 0, x1 = objfactory(1)); 
+
+   CU_ASSERT_EQUAL_FATAL(list->count,3);
+   CU_ASSERT_EQUAL(list->base[0], x1);
+   CU_ASSERT_EQUAL(list->base[1], x2);    
+   CU_ASSERT_EQUAL(list->base[2], x3);   
+
+   /* destroy the arraylist freeing the test object content as well */
+   arraylist_destroy(list,TRUE); 
+
+   g_bytes_allocated = etch_showmem(0,0);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+   memtable_clear();  /* start fresh for next test */   
+}
+
+
+/* 
+ * test arraylist_insert()
+ */
+void test_insert_mid(void)
+{
+   TESTOBJ *x1, *x2, *x3;
+   etch_arraylist* list = new_arraylist(8,0); 
+
+   arraylist_add(list, x1 = objfactory(1));    
+   arraylist_add(list, x3 = objfactory(3));    
+
+   /* insert test obj x1 into slot 1 */
+   arraylist_insert(list, 1, x2 = objfactory(2)); 
+
+   CU_ASSERT_EQUAL_FATAL(list->count,3);
+   CU_ASSERT_EQUAL(list->base[0], x1);
+   CU_ASSERT_EQUAL(list->base[1], x2);    
+   CU_ASSERT_EQUAL(list->base[2], x3);   
+
+   /* destroy the arraylist freeing the test object content as well */
+   arraylist_destroy(list,TRUE); 
+
+   g_bytes_allocated = etch_showmem(0,0);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+   memtable_clear();  /* start fresh for next test */   
+}
+
+
+/* 
+ * test arraylist_insert()
+ */
+void test_insert_end(void)
+{
+   TESTOBJ *x1, *x2, *x3;
+   etch_arraylist* list = new_arraylist(8,0); 
+
+   arraylist_add(list, x1 = objfactory(1));    
+   arraylist_add(list, x2 = objfactory(2));   
+
+   /* insert test obj x1 into slot 1 */
+   arraylist_insert(list, 2, x3 = objfactory(3)); 
+
+   CU_ASSERT_EQUAL_FATAL(list->count,3);
+   CU_ASSERT_EQUAL(list->base[0], x1);
+   CU_ASSERT_EQUAL(list->base[1], x2);    
+   CU_ASSERT_EQUAL(list->base[2], x3);   
+
+   /* destroy the arraylist freeing the test object content as well */
+   arraylist_destroy(list,TRUE); 
+
+   g_bytes_allocated = etch_showmem(0,0);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+   memtable_clear();  /* start fresh for next test */   
+}
+
+
+/* 
+ * test arraylist_containsp(), arraylist_contains()
+ */
+void test_contains(void)
+{
+   TESTOBJ *x1, *x2, *x3;
+   int result = 0;
+   etch_arraylist* list = new_arraylist(8,0); 
+
+   arraylist_add(list, x1 = objfactory(1));    
+   arraylist_add(list, x2 = objfactory(2));
+   arraylist_add(list, x3 = objfactory(3)); 
+
+   result = arraylist_containsp(list, x1, 0); 
+   CU_ASSERT_EQUAL(result, TRUE); 
+
+   result = arraylist_containsp(list, x2, 0); 
+   CU_ASSERT_EQUAL(result, TRUE); 
+
+   result = arraylist_containsp(list, x3, 0); 
+   CU_ASSERT_EQUAL(result, TRUE); 
+
+   result = arraylist_containsp(list, x1, 1); /* start at index 1 */ 
+   CU_ASSERT_EQUAL(result, FALSE); 
+
+   result = arraylist_contains(list, x1, 0, al_comparator);
+   CU_ASSERT_EQUAL(result, TRUE); 
+
+   result = arraylist_contains(list, x2, 0, al_comparator);
+   CU_ASSERT_EQUAL(result, TRUE); 
+
+   result = arraylist_contains(list, x3, 0, al_comparator);
+   CU_ASSERT_EQUAL(result, TRUE); 
+
+   result = arraylist_contains(list, x1, 2, al_comparator); /* start at index 2 */ 
+   CU_ASSERT_EQUAL(result, FALSE); 
+
+   /* destroy the arraylist freeing the test object content as well */
+   arraylist_destroy(list,TRUE); 
+
+   g_bytes_allocated = etch_showmem(0,0);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+   memtable_clear();  /* start fresh for next test */   
+}
+
+/* 
+ * test arraylist_indexofp(), arraylist_indexof()
+ */
+void test_indexof(void)
+{
+   TESTOBJ *x1, *x2, *x3;
+   int result = 0;
+   etch_arraylist* list = new_arraylist(8,0); 
+   x3 = objfactory(3);
+
+   arraylist_add(list, x1 = objfactory(1));    
+   arraylist_add(list, x2 = objfactory(2));
+
+   result = arraylist_indexofp(list, x1, 0); 
+   CU_ASSERT_EQUAL(result, 0); 
+
+   result = arraylist_indexofp(list, x2, 0); 
+   CU_ASSERT_EQUAL(result, 1); 
+
+   result = arraylist_indexofp(list, x3, 0); 
+   CU_ASSERT_EQUAL(result, -1);  /* not found */
+
+   result = arraylist_indexofp(list, x1, 1); /* start at index 1 */ 
+   CU_ASSERT_EQUAL(result, -1); 
+
+   result = arraylist_indexof(list, x1, 0, al_comparator);
+   CU_ASSERT_EQUAL(result, 0); 
+
+   result = arraylist_indexof(list, x2, 0, al_comparator);
+   CU_ASSERT_EQUAL(result, 1); 
+
+   result = arraylist_indexof(list, x3, 0, al_comparator);
+   CU_ASSERT_EQUAL(result, -1); 
+
+   result = arraylist_indexof(list, x1, 1, al_comparator);   
+   CU_ASSERT_EQUAL(result, -1); 
+
+   etch_free(x3);
+
+   /* destroy the arraylist freeing the test object content as well */
+   arraylist_destroy(list,TRUE); 
+
+   g_bytes_allocated = etch_showmem(0,0);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+   memtable_clear();  /* start fresh for next test */   
+}
+
+
+/* 
+ * test arraylist_get()
+ */
+void test_get(void)
+{
+   TESTOBJ *x1, *x2, *x3, *x;
+   etch_arraylist* list = new_arraylist(8,0); 
+
+   arraylist_add(list, x1 = objfactory(1));    
+   arraylist_add(list, x2 = objfactory(2));
+   arraylist_add(list, x3 = objfactory(3));
+
+   x = arraylist_get(list,0); 
+   CU_ASSERT_EQUAL(x, x1); 
+   CU_ASSERT_EQUAL(((TESTOBJ*)x)->signature, OBJSIG); 
+   CU_ASSERT_EQUAL(((TESTOBJ*)x)->id, 1); 
+
+   x = arraylist_get(list,1); 
+   CU_ASSERT_EQUAL(x, x2); 
+   CU_ASSERT_EQUAL(((TESTOBJ*)x)->signature, OBJSIG); 
+   CU_ASSERT_EQUAL(((TESTOBJ*)x)->id, 2); 
+
+   x = arraylist_get(list,2); 
+   CU_ASSERT_EQUAL(x, x3); 
+   CU_ASSERT_EQUAL(((TESTOBJ*)x)->signature, OBJSIG); 
+   CU_ASSERT_EQUAL(((TESTOBJ*)x)->id, 3); 
+
+   x = arraylist_get(list,3); 
+   CU_ASSERT_EQUAL(x, NULL); 
+
+   /* destroy the arraylist freeing the test object content as well */
+   arraylist_destroy(list,TRUE); 
+
+   g_bytes_allocated = etch_showmem(0,0);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+   memtable_clear();  /* start fresh for next test */   
+}
+
+
+/* 
+ * test arraylist_set()
+ */
+void test_set(void)
+{
+   int result = 0;
+   TESTOBJ *x1, *x2, *x3, *x4, *x5;
+   etch_arraylist* list = new_arraylist(8,0); 
+
+   arraylist_add(list, x1 = objfactory(1));    
+   arraylist_add(list, x2 = objfactory(2));
+   arraylist_add(list, x3 = objfactory(3));
+
+   result = arraylist_set(list, 0, x4 = objfactory(4)); 
+   CU_ASSERT_EQUAL(result,0); 
+   CU_ASSERT_EQUAL(list->base[0], x4); 
+
+   result = arraylist_set(list, 2, x5 = objfactory(5)); 
+   CU_ASSERT_EQUAL(result,0); 
+   CU_ASSERT_EQUAL(list->base[2], x5); 
+
+   result = arraylist_set(list, 3, x5); /* attempt replace beyond end of list */
+   CU_ASSERT_EQUAL(result,-1); 
+
+   /* destroy the arraylist without freeing the test object content */
+   arraylist_destroy(list,FALSE); 
+
+   etch_free(x1); etch_free(x2); etch_free(x3); etch_free(x4); etch_free(x5); 
+
+   g_bytes_allocated = etch_showmem(0,0);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+   memtable_clear();  /* start fresh for next test */   
+}
+
+
+/* 
+ * test arraylist auto reallocation
+ */
+void test_expand(void)
+{
+   const int INIT_MAX = 4;
+   TESTOBJ *x1, *x2, *x3, *x4, *x5, *x6, *x;
+   etch_arraylist* list = new_arraylist(INIT_MAX,0); 
+
+   arraylist_add(list, x1 = objfactory(1));    
+   arraylist_add(list, x2 = objfactory(2));
+   arraylist_add(list, x3 = objfactory(3));
+   arraylist_add(list, x4 = objfactory(4));
+   CU_ASSERT_EQUAL(list->size, INIT_MAX * sizeof(void**)); 
+
+   arraylist_add(list, x5 = objfactory(5));
+   CU_ASSERT_EQUAL(list->size, INIT_MAX * sizeof(void**) * 2); 
+   arraylist_add(list, x6 = objfactory(6));
+
+   x = arraylist_get(list,4); 
+   CU_ASSERT_EQUAL(x, x5); 
+   CU_ASSERT_EQUAL(((TESTOBJ*)x)->signature, OBJSIG); 
+   CU_ASSERT_EQUAL(((TESTOBJ*)x)->id, 5); 
+   x = arraylist_get(list,5); 
+   CU_ASSERT_EQUAL(x, x6); 
+
+   /* destroy the arraylist freeing the test object content as well */
+   arraylist_destroy(list,TRUE); 
+
+   g_bytes_allocated = etch_showmem(0,0);  /* 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;
+    CU_set_output_filename("../test_arraylist");
+
+    pSuite = CU_add_suite("suite_arraylist", init_suite, clean_suite);
+
+    CU_add_test(pSuite, "test new_arraylist()", test_new_arraylist); 
+    CU_add_test(pSuite, "test arraylist_add()", test_add);
+    CU_add_test(pSuite, "test arraylist_destroy()", test_destroy);
+    CU_add_test(pSuite, "test arraylist_remove() first", test_remove_firstitem);
+    CU_add_test(pSuite, "test arraylist_remove() last", test_remove_lastitem);
+    CU_add_test(pSuite, "test arraylist_remove() mid", test_remove);
+    CU_add_test(pSuite, "test arraylist_insert() first", test_insert_first);
+    CU_add_test(pSuite, "test arraylist_insert() mid", test_insert_mid); 
+    CU_add_test(pSuite, "test arraylist_insert() end", test_insert_end);
+    CU_add_test(pSuite, "test arraylist_contains(), containsp", test_contains);  
+    CU_add_test(pSuite, "test arraylist_indexof(), indexofp", test_indexof);
+    CU_add_test(pSuite, "test arraylist_get()", test_get); 
+    CU_add_test(pSuite, "test arraylist set", test_set);
+    CU_add_test(pSuite, "test arraylist auto realloc", test_expand);   
+
+    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_assignment.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/test/common/test_assignment.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/test/common/test_assignment.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/test/common/test_assignment.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,1071 @@
+/* $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_assignment.c -- test etch object assignability and assignment
+ */
+#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;
+}
+#define THISTEST_OBJTYPE      0xeee0
+#define CLASSID_CLASS_A       0xeee1
+#define CLASSID_CLASS_B       0xeee2
+#define CLASSID_CLASS_C       0xeee3
+#define CLASSID_CLASS_X       0xeee4
+#define CLASSID_CLASS_Y       0xeee5
+#define CLASSID_CLASSA_VTABLE 0xeed1
+#define CLASSID_CLASSB_VTABLE 0xeed2
+#define CLASSID_CLASSC_VTABLE 0xeed3
+#define CLASSID_CLASSX_VTABLE 0xeed4
+#define CLASSID_CLASSY_VTABLE 0xeed5
+
+
+/**
+ * class_a: base class
+ */
+typedef struct class_a
+{
+    unsigned int    hashkey;    
+    unsigned short  obj_type;  
+    unsigned short  class_id;   
+    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;
+
+    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), THISTEST_OBJTYPE, CLASSID_CLASS_A);
+    memcpy(newobj, origobj, origobj->length);
+    newobj->a_string = new_string(origobj->a_string->v.valw, ETCH_ENCODING_UTF16);  
+    newobj->is_copy  = TRUE; 
+    return newobj; 
+}
+
+
+/**
+ * class_a constructor
+ */
+class_a* new_class_a(const wchar_t* strval)
+{
+    vtabmask* vtab   = NULL;
+    class_a* newobj  = (class_a*) new_object(sizeof(class_a), THISTEST_OBJTYPE, CLASSID_CLASS_A);
+    newobj->destroy  = destroy_class_a;
+    newobj->clone    = clone_class_a;
+    newobj->a_string = new_string(strval, ETCH_ENCODING_UTF16);
+
+    if(!(vtab = cache_find(get_vtable_cachehkey(CLASSID_CLASSA_VTABLE), 0)))  
+    {    vtab = new_vtable(NULL, sizeof(vtabmask), CLASSID_CLASSA_VTABLE);
+         cache_insert(vtab->hashkey, vtab, FALSE);
+    } 
+ 
+    newobj->vtab = vtab;   
+    return newobj;
+}
+
+
+/**
+ * class_b: inherits from class_a
+ */
+typedef struct class_b
+{
+    unsigned int    hashkey;    
+    unsigned short  obj_type; 
+    unsigned short  class_id;
+    vtabmask*       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), THISTEST_OBJTYPE, CLASSID_CLASS_B);
+    memcpy(newobj, origobj, origobj->length);
+
+    newobj->parent = origobj->parent? 
+        origobj->parent->clone(origobj->parent): 
+        new_class_a(NULL);
+
+    if (origobj->data)
+    {   newobj->data     = etch_malloc(origobj->datasize, ETCHTYPEB_BYTES); 
+        newobj->datasize = origobj->datasize;
+        memcpy(newobj->data, origobj->data, origobj->datasize); 
+    }
+ 
+    newobj->is_copy = TRUE;
+    return newobj;
+}
+
+
+/**
+ * class_b constructor
+ */
+class_b* new_class_b(class_a* parent, const int datalen)
+{
+   vtabmask* vtab  = NULL;
+   etchparentinfo* inheritlist = NULL;
+   class_b* newobj = (class_b*) new_object(sizeof(class_b), THISTEST_OBJTYPE, CLASSID_CLASS_B);
+   newobj->parent  = parent? parent: new_class_a(NULL);
+   newobj->destroy = destroy_class_b;
+   newobj->clone   = clone_class_b;
+   newobj->data    = etch_malloc(datalen, ETCHTYPEB_BYTES);
+   memset(newobj->data, 'x', datalen);
+   newobj->datasize = datalen;
+
+   if (NULL == (vtab = cache_find(get_vtable_cachehkey(CLASSID_CLASSB_VTABLE), 0)))  
+   {   
+       vtab = new_vtable(parent->vtab, sizeof(vtabmask), CLASSID_CLASSB_VTABLE);
+       cache_insert(vtab->hashkey, vtab, FALSE);
+        
+       inheritlist = get_vtab_inheritance_list((objmask*)newobj,
+           2, 1, CLASSID_CLASSB_VTABLE); /* create inheritance list */ 
+       inheritlist[1].obj_type = THISTEST_OBJTYPE;
+       inheritlist[1].class_id = CLASSID_CLASS_A;
+    } 
+   newobj->vtab = vtab;  
+   return newobj;
+}
+
+
+/**
+ * class_c: inherits from class_b
+ */
+typedef struct class_c
+{
+    unsigned int    hashkey;    
+    unsigned short  obj_type; 
+    unsigned short  class_id;
+    vtabmask*       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), THISTEST_OBJTYPE, CLASSID_CLASS_C);
+    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), ETCHTYPEB_BYTES);
+        newobj->numitems = origobj->numitems;
+        memcpy(newobj->intarray, origobj->intarray, origobj->numitems * sizeof(int)); 
+    }
+
+    newobj->is_copy = TRUE;
+    return newobj; 
+}
+
+
+/**
+ * class_c constructor
+ */
+class_c* new_class_c(class_b* parent)
+{
+    int i = 0;
+    vtabmask* vtab   = NULL;
+    etchparentinfo*  inheritlist = NULL;
+    class_c* newobj  = (class_c*) new_object(sizeof(class_c), THISTEST_OBJTYPE, CLASSID_CLASS_C);
+    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), ETCHTYPEB_BYTES);
+    for(; i < 4; i++) newobj->intarray[i] = i;
+
+    if (NULL == (vtab = cache_find(get_vtable_cachehkey(CLASSID_CLASSC_VTABLE), 0)))  
+    {   
+       vtab = new_vtable(parent->vtab, sizeof(vtabmask), CLASSID_CLASSC_VTABLE);
+       cache_insert(vtab->hashkey, vtab, FALSE);
+        
+       inheritlist = get_vtab_inheritance_list((objmask*)newobj,
+           3, 2, CLASSID_CLASSC_VTABLE); /* create inheritance list */ 
+       inheritlist[1].obj_type = THISTEST_OBJTYPE;
+       inheritlist[1].class_id = CLASSID_CLASS_B;
+       inheritlist[2].obj_type = THISTEST_OBJTYPE;
+       inheritlist[2].class_id = CLASSID_CLASS_A;
+    } 
+    newobj->vtab = vtab;  
+    return newobj;
+}
+
+
+/**
+ * class_y: inherits from class_x, but is flattened to contain class_x data.
+ * inheritance chain is identified through the object vtable inheritance list
+ */
+typedef struct class_y
+{
+    unsigned int    hashkey;    
+    unsigned short  obj_type; 
+    unsigned short  class_id;
+    vtabmask*       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 class_x_instance_data;
+    int class_y_instance_data;
+
+} class_y;
+
+
+/**
+ * class_x: parent of class_y
+ */
+typedef struct class_x
+{
+    unsigned int    hashkey;    
+    unsigned short  obj_type; 
+    unsigned short  class_id;
+    vtabmask*       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 class_x_instance_data;
+
+} class_x;
+
+
+/**
+ * class_x constructor
+ */
+class_x* new_class_x(int classx_data)
+{
+    class_x* newobj = (class_x*) new_object(sizeof(class_x), THISTEST_OBJTYPE, CLASSID_CLASS_X);
+
+    newobj->class_x_instance_data = classx_data;
+ 
+    /* class_x has no parent so we can omit vtable and inheritance list if we want */
+    return newobj;
+}
+
+
+/**
+ * class_y constructor
+ * inherits from class_x via inheritance type 2 - flat object
+ */
+class_y* new_class_y(int classx_data, int classy_data)
+{
+    etchparentinfo* inheritlist = NULL;
+    vtabmask* vtab  = NULL;
+    class_y* newobj = (class_y*) new_object(sizeof(class_y), THISTEST_OBJTYPE, CLASSID_CLASS_Y);
+
+    newobj->class_x_instance_data = classx_data;
+    newobj->class_y_instance_data = classy_data;
+ 
+    if (NULL == (vtab = cache_find(get_vtable_cachehkey(CLASSID_CLASSY_VTABLE), 0)))  
+    {   
+        vtab = new_vtable(NULL, sizeof(vtabmask), CLASSID_CLASSY_VTABLE);
+        cache_insert(vtab->hashkey, vtab, FALSE);
+        
+        inheritlist = get_vtab_inheritance_list((objmask*)newobj,
+            2, 1, CLASSID_CLASSY_VTABLE); /* create inheritance list */ 
+        inheritlist[1].obj_type = THISTEST_OBJTYPE;
+        inheritlist[1].class_id = CLASSID_CLASS_X; 
+    } 
+    newobj->vtab = vtab;  
+    return newobj;
+}
+
+
+void classarg_init_object(etch_objclass* arg)
+{
+    memset(arg, 0, sizeof(etch_objclass));
+    arg->obj_type = ETCHTYPEB_ETCHOBJECT;
+    arg->class_id = CLASSID_OBJECT;
+}
+
+
+/**
+ * classarg_init_nativearray()
+ * initialize class parameters for a wrapped primitive
+ */
+void classarg_init_primitive(etch_objclass* arg, short class_id)
+{
+    memset(arg, 0, sizeof(etch_objclass));
+    arg->obj_type = ETCHTYPEB_PRIMITIVE;
+    arg->class_id = class_id;
+}
+
+
+/**
+ * classarg_init_nativearray()
+ * initialize class parameters for native array 
+ */
+void classarg_init_nativearray(etch_objclass* arg, short class_id, int dim, short conttype, short contclass )
+{
+    memset(arg, 0, sizeof(etch_objclass));
+    arg->obj_type = ETCHTYPEB_NATIVEARRAY;
+    arg->class_id = class_id;
+    arg->numdims  = dim;
+    arg->content_obj_type = conttype;
+    arg->content_class_id = contclass;
+}
+
+
+/**
+ * classarg_init_customtype_scalar()
+ * initialize class parameters for a custom type with an inheritance hierarchy.
+ * real code would not allocate an inheritance list as we do here, this would  
+ * be handled in the object vtable constructor, and the list subsequently 
+ * accessed via the object's cached vtable.  
+ */
+void classarg_init_customtype_scalar(etch_objclass* arg, short class_id, int numsupers,
+   short superclass_1, short superclass_2)
+{
+    memset(arg, 0, sizeof(etch_objclass));
+    arg->obj_type = THISTEST_OBJTYPE;
+    arg->class_id = class_id;
+
+    arg->inherits_from = etch_malloc(sizeof(etchparentinfo) * (numsupers + 1), ETCHTYPEB_BYTES);
+    arg->inherits_from[0].list_size  = numsupers + 1;
+    arg->inherits_from[0].list_count = numsupers;
+
+    if (numsupers > 0) 
+    { arg->inherits_from[1].obj_type = THISTEST_OBJTYPE; 
+      arg->inherits_from[1].class_id = superclass_1; 
+    }
+
+    if (numsupers > 1) 
+    { arg->inherits_from[2].obj_type = THISTEST_OBJTYPE; 
+      arg->inherits_from[2].class_id = superclass_2; 
+    }
+}
+
+
+void classarg_cleanup(etch_objclass* target, etch_objclass* source) 
+{
+    if (target->inherits_from) etch_free(target->inherits_from);
+    if (source->inherits_from) etch_free(source->inherits_from);
+    target->inherits_from = source->inherits_from = NULL;
+}
+
+
+/**
+ * test_is_assignable_1()
+ * test assignability of various classes 
+ */
+void test_is_assignable_1(void)
+{
+    etch_objclass target, source;
+    int result = 0;
+
+    /* int32obj = int16obj */
+    classarg_init_primitive(&target, CLASSID_PRIMITIVE_INT32);
+    classarg_init_primitive(&source, CLASSID_PRIMITIVE_INT16);
+    result = etchobj_is_assignable_from(&target, &source); 
+    CU_ASSERT_EQUAL(result, FALSE);
+    result = etchobj_is_assignable_from(&source, &target); 
+    CU_ASSERT_EQUAL(result, FALSE);
+
+    /* short[]obj = shortobj */
+    classarg_init_nativearray(&target, CLASSID_ARRAY_INT16, 1, ETCHTYPEB_PRIMITIVE, CLASSID_PRIMITIVE_INT16);
+    classarg_init_primitive(&source, CLASSID_PRIMITIVE_INT16);
+    result = etchobj_is_assignable_from(&target, &source); 
+    CU_ASSERT_EQUAL(result, FALSE);
+    result = etchobj_is_assignable_from(&source, &target); 
+    CU_ASSERT_EQUAL(result, FALSE);
+
+    /* etchobj = longobj */
+    classarg_init_object(&target);
+    classarg_init_primitive(&source, CLASSID_PRIMITIVE_INT64);
+    result = etchobj_is_assignable_from(&target, &source); 
+    CU_ASSERT_EQUAL(result, TRUE);
+    result = etchobj_is_assignable_from(&source, &target); 
+    CU_ASSERT_EQUAL(result, FALSE);
+
+    /* obj[]obj = shortobj */
+    classarg_init_nativearray(&target, CLASSID_ARRAY_OBJECT, 1, ETCHTYPEB_ETCHOBJECT, CLASSID_OBJECT);
+    classarg_init_primitive(&source, CLASSID_PRIMITIVE_INT16);
+    result = etchobj_is_assignable_from(&target, &source); 
+    CU_ASSERT_EQUAL(result, FALSE);
+    result = etchobj_is_assignable_from(&source, &target); 
+    CU_ASSERT_EQUAL(result, FALSE);
+
+    /* obj[]obj = short[]obj */
+    classarg_init_nativearray(&target, CLASSID_ARRAY_OBJECT, 1, ETCHTYPEB_ETCHOBJECT, CLASSID_OBJECT);
+    classarg_init_nativearray(&source, CLASSID_ARRAY_INT16,  1, ETCHTYPEB_PRIMITIVE, CLASSID_PRIMITIVE_INT16);
+    result = etchobj_is_assignable_from(&target, &source); 
+    CU_ASSERT_EQUAL(result, TRUE);
+    result = etchobj_is_assignable_from(&source, &target); 
+    CU_ASSERT_EQUAL(result, FALSE);
+
+    /* short[]obj = short[]obj */
+    classarg_init_nativearray(&target, CLASSID_ARRAY_INT16, 1, ETCHTYPEB_PRIMITIVE, CLASSID_PRIMITIVE_INT16);
+    classarg_init_nativearray(&source, CLASSID_ARRAY_INT16, 1, ETCHTYPEB_PRIMITIVE, CLASSID_PRIMITIVE_INT16);
+    result = etchobj_is_assignable_from(&target, &source); 
+    CU_ASSERT_EQUAL(result, TRUE);
+    result = etchobj_is_assignable_from(&source, &target); 
+    CU_ASSERT_EQUAL(result, TRUE);
+
+    /* custom1obj = custom0obj */
+    classarg_init_customtype_scalar(&target, CLASSID_CLASS_A, 0, 0, 0);
+    classarg_init_customtype_scalar(&source, CLASSID_CLASS_B, 1, CLASSID_CLASS_A, 0);
+    result = etchobj_is_assignable_from(&target, &source); 
+    CU_ASSERT_EQUAL(result, TRUE);
+    result = etchobj_is_assignable_from(&source, &target); 
+    CU_ASSERT_EQUAL(result, FALSE);
+    classarg_cleanup(&source, &target); 
+
+    /* custom2obj = custom0obj */
+    classarg_init_customtype_scalar(&target, CLASSID_CLASS_A, 0, 0, 0);
+    classarg_init_customtype_scalar(&source, CLASSID_CLASS_C, 2, CLASSID_CLASS_B, CLASSID_CLASS_A);
+    result = etchobj_is_assignable_from(&target, &source); 
+    CU_ASSERT_EQUAL(result, TRUE);
+    result = etchobj_is_assignable_from(&source, &target); 
+    CU_ASSERT_EQUAL(result, FALSE);
+    classarg_cleanup(&source, &target); 
+
+    /* custom2obj = custom1obj */
+    classarg_init_customtype_scalar(&target, CLASSID_CLASS_B, 1, CLASSID_CLASS_A, 0);
+    classarg_init_customtype_scalar(&source, CLASSID_CLASS_C, 2, CLASSID_CLASS_B, CLASSID_CLASS_A);
+    result = etchobj_is_assignable_from(&target, &source); 
+    CU_ASSERT_EQUAL(result, TRUE);
+    result = etchobj_is_assignable_from(&source, &target); 
+    CU_ASSERT_EQUAL(result, FALSE);
+    classarg_cleanup(&source, &target); 
+
+    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_assign_long_to_object
+ */
+void test_assign_long_to_object(void)
+{
+    char* objval = etch_malloc(128, ETCHTYPEB_BYTES);
+    etch_object* class_object = new_etch_object(CLASSID_OBJECT, objval);
+    etch_int64*  class_long   = new_int64(0);
+    objmask* resultobj = NULL;
+    int result = etchobj_is_assignable_fromobj((objmask*) class_object, (objmask*) class_long);
+    CU_ASSERT_EQUAL_FATAL(result, TRUE);
+
+    /* an assignment to object causes the source object to be 
+     * wrapped by the target object */
+
+    resultobj = etchobj_assign_to((objmask*) class_object, (objmask*) class_long);
+    CU_ASSERT_PTR_EQUAL(resultobj, class_object);
+
+    class_long->destroy(class_long);
+    class_object->destroy(class_object);
+
+    /* we destroy class_long allocated above, since the assignment caused
+     * it to be wrapped by, but of course not consumed by, class_object.
+     * that is, class_object now contains a reference to class_long, but
+     * does not own the reference (destructor will not attempt to free it).
+     * we do not destroy the character vector objval allocated above, since  
+     * the assignment to class_object caused any content already owned by it,    
+     * in this case objval, to be destroyed as part of the assignment.
+     */
+
+    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_invalid_array_assignment_1
+ * ensure assignment fails when dimensions do not match
+ */
+void test_invalid_array_assignment_1(void)
+{
+    const int numdimbyte = 1, dim0byte = 4;
+    const int numdimobj  = 2, dim0obj  = 4, dim1obj  = 2;
+    objmask* resultobj = NULL;
+
+    etch_nativearray* array_of_byte = new_nativearray 
+        (CLASSID_ARRAY_BYTE, sizeof(byte), numdimbyte, dim0byte, 0, 0);  
+
+    etch_nativearray* array_of_object = new_nativearray 
+        (CLASSID_ARRAY_OBJECT, sizeof(void*), numdimobj, dim0obj, dim1obj, 0); 
+
+    int result = etchobj_is_assignable_fromobj((objmask*) array_of_object, (objmask*) array_of_byte);
+    CU_ASSERT_EQUAL_FATAL(result, FALSE);
+
+    resultobj = etchobj_assign_to((objmask*) array_of_object, (objmask*) array_of_byte);
+    CU_ASSERT_PTR_EQUAL(resultobj, NULL);
+
+    array_of_byte->destroy(array_of_byte);
+    array_of_object->destroy(array_of_object);
+
+    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_invalid_array_assignment_2
+ * ensure assignment fails when types do not match
+ */
+void test_invalid_array_assignment_2(void)
+{
+    const int numdim = 1, dim0 = 4;
+    objmask* resultobj = NULL;
+
+    etch_nativearray* array_of_byte = new_nativearray 
+        (CLASSID_ARRAY_BYTE, sizeof(byte), numdim, dim0, 0, 0);  
+
+    etch_nativearray* array_of_bool = new_nativearray 
+        (CLASSID_ARRAY_BOOL, sizeof(byte), numdim, dim0, 0, 0);  
+
+    int result  = etchobj_is_assignable_fromobj((objmask*) array_of_bool, (objmask*) array_of_byte);
+    CU_ASSERT_EQUAL(result, FALSE);
+    result      = etchobj_is_assignable_fromobj((objmask*) array_of_byte, (objmask*) array_of_bool);
+    CU_ASSERT_EQUAL(result, FALSE);
+
+    resultobj = etchobj_assign_to((objmask*) array_of_bool, (objmask*) array_of_byte);
+    CU_ASSERT_EQUAL(result, NULL);
+
+    array_of_byte->destroy(array_of_byte);
+    array_of_bool->destroy(array_of_bool);
+
+    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_assign_arrayofbyte_to_arrayofobject
+ */
+void test_assign_arrayofbyte_to_arrayofobject(void)
+{
+    const int numdimensions = 2, dim0count = 4, dim1count = 2;
+    objmask* resultobj = NULL;
+
+    etch_nativearray* array_of_byte = new_nativearray 
+        (CLASSID_ARRAY_BYTE, sizeof(byte), numdimensions, dim0count, dim1count, 0);  
+
+    etch_nativearray* array_of_object = new_nativearray 
+        (CLASSID_ARRAY_OBJECT, sizeof(void*), numdimensions, dim0count, dim1count, 0); 
+
+    /* an assignment of one array to the other replaces all array attributes 
+     * and content in the target object. the target object will not own the 
+     * array content of course */
+
+    int result = etchobj_is_assignable_fromobj((objmask*) array_of_object, (objmask*) array_of_byte);
+    CU_ASSERT_EQUAL_FATAL(result, TRUE);
+
+    resultobj = etchobj_assign_to((objmask*) array_of_object, (objmask*) array_of_byte);
+    CU_ASSERT_PTR_EQUAL(resultobj, array_of_object);
+
+    array_of_byte->destroy(array_of_byte);
+    array_of_object->destroy(array_of_object);
+
+    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_assign_verify_arraybyte_to_arrayobj
+ * assign array of byte to array of object and verify content is identical
+ */
+void test_assign_verify_arraybyte_to_arrayobj(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;
+    objmask* resultobj = NULL;
+
+    etch_nativearray* array_of_byte = new_nativearray 
+        (CLASSID_ARRAY_BYTE, sizeof(byte), numdimensions, dim0count, dim1count, 0);   
+
+    etch_nativearray* array_of_object = new_nativearray 
+        (CLASSID_ARRAY_OBJECT, sizeof(void*), numdimensions, dim0count, dim1count, 0); 
+
+    for(i = 0; i < dim1count; i++)    /* initialize array of byte */       
+    {
+        for(j = 0; j < dim0count; j++)      
+        {                                  
+            result = array_of_byte->put2(array_of_byte, &x[i][j], i, j); 
+            CU_ASSERT_EQUAL(result, 0); 
+        }
+    }
+
+    resultobj = etchobj_assign_to((objmask*) array_of_object, (objmask*) array_of_byte);
+    CU_ASSERT_PTR_EQUAL_FATAL(resultobj, array_of_object);
+
+    for(i = 0; i < dim1count; i++)         /* verify arrays are now the same */
+    {
+        for(j = 0; j < dim0count; j++)      
+        {                                   
+            result = array_of_object->get2(array_of_object, &thisx, i, j); 
+            CU_ASSERT_EQUAL(result, 0); 
+            CU_ASSERT_EQUAL(x[i][j], thisx); 
+        }
+    }
+
+    array_of_byte->destroy(array_of_byte);
+    array_of_object->destroy(array_of_object);
+
+    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_assign_arrayofbyte_to_arrayofbyte
+ */
+void test_assign_arrayofbyte_to_arrayofbyte(void)
+{
+    const int numdimensions = 2, dim0count = 4, dim1count = 2;
+    objmask* resultobj = NULL;
+
+    etch_nativearray* array1_of_byte = new_nativearray 
+        (CLASSID_ARRAY_BYTE, sizeof(byte), numdimensions, dim0count, dim1count, 0);  
+
+    etch_nativearray* array2_of_byte = new_nativearray 
+        (CLASSID_ARRAY_BYTE, sizeof(byte), numdimensions, dim0count, dim1count, 0);  
+
+    int result = etchobj_is_assignable_fromobj((objmask*) array1_of_byte, (objmask*) array2_of_byte);
+    CU_ASSERT_EQUAL_FATAL(result, TRUE);
+    result     = etchobj_is_assignable_fromobj((objmask*) array2_of_byte, (objmask*) array1_of_byte);
+    CU_ASSERT_EQUAL_FATAL(result, TRUE);
+
+    resultobj = etchobj_assign_to((objmask*) array1_of_byte, (objmask*) array2_of_byte);
+    CU_ASSERT_PTR_EQUAL(resultobj, array1_of_byte);
+
+    resultobj = etchobj_assign_to((objmask*) array2_of_byte, (objmask*) array1_of_byte);
+    CU_ASSERT_PTR_EQUAL(resultobj, array2_of_byte);
+
+    array1_of_byte->destroy(array1_of_byte);
+    array2_of_byte->destroy(array2_of_byte);
+
+    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_assign_verify_arraybyte_to_arraybyte
+ * assign array of byte to array of byte and verify content is identical
+ */
+void test_assign_verify_arraybyte_to_arraybyte(void)
+{
+    int   i = 0, j = 0, result = 0;
+    char  x[2][4] = { {'a','b','c','d'}, {'e','f','g','h'}, }, thisx = 0;
+    char  y[2][4] = { {'s','t','u','v'}, {'w','x','y','z'}, };
+    const int numdimensions = 2, dim0count = 4, dim1count = 2;
+    objmask* resultobj = NULL;
+
+    etch_nativearray* array1_of_byte = new_nativearray 
+        (CLASSID_ARRAY_BYTE, sizeof(byte), numdimensions, dim0count, dim1count, 0);   
+
+    etch_nativearray* array2_of_byte = new_nativearray 
+        (CLASSID_ARRAY_BYTE, sizeof(byte), numdimensions, dim0count, dim1count, 0); 
+
+    for(i = 0; i < dim1count; i++)    /* initialize both arrays */       
+    {
+        for(j = 0; j < dim0count; j++)      
+        {                                  
+            result = array1_of_byte->put2(array1_of_byte, &x[i][j], i, j); 
+            CU_ASSERT_EQUAL(result, 0); 
+
+            result = array2_of_byte->put2(array2_of_byte, &y[i][j], i, j); 
+            CU_ASSERT_EQUAL(result, 0); 
+        }
+    }
+
+    resultobj = etchobj_assign_to((objmask*) array1_of_byte, (objmask*) array2_of_byte);
+    CU_ASSERT_PTR_EQUAL_FATAL(resultobj, array1_of_byte);
+
+    for(i = 0; i < dim1count; i++)   /* verify assignment */
+    {
+        for(j = 0; j < dim0count; j++)      
+        {                                   
+            result = array1_of_byte->get2(array1_of_byte, &thisx, i, j); 
+            CU_ASSERT_EQUAL(result, 0); 
+            CU_ASSERT_EQUAL(y[i][j], thisx); 
+        }
+    }
+
+    array1_of_byte->destroy(array1_of_byte);
+    array2_of_byte->destroy(array2_of_byte);
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);   
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();  
+}
+
+
+/**
+ * test_assign_derived_2
+ * test that inheritance type 2-derived object can be assigned to its parent
+ */
+void test_assign_derived_2(void)
+{
+    class_a* class_parent = NULL;
+    class_b* class_child  = NULL;
+    objmask* resultobj = NULL;
+    int result = 0;
+
+    class_parent = new_class_a(L"it works!");
+    class_child  = new_class_b(class_parent, 128);
+ 
+    CU_ASSERT_PTR_NOT_NULL_FATAL(class_child->parent);
+    CU_ASSERT_PTR_NULL(class_parent->parent);
+
+    result = etchobj_is_assignable_fromobj((objmask*) class_child, (objmask*) class_parent);
+    CU_ASSERT_EQUAL(result, FALSE);
+
+    result = etchobj_is_assignable_fromobj((objmask*) class_parent, (objmask*) class_child);
+    CU_ASSERT_EQUAL(result, TRUE);
+
+    /* these objects use type 2 inheritance, in which inherited objects chain to
+     * instantiated parent objects. for such objects, when we assign child class
+     * to parent class, the result of the assignment couldl be a different memory
+     * reference than the requested target. however in this case, the object we 
+     * are assigning to is in fact the same object as is in the source object's
+     * inheritance chain (since we passed it to the object's constructor).
+     * is not known at this writing whether this scenario can exist in etch c; 
+     * that is, if we will ever use this inheritance model in conjunction with
+     * the assignment of child to parent.  
+     */
+    resultobj = etchobj_assign_to((objmask*) class_parent, (objmask*) class_child);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(resultobj);
+    CU_ASSERT_EQUAL(resultobj->class_id, class_parent->class_id); 
+
+    /* an object destructor will recursively destroy() its superclass instances */
+    class_child->destroy(class_child);
+
+    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_assign_derived_1a
+ * test that inheritance type 2-derived object can be assigned to its parent
+ */
+void test_assign_derived_2a(void)
+{
+    class_a* class_parent = NULL;
+    class_b* class_child1 = NULL;
+    class_c* class_child2 = NULL;
+    objmask* resultobj = NULL;
+    int result = 0;
+
+    class_parent = new_class_a(L"it works!");
+    class_child1 = new_class_b(class_parent, 128);
+    class_child2 = new_class_c(class_child1);
+ 
+    CU_ASSERT_PTR_NOT_NULL_FATAL(class_child2->parent);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(class_child1->parent);
+    CU_ASSERT_PTR_NULL(class_parent->parent);
+
+    result = etchobj_is_assignable_fromobj((objmask*) class_child2, (objmask*) class_parent);
+    CU_ASSERT_EQUAL(result, FALSE);
+
+    result = etchobj_is_assignable_fromobj((objmask*) class_parent, (objmask*) class_child2);
+    CU_ASSERT_EQUAL(result, TRUE);
+
+    /* see comments at test_assign_derived_2() - they apply again here */
+    resultobj = etchobj_assign_to((objmask*) class_parent, (objmask*) class_child2);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(resultobj);
+    CU_ASSERT_EQUAL(resultobj->class_id, class_parent->class_id); 
+
+    /* an object destructor will recursively destroy() its superclass instances */ 
+    class_child2->destroy(class_child2);
+
+    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_assign_derived_1
+ * test that inheritance type 1-derived object can be assigned to its parent
+ */
+void test_assign_derived_1(void)
+{
+    class_x* class_parent = NULL;
+    class_y* class_child  = NULL;
+    objmask* resultobj = NULL;
+    const int PARENT_CLASSX_DATA = 1, CHILD_CLASSX_DATA = 1000, CHILD_CLASSY_DATA = 1001;
+    int result = 0;
+
+    class_parent = new_class_x(PARENT_CLASSX_DATA);
+    class_child  = new_class_y(CHILD_CLASSX_DATA, CHILD_CLASSY_DATA);
+ 
+    CU_ASSERT_PTR_NOT_NULL_FATAL(class_parent);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(class_child);
+
+    result = etchobj_is_assignable_fromobj((objmask*) class_child, (objmask*) class_parent);
+    CU_ASSERT_EQUAL(result, FALSE);
+
+    result = etchobj_is_assignable_fromobj((objmask*) class_parent, (objmask*) class_child);
+    CU_ASSERT_EQUAL(result, TRUE);
+
+    /* these objects use type 1 inheritance, in which inherited objects contain
+     * their parent's instance data;. there is no physical chaining of objects.
+     * rather inheritance is identified from the object vtable's inheritance list. 
+     */
+    resultobj = etchobj_assign_to((objmask*) class_parent, (objmask*) class_child);
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(resultobj);
+    CU_ASSERT_EQUAL(resultobj->class_id, class_parent->class_id); 
+    /* verify that parent's instance data was replaced with that of the child */
+    CU_ASSERT_EQUAL(((class_x*)resultobj)->class_x_instance_data, class_child->class_x_instance_data); 
+
+    class_child->destroy(class_child);
+    class_parent->destroy(class_parent);
+
+    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 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 assignability",    test_is_assignable_1); 
+    CU_add_test(ps, "assign long to object", test_assign_long_to_object); 
+    CU_add_test(ps, "attempt invalid array assignment 1", test_invalid_array_assignment_1); 
+    CU_add_test(ps, "attempt invalid array assignment 2", test_invalid_array_assignment_2); 
+    CU_add_test(ps, "assign byte[][] to object[][]", test_assign_arrayofbyte_to_arrayofobject); 
+    CU_add_test(ps, "assign byte[][] to object[][] and verify", test_assign_verify_arraybyte_to_arrayobj);
+    CU_add_test(ps, "assign byte[][] to byte[][]", test_assign_arrayofbyte_to_arrayofbyte); 
+    CU_add_test(ps, "assign byte[][] to byte[][] and verify", test_assign_verify_arraybyte_to_arraybyte); 
+    CU_add_test(ps, "assign child to parent (type 2)", test_assign_derived_2); 
+    CU_add_test(ps, "assign 2x child to parent (type 2)", test_assign_derived_2a); 
+    CU_add_test(ps, "assign child to parent (type 1)", test_assign_derived_1); 
+
+    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_cache.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/test/common/test_cache.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/test/common/test_cache.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/test/common/test_cache.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,314 @@
+/* $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_cache.c
+ * test the runtime object cache
+ * we can swap out cache back ends and this test should work the same regardless
+ */
+#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"
+
+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;
+}
+
+
+/**
+ * This subtest instantiates various etch objects which cache some part of 
+ * themselves, and destroys the objects. At each step the test verifies that
+ * the cache contains the expected number of entries, e.g. if I create 
+ * multiple hashtables I should only have cached one hashtable vtable.
+ */
+void test_multiple_items(void)
+{
+    int cache_start_count = 0, cache_current_count;
+    int result1 = 0, result2 = 0, result3 = 0;
+    etch_hashtable* myhashtab1 = NULL;     
+    etch_hashtable* myhashtab2 = NULL; 
+    etch_hashtable* myhashtab3 = NULL;     
+    etch_hashitem   hashbucket;
+    etch_hashitem*  myentry = &hashbucket;
+
+    wchar_t* wstr1 = L"abracadabra"; 
+    wchar_t* wstr2 = L"gilgamesh";
+    wchar_t* wstr3 = L"antidisestablishmentarianism";
+
+    const size_t numElements1 = wcslen(wstr1);
+    const size_t numElements2 = wcslen(wstr2);
+    const size_t numElements3 = wcslen(wstr3);
+
+    const size_t numBytes1 = sizeof(wchar_t) * numElements1;
+    const size_t numBytes2 = sizeof(wchar_t) * numElements2;
+    const size_t numBytes3 = sizeof(wchar_t) * numElements3;
+
+    size_t actlen1 = 0, actlen2 = 0, actlen3 = 0;
+    wchar_t *key1 = NULL, *key2 = NULL, *key3 = NULL;
+
+    key1 = malloc(numBytes1 + 2);   
+    key2 = malloc(numBytes2 + 2); 
+    key3 = malloc(numBytes3 + 2); 
+    CU_ASSERT_PTR_NOT_NULL_FATAL(key1);  
+    CU_ASSERT_PTR_NOT_NULL_FATAL(key2); 
+    CU_ASSERT_PTR_NOT_NULL_FATAL(key3);
+
+    /* create one hashtable first, so in case we are tracking memory, we ensure that 
+     * the hashtable code module paths will already be cached. */
+    myhashtab1 = new_hashtable(16);  
+ 
+    cache_start_count = cache_count();
+        
+    result1 = wcscpy_s(key1, numElements1+1, wstr1);  /* wcscpy_s param 2 must be */
+    result2 = wcscpy_s(key2, numElements2+1, wstr2);  /* number of characters + 1 */
+    result3 = wcscpy_s(key3, numElements3+1, wstr3);  
+    actlen1 = wcslen(key1);  actlen2 = wcslen(key2);  actlen3 = wcslen(key3);
+
+    myhashtab2 = new_hashtable(16);    
+    myhashtab3 = new_hashtable(16);   
+
+    /* we should not have cached any more hashtable vtables */
+    cache_current_count = cache_count();
+    CU_ASSERT_EQUAL(cache_current_count,cache_start_count); 
+
+    myhashtab1->vtab->insert(myhashtab1->realtable, key1, (int)numBytes1, NULL,0,0,0);            
+    myhashtab2->vtab->insert(myhashtab2->realtable, key2, (int)numBytes2, NULL,0,0,0);
+    myhashtab2->vtab->insert(myhashtab3->realtable, key3, (int)numBytes3, NULL,0,0,0);
+
+    /* TODO instantiate some other object here which uses the cache */
+
+    destroy_hashtable(myhashtab1, TRUE, TRUE);
+    destroy_hashtable(myhashtab2, TRUE, TRUE);
+    destroy_hashtable(myhashtab3, TRUE, TRUE);
+    /* note that key1 and key2 are now dangling pointers since we asked the
+     * hashtable to free keys and values memory
+     */
+    
+   g_bytes_allocated = etch_showmem(0,0);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+   memtable_clear();  /* start fresh for next test */   
+}
+
+
+/**
+ * test_intkeys()
+ * tests caching using integer keys as we might do for etchobjects such as vtables
+ */
+void test_intkeys(void)
+{
+    int i, startsize, size;
+    const int STARTKEY = 0, ENDKEY = 512, KEYCOUNT = ENDKEY - STARTKEY;
+    char* teststring = "it works!";
+    char* item = etch_malloc(sizeof(teststring),0);
+    memcpy(item, teststring, sizeof(teststring)); 
+
+    startsize = cache_count();
+
+    for(i = STARTKEY; i < ENDKEY; i++)
+        cache_add(i, item);
+
+    size = cache_count();
+    CU_ASSERT_EQUAL(size, KEYCOUNT + startsize);
+
+    for(i = STARTKEY; i < ENDKEY; i++)
+        CU_ASSERT_PTR_NOT_NULL(cache_find(i, 0));
+
+    for(i = STARTKEY; i < ENDKEY; i++)
+        CU_ASSERT_PTR_NOT_NULL(cache_del(i));
+
+    size = cache_count();
+    CU_ASSERT_EQUAL(size, startsize);
+
+    etch_free(item);
+
+    g_bytes_allocated = etch_showmem(0,0);  /* verify all memory freed */
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();  /* start fresh for next test */  
+}
+
+
+/**
+ * test_intkeys()
+ * tests caching using string keys with no values, as we might do for source  
+ * file paths in the debug allocator  
+ */
+void test_pathkeys(void)
+{
+    char* path1 = "..\\..\\foo\\bar\\file1.dat";
+    char* path2 = "..\\..\\foo\\bar\\file2.dat";
+    char* path3 = "c:\\the\\quick\\brown\\fox\\jumped\\over\\the\\lazy\\dog\\file3.dat";
+    unsigned hash1 = 0, hash2 = 0, hash3 = 0;
+    char* namefound = NULL;
+    etch_hashitem  hashbucket; 
+    etch_hashitem* thisitem = &hashbucket;
+    int result = 0; 
+    int len1 = (int)strlen(path1), len2 = (int)strlen(path2), len3 = (int)strlen(path3);
+ 
+    hash1 = cache_insertx (path1, NULL, FALSE);
+    hash2 = cache_insertx (path2, NULL, FALSE);
+    hash3 = cache_insertx (path3, NULL, FALSE);
+
+    memset(thisitem, 0, sizeof(etch_hashitem));
+    cache_findx(path1, &thisitem);
+    CU_ASSERT_PTR_NOT_NULL(thisitem->key);
+    CU_ASSERT_EQUAL(hash1, thisitem->hash);
+    result = strncmp(path1, thisitem->key, len1);
+    CU_ASSERT_EQUAL(result,0);
+
+    memset(thisitem, 0, sizeof(etch_hashitem));
+    cache_findx(path2, &thisitem);
+    CU_ASSERT_PTR_NOT_NULL(thisitem->key);
+    CU_ASSERT_EQUAL(hash2, thisitem->hash);
+    result = strncmp(path2, thisitem->key, len2);
+    CU_ASSERT_EQUAL(result,0);
+
+    memset(thisitem, 0, sizeof(etch_hashitem));
+    cache_findx(path3, &thisitem);
+    CU_ASSERT_PTR_NOT_NULL(thisitem->key);
+    CU_ASSERT_EQUAL(hash3, thisitem->hash);
+    result = strncmp(path3, thisitem->key, len3);
+    CU_ASSERT_EQUAL(result,0);
+
+    memset(thisitem, 0, sizeof(etch_hashitem));
+    cache_find_by_hash(hash1, &thisitem);
+    CU_ASSERT_PTR_NOT_NULL(thisitem->key);
+    result = strncmp(path1, thisitem->key, len1);
+    CU_ASSERT_EQUAL(result,0);
+
+    memset(thisitem, 0, sizeof(etch_hashitem));
+    cache_find_by_hash(hash2, &thisitem);
+    CU_ASSERT_PTR_NOT_NULL(thisitem->key);
+    result = strncmp(path2, thisitem->key, len2);
+    CU_ASSERT_EQUAL(result,0);
+
+    memset(thisitem, 0, sizeof(etch_hashitem));
+    cache_find_by_hash(hash3, &thisitem);
+    CU_ASSERT_PTR_NOT_NULL(thisitem->key);
+    result = strncmp(path3, thisitem->key, len3);
+    CU_ASSERT_EQUAL(result,0);
+}
+
+
+/**
+ * main   
+ */
+int _tmain(int argc, _TCHAR* argv[])
+{
+    char c=0;
+    CU_pSuite pSuite = NULL;
+    g_is_automated_test = argc > 1 && 0 != wcscmp(argv[1], L"-a");
+
+    if (CUE_SUCCESS != CU_initialize_registry()) return CU_get_error();
+    CU_set_output_filename("../test_cache");
+    pSuite = CU_add_suite("suite_cache", init_suite, clean_suite);
+
+    CU_add_test(pSuite, "test path strings as keys", test_pathkeys);
+    CU_add_test(pSuite, "multiple of same object test", test_multiple_items); 
+    CU_add_test(pSuite, "integer cache key test", test_intkeys);
+
+    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_conn.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/test/common/test_conn.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/test/common/test_conn.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/test/common/test_conn.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,184 @@
+/**
+ * etchconn test routines.
+ */
+ 
+ #include "CUnit.h"
+#include "Basic.h"
+#include "Console.h"
+#include "Automated.h"
+#include "etchconn.h"
+#include "apr_time.h"
+#include "etchlog.h"
+
+#define MAX_TEST_CONNECTIONS    10
+
+static apr_pool_t *pool_ptr = NULL;
+static etch_tcpconn *tcpconn_ptr = NULL;
+static etch_tcpconn *tcpconn2_ptr = NULL;
+static etch_tcplistener *listener_ptr = NULL;
+static etch_tcpconn *accepted[MAX_TEST_CONNECTIONS];
+static BOOLEAN got_accepted(apr_socket_t *socket_ptr);
+
+static void got_data(void *data_ptr, size_t len);
+
+int setup(void)
+{
+    apr_status_t r;
+    r = apr_initialize();
+    if (r == APR_SUCCESS)
+        r = apr_pool_create(&pool_ptr, NULL);
+
+    if (r == APR_SUCCESS )
+    {
+        listener_ptr = etchconn_create_listener("127.0.0.1", 7302, 5, 5, pool_ptr);
+        if (listener_ptr != NULL)
+            listener_ptr->conn.handle_accepted = got_accepted;
+        tcpconn_ptr = etchconn_create_tcp("127.0.0.1", 7302, 5, pool_ptr);
+        /* create another connection to listener */
+        tcpconn2_ptr = etchconn_create_tcp("127.0.0.1", 7302, 5, pool_ptr);
+    }
+    
+    memset(accepted, 0, sizeof(accepted));
+
+    return (listener_ptr != NULL  && tcpconn_ptr != NULL  && tcpconn2_ptr != NULL ? 0 : 1);
+}
+
+int teardown(void)
+{
+    int i;
+    etchconn_destroy((etchconn*)tcpconn_ptr);
+    etchconn_destroy((etchconn*)tcpconn2_ptr);
+    etchconn_destroy((etchconn*)listener_ptr);
+    
+    for(i = 0; i < MAX_TEST_CONNECTIONS && accepted[i] != NULL; i++)
+    {
+         etchconn_destroy((etchconn*)accepted[i]);
+         accepted[i] = NULL;
+    }
+
+    if (pool_ptr != NULL)
+        apr_pool_destroy(pool_ptr);
+    pool_ptr = NULL;
+
+    apr_terminate();
+
+    return 0;
+}
+
+static BOOLEAN got_accepted(apr_socket_t *socket_ptr)
+{
+    BOOLEAN rc = FALSE;
+    int i;
+
+    etch_tcpconn *accepted_ptr = etchconn_create_tcp_with_socket(socket_ptr);
+    if (accepted_ptr != NULL)
+    {
+        /* need to initialize data handler */
+        accepted_ptr->conn.handle_data = got_data; 
+        rc = etchconn_start((etchconn *) accepted_ptr);
+        
+        /* save the pointer for later releasing */
+        i = 0;
+
+        while (i < MAX_TEST_CONNECTIONS && accepted[i] != NULL)
+            ++i;
+        if (i < MAX_TEST_CONNECTIONS)
+            accepted[i] = accepted_ptr;
+    }
+
+    return rc;
+}
+
+static void got_data(void *data_ptr, size_t len)
+{
+    etchlog_report("etchconntest", ETCHLOG_DEBUG, "Got data: %s\n", (const char*) data_ptr);
+}
+
+void testSimple(void)
+{
+    int i;
+    int rc;
+    char data[] = "this is testSimple data.";
+
+    CU_ASSERT(etchconn_start((etchconn*)listener_ptr));
+    rc = etchmon_wait_until_equal(listener_ptr->conn.monitor_ptr, ETCHCONN_UP, (strlen(ETCHCONN_UP)+1)*sizeof(char),0);
+    CU_ASSERT(etchconn_start((etchconn*)tcpconn_ptr));
+
+    rc = etchmon_wait_until_equal(tcpconn_ptr->conn.monitor_ptr, ETCHCONN_UP, (strlen(ETCHCONN_UP)+1)*sizeof(char),0);
+    CU_ASSERT(rc==ETCHMON_STATUS_SUCCESS);
+    for(i = 0; i < 50; i++)
+    {
+        CU_ASSERT(etchconn_send_tcp((etchconn*)tcpconn_ptr, data, (strlen(data)+1)*sizeof(char)));
+        apr_sleep(100000);
+    }
+    apr_sleep(1000000);
+    etchconn_stop((etchconn*)tcpconn_ptr);
+
+    apr_sleep(1000000);
+    CU_ASSERT_PTR_NOT_NULL(accepted[0]);
+    etchconn_stop((etchconn*)accepted[0]);
+
+    etchconn_stop((etchconn*)listener_ptr);
+}
+
+void testMoreConnections(void)
+{
+    int i;
+    int rc;
+    char data[] = "CONN1: this is testMoreConnections data.";
+    char data2[] = "CONN2: this is testMoreConnections data.";
+
+    CU_ASSERT(etchconn_start((etchconn*)listener_ptr));
+    rc = etchmon_wait_until_equal(listener_ptr->conn.monitor_ptr, ETCHCONN_UP, (strlen(ETCHCONN_UP)+1)*sizeof(char),0);
+    CU_ASSERT(etchconn_start((etchconn*)tcpconn_ptr));
+
+    /* create another connection to listener */
+    CU_ASSERT(etchconn_start((etchconn*) tcpconn2_ptr));
+
+    rc = etchmon_wait_until_equal(tcpconn_ptr->conn.monitor_ptr, ETCHCONN_UP, (strlen(ETCHCONN_UP)+1)*sizeof(char),0);
+    CU_ASSERT(rc==ETCHMON_STATUS_SUCCESS);
+
+    rc = etchmon_wait_until_equal(tcpconn2_ptr->conn.monitor_ptr, ETCHCONN_UP, (strlen(ETCHCONN_UP)+1)*sizeof(char),0);
+    CU_ASSERT(rc==ETCHMON_STATUS_SUCCESS);
+
+    for(i = 0; i < 100; i++)
+    {
+        CU_ASSERT(etchconn_send_tcp((etchconn*)tcpconn_ptr, data, (strlen(data)+1)*sizeof(char)));
+        CU_ASSERT(etchconn_send_tcp((etchconn*)tcpconn2_ptr, data2, (strlen(data2)+1)*sizeof(char)));
+        apr_sleep(10000);
+    }
+
+    apr_sleep(1000000);
+    etchconn_stop((etchconn*)tcpconn_ptr);
+
+    etchconn_stop((etchconn*)tcpconn2_ptr);
+
+    apr_sleep(1000000);
+    CU_ASSERT_PTR_NOT_NULL(accepted[0]);
+    etchconn_stop((etchconn*)accepted[0]);
+
+    CU_ASSERT_PTR_NOT_NULL(accepted[1]);
+    etchconn_stop((etchconn*)accepted[1]);
+
+    etchconn_stop((etchconn*)listener_ptr);
+}
+
+
+int main(int argc, char **argv)
+{
+    CU_pSuite ps;
+    CU_pTest pt;
+
+    printf("hellor world!");
+    CU_initialize_registry();
+    
+    ps = CU_add_suite("etchconn test suit", setup, teardown);
+    pt = CU_add_test(ps, "testSimple", testSimple);
+    pt = CU_add_test(ps, "testMoreConnections", testMoreConnections);
+
+    CU_automated_run_tests();
+    /*CU_console_run_tests();*/
+    
+    CU_cleanup_registry();
+    return 0;
+}
\ No newline at end of file