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 [33/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/transport/test_packetizer.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/test/transport/test_packetizer.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/test/transport/test_packetizer.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/test/transport/test_packetizer.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,2314 @@
+/* $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_packetizer.c
+ */
+
+#include "apr_time.h" /* some apr must be included first */
+#include "etch_packetizer.h"  /* must be included second */
+
+#include <tchar.h>
+#include <stdio.h>
+#include <conio.h>
+
+#include "cunit.h"
+#include "basic.h"
+#include "automated.h"
+
+#include "etch_connection.h"
+#include "etch_global.h"
+#include "etch_encoding.h"
+#include "etchthread.h"
+#include "etchlog.h"
+
+
+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;
+}
+
+/* - - - - - - - - - - - - - - 
+ * unit test support
+ * - - - - - - - - - - - - - -
+ */
+
+etch_packetizer*        g_my_packetizer;
+i_sessionpacket*        g_my_sessionpacket;
+i_transportdata*        g_my_transportdata; 
+etch_flexbuffer*        g_mybuf;
+etch_who*               g_who;
+
+#define THISTEST_WHO_VALUE 0x5151
+unsigned short CLASSID_MY_IMPL_SP;
+unsigned short CLASSID_MY_IMPL_TD;
+
+#define is_my_impl_transportdata(x) \
+ (x && ((objmask*)x)->obj_type == ETCHTYPEB_TRANSPORTDATA && ((objmask*)x)->class_id == CLASSID_MY_IMPL_TD)
+
+#define is_my_impl_sessionpkt(x) \
+ (x && ((objmask*)x)->obj_type == ETCHTYPEB_SESSIONPKT&& ((objmask*)x)->class_id == CLASSID_MY_IMPL_SP)
+
+int check_packetizer_results(i_transportdata*, etch_nativearray*);
+int check_packetizer_resultx(i_sessionpacket*, etch_nativearray*);
+int check_packetized_results (etch_arraylist*, etch_nativearray*);
+int check_packetized_result  (byte* v1, size_t c1, byte* v2, size_t c2);
+etch_arraylist* new_packetizertest_list();
+
+
+typedef enum etch_what
+{ WHAT_NONE, WHAT_DATA, WHAT_PACKET, 
+  TRANSPORT_QUERY, TRANSPORT_CONTROL, TRANSPORT_NOTIFY,
+  SESSION_QUERY,   SESSION_CONTROL,   SESSION_NOTIFY
+} etch_what;
+
+
+int is_equal_who(etch_who* who1, etch_who* who2)
+{
+    int n1 = 0, n2 = 0;
+    if (!who1 || !who2) return FALSE;
+    if (who1->class_id != CLASSID_WHO || who2->class_id != CLASSID_WHO) return FALSE;
+    if (!who1->value  || !who2->value) return FALSE;
+    if (!is_etch_int32(who1->value) || !is_etch_int32(who2->value)) return FALSE;
+    n1 = ((etch_int32*)who1->value)->value;
+    n2 = ((etch_int32*)who2->value)->value;
+    return n1 == n2;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
+ * my_impl_transportdata (i_transportdata implementation) 
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
+ */
+
+/**
+ * my_impl_transportdata
+ * test object implementing i_transportdata
+ */
+typedef struct my_impl_transportdata
+{
+    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;
+
+    /* i_transportdata interface and methods, plus original destructor
+     * which becomes replaced with a custom destructor to destroy this
+     * object. this is the model for destroying an interface wrapper object
+     * when we do not save and pass around a pointer to the wrapper, but rather
+     * a pointer to the interface. the interface in question, i_transportdata
+     * in this case, contains a pointer to the wrapper object, in this case a
+     * my_impl_transportdata*. when the interface is instantiated, its original 
+     * destructor is saved, and is replaced with a destructor which invokes
+     * the wrapper's destructor. the wrapper destructor must then know to 
+     * invoke the interface's original destructor when destroying the interface.
+     */
+    i_transportdata* itd;         /* owned */ 
+    objdtor destroy_transportdata;     /* i_transportdata original destructor */
+    etch_transport_data transport_data;  /* i_transportdata::transport_data() */
+
+    i_sessiondata*  session;      /* not owned */
+
+    etch_what       what;          
+    etch_who*       recipient;    /* not owned */
+    etch_arraylist* list;         /* owned */    
+    etch_object*    query;        /* owned */
+    etch_object*    query_result; /* owned */
+    etch_object*    control;      /* owned */
+    etch_object*    value;        /* owned */
+    etch_object*    eventx;       /* owned */
+
+} my_impl_transportdata;
+
+
+/**
+ * destroy_my_impl_transportdata()
+ * my_impl_transportdata destructor
+ */
+int destroy_my_impl_transportdata (my_impl_transportdata* thisx)
+{
+    if (thisx->refcount > 0 && --thisx->refcount > 0) return -1;  
+
+    if (!is_etchobj_static_content(thisx))
+    {       /* invoke original i_transportdata destructor */
+        if (thisx->itd && thisx->destroy_transportdata)   
+            thisx->destroy_transportdata(thisx->itd);
+
+       if (thisx->list)
+            thisx->list->destroy(thisx->list);
+
+        if (thisx->query)
+            thisx->query->destroy(thisx->query);
+
+        if (thisx->query_result)
+            thisx->query_result->destroy(thisx->query_result);
+
+        if (thisx->control)
+            thisx->control->destroy(thisx->control);
+
+        if (thisx->value)
+            thisx->value->destroy(thisx->value);
+
+        if (thisx->eventx)
+            thisx->eventx->destroy(thisx->eventx);
+    }
+
+   return destroy_objectex((objmask*) thisx);
+}
+
+
+
+/**
+ * impl_transport_data()
+ * my_impl_transportdata::transport_data
+ * @param whoto caller retains, can be null
+ * @param fbuf caller retains
+ */
+int impl_transport_data (my_impl_transportdata* mytd, etch_who* whoto, etch_flexbuffer* fbuf)
+{
+    etch_nativearray* wrapped_array = NULL;
+    byte* newbuf = NULL;
+    size_t bytecount = 0;
+
+    assert(is_my_impl_transportdata(mytd));   
+    assert(is_etch_transportdata(mytd->itd));     
+
+    mytd->what = WHAT_DATA;
+    mytd->recipient = whoto;   
+   
+    /* get a new byte vector of the entire packet from the buffer */
+    newbuf = etch_flexbuf_get_all (fbuf, &bytecount);
+
+    /* wrap the packet bytes in an etch_nativearray object */
+    wrapped_array = new_nativearray_from (newbuf,
+        CLASSID_ARRAY_BYTE, sizeof(byte), 1, (int) bytecount, 0, 0); 
+
+    /* we want wrapped array to own new packet bytes memory */
+    wrapped_array->is_content_owned = TRUE;
+
+    return arraylist_add (mytd->list, wrapped_array);
+}
+
+
+/**
+ * my_transport_control()
+ * my_impl_transportdata::itransport::transport_control 
+ */
+int my_transport_control (my_impl_transportdata* mytd, etch_object* control, etch_object* value)
+{
+    /* changed parameter from i_transportdata* to my_impl_transportdata to correspond to change  
+     * in etch_pktizer_transport_control to pass pzr->transport->thisx rather than pzr->transport.
+     * likewise for my_transport_notify() and my_transport_query. */
+    CU_ASSERT_FATAL(is_my_impl_transportdata(mytd));
+    mytd->what    = TRANSPORT_CONTROL;
+    mytd->control = control;
+    mytd->value   = value;
+    return 0;
+}
+
+
+/**
+ * my_transport_notify()
+ * my_impl_transportdata::itransport::transport_notify 
+ */
+int my_transport_notify (my_impl_transportdata* mytd, etch_object* evt)
+{
+    CU_ASSERT_FATAL(is_my_impl_transportdata(mytd));
+    mytd->what   = TRANSPORT_NOTIFY;
+    mytd->eventx = evt;
+    return 0;
+}
+
+
+/**
+ * my_transport_query()
+ * my_impl_transportdata::itransport::transport_query 
+ */
+objmask* my_transport_query (my_impl_transportdata* mytd, etch_object* query) 
+{
+    etch_object* resultobj = NULL;
+    CU_ASSERT_FATAL(is_my_impl_transportdata(mytd));
+    resultobj   = mytd->query_result; /* set artificially in test */
+    mytd->what  = TRANSPORT_QUERY;
+    mytd->query = query;
+    mytd->query_result = NULL;
+    return (objmask*) resultobj;  /* caller owns */
+}
+
+
+/**
+ * my_transport_get_session()
+ * my_impl_transportdata::itransport::get_session 
+ */
+i_sessiondata* my_transport_get_session (my_impl_transportdata* mytd)
+{
+    ETCH_ASSERT(is_etch_transportdata(mytd));
+    return mytd->session;
+}
+
+
+/**
+ * my_transport_set_session()
+ * my_impl_transportdata::itransport::set_session
+ */
+void my_transport_set_session (my_impl_transportdata* mytd, i_sessiondata* newsession)
+{   
+    ETCH_ASSERT(is_etch_transportdata(mytd));
+    ETCH_ASSERT(is_etch_sessiondata(newsession));
+    mytd->session = newsession;
+}
+
+
+/*
+ * destroy_my_transportdata()
+ * i_transportdata destructor
+ * this destructor will destroy its parent (my_impl_transportdata), 
+ * which will in turn destroy this object.
+ */
+int destroy_my_transportdata(i_transportdata* itd)
+{
+    my_impl_transportdata* mytd = NULL;
+    if (NULL == itd) return -1;
+
+    mytd = itd->thisx;  
+
+    mytd->destroy(mytd);
+
+    return 0;
+}
+
+
+/**
+ * new_my_impl_transportdata()
+ * my_impl_transportdata constructor
+ */
+my_impl_transportdata* new_my_impl_transportdata()
+{
+    i_transportdata* itd  = NULL;
+    i_transport* itransport = NULL;
+    /* this is a model for dynamic class ID assigment */
+    unsigned short class_id = CLASSID_MY_IMPL_TD? CLASSID_MY_IMPL_TD: 
+        (CLASSID_MY_IMPL_TD = get_dynamic_classid());
+
+    my_impl_transportdata* mytd = (my_impl_transportdata*) new_object
+      (sizeof(my_impl_transportdata), ETCHTYPEB_TRANSPORTDATA, class_id);
+
+    mytd->destroy = destroy_my_impl_transportdata;
+
+    itransport = new_transport_interface_ex (mytd,
+        (etch_transport_control)     my_transport_control, 
+        (etch_transport_notify)      my_transport_notify, 
+        (etch_transport_query)       my_transport_query,
+        (etch_transport_get_session) my_transport_get_session, 
+        (etch_transport_set_session) my_transport_set_session);
+
+    itd = new_transportdata_interface(mytd, impl_transport_data, itransport);
+
+    /* save off i_transportdata destructor */
+    mytd->destroy_transportdata = itd->destroy;   
+
+    /* replace i_transportdata destructor with one which will destroy this object */
+    itd->destroy = destroy_my_transportdata;
+
+    mytd->list = new_packetizertest_list();
+
+    /* g_my_transportdata will get set to this interface */
+    mytd->itd = itd;  
+
+    return mytd;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
+ * my_impl_sessionpacket (i_sessionpacket implementation) 
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
+ */
+
+/**
+ * my_impl_sessionpacket
+ * test object implementing i_sessionpacket
+ */
+typedef struct my_impl_sessionpacket
+{
+    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;
+
+    /* i_sessionpacket interface and methods, plus original destructor
+     * which becomes replaced with a custom destructor to destroy this
+     * object. this is the model for destroying an interface wrapper object
+     * when we do not save and pass around a pointer to the wrapper, but rather
+     * a pointer to the interface. the interface in question, i_sessionpacket
+     * in this case, contains a pointer to the wrapper object, in this case a
+     * my_impl_sessionpacket*. when the interface is instantiated, its original 
+     * destructor is saved, and is replaced with a destructor which invokes
+     * the wrapper's destructor. the wrapper destructor must then know to 
+     * invoke the interface's original destructor when destroying the interface.
+     */
+    i_sessionpacket* isp;          /* owned */
+
+    objdtor destroy_sessionpacket; /* i_sessionpacket original destructor */
+    etch_session_packet session_packet;  /* session_packet() */
+
+    etch_what       what;          
+    etch_who*       sender;        /* not owned */ 
+    etch_arraylist* list;          /* owned */    
+    etch_object*    query;         /* owned */
+    etch_object*    query_result;  /* owned */
+    etch_object*    control;       /* owned */
+    etch_object*    value;         /* owned */
+    etch_object*    eventx;        /* owned */
+
+} my_impl_sessionpacket;
+
+
+/**
+ * destroy_my_impl_sessionpacket()
+ * my_impl_sessionpacket destructor
+ */
+int destroy_my_impl_sessionpacket(my_impl_sessionpacket* thisx)
+{
+    if (thisx->refcount > 0 && --thisx->refcount > 0) return -1;  
+
+    if (!is_etchobj_static_content(thisx))
+    {       /* invoke original i_sessionpacket destructor */
+        if (thisx->isp && thisx->destroy_sessionpacket)   
+            thisx->destroy_sessionpacket(thisx->isp);
+  
+        if (thisx->list)
+            thisx->list->destroy(thisx->list);
+
+        if (thisx->query)
+            thisx->query->destroy(thisx->query);
+
+        if (thisx->query_result)
+            thisx->query_result->destroy(thisx->query_result);
+
+        if (thisx->control)
+            thisx->control->destroy(thisx->control);
+
+        if (thisx->value)
+            thisx->value->destroy(thisx->value);
+
+        if (thisx->eventx)
+            thisx->eventx->destroy(thisx->eventx);
+    }
+
+   return destroy_objectex((objmask*) thisx);
+}
+
+
+/**
+ * impl_session_packet()
+ * my_impl_sessionpacket::session_packet
+ * @param whofrom caller retains, can be null
+ * @param fbuf caller retains
+ */
+int impl_session_packet (my_impl_sessionpacket* mysp, etch_who* whofrom, etch_flexbuffer* fbuf)
+{
+    etch_nativearray* wrapped_array = NULL;
+    byte* newbuf = NULL;
+    size_t bytecount = 0;
+    CU_ASSERT_FATAL(is_my_impl_sessionpkt(mysp));
+    mysp->what   = WHAT_PACKET;
+    mysp->sender = whofrom;   
+   
+    /* get a new byte vector of the entire packet from the buffer */
+    newbuf = etch_flexbuf_get_all(fbuf, &bytecount);
+
+    /* wrap the packet bytes in an etch_nativearray object */
+    wrapped_array = new_nativearray_from(newbuf,
+        CLASSID_ARRAY_BYTE, sizeof(byte), 1, (int) bytecount, 0, 0); 
+
+    /* we want wrapped array to own new packet bytes memory */
+    wrapped_array->is_content_owned = TRUE;
+
+    return arraylist_add(mysp->list, wrapped_array);
+}
+
+
+/**
+ * my_session_control()
+ * my_impl_sessionpacket::isession::session_control 
+ */
+int my_session_control (my_impl_sessionpacket* mysp, etch_object* control, etch_object* value)
+{
+    CU_ASSERT_FATAL(is_my_impl_sessionpkt(mysp));
+    mysp->what    = SESSION_CONTROL;
+    mysp->control = control;
+    mysp->value   = value;
+    return 0;
+}
+
+
+/**
+ * my_session_notify()
+ * my_impl_sessionpacket::isession::session_notify 
+ */
+int my_session_notify (my_impl_sessionpacket* mysp, etch_object* evt)
+{
+    CU_ASSERT_FATAL(is_my_impl_sessionpkt(mysp));
+    mysp->what   = SESSION_NOTIFY;
+    mysp->eventx = evt;
+    return 0;
+}
+
+
+/**
+ * my_session_query()
+ * my_impl_sessionpacket::isession::session_query 
+ */
+objmask* my_session_query (my_impl_sessionpacket* mysp, etch_object* query) 
+{
+    etch_object* resultobj = NULL;
+    CU_ASSERT_FATAL(is_my_impl_sessionpkt(mysp));
+    resultobj = mysp->query_result; /* set artificially in test */
+    mysp->what  = SESSION_QUERY;
+    mysp->query = query;
+    mysp->query_result = NULL;
+    return (objmask*) resultobj;  /* caller owns */
+}
+
+
+/**
+ * new_packetizertest_list()
+ * constructor for a list which owns content memory and where content is etch_object derived.
+ * content will be etch_nativearray objects
+ */
+etch_arraylist* new_packetizertest_list()
+{
+    etch_arraylist* list = new_arraylist(32,0);
+    list->content_type = ETCHARRAYLIST_CONTENT_OBJECT; /* list can call destroy() on list item */
+    list->is_readonly  = FALSE;
+    return list;
+}
+
+
+/*
+ * destroy_my_sessionpacket()
+ * i_sessionpacket destructor
+ * this destructor will destroy its parent (my_impl_sessionpacket), 
+ * which will in turn destroy this object.
+ */
+int destroy_my_sessionpacket(i_sessionpacket* itp)
+{
+    my_impl_sessionpacket* mytp = NULL;
+    if (NULL == itp) return -1;
+
+    mytp = itp->thisx;  
+
+    mytp->destroy(mytp);
+
+    return 0;
+}
+
+
+/**
+ * new_my_impl_sessionpacket()
+ * my_impl_sessionpacket constructor
+ */
+my_impl_sessionpacket* new_my_impl_sessionpacket()
+{
+    i_sessionpacket* isessionpkt  = NULL;
+    i_session* isession = NULL;
+    /* this is a model for dynamic class ID assigment */
+    unsigned short class_id = CLASSID_MY_IMPL_SP? CLASSID_MY_IMPL_SP: 
+        (CLASSID_MY_IMPL_SP = get_dynamic_classid());
+
+    my_impl_sessionpacket* mysessionpkt = (my_impl_sessionpacket*) new_object
+      (sizeof(my_impl_sessionpacket), ETCHTYPEB_SESSIONPKT, class_id);
+
+    mysessionpkt->destroy = destroy_my_impl_sessionpacket;
+
+    mysessionpkt->list = new_packetizertest_list();
+
+    isession = new_session_interface(mysessionpkt,
+        (etch_session_control) my_session_control, 
+        (etch_session_notify)  my_session_notify, 
+        (etch_session_query)   my_session_query);
+
+    isessionpkt = new_sessionpkt_interface(mysessionpkt, impl_session_packet, isession);
+
+    /* save off i_sessionpacket destructor */
+    mysessionpkt->destroy_sessionpacket = isessionpkt->destroy;
+
+    /* replace i_sessionpacket destructor with one which will destroy this object */
+    isessionpkt->destroy = destroy_my_sessionpacket;
+
+    /* g_my_sessionpacket will get set to this interface */
+    mysessionpkt->isp = isessionpkt;  
+
+    return mysessionpkt;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - 
+ * support functions
+ * - - - - - - - - - - - - - - - - - - - - - -
+ */
+
+/**
+ * check_packetizer_results()
+ * check array of packetizer result byte arrays against a control byte array. 
+ * arrays may be packet payloads, or packets with headers, depending on test. 
+ * result arrays are found in the packet handler arraylist, each such list item
+ * being an etch_nativearray object of one dimension, wrapping that result array. 
+ * control arrays are passed as an etch_nativearray of two dimensions, created 
+ * from a static 2-dimensional array.
+ */
+int check_packetizer_results(i_transportdata* itd, etch_nativearray* expected_array)
+{   
+    my_impl_transportdata*  mytd = (my_impl_transportdata*) itd->thisx;
+    const int packetcount = mytd->list->count; /* # of result arrays in list */
+    int errors = 0;
+
+    if (NULL == expected_array) /* todo: also check for zero populated count */
+        return packetcount == 0? 0: -1;
+
+    if (packetcount != expected_array->dimension[1]) 
+        return -1; /* check against count of expected results */
+
+    errors = check_packetized_results(mytd->list, expected_array);
+     
+    return errors? -1: 0;
+}
+
+
+/**
+ * check_packetizer_resultx()
+ * check array of packetizer result byte arrays against a control byte array. 
+ * arrays may be packet payloads, or packets with headers, depending on test. 
+ * result arrays are found in the packet handler arraylist, each such list item
+ * being an etch_nativearray object of one dimension, wrapping that result array. 
+ * control arrays are passed as an etch_nativearray of two dimensions, created 
+ * from a static 2-dimensional array.
+ */
+int check_packetizer_resultx(i_sessionpacket* isp, etch_nativearray* expected_array)
+{   
+    my_impl_sessionpacket*  mysp = (my_impl_sessionpacket*) isp->thisx;
+    const int packetcount = mysp->list->count; /* # of result arrays in list */
+    int errors = 0;
+
+    if (NULL == expected_array) /* todo: also check for zero populated count */
+        return packetcount == 0? 0: -1;
+
+    if (packetcount != expected_array->dimension[1]) 
+        return -1; /* check against count of expected results */
+
+    errors = check_packetized_results(mysp->list, expected_array);
+     
+    return errors? -1: 0;
+}
+
+
+/**
+ * check_packetized_results()
+ */
+int check_packetized_results(etch_arraylist* list, etch_nativearray* expected_array)
+{
+    etch_iterator iterator;
+    int result = 0, errors = 0, i = 0;
+    set_iterator(&iterator, list, &list->iterable);
+
+    while(iterator.has_next(&iterator))
+    {   
+        /* get result (one-dimension byte array) out of list */
+        etch_nativearray* resultobj = arraylist_get(list, i);
+        byte*  packetizedbytes = resultobj->values;   
+        size_t packetizedbytecount = resultobj->dimension[0];
+
+        /* get (offset to) this result out of expected results */
+        size_t dim2offset = etch_nativearray_off2(expected_array, i, 0);
+        byte*  expected_bytes = (byte*) expected_array->values + dim2offset;  
+        size_t expected_bytecount = expected_array->dimension[0];
+
+        result = check_packetized_result(packetizedbytes, packetizedbytecount, 
+            expected_bytes, expected_bytecount);
+
+        if (result == -1)
+            errors++;
+
+        i++;
+        iterator.next(&iterator);
+    }
+     
+    return errors;
+}
+
+
+/**
+ * check_packetized_result()
+ * check a single packetizer result array against a control array, 
+ * each represented as a byte vector. the array can be a packet, or a packet payload,
+ * depending on tested direction of the packetizer call.
+ */
+int check_packetized_result (byte* v1, size_t c1, byte* v2, size_t c2)
+{   
+    byte  *p = 0, *q = 0;
+    size_t i = 0, errors = 0;
+
+    if (c1 != c2)   return FALSE;
+    if (!v1 && !v2) return TRUE;
+    if (!v1 || !v2) return FALSE;
+
+    for(p = v1, q = v2; i < c1; i++, p++, q++)
+        if (*p != *q) 
+            errors++;
+
+    return errors? -1: 0;
+}
+  
+
+/* - - - - - - - - - - - - - - - - - - - - - - 
+ * individual setup and teardown
+ * - - - - - - - - - - - - - - - - - - - - - -
+ */
+
+/**
+ * setup_this_test()
+ */
+int setup_this_test()
+{
+    my_impl_transportdata* mytd_impl = NULL;
+    my_impl_sessionpacket* mysp_impl = NULL;
+
+    /* we instantiate a wrapper x which implements and instantiates i_transportpacket.
+     * the instantiation of i_transportpacket will contain a pointer to x.
+     * our global reference g_my_transportpacket is a pointer to the interface.
+     * the purpose of this excercise is that, in the real binding we can pass
+     * around the interface, whose methods can be then invoked without knowing
+     * anything about the wrapper. when we want to reference the wrapper x, 
+     * it is (my_impl_transportpacket) g_my_transportpacket->thisx. 
+     */
+    mytd_impl = new_my_impl_transportdata();
+    g_my_transportdata = mytd_impl->itd;
+    CU_ASSERT_FATAL(is_my_impl_transportdata(g_my_transportdata->thisx));
+
+    /* we instantiate a wrapper y which implements and instantiates i_sessionpacket.
+     * the instantiation of i_sessionpacket will contain a pointer to y.
+     * our global reference g_my_sessionpacket is a pointer to the interface.
+     * the purpose of this excercise is that, in the real binding we can pass
+     * around the interface, whose methods can be then invoked without knowing
+     * anything about the wrapper. when we want to reference the wrapper x, 
+     * it is (my_impl_sessionpacket*) g_my_sessionpacket->thisx. 
+     */
+    mysp_impl = new_my_impl_sessionpacket();
+    g_my_sessionpacket = mysp_impl->isp;
+    
+    g_who = new_who(new_int32(THISTEST_WHO_VALUE), TRUE);
+
+    /* finally instantiate the test packetizer */
+    g_my_packetizer = new_packetizer(g_my_transportdata, L"tcp", NULL);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(g_my_packetizer);
+    g_my_packetizer->set_session(g_my_packetizer, g_my_sessionpacket);
+  
+    return 0; 
+}
+
+
+/**
+ * teardown_this_test()
+ */
+int teardown_this_test()
+{
+    g_my_packetizer->destroy(g_my_packetizer);
+
+    g_my_sessionpacket->destroy(g_my_sessionpacket);  // destroy() is now 0xfeeefeee
+
+    g_my_transportdata->destroy(g_my_transportdata);
+
+    g_who->destroy(g_who);
+
+    if (g_mybuf)
+        g_mybuf->destroy(g_mybuf);
+
+    g_my_packetizer = NULL;
+    g_my_sessionpacket = NULL; 
+    g_my_transportdata = NULL;
+    g_mybuf = NULL;
+    g_who = NULL;
+
+    return 0; 
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - 
+ * tests
+ * - - - - - - - - - - - - - - - - - - - - - -
+ */
+
+/**
+ * test_sessionpacket_constructor()
+ */
+void test_sessionpacket_constructor(void)
+{
+    my_impl_sessionpacket* mysp_impl = new_my_impl_sessionpacket();
+    CU_ASSERT_PTR_NOT_NULL_FATAL(mysp_impl);
+
+    /* the custom interface object destructors are coded to destroy their
+     * implementing objects, so we do that here to verify this functionality.
+     */
+    do 
+    {   i_sessionpacket* isp = mysp_impl->isp;
+        isp->destroy(isp);
+
+    } while(0);
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE); /* verify all memory freed */
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();  /* start fresh for next test */   
+}
+
+
+/**
+ * test_transportdata_constructor()
+ */
+void test_transportdata_constructor(void)
+{
+    my_impl_transportdata* mytd_impl = new_my_impl_transportdata();
+    CU_ASSERT_PTR_NOT_NULL_FATAL(mytd_impl);
+
+    /* the custom interface object destructors are coded to destroy their
+     * implementing objects, so we do that here to verify this functionality.
+     */
+    do 
+    {   i_transportdata* itd = mytd_impl->itd;
+        itd->destroy(itd);
+
+    } while(0);
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE); /* verify all memory freed */
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();  /* start fresh for next test */   
+}
+
+
+/**
+ * test_packetizer_constructor()
+ */
+void test_packetizer_constructor(void)
+{
+    etch_packetizer* pzr = NULL;
+    i_transportdata* itd = NULL;
+    my_impl_transportdata* mytd_impl = NULL;
+
+    mytd_impl = new_my_impl_transportdata();   
+    CU_ASSERT_PTR_NOT_NULL_FATAL(mytd_impl);
+
+    itd = mytd_impl->itd;
+    CU_ASSERT_PTR_NOT_NULL_FATAL(itd);
+
+    /* packetizer does not own i_transportdata* itd */
+    pzr = new_packetizer(itd, L"tcp", NULL);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(pzr);
+
+    pzr->destroy(pzr);
+
+    /* i_transportdata.destroy() will destroy my_impl_transportdata */
+    itd->destroy(itd);
+
+    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_test_setup()
+ * test that the test setup works with all memory accounted for.
+ * if this test fails, all subsequent tests would also fail.
+ * all subsequent tests should include this skeleton code.
+ */
+void test_test_setup(void)
+{
+    int result = setup_this_test();
+
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(g_who);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(g_my_packetizer);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(g_my_sessionpacket);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(g_my_transportdata);
+
+    teardown_this_test();
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);  
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();  /* start fresh for next test */
+}
+
+
+/**
+ * test_to_source_packet1()
+ * test 1 for packets delivered to packet source
+ */
+void test_to_source_packet1(void)
+{
+    setup_this_test();
+
+    do          
+    {   int result = 0;
+        byte* disposable_packet = NULL;
+        #define EXPECTED_HEADERSIZE 8
+        etch_nativearray* expected_result_array = NULL;
+        my_impl_transportdata* mytransport = g_my_transportdata->thisx; 
+
+        byte empty_packet[EXPECTED_HEADERSIZE] = { 0,0,0,0, 0,0,0,0, };
+
+        byte expected_result[][EXPECTED_HEADERSIZE] = 
+        {
+            {
+                -34,-83,-66,-17,  0,0,0,0,
+            },
+        };
+
+        CU_ASSERT_EQUAL_FATAL(g_my_packetizer->headersize, EXPECTED_HEADERSIZE);
+
+        expected_result_array = new_nativearray_from
+          (&expected_result, CLASSID_ARRAY_BYTE, sizeof(byte), 2, EXPECTED_HEADERSIZE, 1, 0);
+      
+        disposable_packet = etch_malloc(sizeof(empty_packet), ETCHTYPEB_BYTES);
+        memcpy(disposable_packet, empty_packet, sizeof(empty_packet));
+       
+        g_mybuf = new_flexbuffer_from(disposable_packet, sizeof(empty_packet), 1024, 0);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(g_mybuf);
+
+        result = g_my_packetizer->transport_packet(g_my_packetizer, g_who, g_mybuf);
+        CU_ASSERT_EQUAL(result, 0);
+         
+        result = check_packetizer_results(g_my_packetizer->transport, expected_result_array);
+        CU_ASSERT_EQUAL(result, 0);
+
+        CU_ASSERT_EQUAL(mytransport->what, WHAT_DATA);
+        result = is_equal_who(mytransport->recipient, g_who);
+        CU_ASSERT_EQUAL(result, TRUE);
+
+        expected_result_array->destroy(expected_result_array);
+
+     } while(0);
+
+    teardown_this_test();
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);  
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();  /* start fresh for next test */
+}
+
+
+/**
+ * test_to_source_packet2()
+ * test 2 for packets delivered to packet source
+ */
+void test_to_source_packet2(void)
+{
+   setup_this_test();
+
+    do          
+    {   int result = 0;
+        #define TTSP2BYTECOUNT 9
+        byte* disposable_packet = NULL;
+        etch_nativearray* expected_result_array = NULL;
+        my_impl_transportdata* mytransport = g_my_transportdata->thisx; 
+
+        byte test_packet[TTSP2BYTECOUNT] = { 0,0,0,0, 0,0,0,0, 1 };
+
+        byte expected_result[][TTSP2BYTECOUNT] = 
+        {     /* --signature---  data-length  data  */
+            { /* de  ad  be  ef  00 00 00 01  01    */
+                -34,-83,-66,-17,  0, 0, 0, 1,  1
+            },
+        };
+
+        CU_ASSERT_EQUAL_FATAL(g_my_packetizer->headersize, EXPECTED_HEADERSIZE);
+
+        expected_result_array = new_nativearray_from
+          (&expected_result, CLASSID_ARRAY_BYTE, sizeof(byte), 2, TTSP2BYTECOUNT, 1, 0);
+      
+        disposable_packet = etch_malloc(sizeof(test_packet), ETCHTYPEB_BYTES);
+        memcpy(disposable_packet, test_packet, sizeof(test_packet));
+       
+        g_mybuf = new_flexbuffer_from(disposable_packet, sizeof(test_packet), 64, 0);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(g_mybuf);
+
+        result = g_my_packetizer->transport_packet(g_my_packetizer, g_who, g_mybuf);
+        CU_ASSERT_EQUAL(result, 0);
+         
+        result = check_packetizer_results(g_my_packetizer->transport, expected_result_array);
+        CU_ASSERT_EQUAL(result, 0);
+
+        CU_ASSERT_EQUAL(mytransport->what, WHAT_DATA);
+        result = is_equal_who(mytransport->recipient, g_who);
+        CU_ASSERT_EQUAL(result, TRUE);
+
+        expected_result_array->destroy(expected_result_array);
+
+    } while(0);
+
+    teardown_this_test();
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);  
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();  /* start fresh for next test */
+}
+
+
+/**
+ * test_to_source_packet3()
+ * test 3 for packets delivered to packet source
+ */
+void test_to_source_packet3(void)
+{
+    setup_this_test();
+
+    do          
+    {   int result = 0;
+        #define TTSP3BYTECOUNT 10
+        byte* disposable_packet = NULL;
+        etch_nativearray* expected_result_array = NULL;
+        my_impl_transportdata* mytransport = g_my_transportdata->thisx; 
+
+        byte test_packet[TTSP3BYTECOUNT] = { 0,0,0,0, 0,0,0,0, 2, 3 };
+
+        byte expected_result[][TTSP3BYTECOUNT] = 
+        {     /* --signature---  data-length  data  */
+            { /* de  ad  be  ef  00 00 00 02  02 03 */
+                -34,-83,-66,-17,  0, 0, 0, 2,  2, 3
+            },
+        };
+
+        CU_ASSERT_EQUAL_FATAL(g_my_packetizer->headersize, EXPECTED_HEADERSIZE);
+
+        expected_result_array = new_nativearray_from
+          (&expected_result, CLASSID_ARRAY_BYTE, sizeof(byte), 2, TTSP3BYTECOUNT, 1, 0);
+      
+        disposable_packet = etch_malloc(sizeof(test_packet), ETCHTYPEB_BYTES);
+        memcpy(disposable_packet, test_packet, sizeof(test_packet));
+       
+        g_mybuf = new_flexbuffer_from(disposable_packet, sizeof(test_packet), 64, 0);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(g_mybuf);
+
+        result = g_my_packetizer->transport_packet(g_my_packetizer, g_who, g_mybuf);
+        CU_ASSERT_EQUAL(result, 0);
+         
+        result = check_packetizer_results(g_my_packetizer->transport, expected_result_array);
+        CU_ASSERT_EQUAL(result, 0);
+
+        CU_ASSERT_EQUAL(mytransport->what, WHAT_DATA);
+        result = is_equal_who(mytransport->recipient, g_who);
+        CU_ASSERT_EQUAL(result, TRUE);
+
+        expected_result_array->destroy(expected_result_array);
+
+    } while(0);
+
+    teardown_this_test();
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);  
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();  /* start fresh for next test */
+}
+
+
+/**
+ * test_to_source_badpacket1()
+ * test 4 for packets delivered to packet source
+ */
+void test_to_source_badpacket1(void)
+{
+    setup_this_test();
+
+    do          
+    {   int result = 0;
+        #define TTSP4BYTECOUNT 7
+        byte* disposable_packet = NULL;
+        etch_nativearray* expected_result_array = NULL;
+        my_impl_transportdata* mytransport = g_my_transportdata->thisx; 
+
+        byte test_packet[TTSP4BYTECOUNT] = { 0,0,0,0, 0,0,0 }; /* too short */
+      
+        disposable_packet = etch_malloc(sizeof(test_packet), ETCHTYPEB_BYTES);
+        memcpy(disposable_packet, test_packet, sizeof(test_packet));
+       
+        g_mybuf = new_flexbuffer_from(disposable_packet, sizeof(test_packet), 256, 0);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(g_mybuf);
+
+        result = g_my_packetizer->transport_packet(g_my_packetizer, g_who, g_mybuf);
+        CU_ASSERT_EQUAL(result, -1);
+
+    } while(0);
+
+    teardown_this_test();
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);  
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();  /* start fresh for next test */
+}
+
+
+/**
+ * test_badpacket1()
+ * test 1 for bad packet data
+ */
+void test_badpacket1(void)
+{
+   setup_this_test();
+
+    do          
+    {   int result = 0;     
+        #define TBP1COUNT 8
+        byte* disposable_packet = NULL;        
+        byte  test_packet_1[TBP1COUNT] = { 0,0,0,0,          0,0,0,0 };  /* bad sig */
+        byte  test_packet_2[TBP1COUNT] = { 1,2,3,4,          0,0,0,0 };  /* bad sig */
+        byte  test_packet_3[TBP1COUNT] = { -34,-83,-66,-17,  0,1,0,0 };  /* bad len */
+      
+        /* bad signature 1 */
+        disposable_packet = etch_malloc(sizeof(test_packet_1), ETCHTYPEB_BYTES);
+        memcpy(disposable_packet, test_packet_1, sizeof(test_packet_1));
+       
+        g_mybuf = new_flexbuffer_from(disposable_packet, sizeof(test_packet_1), 256, 0);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(g_mybuf);
+
+        result = g_my_packetizer->session_data(g_my_packetizer, g_who, g_mybuf);
+        CU_ASSERT_EQUAL(result, -1);
+
+        g_mybuf->destroy(g_mybuf); g_mybuf = NULL;
+
+        /* bad signature 2 */
+        disposable_packet = etch_malloc(sizeof(test_packet_2), ETCHTYPEB_BYTES);
+        memcpy(disposable_packet, test_packet_2, sizeof(test_packet_2));
+       
+        g_mybuf = new_flexbuffer_from(disposable_packet, sizeof(test_packet_2), 256, 0);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(g_mybuf);  
+
+        result = g_my_packetizer->session_data(g_my_packetizer, g_who, g_mybuf);
+        CU_ASSERT_EQUAL(result, -1);
+
+        g_mybuf->destroy(g_mybuf); g_mybuf = NULL; 
+
+        /* bad data length (65536) */
+        disposable_packet = etch_malloc(sizeof(test_packet_3), ETCHTYPEB_BYTES);
+        memcpy(disposable_packet, test_packet_3, sizeof(test_packet_3));
+       
+        g_mybuf = new_flexbuffer_from(disposable_packet, sizeof(test_packet_3), 256, 0);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(g_mybuf);  
+
+        result = g_my_packetizer->session_data(g_my_packetizer, g_who, g_mybuf);
+        CU_ASSERT_EQUAL(result, -1);
+
+        g_mybuf->destroy(g_mybuf); g_mybuf = NULL; 
+
+    } while(0);
+
+    teardown_this_test();
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);  
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();  /* start fresh for next test */
+}
+
+
+/**
+ * test_single_single_data()
+ * 3 tests for single packet in a single buffer
+ */
+void test_single_single_data(void)
+{
+    setup_this_test();
+
+    do          
+    {   int result = 0;     
+        #define TSPSB1BYTECOUNT 8
+        #define TSPSB2BYTECOUNT 9
+        #define TSPSB2RESULTBYTECOUNT 1
+        #define TSPSB3BYTECOUNT 10
+        #define TSPSB3RESULTBYTECOUNT 2
+        byte* disposable_packet = NULL;        
+        etch_nativearray* expected_result_2_array = NULL;
+        etch_nativearray* expected_result_3_array = NULL;
+
+        my_impl_sessionpacket* mysessionpkt = g_my_sessionpacket->thisx; 
+
+        byte test_packet_1[TSPSB1BYTECOUNT] = { -34,-83,-66,-17,  0,0,0,0,      }; 
+        byte test_packet_2[TSPSB2BYTECOUNT] = { -34,-83,-66,-17,  0,0,0,1,  1,  }; 
+        byte test_packet_3[TSPSB3BYTECOUNT] = { -34,-83,-66,-17,  0,0,0,2,  3,4 }; 
+
+        byte expected_result_2[][TSPSB2RESULTBYTECOUNT] = 
+        {      
+            {  
+               1
+            },
+        };
+
+        byte expected_result_3[][TSPSB3RESULTBYTECOUNT] = 
+        {      
+            {  
+               3, 4
+            },
+        };
+
+        /* test 1 */
+        disposable_packet = etch_malloc(sizeof(test_packet_1), ETCHTYPEB_BYTES);
+        memcpy(disposable_packet, test_packet_1, sizeof(test_packet_1));
+       
+        g_mybuf = new_flexbuffer_from(disposable_packet, sizeof(test_packet_1), 64, 0);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(g_mybuf);
+        CU_ASSERT_EQUAL(g_mybuf->datalen, sizeof(test_packet_1));
+
+        result = g_my_packetizer->session_data (g_my_packetizer, g_who, g_mybuf);
+        CU_ASSERT_EQUAL(result,0);
+
+        result = check_packetizer_resultx(g_my_sessionpacket, NULL);
+        CU_ASSERT_EQUAL(result, 0);
+
+        CU_ASSERT_EQUAL(mysessionpkt->what, WHAT_NONE);
+        CU_ASSERT_PTR_NULL(mysessionpkt->sender);
+
+        g_mybuf->destroy(g_mybuf); g_mybuf = NULL;
+
+        /* test 2 */ 
+        disposable_packet = etch_malloc(sizeof(test_packet_2), ETCHTYPEB_BYTES);
+        memcpy(disposable_packet, test_packet_2, sizeof(test_packet_2));
+       
+        g_mybuf = new_flexbuffer_from(disposable_packet, sizeof(test_packet_2), 64, 0);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(g_mybuf);
+        CU_ASSERT_EQUAL(g_mybuf->datalen, sizeof(test_packet_2));
+
+        result = g_my_packetizer->session_data (g_my_packetizer, g_who, g_mybuf);
+        CU_ASSERT_EQUAL(result,0);
+
+        expected_result_2_array = new_nativearray_from
+         (&expected_result_2, CLASSID_ARRAY_BYTE, sizeof(byte), 2, TSPSB2RESULTBYTECOUNT, 1, 0);
+
+        result = check_packetizer_resultx (g_my_sessionpacket, expected_result_2_array);
+        CU_ASSERT_EQUAL(result, 0);
+
+        CU_ASSERT_EQUAL(mysessionpkt->what, WHAT_PACKET);
+        result = is_equal_who(mysessionpkt->sender, g_who);
+        CU_ASSERT_EQUAL(result, TRUE);
+
+        expected_result_2_array->destroy(expected_result_2_array);
+        g_mybuf->destroy(g_mybuf); g_mybuf = NULL; 
+        arraylist_clear (mysessionpkt->list, TRUE);
+
+        /* test 3 */
+        disposable_packet = etch_malloc(sizeof(test_packet_3), ETCHTYPEB_BYTES);
+        memcpy(disposable_packet, test_packet_3, sizeof(test_packet_3));
+       
+        g_mybuf = new_flexbuffer_from(disposable_packet, sizeof(test_packet_3), 64, 0);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(g_mybuf);
+        CU_ASSERT_EQUAL(g_mybuf->datalen, sizeof(test_packet_3));
+
+        result = g_my_packetizer->session_data (g_my_packetizer, g_who, g_mybuf);
+        CU_ASSERT_EQUAL(result,0);
+
+        expected_result_3_array = new_nativearray_from
+          (&expected_result_3, CLASSID_ARRAY_BYTE, sizeof(byte), 2, TSPSB3RESULTBYTECOUNT, 1, 0);
+        
+        result = check_packetizer_resultx (g_my_sessionpacket, expected_result_3_array);
+        CU_ASSERT_EQUAL(result, 0);
+
+        CU_ASSERT_EQUAL(mysessionpkt->what, WHAT_PACKET);
+        result = is_equal_who(mysessionpkt->sender, g_who);
+        CU_ASSERT_EQUAL(result, TRUE);
+
+        expected_result_3_array->destroy(expected_result_3_array);
+        g_mybuf->destroy(g_mybuf); g_mybuf = NULL; 
+
+    } while(0);
+
+    teardown_this_test();
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);  
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();  /* start fresh for next test */
+}
+
+
+/**
+ * test_two_in_one_buffer_data_1()
+ * test two packets in a single buffer
+ */
+void test_two_in_one_buffer_data_1(void)
+{
+    setup_this_test();
+
+    do          
+    {   int result = 0;     
+        #define TWOIN1_1_BYTECOUNT (8 + 8)
+        signed char* disposable_packet;
+     
+        signed char test_packet[TWOIN1_1_BYTECOUNT] 
+            = { -34,-83,-66,-17,  0,0,0,0,   
+                -34,-83,-66,-17,  0,0,0,0,  
+              }; 
+
+        my_impl_sessionpacket* mysessionpkt = g_my_sessionpacket->thisx; 
+        disposable_packet = etch_malloc(sizeof(test_packet), ETCHTYPEB_BYTES);
+        memcpy(disposable_packet, test_packet, sizeof(test_packet));
+       
+        g_mybuf = new_flexbuffer_from(disposable_packet, sizeof(test_packet), 64, 0);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(g_mybuf);
+        CU_ASSERT_EQUAL(g_mybuf->datalen, sizeof(test_packet));
+
+        result = g_my_packetizer->session_data(g_my_packetizer, g_who, g_mybuf);
+        CU_ASSERT_EQUAL(result,0);
+
+        result = check_packetizer_resultx(g_my_sessionpacket, NULL);
+        CU_ASSERT_EQUAL(result, 0);
+        CU_ASSERT_EQUAL(mysessionpkt->what, WHAT_NONE);
+        CU_ASSERT_PTR_NULL(mysessionpkt->sender);
+
+        g_mybuf->destroy(g_mybuf); g_mybuf = NULL;
+
+    } while(0);
+
+    teardown_this_test();
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);  
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();  /* start fresh for next test */
+}
+
+
+/**
+ * test_two_in_one_buffer_data_2()
+ * test two packets in a single buffer - 2
+ */
+void test_two_in_one_buffer_data_2(void)
+{
+    setup_this_test();
+
+    do          
+    {   int result = 0;    
+        #define TWOIN1_2_BYTECOUNT (8 + 1 + 8)
+        #define TWOIN1_2_RESULT_BYTECOUNT 1
+        byte* disposable_packet;
+     
+        byte test_packet[TWOIN1_2_BYTECOUNT] 
+            = { -34,-83,-66,-17,  0,0,0,1, 1,  
+                -34,-83,-66,-17,  0,0,0,0,  
+              }; 
+
+        byte expected_result[][TWOIN1_2_RESULT_BYTECOUNT] = 
+        {      
+            {  
+               1
+            },
+        };
+
+        my_impl_sessionpacket* mysessionpkt = g_my_sessionpacket->thisx; 
+
+        etch_nativearray* expected_result_array = new_nativearray_from
+          (&expected_result, CLASSID_ARRAY_BYTE, sizeof(byte), 2, 
+            TWOIN1_2_RESULT_BYTECOUNT, 1, 0);
+
+        disposable_packet = etch_malloc(sizeof(test_packet), ETCHTYPEB_BYTES);
+        memcpy(disposable_packet, test_packet, sizeof(test_packet));
+       
+        g_mybuf = new_flexbuffer_from(disposable_packet, sizeof(test_packet), 64, 0);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(g_mybuf);
+        CU_ASSERT_EQUAL(g_mybuf->datalen, sizeof(test_packet));
+
+        result = g_my_packetizer->session_data(g_my_packetizer, g_who, g_mybuf);
+        CU_ASSERT_EQUAL(result,0);
+
+        result = check_packetizer_resultx(g_my_sessionpacket, expected_result_array);
+        CU_ASSERT_EQUAL(result, 0);
+
+        CU_ASSERT_EQUAL(mysessionpkt->what, WHAT_PACKET);
+        result = is_equal_who(mysessionpkt->sender, g_who);
+        CU_ASSERT_EQUAL(result, TRUE);
+       
+        g_mybuf->destroy(g_mybuf); g_mybuf = NULL;
+        expected_result_array->destroy(expected_result_array);
+
+    } while(0);
+
+    teardown_this_test();
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);  
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();  /* start fresh for next test */
+}
+
+
+/**
+ * test_two_in_one_buffer_data_3()
+ * test two packets in a single buffer - 3
+ */
+void test_two_in_one_buffer_data_3(void)
+{
+    setup_this_test();
+
+    do          
+    {   int result = 0;    
+        #define TWOIN1_3_BYTECOUNT (8 + 8 + 1)
+        #define TWOIN1_3_RESULT_BYTECOUNT 1
+        byte* disposable_packet;
+     
+        byte test_packet[TWOIN1_3_BYTECOUNT] 
+            = { -34,-83,-66,-17,  0,0,0,0,   
+                -34,-83,-66,-17,  0,0,0,1, 2  
+              }; 
+
+        byte expected_result[][TWOIN1_3_RESULT_BYTECOUNT] = 
+        {      
+            {  
+               2
+            },
+        };
+
+        my_impl_sessionpacket* mysessionpkt = g_my_sessionpacket->thisx; 
+
+        etch_nativearray* expected_result_array = new_nativearray_from
+          (&expected_result, CLASSID_ARRAY_BYTE, sizeof(byte), 2, 
+            TWOIN1_3_RESULT_BYTECOUNT, 1, 0);
+
+        disposable_packet = etch_malloc(sizeof(test_packet), ETCHTYPEB_BYTES);
+        memcpy(disposable_packet, test_packet, sizeof(test_packet));
+       
+        g_mybuf = new_flexbuffer_from(disposable_packet, sizeof(test_packet), 64, 0);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(g_mybuf);
+        CU_ASSERT_EQUAL(g_mybuf->datalen, sizeof(test_packet));
+
+        result = g_my_packetizer->session_data(g_my_packetizer, g_who, g_mybuf);
+        CU_ASSERT_EQUAL(result,0);
+
+        result = check_packetizer_resultx(g_my_sessionpacket, expected_result_array);
+        CU_ASSERT_EQUAL(result, 0);
+
+        CU_ASSERT_EQUAL(mysessionpkt->what, WHAT_PACKET);
+        result = is_equal_who(mysessionpkt->sender, g_who);
+        CU_ASSERT_EQUAL(result, TRUE);
+
+        g_mybuf->destroy(g_mybuf); g_mybuf = NULL;
+        expected_result_array->destroy(expected_result_array);
+
+    } while(0);
+
+    teardown_this_test();
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);  
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();  /* start fresh for next test */
+}
+
+
+/**
+ * test_two_in_one_buffer_data_4()
+ * test two packets in a single buffer - 4
+ */
+void test_two_in_one_buffer_data_4(void)
+{
+    setup_this_test();
+
+    do          
+    {   int result = 0;        
+        signed char* disposable_packet;
+
+        /* byte count for all packets */
+        #define TWOIN1_4_BYTECOUNT (8 + 1 + 8 + 1)
+
+        /* byte count for low order dimension of expected result array ( [2][1] ) */
+        #define TWOIN1_4_RESULT_BYTECOUNT 1 
+     
+        signed char test_packet[TWOIN1_4_BYTECOUNT] 
+            = { -34,-83,-66,-17,  0,0,0,1,  1,  
+                -34,-83,-66,-17,  0,0,0,1,  2,  
+              }; 
+
+        signed char expected_result[][TWOIN1_4_RESULT_BYTECOUNT] = 
+        {      
+            {  
+               1,    /* packet 1 data */
+            },
+            {  
+               2,    /* packet 2 data */
+            },
+        };
+
+        my_impl_sessionpacket* mysessionpkt = g_my_sessionpacket->thisx; 
+
+        etch_nativearray* expected_result_array = new_nativearray_from
+          (&expected_result, CLASSID_ARRAY_BYTE, 
+                sizeof(byte), /* size of an array item is 1 */
+                2,            /* count of dimensions [2][1] */
+                1,            /* count of items in low order dimension */
+                2,            /* count of items in secondary dimension */          
+                0);           /* 3rd dimension (not applicable) */
+
+        disposable_packet = etch_malloc(sizeof(test_packet), ETCHTYPEB_BYTES);
+        memcpy(disposable_packet, test_packet, sizeof(test_packet));
+       
+        g_mybuf = new_flexbuffer_from(disposable_packet, sizeof(test_packet), 0, 0);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(g_mybuf);
+        CU_ASSERT_EQUAL(g_mybuf->datalen, sizeof(test_packet));
+
+        result = g_my_packetizer->session_data(g_my_packetizer, g_who, g_mybuf);
+        CU_ASSERT_EQUAL(result,0);
+
+        result = check_packetizer_resultx(g_my_sessionpacket, expected_result_array);
+        CU_ASSERT_EQUAL(result, 0);
+
+        CU_ASSERT_EQUAL(mysessionpkt->what, WHAT_PACKET);
+        result = is_equal_who(mysessionpkt->sender, g_who);
+        CU_ASSERT_EQUAL(result, TRUE);
+
+        g_mybuf->destroy(g_mybuf); g_mybuf = NULL;
+        expected_result_array->destroy(expected_result_array);
+
+    } while(0);
+
+    teardown_this_test();
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);  
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();  /* start fresh for next test */
+}
+
+
+/**
+ * test_two_in_one_buffer_data_5()
+ * test two packets in a single buffer - 5
+ */
+void test_two_in_one_buffer_data_5(void)
+{
+    setup_this_test();
+
+    do          
+    {   int result = 0;        
+        signed char* disposable_packet;
+
+        /* byte count for all packets */
+        #define TWOIN1_5_BYTECOUNT (8 + 2 + 8 + 2)
+
+        /* byte count for low order dimension of expected result array ( [2][2] ) */
+        #define TWOIN1_5_RESULT_BYTECOUNT 2 
+     
+        signed char test_packet[TWOIN1_5_BYTECOUNT] 
+            = { -34,-83,-66,-17,  0,0,0,2,  3, 4,   
+                -34,-83,-66,-17,  0,0,0,2,  5, 6,  
+              }; 
+
+        signed char expected_result[][TWOIN1_5_RESULT_BYTECOUNT] = 
+        {      
+            {  
+               3, 4,    /* packet 1 data */
+            },
+            {  
+               5, 6,    /* packet 2 data */
+            },
+        };
+
+        my_impl_sessionpacket* mysessionpkt = g_my_sessionpacket->thisx; 
+
+        etch_nativearray* expected_result_array = new_nativearray_from
+          (&expected_result, CLASSID_ARRAY_BYTE, 
+                sizeof(byte), /* size of an array item is 1 */
+                2,            /* count of dimensions [2][2] */
+                2,            /* count of items in low order dimension */
+                2,            /* count of items in secondary dimension */          
+                0);           /* 3rd dimension (not applicable) */
+
+        disposable_packet = etch_malloc(sizeof(test_packet), ETCHTYPEB_BYTES);
+        memcpy(disposable_packet, test_packet, sizeof(test_packet));
+       
+        g_mybuf = new_flexbuffer_from(disposable_packet, sizeof(test_packet), 0, 0);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(g_mybuf);
+        CU_ASSERT_EQUAL(g_mybuf->datalen, sizeof(test_packet));
+
+        result = g_my_packetizer->session_data(g_my_packetizer, g_who, g_mybuf);
+        CU_ASSERT_EQUAL(result,0);
+
+        result = check_packetizer_resultx(g_my_sessionpacket, expected_result_array);
+        CU_ASSERT_EQUAL(result, 0);
+
+        CU_ASSERT_EQUAL(mysessionpkt->what, WHAT_PACKET);
+        result = is_equal_who(mysessionpkt->sender, g_who);
+        CU_ASSERT_EQUAL(result, TRUE);
+
+        g_mybuf->destroy(g_mybuf); g_mybuf = NULL;
+        expected_result_array->destroy(expected_result_array);
+
+    } while(0);
+
+    teardown_this_test();
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);  
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();  /* start fresh for next test */
+}
+
+
+/**
+ * test_two_in_two_buffers_data_1()
+ * test two packets in two buffers with header split across buffers
+ * packets are empty in this test
+ */
+void test_two_in_two_buffers_data_1(void)
+{
+    setup_this_test();
+
+    do          
+    {   int result = 0;    
+        #define TWOIN2_1_BUF1_BYTECOUNT 6
+        #define TWOIN2_1_BUF2_BYTECOUNT 10
+        etch_flexbuffer* mybuf2=0;
+        byte* disposable_packet=0;
+     
+        byte buf1_data[TWOIN2_1_BUF1_BYTECOUNT] 
+            = { -34,-83,-66,-17,  0,0,      /* packet 1 header (partial) */  
+              }; 
+
+        byte buf2_data[TWOIN2_1_BUF2_BYTECOUNT] 
+            = {  0, 0,                      /* packet 1 header (balance) */ 
+                -34,-83,-66,-17,  0,0,0,0,  /* packet 2 header */   
+              }; 
+
+        my_impl_sessionpacket* mysessionpkt = g_my_sessionpacket->thisx; 
+
+        /* buffer 1 */
+        disposable_packet = etch_malloc(sizeof(buf1_data), ETCHTYPEB_BYTES);
+        memcpy(disposable_packet, buf1_data, sizeof(buf1_data));
+       
+        g_mybuf = new_flexbuffer_from(disposable_packet, sizeof(buf1_data), 0, 0);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(g_mybuf);
+        CU_ASSERT_EQUAL(g_mybuf->datalen, sizeof(buf1_data));
+
+        result = g_my_packetizer->session_data(g_my_packetizer, g_who, g_mybuf);
+        CU_ASSERT_EQUAL(result,0);
+
+        CU_ASSERT_EQUAL(mysessionpkt->what, WHAT_NONE);
+        CU_ASSERT_PTR_NULL(mysessionpkt->sender);
+
+        /* buffer 2 */
+        disposable_packet = etch_malloc(sizeof(buf2_data), ETCHTYPEB_BYTES);
+        memcpy(disposable_packet, buf2_data, sizeof(buf2_data));
+       
+        mybuf2 = new_flexbuffer_from(disposable_packet, sizeof(buf2_data), 0, 0);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(mybuf2);
+        CU_ASSERT_EQUAL(mybuf2->datalen, sizeof(buf2_data));
+
+        result = g_my_packetizer->session_data(g_my_packetizer, g_who, g_mybuf);
+        CU_ASSERT_EQUAL(result,0);
+
+        CU_ASSERT_EQUAL(mysessionpkt->what, WHAT_NONE);
+        CU_ASSERT_PTR_NULL(mysessionpkt->sender);
+
+        /* done - free memory */
+        g_mybuf->destroy(g_mybuf); g_mybuf = NULL;
+        mybuf2 ->destroy(mybuf2);    
+
+    } while(0);
+
+    teardown_this_test();
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);  
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();  /* start fresh for next test */
+}
+
+
+/**
+ * test_two_in_two_buffers_data_2()
+ * test two packets in two buffers with header split across buffers
+ * packets include bodies in this test
+ */
+void test_two_in_two_buffers_data_2(void)
+{
+    setup_this_test();
+
+    do          
+    {   int result = 0; 
+        #define TWOIN2_2_BUF1_BYTECOUNT 6
+        #define TWOIN2_2_BUF2_BYTECOUNT (2 + 2 + 8 + 2)
+        /* byte count for low order dimension of expected result array ( [2][2] ) */
+        #define TWOIN2_2_RESULT_BYTECOUNT 2 
+        etch_flexbuffer* mybuf2=0;
+        byte* disposable_packet=0;
+     
+        byte buf1_data[TWOIN2_2_BUF1_BYTECOUNT] 
+            = { -34,-83,-66,-17,  0,0,      /* packet 1 header (partial) */  
+              }; 
+
+        byte buf2_data[TWOIN2_2_BUF2_BYTECOUNT] 
+            = {  0, 2,                      /* packet 1 header (balance) */ 
+                 3, 4,                      /* packet 1 body */ 
+                -34,-83,-66,-17,  0,0,0,2,  /* packet 2 header */  
+                 5, 6,                      /* packet 2 body */ 
+              }; 
+
+        byte expected_result[][TWOIN2_2_RESULT_BYTECOUNT] = 
+        {      
+            {  
+               3, 4,    /* packet 1 body */
+            },
+            {  
+               5, 6,    /* packet 2 body */
+            },
+        };
+
+        my_impl_sessionpacket* mysessionpkt = g_my_sessionpacket->thisx; 
+
+        etch_nativearray* expected_result_array = new_nativearray_from
+          (&expected_result, CLASSID_ARRAY_BYTE, 
+                sizeof(byte), /* size of an array item is 1 */
+                2,            /* count of dimensions [2][2] */
+                2,            /* count of items in low order dimension */
+                2,            /* count of items in secondary dimension */          
+                0             /* 3rd dimension (not applicable) */
+          );           
+
+        /* buffer 1 */
+        disposable_packet = etch_malloc(sizeof(buf1_data), ETCHTYPEB_BYTES);
+        memcpy(disposable_packet, buf1_data, sizeof(buf1_data));
+       
+        g_mybuf = new_flexbuffer_from(disposable_packet, sizeof(buf1_data), 0, 0);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(g_mybuf);
+        CU_ASSERT_EQUAL(g_mybuf->datalen, sizeof(buf1_data));
+
+        result = g_my_packetizer->session_data(g_my_packetizer, g_who, g_mybuf);
+        CU_ASSERT_EQUAL(result,0);
+
+        CU_ASSERT_EQUAL(mysessionpkt->what, WHAT_NONE);
+        CU_ASSERT_PTR_NULL(mysessionpkt->sender);
+
+        /* buffer 2 */
+        disposable_packet = etch_malloc(sizeof(buf2_data), ETCHTYPEB_BYTES);
+        memcpy(disposable_packet, buf2_data, sizeof(buf2_data));
+       
+        mybuf2 = new_flexbuffer_from(disposable_packet, sizeof(buf2_data), 0, 0);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(mybuf2);
+        CU_ASSERT_EQUAL(mybuf2->datalen, sizeof(buf2_data));
+
+        result = g_my_packetizer->session_data(g_my_packetizer, g_who, mybuf2);
+        CU_ASSERT_EQUAL(result,0);
+
+        result = check_packetizer_resultx(g_my_sessionpacket, expected_result_array);
+        CU_ASSERT_EQUAL(result, 0);
+
+        CU_ASSERT_EQUAL(mysessionpkt->what, WHAT_PACKET);
+        result = is_equal_who(mysessionpkt->sender, g_who);
+        CU_ASSERT_EQUAL(result, TRUE);
+      
+        /* done - free memory */
+        expected_result_array->destroy(expected_result_array);
+        g_mybuf->destroy(g_mybuf); g_mybuf = NULL;
+        mybuf2 ->destroy(mybuf2);    
+
+    } while(0);
+
+    teardown_this_test();
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);  
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();  /* start fresh for next test */
+}
+
+
+/**
+ * test_two_in_two_buffers_data_3()
+ * test two packets in two buffers with body split across buffers
+ */
+void test_two_in_two_buffers_data_3(void)
+{
+    setup_this_test();
+
+    do          
+    {   int result = 0; 
+        #define TWOIN2_3_BUF1_BYTECOUNT (8 + 1)     /* header1 + body1 1 of 2 */
+        #define TWOIN2_3_BUF2_BYTECOUNT (1 + 8 + 2) /* body1 2 of 2 + header2 + body2 */
+        /* byte count for low order dimension of expected result array ( [2][2] ) */
+        #define TWOIN2_3_RESULT_BYTECOUNT 2 
+        etch_flexbuffer* mybuf2 = NULL;
+        signed char* disposable_packet = NULL;
+     
+        signed char buf1_data[TWOIN2_3_BUF1_BYTECOUNT] 
+            = { -34,-83,-66,-17,  0, 0, 0, 2,   /* packet 1 header (length 2) */
+                 1,                             /* packet 1 partial body */  
+              }; 
+
+        signed char buf2_data[TWOIN2_3_BUF2_BYTECOUNT] 
+            = {  2,                             /* packet 1 body balance */       
+                -34,-83,-66,-17,  0, 0, 0, 2,   /* packet 2 header */  
+                 3, 4,                          /* packet 2 body */ 
+              }; 
+
+        signed char expected_result[][TWOIN2_3_RESULT_BYTECOUNT] = 
+        {      
+            {  
+               1, 2,    /* packet 1 body */
+            },
+            {  
+               3, 4,    /* packet 2 body */
+            },
+        };
+
+        my_impl_sessionpacket* mysessionpkt = g_my_sessionpacket->thisx; 
+
+        etch_nativearray* expected_result_array = new_nativearray_from
+          (&expected_result, CLASSID_ARRAY_BYTE, 
+                sizeof(byte), /* size of an array item is 1 */
+                2,            /* count of dimensions [2][2] */
+                2,            /* count of items in low order dimension */
+                2,            /* count of items in secondary dimension */          
+                0             /* 3rd dimension (not applicable) */
+          );           
+
+        /* buffer 1 */
+        disposable_packet = etch_malloc(sizeof(buf1_data), ETCHTYPEB_BYTES);
+        memcpy(disposable_packet, buf1_data, sizeof(buf1_data));
+       
+        g_mybuf = new_flexbuffer_from(disposable_packet, sizeof(buf1_data), 0, 0);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(g_mybuf);
+        CU_ASSERT_EQUAL(g_mybuf->datalen, sizeof(buf1_data));
+
+        result = g_my_packetizer->session_data(g_my_packetizer, g_who, g_mybuf);
+        CU_ASSERT_EQUAL(result,0);
+
+        CU_ASSERT_EQUAL(mysessionpkt->what, WHAT_NONE);
+        CU_ASSERT_PTR_NULL(mysessionpkt->sender);
+
+        /* buffer 2 */
+        disposable_packet = etch_malloc(sizeof(buf2_data), ETCHTYPEB_BYTES);
+        memcpy(disposable_packet, buf2_data, sizeof(buf2_data));
+       
+        mybuf2 = new_flexbuffer_from(disposable_packet, sizeof(buf2_data), 0, 0);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(mybuf2);
+        CU_ASSERT_EQUAL(mybuf2->datalen, sizeof(buf2_data));
+
+        result = g_my_packetizer->session_data(g_my_packetizer, g_who, mybuf2);
+        CU_ASSERT_EQUAL(result,0);
+
+        result = check_packetizer_resultx(g_my_sessionpacket, expected_result_array);
+        CU_ASSERT_EQUAL(result, 0);
+
+        CU_ASSERT_EQUAL(mysessionpkt->what, WHAT_PACKET);
+        result = is_equal_who(mysessionpkt->sender, g_who);
+        CU_ASSERT_EQUAL(result, TRUE);
+
+        /* done - free memory */
+        expected_result_array->destroy(expected_result_array);
+        g_mybuf->destroy(g_mybuf); g_mybuf = NULL;
+        mybuf2 ->destroy(mybuf2);    
+
+    } while(0);
+
+    teardown_this_test();
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);  
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();  /* start fresh for next test */
+}
+
+
+/**
+ * test_two_in_two_buffers_data_4()
+ * test two packets in two buffers with body split across buffers
+ */
+void test_two_in_two_buffers_data_4(void)
+{
+    setup_this_test();
+
+    do          
+    {   int result = 0; 
+        #define TWOIN2_4_BUF1_BYTECOUNT (8 + 2)     /* header1 + body1 2 of 3 */
+        #define TWOIN2_4_BUF2_BYTECOUNT (1 + 8 + 3) /* body1 3 of 3 + header2 + body2 */
+        /* byte count for low order dimension of expected result array ( [2][2] ) */
+        #define TWOIN2_4_RESULT_BYTECOUNT 3 
+        etch_flexbuffer* mybuf2=0;
+        byte* disposable_packet=0;
+     
+        byte buf1_data[TWOIN2_4_BUF1_BYTECOUNT] 
+            = { -34,-83,-66,-17,  0, 0, 0, 3,   /* packet 1 header (length 2) */
+                 5, 6,                          /* packet 1 partial body */  
+              }; 
+
+        byte buf2_data[TWOIN2_4_BUF2_BYTECOUNT] 
+            = {  7,                             /* packet 1 body balance */       
+                -34,-83,-66,-17,  0, 0, 0, 3,   /* packet 2 header */  
+                 8, 9, 10                       /* packet 2 body */ 
+              }; 
+
+        byte expected_result[][TWOIN2_4_RESULT_BYTECOUNT] = 
+        {      
+            {  
+               5, 6, 7,    /* packet 1 body */
+            },
+            {  
+               8, 9, 10,   /* packet 2 body */
+            },
+        };
+
+        etch_nativearray* expected_result_array = new_nativearray_from
+          (&expected_result, CLASSID_ARRAY_BYTE, 
+                sizeof(byte), /* size of an array item is 1 */
+                2,            /* count of dimensions [2][2] */
+                3,            /* count of items in low order dimension */
+                2,            /* count of items in secondary dimension */          
+                0             /* 3rd dimension (not applicable) */
+          );  
+
+        my_impl_sessionpacket* mysessionpkt = g_my_sessionpacket->thisx;          
+
+        /* buffer 1 */
+        disposable_packet = etch_malloc(sizeof(buf1_data), ETCHTYPEB_BYTES);
+        memcpy(disposable_packet, buf1_data, sizeof(buf1_data));
+       
+        g_mybuf = new_flexbuffer_from(disposable_packet, sizeof(buf1_data), 0, 0);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(g_mybuf);
+        CU_ASSERT_EQUAL(g_mybuf->datalen, sizeof(buf1_data));
+
+        result = g_my_packetizer->session_data(g_my_packetizer, g_who, g_mybuf);
+        CU_ASSERT_EQUAL(result,0);
+
+        CU_ASSERT_EQUAL(mysessionpkt->what, WHAT_NONE);
+        CU_ASSERT_PTR_NULL(mysessionpkt->sender);
+
+        /* buffer 2 */
+        disposable_packet = etch_malloc(sizeof(buf2_data), ETCHTYPEB_BYTES);
+        memcpy(disposable_packet, buf2_data, sizeof(buf2_data));
+       
+        mybuf2 = new_flexbuffer_from(disposable_packet, sizeof(buf2_data), 0, 0);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(mybuf2);
+        CU_ASSERT_EQUAL(mybuf2->datalen, sizeof(buf2_data));
+
+        result = g_my_packetizer->session_data(g_my_packetizer, g_who, mybuf2);
+        CU_ASSERT_EQUAL(result,0);
+
+        result = check_packetizer_resultx(g_my_sessionpacket, expected_result_array);
+        CU_ASSERT_EQUAL(result, 0);
+
+        CU_ASSERT_EQUAL(mysessionpkt->what, WHAT_PACKET);
+        result = is_equal_who(mysessionpkt->sender, g_who);
+        CU_ASSERT_EQUAL(result, TRUE);
+        /* done - free memory */
+        expected_result_array->destroy(expected_result_array);
+        g_mybuf->destroy(g_mybuf); g_mybuf = NULL;
+        mybuf2 ->destroy(mybuf2);    
+
+   } while(0);
+
+    teardown_this_test();
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);  
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();  /* start fresh for next test */
+}
+
+
+/**
+ * test_session_control
+ * test the session control notification plumbing
+ */
+void test_session_control(void)
+{
+    setup_this_test();
+
+    do          
+    {   int result = 0;
+        const int MY_CONTROL_CLASSID = 0x5200, MY_VALUE_CLASSID = 0x5201;
+        etch_object* mycontrolobj = new_etch_object(MY_CONTROL_CLASSID, NULL);
+        etch_object* myvalueobj   = new_etch_object(MY_VALUE_CLASSID, NULL);
+
+        /* g_my_sessionpacket is the i_sessionpacket interface    
+         * my_impl_sessionpacket is the implementing test class */
+        my_impl_sessionpacket* my_session = g_my_sessionpacket->thisx;          
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_session);
+        CU_ASSERT_EQUAL(my_session->what, WHAT_NONE);
+        CU_ASSERT_PTR_NULL(my_session->control);
+        CU_ASSERT_PTR_NULL(my_session->value);
+
+        /* we relinquish memory for mycontrolobj and myvalueobj here. 
+         * the session_control terminal destination must destroy them, which here
+         * is handled by our session object destructor when we teardown_this_test() */
+        g_my_packetizer->session_control (g_my_packetizer, mycontrolobj, myvalueobj);
+
+        CU_ASSERT_EQUAL(my_session->what, SESSION_CONTROL);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_session->control);
+        CU_ASSERT_EQUAL(my_session->control->class_id, MY_CONTROL_CLASSID);
+        CU_ASSERT_EQUAL(my_session->value->class_id,   MY_VALUE_CLASSID);
+
+    } while(0);
+
+    teardown_this_test();
+
+    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_session_notify
+ * test the session notify notification plumbing
+ */
+void test_session_notify(void)
+{
+    setup_this_test();
+
+    do          
+    {   int result = 0;
+        const int MY_EVENT_CLASSID = 0x5202;
+        etch_object* myeventobj = new_etch_object(MY_EVENT_CLASSID, NULL);
+
+        /* g_my_sessionpacket is the i_sessionpacket interface    
+         * my_impl_sessionpacket is the implementing test class */
+        my_impl_sessionpacket* my_session = g_my_sessionpacket->thisx;   
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_session);
+        CU_ASSERT_EQUAL(my_session->what, WHAT_NONE);
+        CU_ASSERT_PTR_NULL(my_session->eventx);
+
+        /* we relinquish memory for myeventobj here. 
+         * the session_control terminal destination must destroy it, which here
+         * is handled by our session object destructor when we teardown_this_test() */
+        g_my_packetizer->session_notify(g_my_packetizer, myeventobj);
+
+        CU_ASSERT_EQUAL(my_session->what, SESSION_NOTIFY);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_session->eventx);
+        CU_ASSERT_EQUAL(my_session->eventx->class_id, MY_EVENT_CLASSID);
+
+    } while(0);
+
+    teardown_this_test();
+
+    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_session_query
+ * test the session query notification plumbing
+ */
+void test_session_query(void)
+{
+    setup_this_test();
+
+    do          
+    {   int result = 0;
+        const int MY_QUERY_CLASSID = 0x5203, MY_RESULT_CLASSID = 0x5204;
+        etch_object* myqueryobj  = new_etch_object(MY_QUERY_CLASSID, NULL);
+        etch_object* myresultobj = new_etch_object(MY_RESULT_CLASSID, NULL);
+        etch_object* queryresult = NULL;
+
+        /* g_my_sessionpacket is the i_sessionpacket interface    
+         * my_impl_sessionpacket is the implementing test class */
+        my_impl_sessionpacket* my_session = g_my_sessionpacket->thisx;          
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_session);
+        CU_ASSERT_EQUAL(my_session->what, WHAT_NONE);
+        CU_ASSERT_PTR_NULL(my_session->query);
+
+        /* we relinquish myresultobj here. see comments following */
+        my_session->query_result = myresultobj; 
+
+        /* we relinquish memory for myqueryobj here and assume queryresult. 
+         * the session_control terminal destination must destroy it, which here
+         * is handled by our session object destructor when we teardown_this_test() */
+        queryresult = g_my_packetizer->session_query(g_my_packetizer, myqueryobj);
+
+        CU_ASSERT_EQUAL(my_session->what, SESSION_QUERY);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_session->query);
+        CU_ASSERT_EQUAL(my_session->query->class_id, MY_QUERY_CLASSID);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(queryresult);
+        CU_ASSERT_EQUAL(queryresult->class_id, MY_RESULT_CLASSID);
+        queryresult->destroy(queryresult);
+
+    } while(0);
+
+    teardown_this_test();
+
+    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_transport_control
+ * test the transport control notification plumbing
+ */
+void test_transport_control(void)
+{
+    setup_this_test();
+
+    do          
+    {   int result = 0;
+        const int MY_CONTROL_CLASSID = 0x5200, MY_VALUE_CLASSID = 0x5201;
+        etch_object* mycontrolobj = new_etch_object(MY_CONTROL_CLASSID, NULL);
+        etch_object* myvalueobj   = new_etch_object(MY_VALUE_CLASSID, NULL);
+
+        /* g_my_transportdata is the i_transportdata interface    
+         * my_impl_transportdata is the implementing test class */
+        my_impl_transportdata* my_transport = g_my_transportdata->thisx; 
+        CU_ASSERT_FATAL(is_my_impl_transportdata(my_transport));
+        CU_ASSERT_EQUAL(my_transport->what, WHAT_NONE);
+        CU_ASSERT_PTR_NULL(my_transport->control);
+        CU_ASSERT_PTR_NULL(my_transport->value);
+
+        /* we relinquish memory for mycontrolobj and myvalueobj here. 
+         * the transport_control terminal destination must destroy them, which here
+         * is handled by our transport object destructor when we teardown_this_test() */
+        g_my_packetizer->transport_control(g_my_packetizer, mycontrolobj, myvalueobj);
+
+        CU_ASSERT_EQUAL(my_transport->what, TRANSPORT_CONTROL);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_transport->control);
+        CU_ASSERT_EQUAL(my_transport->control->class_id, MY_CONTROL_CLASSID);
+        CU_ASSERT_EQUAL(my_transport->value->class_id,   MY_VALUE_CLASSID);
+
+    } while(0);
+
+    teardown_this_test();
+
+    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_transport_notify
+ * test the transport notify notification plumbing
+ */
+void test_transport_notify(void)
+{
+    setup_this_test();
+
+    do          
+    {   int result = 0;
+        const int MY_EVENT_CLASSID = 0x5202;
+        etch_object* myeventobj = new_etch_object(MY_EVENT_CLASSID, NULL);
+
+        /* g_my_transportdata is the i_transportdata interface    
+         * my_impl_transportdata is the implementing test class */
+        my_impl_transportdata* my_transport = g_my_transportdata->thisx; 
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_transport);
+        CU_ASSERT_EQUAL(my_transport->what, WHAT_NONE);
+        CU_ASSERT_PTR_NULL(my_transport->control);
+        CU_ASSERT_PTR_NULL(my_transport->value);
+
+        /* we relinquish memory for myeventobj here. 
+         * the transport_control terminal destination must destroy it, which here
+         * is handled by our transport object destructor when we teardown_this_test() */
+        g_my_packetizer->transport_notify(g_my_packetizer, myeventobj);
+
+        CU_ASSERT_EQUAL(my_transport->what, TRANSPORT_NOTIFY);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_transport->eventx);
+        CU_ASSERT_EQUAL(my_transport->eventx->class_id, MY_EVENT_CLASSID);
+
+    } while(0);
+
+    teardown_this_test();
+
+    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_transport_query
+ * test the transport query notification plumbing
+ */
+void test_transport_query(void)
+{
+    setup_this_test();
+
+    do          
+    {   int result = 0;
+        const int MY_QUERY_CLASSID = 0x5203, MY_RESULT_CLASSID = 0x5204;
+        etch_object* myqueryobj  = new_etch_object(MY_QUERY_CLASSID, NULL);
+        etch_object* myresultobj = new_etch_object(MY_RESULT_CLASSID, NULL);
+        etch_object* queryresult = NULL;
+
+        /* g_my_transportdata is the i_transportdata interface    
+         * my_impl_transportdata is the implementing test class */
+        my_impl_transportdata* my_transport = g_my_transportdata->thisx; 
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_transport);
+        CU_ASSERT_EQUAL(my_transport->what, WHAT_NONE);
+        CU_ASSERT_PTR_NULL(my_transport->query);
+
+        /* we relinquish myresultobj here. see comments following */
+        my_transport->query_result = myresultobj; 
+
+        /* we relinquish memory for myqueryobj here and assume queryresult. 
+         * the transport_control terminal destination must destroy it, which here
+         * is handled by our transport object destructor when we teardown_this_test() */
+        queryresult = g_my_packetizer->transport_query(g_my_packetizer, myqueryobj);
+
+        CU_ASSERT_EQUAL(my_transport->what, TRANSPORT_QUERY);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_transport->query);
+        CU_ASSERT_EQUAL(my_transport->query->class_id, MY_QUERY_CLASSID);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(queryresult);
+        CU_ASSERT_EQUAL(queryresult->class_id, MY_RESULT_CLASSID);
+        queryresult->destroy(queryresult);
+
+    } while(0);
+
+    teardown_this_test();
+
+    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_packetizer");
+    ps = CU_add_suite("suite_packetizer", init_suite, clean_suite);
+    etch_watch_id = 0; 
+
+    CU_add_test(ps, "test sessionpacket ctor/dtor", test_sessionpacket_constructor);
+    CU_add_test(ps, "test transportdata ctor/dtor", test_transportdata_constructor);
+    CU_add_test(ps, "test packetizer ctor/dtor", test_packetizer_constructor);
+    CU_add_test(ps, "test unit test setup/teardown", test_test_setup);
+    CU_add_test(ps, "test packet1 to source", test_to_source_packet1);
+    CU_add_test(ps, "test packet2 to source", test_to_source_packet2);
+    CU_add_test(ps, "test packet3 to source", test_to_source_packet3);
+    CU_add_test(ps, "test bad packet 0", test_to_source_badpacket1);
+    CU_add_test(ps, "test bad packet 1", test_badpacket1);
+
+    CU_add_test(ps, "test 1 packet 1 buffer", test_single_single_data);
+    CU_add_test(ps, "test 2 in 1 buffer 1",  test_two_in_one_buffer_data_1);
+    CU_add_test(ps, "test 2 in 1 buffer 2",  test_two_in_one_buffer_data_2);
+    CU_add_test(ps, "test 2 in 1 buffer 3",  test_two_in_one_buffer_data_3);
+    CU_add_test(ps, "test 2 in 1 buffer 4",  test_two_in_one_buffer_data_4);
+    CU_add_test(ps, "test 2 in 1 buffer 5",  test_two_in_one_buffer_data_5);
+    CU_add_test(ps, "test 2 in 2 buffers 1", test_two_in_two_buffers_data_1);
+    CU_add_test(ps, "test 2 in 2 buffers 2", test_two_in_two_buffers_data_2);
+    CU_add_test(ps, "test 2 in 2 buffers 3", test_two_in_two_buffers_data_3);
+    CU_add_test(ps, "test 2 in 2 buffers 4", test_two_in_two_buffers_data_4);
+
+    CU_add_test(ps, "test session control",  test_session_control); 
+    CU_add_test(ps, "test session notify",  test_session_notify); 
+    CU_add_test(ps, "test session query",  test_session_query); 
+    CU_add_test(ps, "test transport control",  test_transport_control); 
+    CU_add_test(ps, "test transport notify",  test_transport_notify); 
+    CU_add_test(ps, "test transport query",  test_transport_query); 
+
+    if (g_is_automated_test)    
+        CU_automated_run_tests();    
+    else
+    {   CU_basic_set_mode(CU_BRM_VERBOSE);
+        CU_basic_run_tests();
+    }
+
+    if (!g_is_automated_test) { printf("any key ..."); while(!c) c = _getch(); wprintf(L"\n"); }     
+    CU_cleanup_registry();
+    return CU_get_error();
+}
\ No newline at end of file