blob: 378b07934686caa122e76cb0fd712611350ba5f4 [file]
/* $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_messagizer.c
*/
#include "apr_time.h" /* some apr must be included first */
#include "etch_messagizer.h"
#include "etch_defvalufact.h"
#include <tchar.h>
#include <stdio.h>
#include <conio.h>
#include "cunit.h"
#include "basic.h"
#include "automated.h"
#include "etchthread.h"
#include "etch_global.h"
#include "etchmap.h"
#include "etchlog.h"
#include "etch_syncobj.h"
#include "etchexcp.h"
int apr_setup(void);
int apr_teardown(void);
int this_setup();
int this_teardown();
apr_pool_t* g_apr_mempool;
const char* pooltag = "etchpool";
/* - - - - - - - - - - - - - -
* 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
* - - - - - - - - - - - - - -
*/
typedef struct test_value_factory test_value_factory;
etch_messagizer* g_my_messagizer;
i_transportpacket* g_my_transportpacket;
i_sessionmessage* g_my_sessionmessage;
etch_flexbuffer* g_flexbuffer;
etch_resources* g_my_resources;
vf_idname_map* g_type_map;
class_to_type_map* g_class_to_type_map;
etch_who* g_who;
default_value_factory* g_my_vf;
test_value_factory* g_my_test_vf;
int g_which_valuefactory;
unsigned short CLASSID_MY_VF;
unsigned short CLASSID_MY_VF_VTAB;
unsigned short CLASSID_MY_VF_IMPL;
unsigned short CLASSID_MY_IMPL_TP;
unsigned short CLASSID_MY_IMPL_SM;
#define OBJTYPE_MY_IMPL_TP 0x5170
#define OBJTYPE_MY_IMPL_SM 0x5171
#define is_my_impl_tp(x) (x && ((objmask*)x)->obj_type == OBJTYPE_MY_IMPL_TP)
#define is_my_impl_sm(x) (x && ((objmask*)x)->obj_type == OBJTYPE_MY_IMPL_SM)
#define THISTEST_HEADERSIZE 8
#define TAGDATA_VERSION 3
#define TYPECODE_EOD_MARK (-127)
#define THISTEST_WHO_VALUE 0x5151
#define WHICHVF_TESTVF 1
#define WHICHVF_MYVF 2
#define FAKEID_TYPE_ADD 1
#define FAKEID_TYPE_ADD_RESULT 2
#define FAKEID_FIELD_X 3
#define FAKEID_FIELD_Y 4
#define FAKEID_FIELD_RESULT 5
default_value_factory* get_current_valuefactory()
{
if (g_my_test_vf) return (default_value_factory*) g_my_test_vf;
if (g_my_vf) return g_my_vf;
return NULL;
}
typedef enum etch_what
{ WHAT_NONE,
TRANSPORT_PACKET, TRANSPORT_QUERY, TRANSPORT_CONTROL, TRANSPORT_NOTIFY,
SESSION_MESSAGE, 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_transportpacket (i_transportpacket implementation)
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
/**
* my_impl_transportpacket
* test object implementing i_transportpacket
*/
typedef struct my_impl_transportpacket
{
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_transportpacket 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_transportpacket
* in this case, contains a pointer to the wrapper object, in this case a
* my_impl_transportpacket*. 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_transportpacket* ixp; /* owned */
objdtor destroy_transportpacket; /* i_transportpacket original destructor */
etch_transport_packet transport_packet; /* transport_packet() */
etch_transport_packet_headersize header_size; /* header_size() */
i_sessionpacket* session; /* not owned */
etch_who* recipient; /* not owned */
etch_what what;
size_t bufcount;
char* buf; /* owned */
etch_object* query; /* owned */
etch_object* query_result; /* owned */
etch_object* control; /* owned */
etch_object* value; /* owned */
etch_object* eventx; /* owned */
} my_impl_transportpacket;
/**
* destroy_my_impl_transportpacket()
* my_impl_transportpacket destructor
*/
int destroy_my_impl_transportpacket(my_impl_transportpacket* thisx)
{
assert(is_my_impl_tp(thisx));
if (thisx->refcount > 0 && --thisx->refcount > 0) return -1;
if (!is_etchobj_static_content(thisx))
{ /* invoke original i_transportpacket destructor */
if (thisx->ixp && thisx->destroy_transportpacket)
thisx->destroy_transportpacket(thisx->ixp);
if (thisx->buf)
etch_free(thisx->buf);
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_packet()
* my_impl_transportpacket::transport_packet
* @param whoto caller retains, can be null
* @param fbuf caller retains
*/
int impl_transport_packet (my_impl_transportpacket* mytp, etch_who* whoto, etch_flexbuffer* fbuf)
{
CU_ASSERT_FATAL(is_my_impl_tp(mytp));
mytp->what = TRANSPORT_PACKET;
mytp->recipient = whoto;
/* retrieve the packet data. don't skip over header (0 is skip bytes) */
mytp->buf = etch_flexbuf_get_allfrom(fbuf, 0, &mytp->bufcount);
return 0;
}
/**
* my_transport_control()
* my_impl_transportpacket::itransport::transport_control
*/
int my_transport_control (my_impl_transportpacket* mytp, etch_object* control, etch_object* value)
{
CU_ASSERT_FATAL(is_my_impl_tp(mytp));
mytp->what = TRANSPORT_CONTROL;
mytp->control = control;
mytp->value = value;
return 0;
}
/**
* my_transport_notify()
* my_impl_transportpacket::itransport::transport_notify
*/
int my_transport_notify (my_impl_transportpacket* mytp, etch_object* evt)
{
CU_ASSERT_FATAL(is_my_impl_tp(mytp));
mytp->what = TRANSPORT_NOTIFY;
mytp->eventx = evt;
return 0;
}
/**
* my_transport_query()
* my_impl_transportpacket::itransport::transport_query
*/
objmask* my_transport_query (my_impl_transportpacket* mytp, etch_object* query)
{
etch_object* resultobj = NULL;
CU_ASSERT_FATAL(is_my_impl_tp(mytp));
resultobj = mytp->query_result; /* set artificially in test */
mytp->what = TRANSPORT_QUERY;
mytp->query = query;
mytp->query_result = NULL;
return (objmask*) resultobj; /* caller owns */
}
/**
* my_transport_get_session()
* my_impl_transportpacket::itransport::get_session
*/
i_sessionpacket* my_transport_get_session(my_impl_transportpacket* mytp)
{
CU_ASSERT_FATAL(is_my_impl_tp(mytp));
return mytp->session;
}
/**
* my_transport_set_session()
* my_impl_transportpacket::itransport::set_session
*/
void my_transport_set_session(my_impl_transportpacket* mytp, i_sessionpacket* session)
{
CU_ASSERT_FATAL(is_my_impl_tp(mytp));
CU_ASSERT_FATAL(is_etch_sessionpacket(session));
mytp->session = session;
}
/*
* destroy_my_transportpacket()
* i_transportpacket destructor
* this destructor will destroy its parent (my_impl_transportpacket),
* which will in turn destroy this object.
*/
int destroy_my_transportpacket(i_transportpacket* itp)
{
my_impl_transportpacket* mytp = NULL;
assert(is_etch_transportpkt(itp));
mytp = itp->thisx;
assert(is_my_impl_tp(mytp));
mytp->destroy(mytp);
return 0;
}
/**
* new_my_impl_transportpacket()
* my_impl_transportpacket constructor
*/
my_impl_transportpacket* new_my_impl_transportpacket()
{
i_transportpacket* itp = NULL;
i_transport* itransport = NULL;
/* this is a model for dynamic class ID assigment */
unsigned short class_id = get_dynamic_classid_unique(&CLASSID_MY_IMPL_TP);
my_impl_transportpacket* mytp = (my_impl_transportpacket*) new_object
(sizeof(my_impl_transportpacket), OBJTYPE_MY_IMPL_TP, class_id);
mytp->destroy = destroy_my_impl_transportpacket;
itransport = new_transport_interface_ex(mytp,
(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);
itp = new_transportpkt_interface(mytp, impl_transport_packet, itransport);
/* default header_size() will return this value so no need to override */
itp->header_size = THISTEST_HEADERSIZE;
/* save off i_transportpacket destructor */
mytp->destroy_transportpacket = itp->destroy;
/* replace i_transportpacket destructor with one which will destroy this object */
itp->destroy = destroy_my_transportpacket;
/* g_my_transportpacket will get set to this interface */
mytp->ixp = itp;
return mytp;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* my_impl_sessionmessage (i_sessionmessage implementation)
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
/**
* my_impl_sessionmessage
* test object implementing i_sessionmessage
*/
typedef struct my_impl_sessionmessage
{
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_sessionmessage 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_sessionmessage
* in this case, contains a pointer to the wrapper object, in this case a
* my_impl_sessionmessage*. 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_sessionmessage* ism; /* owned */
objdtor destroy_sessionmessage; /* i_sessionmessage original destructor */
etch_session_message session_message; /* session_message() method */
etch_what what;
etch_who* sender; /* not owned */
etch_message* msg; /* not owned */
int is_msg_handled;
etch_object* query; /* owned */
etch_object* query_result; /* owned */
etch_object* control; /* owned */
etch_object* value; /* owned */
etch_object* eventx; /* owned */
i_sessionpacket* session;
} my_impl_sessionmessage;
/**
* destroy_my_impl_sessionmessage()
* my_impl_sessionmessage destructor
*/
int destroy_my_impl_sessionmessage(my_impl_sessionmessage* thisx)
{
if (thisx->refcount > 0 && --thisx->refcount > 0) return -1;
if (!is_etchobj_static_content(thisx))
{ /* invoke original i_sessionmessage destructor */
if (thisx->ism && thisx->destroy_sessionmessage)
thisx->destroy_sessionmessage(thisx->ism);
/* these are objects which would be destroyed in the binding
* by the last method to touch them */
if (thisx->msg)
thisx->msg->destroy(thisx->msg);
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_message()
* my_impl_sessionmessage::ism::session_message.
* @param whofrom caller retains, can be null.
* @param msg caller abandons
*/
int impl_session_message (my_impl_sessionmessage* mysm, etch_who* whofrom, etch_message* msg)
{
CU_ASSERT_FATAL(is_my_impl_sm(mysm));
mysm->what = SESSION_MESSAGE;
/* in this emulation we are the session consuming a message. if successful,
* (i.e., the message is handled), the binding will eventually destroy the
* message (the caller relinquishes message memory), and the who object.
* if not successful (message not handled) the caller retains message and
* who memory in order to forward the message and who somewhere else
* (as an unwanted message). so we model that here: if the message is not
* handled (a manual switch in these tests), we do not save references to
* the messaqe and who for cleanup, because the unwanted message, containing
* these objects, will be cleaned up instead.
*/
if (mysm->is_msg_handled)
{
mysm->msg = msg;
mysm->sender = whofrom;
return 0;
}
mysm->msg = NULL;
mysm->sender = NULL;
return -1;
}
/**
* my_session_control()
* my_impl_sessionmessage::ism::isession::session_control
* control and value are always abandoned by caller so mysm must clean them up.
*/
int my_session_control (my_impl_sessionmessage* mysm, etch_object* control, etch_object* value)
{
CU_ASSERT_FATAL(is_my_impl_sm(mysm));
mysm->what = SESSION_CONTROL;
mysm->control = control;
mysm->value = value;
return 0;
}
/**
* my_session_notify()
* my_impl_sessionmessage::ism::isession::session_notify
* evt is always abandoned by caller so mysm must clean it up.
*/
int my_session_notify (my_impl_sessionmessage* mysm, etch_object* evt)
{
CU_ASSERT_FATAL(is_my_impl_sm(mysm));
mysm->what = SESSION_NOTIFY;
mysm->eventx = evt;
return 0;
}
/**
* my_session_query()
* my_impl_sessionmessage::ism::isession::session_query
* query is always abandoned by caller so mysm must clean it up.
*/
objmask* my_session_query (my_impl_sessionmessage* mysm, etch_object* query)
{
etch_object* resultobj = NULL;
CU_ASSERT_FATAL(is_my_impl_sm(mysm));
resultobj = mysm->query_result; /* artifically set in test */
mysm->what = SESSION_QUERY;
mysm->query = query;
mysm->query_result = NULL;
return (objmask*) resultobj; /* caller owns */
}
/*
* destroy_my_sessionmessage()
* i_sessionmessage destructor
* this destructor will destroy its parent (my_impl_sessionmessage),
* which will in turn destroy this object.
*/
int destroy_my_sessionmessage(i_sessionmessage* ism)
{
my_impl_sessionmessage* mysm = NULL;
if (NULL == ism) return -1;
mysm = ism->thisx;
mysm->destroy(mysm);
return 0;
}
/**
* new_my_impl_sessionmessage()
* my_impl_sessionmessage constructor
*/
my_impl_sessionmessage* new_my_impl_sessionmessage()
{
i_sessionmessage* ism = NULL;
i_session* isession = NULL;
/* this is a model for dynamic class ID assigment */
unsigned short class_id = CLASSID_MY_IMPL_SM? CLASSID_MY_IMPL_SM:
(CLASSID_MY_IMPL_SM = get_dynamic_classid());
my_impl_sessionmessage* mysm = (my_impl_sessionmessage*) new_object
(sizeof(my_impl_sessionmessage), OBJTYPE_MY_IMPL_SM, class_id);
mysm->destroy = destroy_my_impl_sessionmessage;
isession = new_session_interface(mysm,
(etch_session_control) my_session_control,
(etch_session_notify) my_session_notify,
(etch_session_query) my_session_query);
ism = new_sessionmsg_interface(mysm, impl_session_message, isession);
/* save off i_sessionmessage destructor */
mysm->destroy_sessionmessage = ism->destroy;
/* custom destructor will destroy the my_impl_sessionmessage */
ism->destroy = destroy_my_sessionmessage;
/* g_my_sessionmessage will get set to this interface */
mysm->ism = ism;
return mysm;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* test value factories
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
/**
* test_value_factory
* value factory version 1
* this version uses inherited data coded into the object, as opposed to
* instantiating an impl object to contain inherited data and methods.
*/
typedef struct test_value_factory
{
unsigned int hashkey;
unsigned short obj_type;
unsigned short class_id;
i_value_factory* vtab;
int (*destroy) (void*);
void*(*clone) (void*);
obj_gethashkey get_hashkey;
struct objmask* parent;
etchresult* result;
unsigned int refcount;
unsigned int length;
unsigned char is_null;
unsigned char is_copy;
unsigned char is_static;
unsigned char reserved;
/* - - - - - - - - - - - - -
* default value factory
* - - - - - - - - - - - - -
*/
objmask* impl;
class_to_type_map* class_to_type;
vf_idname_map* types;
etch_arraylist* mixins;
unsigned char is_own_types;
unsigned char is_own_class_to_type;
/* - - - - - - - - - - - - -
* test value factory
* - - - - - - - - - - - - -
*/
etch_type* mt_add;
etch_type* mt_add_result;
etch_field* mf_x;
etch_field* mf_y;
etch_field* mf_result;
} test_value_factory;
/**
* destroy_test_value_factory()
* destructor for value factory version 1
*/
int destroy_test_value_factory(test_value_factory* vf)
{
if (NULL == vf) return -1;
if (vf->refcount > 0)
if (vf->refcount != 1) /* if refcount is 1 */
{ vf->refcount--; /* parent dtor will decrement */
return -1;
}
if (!is_etchobj_static_content(vf))
{
destroy_static_type(vf->mt_add);
destroy_static_type(vf->mt_add_result);
destroy_static_field(vf->mf_x);
destroy_static_field(vf->mf_y);
destroy_static_field(vf->mf_result);
}
return destroy_default_value_factory((default_value_factory*) vf);
}
/**
* new_test_valuefactory()
* constructor for value factory version 1 inheriting from default_value_factory
*/
test_value_factory* new_test_valuefactory()
{
etchparentinfo* inheritlist = NULL;
test_value_factory* vf = NULL;
/* establish global dynamic class IDs for the custom vf.
* these global objects are generated by the etch compiler.
*/
const unsigned short class_id_vf = CLASSID_MY_VF? CLASSID_MY_VF:
(CLASSID_MY_VF = get_dynamic_classid());
const unsigned short class_id_vf_vtab = CLASSID_MY_VF_VTAB? CLASSID_MY_VF_VTAB:
(CLASSID_MY_VF_VTAB = get_dynamic_classid());
g_type_map = new_vf_types_collection(ETCH_DEFSIZE);
/* since we explicitly instantiate a type map, and since we explicitly destroy
* the test's custom types, we want the type maps destructor to not destroy
* the map content. overriding the map's content clear callback is one way
* to do this. */
g_type_map->freehook = etch_noop_clear_handler;
g_class_to_type_map = new_class_to_type_map(ETCH_DEFSIZE);
/* instantiate the new value factory.
* this vf does NOT own its type maps since we supply them here.
* however if we wanted to abandon ownership, we could set the
* vf.is_own_types and vf.is_own_class_to_type flags here.
*/
vf = (test_value_factory*) new_default_value_factory_a
(sizeof(test_value_factory), g_type_map, g_class_to_type_map);
vf->destroy = destroy_test_value_factory;
/* ensure parent type keys exist in the (one-based) inheritance list.
* parent class of our custom vf is default_value_factory.
* inheritance list is used by validators and object assignment logic.
*/
inheritlist = get_vtab_inheritance_list((objmask*)vf, 2, 1, CLASSID_MY_VF_VTAB);
inheritlist[1].obj_type = ETCHTYPEB_VALUEFACTORY;
inheritlist[1].class_id = CLASSID_VALUEFACTORY; /* parent class */
vf->class_id = CLASSID_MY_VF; /* our class */
/* instantiate the custom vf's instance data and assign it to the vf.
*/
vf->mt_add = new_static_type(L"add");
vf->mt_add_result = new_static_type(L"add_result");
vf->mf_x = new_static_field(L"x");
vf->mf_y = new_static_field(L"y");
vf->mf_result = new_static_field(L"xresult");
/* we replace generated ids with 1-byte IDs to make test data buffers easier to construct */
vf->mt_add->id = FAKEID_TYPE_ADD;
vf->mt_add_result->id = FAKEID_TYPE_ADD_RESULT;
vf->mf_x->id = FAKEID_FIELD_X;
vf->mf_y->id = FAKEID_FIELD_Y;
vf->mf_result->id = FAKEID_FIELD_RESULT;
vf->vtab->add_type(vf, vf->mt_add);
vf->vtab->add_type(vf, vf->mt_add_result);
etchtype_put_validator(vf->mt_add, clone_field(vf->mf_x),
(objmask*) etchvtor_int32_get(0));
etchtype_put_validator(vf->mt_add, clone_field(vf->mf_y),
(objmask*) etchvtor_int32_get(0));
etchtype_put_validator(vf->mt_add, clone_field(builtins._mf__message_id),
(objmask*) etchvtor_int64_get(0));
etchtype_put_validator(vf->mt_add_result, clone_field(vf->mf_result),
(objmask*) etchvtor_int32_get(0));
etchtype_put_validator(vf->mt_add_result, clone_field(builtins._mf__message_id),
(objmask*) etchvtor_int64_get(0));
etchtype_put_validator(vf->mt_add_result, clone_field(builtins._mf__in_reply_to),
(objmask*) etchvtor_int64_get(0));
g_my_test_vf = vf;
return g_my_test_vf;
}
/**
* my_valufactory_impl
* value factory version 2 instance data object
*/
typedef struct my_valufactory_impl
{
unsigned int hashkey;
unsigned short obj_type;
unsigned short class_id;
struct objmask* vtab;
int (*destroy)(void*);
void*(*clone) (void*);
obj_gethashkey get_hashkey;
struct objmask* parent;
etchresult* result;
unsigned int refcount;
unsigned int length;
unsigned char is_null;
unsigned char is_copy;
unsigned char is_static;
unsigned char reserved;
etch_type* mt_add;
etch_type* mt_add_result;
etch_field* mf_x;
etch_field* mf_y;
etch_field* mf_result;
} my_valufactory_impl;
/**
* destroy_my_valufactory_impl()
* destructor for inheriting value factory version 2 instance data
*/
int destroy_my_valufactory_impl(my_valufactory_impl* impl)
{
if (NULL == impl) return -1;
if (impl->refcount > 0 && --impl->refcount > 0) return -1;
if (!is_etchobj_static_content(impl))
{
destroy_static_type(impl->mt_add);
destroy_static_type(impl->mt_add_result);
destroy_static_field(impl->mf_x);
destroy_static_field(impl->mf_y);
destroy_static_field(impl->mf_result);
}
return destroy_objectex((objmask*) impl);
}
/**
* new_my_valufactory_impl()
* constructor for inheriting value factory version 2 instance data
*/
my_valufactory_impl* new_my_valufactory_impl()
{
unsigned short class_id = CLASSID_MY_VF_IMPL? CLASSID_MY_VF_IMPL:
(CLASSID_MY_VF_IMPL = get_dynamic_classid());
my_valufactory_impl* impl = (my_valufactory_impl*) new_object
(sizeof(my_valufactory_impl), ETCHTYPEB_VALUEFACTIMP, class_id);
impl->destroy = destroy_my_valufactory_impl;
impl->mt_add = new_static_type(L"add");
impl->mt_add_result = new_static_type(L"add_result");
impl->mf_x = new_static_field(L"x");
impl->mf_y = new_static_field(L"y");
impl->mf_result = new_static_field(L"xresult");
/* we replace generated ids with 1-byte IDs to make test data buffers easier to construct */
impl->mt_add->id = FAKEID_TYPE_ADD;
impl->mt_add_result->id = FAKEID_TYPE_ADD_RESULT;
impl->mf_x->id = FAKEID_FIELD_X;
impl->mf_y->id = FAKEID_FIELD_Y;
impl->mf_result->id = FAKEID_FIELD_RESULT;
etchtype_put_validator(impl->mt_add, clone_field(impl->mf_x),
(objmask*) etchvtor_int32_get(0));
etchtype_put_validator(impl->mt_add, clone_field(impl->mf_y),
(objmask*) etchvtor_int32_get(0));
etchtype_put_validator(impl->mt_add, clone_field(builtins._mf__message_id),
(objmask*) etchvtor_int64_get(0));
etchtype_put_validator(impl->mt_add_result, clone_field(impl->mf_result),
(objmask*) etchvtor_int32_get(0));
etchtype_put_validator(impl->mt_add_result, clone_field(builtins._mf__message_id),
(objmask*) etchvtor_int64_get(0));
etchtype_put_validator(impl->mt_add_result, clone_field(builtins._mf__in_reply_to),
(objmask*) etchvtor_int64_get(0));
return impl;
}
/**
* new_bogus_valuefactory()
* constructor for value factory version 2 inheriting from default_value_factory
*/
default_value_factory* new_bogus_valuefactory()
{
etchparentinfo* inheritlist = NULL;
my_valufactory_impl* impl = NULL;
/* establish global dynamic class IDs for the custom vf.
* these global objects are generated by the etch compiler.
*/
const unsigned short class_id_vf = CLASSID_MY_VF? CLASSID_MY_VF:
(CLASSID_MY_VF = get_dynamic_classid());
const unsigned short class_id_vf_vtab = CLASSID_MY_VF_VTAB? CLASSID_MY_VF_VTAB:
(CLASSID_MY_VF_VTAB = get_dynamic_classid());
g_type_map = new_vf_types_collection(ETCH_DEFSIZE);
/* since we explicitly instantiate a type map, and since we explicitly destroy
* the test's custom types, we want the type maps destructor to not destroy
* the map content. overriding the map's content clear callback is one way
* to do this. */
g_type_map->freehook = etch_noop_clear_handler;
g_class_to_type_map = new_class_to_type_map(ETCH_DEFSIZE);
/* instantiate the new value factory.
* this vf does NOT own its type maps since we supply them here.
* however if we wanted to abandon ownership, we could clear the
* vf.is_own_types and vf.is_own_class_to_type flags here.
*/
g_my_vf = new_default_value_factory(g_type_map, g_class_to_type_map);
/* ensure parent type keys exist in the (one-based) inheritance list.
* parent class of our custom vf is default_value_factory.
* inheritance list is used by validators and object assignment logic.
*/
inheritlist = get_vtab_inheritance_list((objmask*)g_my_vf, 2, 1, CLASSID_MY_VF_VTAB);
inheritlist[1].obj_type = ETCHTYPEB_VALUEFACTORY;
inheritlist[1].class_id = CLASSID_VALUEFACTORY; /* parent class */
g_my_vf->class_id = CLASSID_MY_VF; /* our class */
/* instantiate the custom vf's instance data and assign it to the vf.
* the impl comprises all data specific to the inheriting class, including
* data and methods if any. the default value factory destructor will call
* the destructor on the vf's impl object.
*/
impl = new_my_valufactory_impl();
g_my_vf->impl = (objmask*) impl;
g_my_vf->vtab->add_type(g_my_vf, impl->mt_add);
g_my_vf->vtab->add_type(g_my_vf, impl->mt_add_result);
return g_my_vf;
}
/**
* get_vftype()
* return a type depending on which version of value factory is instantiated
*/
etch_type* get_vftype(const int typeid)
{
etch_type* type = NULL;
if (g_my_vf)
{
my_valufactory_impl* impl = (my_valufactory_impl*) g_my_vf->impl;
if (typeid == impl->mt_add->id)
type = impl->mt_add;
else
if (typeid == impl->mt_add_result->id)
type = impl->mt_add_result;
}
else
if (g_my_test_vf)
{
if (typeid == g_my_test_vf->mt_add->id)
type = g_my_test_vf->mt_add;
else
if (typeid == g_my_test_vf->mt_add_result->id)
type = g_my_test_vf->mt_add_result;
}
return type;
}
/* - - - - - - - - - - - - - - - - -
* test messagizer
* - - - - - - - - - - - - - - - - -
*/
/**
* new_bogus_messagizer()
*/
etch_messagizer* new_bogus_messagizer(i_transportpacket* transport)
{
g_my_messagizer = new_messagizer(transport, L"foo:?Messagizer.format=binary", g_my_resources);
return g_my_messagizer;
}
/* - - - - - - - - - - - - - - - - - - - - -
* individual test data setup and teardown
* - - - - - - - - - - - - - - - - - - - - -
*/
/**
* setup_this_test()
*/
int setup_this_test(const int which_valuefactory)
{
my_impl_transportpacket* mytp_impl = NULL;
my_impl_sessionmessage* mysm_impl = NULL;
default_value_factory* thisvf = NULL;
g_which_valuefactory = which_valuefactory;
/* two versions of value factory using different inheritance models */
if (which_valuefactory == WHICHVF_TESTVF) /* vf version 1 inline inheritance */
{ thisvf = (default_value_factory*) new_test_valuefactory();
set_etchobj_static_all(g_my_test_vf); /* so resources will not destroy */
}
else
{ thisvf = new_bogus_valuefactory(); /* vf version 2 impl object inheritance */
set_etchobj_static_all(g_my_vf); /* so resources will not destroy */
}
g_my_resources = new_etch_resources(ETCH_DEFSIZE);
etch_resources_add(g_my_resources, ETCH_RESXKEY_MSGIZER_VALUFACT, (objmask*) thisvf);
/* 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.
*/
mytp_impl = new_my_impl_transportpacket();
g_my_transportpacket = mytp_impl->ixp;
/* we instantiate a wrapper y which implements and instantiates i_sessionmessage.
* the instantiation of i_sessionmessage will contain a pointer to y.
* our global reference g_my_sessionmessage 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_sessionmessage*) g_my_sessionmessage->thisx.
*/
mysm_impl = new_my_impl_sessionmessage();
g_my_sessionmessage = mysm_impl->ism;
g_who = new_who(new_int32(THISTEST_WHO_VALUE), TRUE);
/* finally instantiate the test messagizer */
new_bogus_messagizer(g_my_transportpacket);
CU_ASSERT_PTR_NOT_NULL_FATAL(g_my_messagizer);
etch_msgizer_set_session(g_my_messagizer, g_my_sessionmessage);
return 0;
}
/**
* teardown_this_test()
*/
int teardown_this_test()
{
g_my_messagizer->destroy(g_my_messagizer);
g_my_transportpacket->destroy(g_my_transportpacket);
g_my_sessionmessage->destroy(g_my_sessionmessage);
g_my_resources->destroy(g_my_resources);
if (g_my_vf)
{ clear_etchobj_static_all(g_my_vf);
g_my_vf->destroy(g_my_vf);
}
else /* can only instantiate one or the other */
if (g_my_test_vf)
{ clear_etchobj_static_all(g_my_test_vf);
g_my_test_vf->destroy(g_my_test_vf);
}
g_who->destroy(g_who);
g_type_map->destroy(g_type_map); // ************************************************
g_class_to_type_map->destroy(g_class_to_type_map);
if (g_flexbuffer)
g_flexbuffer->destroy(g_flexbuffer);
g_my_transportpacket = NULL;
g_my_sessionmessage = NULL;
g_class_to_type_map = NULL;
g_my_messagizer = NULL;
g_my_resources = NULL;
g_flexbuffer = NULL;
g_my_test_vf = NULL;
g_type_map = NULL;
g_my_vf = NULL;
g_who = NULL;
etchvf_free_builtins();
return 0;
}
/* - - - - - - - - - - - - - -
* unit tests
* - - - - - - - - - - - - - -
*/
/**
* test_transportpacket_constructor()
*/
void test_transportpacket_constructor(void)
{
my_impl_transportpacket* mytp_impl = new_my_impl_transportpacket();
CU_ASSERT_PTR_NOT_NULL_FATAL(mytp_impl);
/* the custom interface object destructors are coded to destroy their
* implementing objects, so we do that here to verify this functionality.
*/
do
{ i_transportpacket* itp = mytp_impl->ixp;
itp->destroy(itp);
} 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_sessionmessage_constructor()
*/
void test_sessionmessage_constructor(void)
{
my_impl_sessionmessage* mysm_impl = new_my_impl_sessionmessage();
CU_ASSERT_PTR_NOT_NULL_FATAL(mysm_impl);
/* the custom interface object destructors are coded to destroy their
* implementing objects, so we do that here to verify this functionality.
*/
do
{ i_sessionmessage* ism = mysm_impl->ism;
ism->destroy(ism);
} 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_messagizer_constructor()
*/
void test_messagizer_constructor(void)
{
etch_messagizer* mzr = NULL;
i_transportpacket* itp = NULL;
etch_resources* resxmap = NULL;
default_value_factory* vf = NULL;
my_impl_transportpacket* mytp_impl = NULL;
vf = new_default_value_factory(NULL, NULL);
CU_ASSERT_PTR_NOT_NULL_FATAL(vf);
set_etchobj_static_all(vf); /* so resources will not destroy */
resxmap = new_etch_resources(ETCH_DEFSIZE);
CU_ASSERT_PTR_NOT_NULL_FATAL(resxmap);
etch_resources_add(resxmap, ETCH_RESXKEY_MSGIZER_VALUFACT, (objmask*) vf);
mytp_impl = new_my_impl_transportpacket();
CU_ASSERT_PTR_NOT_NULL_FATAL(mytp_impl);
itp = mytp_impl->ixp;
CU_ASSERT_PTR_NOT_NULL_FATAL(itp);
/* messagizer does not own i_transportpacket* itp */
mzr = new_messagizer(itp, L"foo:?Messagizer.format=binary", resxmap);
CU_ASSERT_PTR_NOT_NULL_FATAL(mzr);
mzr->destroy(mzr);
/* i_transportpacket.destroy() will destroy my_impl_transportpacket */
itp->destroy(itp);
resxmap->destroy(resxmap);
clear_etchobj_static_all(vf); /* so we can destroy it now */
vf->destroy(vf);
etchvf_free_builtins();
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_testsetup_teardown_a
*/
void test_testsetup_teardown_a(void)
{
setup_this_test(WHICHVF_TESTVF);
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_testsetup_teardown_b
*/
void test_testsetup_teardown_b(void)
{
setup_this_test(WHICHVF_MYVF);
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_packet_1
* mimics the transport messagizing a packet and delivering the message to the session
*/
void test_packet_1(void)
{
setup_this_test(WHICHVF_TESTVF);
do
{ int result = 0;
etch_type* msgtype = NULL;
etch_flexbuffer* fbuf = NULL;
const int THISTEST_BUFSIZE = 4;
char* buf = etch_malloc(THISTEST_BUFSIZE, ETCHTYPEB_BYTES);
/* g_my_sessionmessage is the i_sessionmessage interface
* my_impl_sessionmessage is the implementing test class */
my_impl_sessionmessage* my_session = g_my_sessionmessage->thisx;
CU_ASSERT_PTR_NOT_NULL_FATAL(my_session);
/* load up the packet buffer with test data */
buf[0] = TAGDATA_VERSION; buf[1] = FAKEID_TYPE_ADD; buf[2] = 0; buf[3] = TYPECODE_EOD_MARK;
g_flexbuffer = new_flexbuffer_from(buf, THISTEST_BUFSIZE, THISTEST_BUFSIZE, 0);
my_session->is_msg_handled = TRUE;
/* messagize the packet and deliver the message to the session */
result = g_my_messagizer->session_packet (g_my_messagizer, g_who, g_flexbuffer);
CU_ASSERT_EQUAL(result, 0);
if (0 != result) break;
CU_ASSERT_EQUAL(my_session->what, SESSION_MESSAGE);
result = is_equal_who(my_session->sender, g_who);
CU_ASSERT_EQUAL(result, TRUE);
CU_ASSERT_EQUAL(message_size(my_session->msg), 0);
CU_ASSERT_PTR_NULL(my_session->eventx);
/* assert that message type is "add" (since we buffered FAKEID_TYPE_ADD above) */
msgtype = message_type(my_session->msg);
CU_ASSERT_PTR_NOT_NULL_FATAL(msgtype);
CU_ASSERT_EQUAL(msgtype->id, FAKEID_TYPE_ADD);
} 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_packet_2
* mimics the transport messagizing a packet and delivering the message to the session
* which rejects the message and forwards the message as rejected.
*/
void test_packet_2(void)
{
setup_this_test(WHICHVF_TESTVF);
do
{ int result = 0;
etch_type* msgtype = NULL;
etch_flexbuffer* fbuf = NULL;
const int THISTEST_BUFSIZE = 4;
etch_message* thismessage = NULL;
etch_unwanted_message* uwmsg = NULL;
char* buf = etch_malloc(THISTEST_BUFSIZE, ETCHTYPEB_BYTES);
/* g_my_sessionmessage is the i_sessionmessage interface
* my_impl_sessionmessage is the implementing test class */
my_impl_sessionmessage* my_session = g_my_sessionmessage->thisx;
CU_ASSERT_PTR_NOT_NULL_FATAL(my_session);
/* load up the packet buffer with test data */
buf[0] = TAGDATA_VERSION; buf[1] = FAKEID_TYPE_ADD; buf[2] = 0; buf[3] = TYPECODE_EOD_MARK;
g_flexbuffer = new_flexbuffer_from(buf, THISTEST_BUFSIZE, THISTEST_BUFSIZE, 0);
/* for the purposes of this test we manually specify that the message was not handled.
* when this is the case, the message and who will be wrapped up in an "unwanted message"
* which is forwarded to the session as an event. when this is the case, memory for the
* message and who is not cleaned up by the session in the normal manner, but is instead
* owned by the unwanted message, and destroyed with that object.
*/
my_session->is_msg_handled = FALSE;
/* messagize the packet and deliver the message to the session */
result = g_my_messagizer->session_packet (g_my_messagizer, g_who, g_flexbuffer);
CU_ASSERT_EQUAL(result, 0);
if (0 != result) break;
CU_ASSERT_EQUAL(my_session->what, SESSION_NOTIFY);
CU_ASSERT_EQUAL(message_size(my_session->msg), 0);
CU_ASSERT_PTR_NOT_NULL_FATAL(my_session->eventx);
uwmsg = (etch_unwanted_message*) my_session->eventx;
CU_ASSERT_EQUAL_FATAL(uwmsg->class_id, CLASSID_EVENT_UNWANTMSG);
/* find the message and who in the "unwanted message" wrapper */
result = is_equal_who(uwmsg->whofrom, g_who);
CU_ASSERT_EQUAL(result, TRUE);
thismessage = uwmsg->message;
CU_ASSERT_PTR_NOT_NULL_FATAL(thismessage);
/* assert that message type is "add" (since we buffered FAKEID_TYPE_ADD above) */
msgtype = message_type(thismessage);
CU_ASSERT_PTR_NOT_NULL_FATAL(msgtype);
CU_ASSERT_EQUAL(msgtype->id, FAKEID_TYPE_ADD);
} 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_packet_3
* mimics the transport messagizing a packet and delivering the message to the session
*/
void test_packet_3(void)
{
setup_this_test(WHICHVF_TESTVF);
do
{ int result = 0;
etch_type* msgtype = NULL;
etch_flexbuffer* fbuf = NULL;
const int THISTEST_BUFSIZE = 4;
etch_message* thismessage = NULL;
etch_unwanted_message* uwmsg = NULL;
char* buf = etch_malloc(THISTEST_BUFSIZE, ETCHTYPEB_BYTES);
/* g_my_sessionmessage is the i_sessionmessage interface
* my_impl_sessionmessage is the implementing test class */
my_impl_sessionmessage* my_session = g_my_sessionmessage->thisx;
CU_ASSERT_PTR_NOT_NULL_FATAL(my_session);
/* load up the packet buffer with test data */
buf[0] = TAGDATA_VERSION;
buf[1] = FAKEID_TYPE_ADD_RESULT;
buf[2] = 0;
buf[3] = TYPECODE_EOD_MARK;
g_flexbuffer = new_flexbuffer_from(buf, THISTEST_BUFSIZE, THISTEST_BUFSIZE, 0);
/* for the purposes of this test we manually specify that the message was handled */
my_session->is_msg_handled = TRUE;
/* messagize the packet and deliver the message to the session */
result = g_my_messagizer->session_packet (g_my_messagizer, g_who, g_flexbuffer);
CU_ASSERT_EQUAL(result, 0);
if (0 != result) break;
CU_ASSERT_EQUAL(my_session->what, SESSION_MESSAGE);
CU_ASSERT_EQUAL(message_size(my_session->msg), 0);
/* assert that message type is "add_result" (since we buffered FAKEID_TYPE_ADD_RESULT above) */
CU_ASSERT_PTR_NOT_NULL_FATAL(my_session->msg);
msgtype = message_type(my_session->msg);
CU_ASSERT_PTR_NOT_NULL_FATAL(msgtype);
CU_ASSERT_EQUAL(msgtype->id, FAKEID_TYPE_ADD_RESULT);
} 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_message_1
* mimics the session buffering a message and delivering it to the transport
*/
void test_message_1(void)
{
setup_this_test(WHICHVF_TESTVF);
do
{ int result = 0;
etch_type* msgtype = NULL;
etch_value_factory* vf = NULL;
const int EXPECTED_BUFSIZE = 4;
etch_message* thismessage = NULL;
/* g_my_transportpacket is the i_transportpacket interface
* my_impl_transportpacket is the implementing test class */
my_impl_transportpacket* my_transport = g_my_transportpacket->thisx;
CU_ASSERT_PTR_NOT_NULL_FATAL(my_transport);
vf = (etch_value_factory*) get_current_valuefactory();
msgtype = get_vftype(FAKEID_TYPE_ADD);
g_my_transportpacket->header_size = 0; /* test no header */
thismessage = new_message(msgtype, ETCH_DEFSIZE, vf);
/* buffer up the message and deliver to transport */
result = g_my_messagizer->transport_message (g_my_messagizer, g_who, thismessage);
CU_ASSERT_EQUAL(result, 0);
if (0 != result) break;
CU_ASSERT_EQUAL(my_transport->what, TRANSPORT_PACKET);
result = is_equal_who(my_transport->recipient, g_who);
CU_ASSERT_EQUAL(result, TRUE);
CU_ASSERT_PTR_NOT_NULL_FATAL(my_transport->buf);
CU_ASSERT_EQUAL(my_transport->bufcount, EXPECTED_BUFSIZE);
/* check that packet buffer contains expected serialized message */
CU_ASSERT_EQUAL(my_transport->buf[0], TAGDATA_VERSION);
CU_ASSERT_EQUAL(my_transport->buf[1], FAKEID_TYPE_ADD);
CU_ASSERT_EQUAL(my_transport->buf[2], 0);
CU_ASSERT_EQUAL(my_transport->buf[3], TYPECODE_EOD_MARK);
} 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_message_2
* mimics the session buffering a message and delivering it to the transport
*/
void test_message_2(void)
{
setup_this_test(WHICHVF_TESTVF);
do
{ int result = 0, i = 0, errs = 0;
etch_type* msgtype = NULL;
etch_value_factory* vf = NULL;
etch_message* thismessage = NULL;
const int TEST_HEADER_SIZE = 8, EXPECTED_BUFSIZE = 4 + TEST_HEADER_SIZE;
/* g_my_transportpacket is the i_transportpacket interface
* my_impl_transportpacket is the implementing test class */
my_impl_transportpacket* my_transport = g_my_transportpacket->thisx;
CU_ASSERT_PTR_NOT_NULL_FATAL(my_transport);
vf = (etch_value_factory*) get_current_valuefactory();
msgtype = get_vftype(FAKEID_TYPE_ADD_RESULT);
g_my_transportpacket->header_size = TEST_HEADER_SIZE; /* test with 8-byte header */
thismessage = new_message(msgtype, ETCH_DEFSIZE, vf);
/* buffer up the message and deliver to transport */
result = g_my_messagizer->transport_message(g_my_messagizer, g_who, thismessage);
CU_ASSERT_EQUAL(result, 0);
if (0 != result) break;
CU_ASSERT_EQUAL(my_transport->what, TRANSPORT_PACKET);
result = is_equal_who(my_transport->recipient, g_who);
CU_ASSERT_EQUAL(result, TRUE);
CU_ASSERT_PTR_NOT_NULL_FATAL(my_transport->buf);
CU_ASSERT_EQUAL(my_transport->bufcount, EXPECTED_BUFSIZE);
/* check that packet buffer contains expected serialized message */
for(; i < TEST_HEADER_SIZE; i++) if (my_transport->buf[i]) errs++;
CU_ASSERT_EQUAL(errs, 0);
CU_ASSERT_EQUAL(my_transport->buf[8], TAGDATA_VERSION);
CU_ASSERT_EQUAL(my_transport->buf[9], FAKEID_TYPE_ADD_RESULT);
CU_ASSERT_EQUAL(my_transport->buf[10],0);
CU_ASSERT_EQUAL(my_transport->buf[11],TYPECODE_EOD_MARK);
} 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_control
* test the session control notification plumbing
*/
void test_session_control(void)
{
setup_this_test(WHICHVF_TESTVF);
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_sessionmessage is the i_sessionmessage interface
* my_impl_sessionmessage is the implementing test class */
my_impl_sessionmessage* my_session = g_my_sessionmessage->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_messagizer->session_control(g_my_messagizer, 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(WHICHVF_TESTVF);
do
{ int result = 0;
const int MY_EVENT_CLASSID = 0x5202;
etch_object* myeventobj = new_etch_object(MY_EVENT_CLASSID, NULL);
/* g_my_sessionmessage is the i_sessionmessage interface
* my_impl_sessionmessage is the implementing test class */
my_impl_sessionmessage* my_session = g_my_sessionmessage->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_messagizer->session_notify(g_my_messagizer, 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(WHICHVF_TESTVF);
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_sessionmessage is the i_sessionmessage interface
* my_impl_sessionmessage is the implementing test class */
my_impl_sessionmessage* my_session = g_my_sessionmessage->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_messagizer->session_query (g_my_messagizer, 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(WHICHVF_TESTVF);
do
{ int result = 0;
my_impl_transportpacket* my_transport = NULL;
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_transportpacket is the i_transportpacket interface
* my_impl_transportpacket is the implementing test class
*/
g_my_messagizer->transport = g_my_transportpacket;
my_transport = g_my_transportpacket->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 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_messagizer->transport_control (g_my_messagizer, 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(WHICHVF_TESTVF);
do
{ int result = 0;
my_impl_transportpacket* my_transport = NULL;
const int MY_EVENT_CLASSID = 0x5202;
etch_object* myeventobj = new_etch_object(MY_EVENT_CLASSID, NULL);
/* g_my_transportpacket is the i_transportpacket interface
* my_impl_transportpacket is the implementing test class
*/
g_my_messagizer->transport = g_my_transportpacket;
my_transport = g_my_transportpacket->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_messagizer->transport_notify (g_my_messagizer, 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(WHICHVF_TESTVF);
do
{ int result = 0;
my_impl_transportpacket* my_transport = NULL;
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_transportpacket is the i_transportpacket interface
* my_impl_transportpacket is the implementing test class
*/
g_my_messagizer->transport = g_my_transportpacket;
my_transport = g_my_transportpacket->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 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_messagizer->transport_query (g_my_messagizer, 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 pSuite = NULL;
g_is_automated_test = argc > 1 && 0 != wcscmp(argv[1], L"-a");
if (CUE_SUCCESS != CU_initialize_registry()) return 0;
pSuite = CU_add_suite("suite messagizer", init_suite, clean_suite);
CU_set_output_filename("../test_messagizer");
etch_watch_id = 0;
CU_add_test(pSuite, "test transportpacket impl constructor", test_transportpacket_constructor);
CU_add_test(pSuite, "test sessionmessage impl constructor", test_sessionmessage_constructor);
CU_add_test(pSuite, "test messagizer constructor", test_messagizer_constructor);
CU_add_test(pSuite, "test test setup and teardown v1", test_testsetup_teardown_a);
CU_add_test(pSuite, "test test setup and teardown v2", test_testsetup_teardown_b);
CU_add_test(pSuite, "test packet 1", test_packet_1);
CU_add_test(pSuite, "test packet 2", test_packet_2);
CU_add_test(pSuite, "test packet 3", test_packet_2);
CU_add_test(pSuite, "test message 1", test_message_1);
CU_add_test(pSuite, "test message 2", test_message_2);
CU_add_test(pSuite, "test session control",test_session_control);
CU_add_test(pSuite, "test session notify", test_session_notify);
CU_add_test(pSuite, "test session query", test_session_query);
CU_add_test(pSuite, "test transport control",test_transport_control);
CU_add_test(pSuite, "test transport notify", test_transport_notify);
CU_add_test(pSuite, "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(); printf("\n"); }
CU_cleanup_registry();
return CU_get_error();
}