blob: d09231eaf80f10932b6823943c8e86fedbf03e36 [file] [log] [blame]
/* $Id$
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to you under the Apache License, Version
* 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* test_etchobject.c.c -- test etch object inheritance and primitives
*/
#include "etch_runtime.h"
#include "etch_object.h"
#include "etch_objecttypes.h"
#include "etch_nativearray.h"
#include "etch_mem.h"
#include <stdio.h>
#include "CUnit.h"
#include <wchar.h>
#define IS_DEBUG_CONSOLE FALSE
// extern types
extern apr_pool_t* g_etch_main_pool;
int init_suite(void)
{
etch_status_t etch_status = ETCH_SUCCESS;
etch_status = etch_runtime_initialize(NULL);
if(etch_status != NULL) {
// error
}
return 0;
}
static int clean_suite(void)
{
//this_teardown();
etch_runtime_shutdown();
return 0;
}
/**
* class_a: base class
*/
typedef struct class_a
{
etch_object object;
etch_string* a_string;
} class_a;
/**
* class_a destructor
*/
static int destroy_class_a(void* data)
{
class_a* thisp = (class_a*)data;
if (thisp->a_string)
etch_object_destroy(thisp->a_string);
destroy_object((etch_object*) thisp);
return 0;
}
/**
* class_a copy consttructor
*/
static void* clone_class_a(void* data)
{
class_a* origobj = (class_a*)data;
class_a* newobj = (class_a*) new_object(sizeof(class_a), 413, 0);
memcpy(newobj, origobj, sizeof(etch_object));
newobj->a_string = (etch_string*)etch_object_clone_func(origobj->a_string);
return newobj;
}
/**
* class_a constructor
*/
static class_a* new_class_a(const wchar_t* strval)
{
class_a* newobj = (class_a*) new_object(sizeof(class_a), 403, 0);
((etch_object*)newobj)->destroy = destroy_class_a;
((etch_object*)newobj)->clone = clone_class_a;
newobj->a_string = new_stringw(strval);
return newobj;
}
/**
* class_b: inherits from class_a
*/
typedef struct class_b
{
etch_object object;
char* data;
int datasize;
} class_b;
/**
* class_b destructor
*/
static int destroy_class_b(void* data)
{
class_b* thisp = (class_b*)data;
etch_free(thisp->data);
destroy_object((etch_object*) thisp);
return 0;
}
/**
* class_b copy consttructor
*/
static void* clone_class_b(void* data)
{
class_b* origobj = (class_b*)data;
class_b* newobj = (class_b*) new_object(sizeof(class_b), 415, 0);
memcpy(newobj, origobj, sizeof(etch_object));
((etch_object*)newobj)->parent = ((etch_object*)origobj)->parent?
etch_object_clone_func(((etch_object*)origobj)->parent):
(etch_object*)new_class_a(NULL);
if (origobj->data)
{
newobj->data = etch_malloc(origobj->datasize, 412);
newobj->datasize = origobj->datasize;
memcpy(newobj->data, origobj->data, origobj->datasize);
}
return newobj;
}
/**
* class_b constructor
*/
static class_b* new_class_b(class_a* parent, const int datalen)
{
class_b* newobj = (class_b*) new_object(sizeof(class_b), 404, 0);
((etch_object*)newobj)->parent = (etch_object*)(parent? parent: new_class_a(NULL));
((etch_object*)newobj)->destroy = destroy_class_b;
((etch_object*)newobj)->clone = clone_class_b;
newobj->data = etch_malloc(datalen, 402);
memset(newobj->data, 'x', datalen);
newobj->datasize = datalen;
return newobj;
}
/**
* class_c: inherits from class_b
*/
typedef struct class_c
{
etch_object object;
int* intarray;
int numitems;
} class_c;
/**
* class_c destructor
*/
static int destroy_class_c(void* data)
{
class_c* thisp = (class_c*)data;
etch_free(thisp->intarray);
destroy_object((etch_object*) thisp);
return 0;
}
/**
* class_c copy consttructor
*/
static void* clone_class_c(void* data)
{
class_c* origobj = (class_c*)data;
class_c* newobj = (class_c*) new_object(sizeof(class_c), 410, 0);
memcpy(newobj, origobj, sizeof(etch_object));
if (((etch_object*)origobj)->parent)
((etch_object*)newobj)->parent = etch_object_clone_func(((etch_object*)origobj)->parent);
else ((etch_object*)newobj)->parent = (etch_object*)new_class_b(NULL, 0);
if (origobj->intarray)
{
newobj->intarray = etch_malloc(origobj->numitems * sizeof(int), 411);
newobj->numitems = origobj->numitems;
memcpy(newobj->intarray, origobj->intarray, origobj->numitems * sizeof(int));
}
return newobj;
}
/**
* class_c constructor
*/
static class_c* new_class_c(class_b* parent)
{
int i = 0;
class_c* newobj = (class_c*) new_object(sizeof(class_b), 400, 0);
((etch_object*)newobj)->parent = (etch_object*)(parent? parent: new_class_b(NULL, 0));
((etch_object*)newobj)->destroy = destroy_class_c;
((etch_object*)newobj)->clone = clone_class_c;
newobj->numitems = 4;
newobj->intarray = etch_malloc(4 * sizeof(int), 401);
for(; i < 4; i++) newobj->intarray[i] = i;
return newobj;
}
/**
* test_inheritance()
* test that in scenario c inherits from b inherits from a,
* destroying c destroys b destroys a.
*/
static void test_inheritance(void)
{
class_a* class_toplevel = NULL;
class_b* class_midlevel = NULL;
class_c* class_lowlevel = NULL;
class_toplevel = new_class_a(L"it works!");
class_midlevel = new_class_b(class_toplevel, 128);
class_lowlevel = new_class_c(class_midlevel);
/* any object destructor should recursively destroy() its superclasses */
CU_ASSERT_PTR_NOT_NULL_FATAL(((etch_object*)class_lowlevel)->parent);
CU_ASSERT_PTR_NOT_NULL_FATAL(((etch_object*)class_midlevel)->parent);
CU_ASSERT_PTR_NULL_FATAL(((etch_object*)class_toplevel)->parent);
etch_object_destroy(class_lowlevel);
#ifdef ETCH_DEBUGALLOC
g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE); /* verify all memory freed */
CU_ASSERT_EQUAL(g_bytes_allocated, 0);
// start fresh for next test
memtable_clear();
#endif
}
/**
* test_clone()
* test validity of cloned objects, also test construction of inherited object
* when the parent(s) implementation(s) is/are not specified.
* clones must be disposable, i.e. they must own all their memory
* including that of their superclasses, such that if c inherits from b
* inherits from a, and I clone c giving c', and I then destroy c, then
* I can subsequently destroy c' via normal channels.
*/
static void test_clone(void)
{
class_c* class_lowlevel = NULL;
class_b* class_midlevel = NULL;
class_a* class_toplevel = NULL;
class_c* clone_lowlevel = NULL;
class_b* clone_midlevel = NULL;
class_a* clone_toplevel = NULL;
/* construct class c and all its superclasses */
class_lowlevel = new_class_c(NULL);
/* verify that superclasses were created */
class_midlevel = (class_b*) ((etch_object*)class_lowlevel)->parent;
CU_ASSERT_PTR_NOT_NULL_FATAL(class_midlevel);
class_toplevel = (class_a*) ((etch_object*)class_midlevel)->parent;
CU_ASSERT_PTR_NOT_NULL_FATAL(class_toplevel);
CU_ASSERT_PTR_NULL_FATAL(((etch_object*)class_toplevel)->parent);
/* clone class c and all its superclasses */
clone_lowlevel = (class_c*)etch_object_clone_func(class_lowlevel);
/* verify that superclasses were created */
clone_midlevel = (class_b*) ((etch_object*)clone_lowlevel)->parent;
CU_ASSERT_PTR_NOT_NULL_FATAL(clone_midlevel);
clone_toplevel = (class_a*) ((etch_object*)clone_midlevel)->parent;
CU_ASSERT_PTR_NOT_NULL_FATAL(clone_toplevel);
CU_ASSERT_PTR_NULL_FATAL(((etch_object*)clone_toplevel)->parent);
/* verify that superclass and data clones are not references to old memory */
CU_ASSERT_NOT_EQUAL_FATAL(class_midlevel, clone_midlevel);
CU_ASSERT_NOT_EQUAL_FATAL(class_toplevel, clone_toplevel);
if (class_midlevel->data != 0 && clone_midlevel->data != 0)
CU_ASSERT_NOT_EQUAL_FATAL(class_midlevel->data, clone_midlevel->data);
if (class_toplevel->a_string != 0 && clone_toplevel->a_string != 0)
CU_ASSERT_NOT_EQUAL_FATAL(class_toplevel->a_string, clone_toplevel->a_string);
// clean data of clone_midlevel so we get no memory leaks
if(clone_midlevel->data) {
etch_free(clone_midlevel->data);
}
/* we don't need to do this for the test, but here we illustrate
* the etch C way of accessing superclass data from a subclass,
* which is to traverse the parent chain to the class you want,
* and cast the parent* to that class, if it is not so cast already.
*/
clone_midlevel->datasize = 1024;
clone_midlevel->data = etch_malloc(clone_midlevel->datasize, 419);
memset(clone_midlevel->data, '-', clone_midlevel->datasize);
/* destroy class c with all its superclasses and associated instance data */
etch_object_destroy(class_lowlevel);
/* destroy class c clone and all its superclasses
* if the clone of class_c had not properly cloned all its superclasses and
* data, this would crash on attempt to free dangling pointer.
*/
etch_object_destroy(clone_lowlevel);
}
static void test_primitive_byte(void)
{
signed char v = 255;
etch_byte* newobj = new_byte(v);
CU_ASSERT_PTR_NOT_NULL_FATAL(newobj);
CU_ASSERT_EQUAL(v, newobj->value);
etch_object_destroy(newobj);
#ifdef ETCH_DEBUGALLOC
g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE); /* verify all memory freed */
CU_ASSERT_EQUAL(g_bytes_allocated, 0);
// start fresh for next test
memtable_clear();
#endif
}
static void test_primitive_bool(void)
{
etch_boolean* newobj = new_boolean(100);
CU_ASSERT_PTR_NOT_NULL_FATAL(newobj);
CU_ASSERT_EQUAL(newobj->value, TRUE);
etch_object_destroy(newobj);
#ifdef ETCH_DEBUGALLOC
g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE); /* verify all memory freed */
CU_ASSERT_EQUAL(g_bytes_allocated, 0);
// start fresh for next test
memtable_clear();
#endif
}
static void test_primitive_int8(void)
{
signed char v = -1;
etch_int8* newobj = new_int8(v);
CU_ASSERT_PTR_NOT_NULL_FATAL(newobj);
CU_ASSERT_EQUAL(newobj->value,v);
etch_object_destroy(newobj);
#ifdef ETCH_DEBUGALLOC
g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE); /* verify all memory freed */
CU_ASSERT_EQUAL(g_bytes_allocated, 0);
// start fresh for next test
memtable_clear();
#endif
}
static void test_primitive_int16(void)
{
short v = -1;
etch_int16* newobj = new_int16(v);
CU_ASSERT_PTR_NOT_NULL_FATAL(newobj);
CU_ASSERT_EQUAL(newobj->value,v);
etch_object_destroy(newobj);
#ifdef ETCH_DEBUGALLOC
g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE); /* verify all memory freed */
CU_ASSERT_EQUAL(g_bytes_allocated, 0);
// start fresh for next test
memtable_clear();
#endif
}
static void test_primitive_int32(void)
{
int v = 1 << 31;
etch_int32* newobj = new_int32(v);
CU_ASSERT_PTR_NOT_NULL_FATAL(newobj);
CU_ASSERT_EQUAL(newobj->value,v);
etch_object_destroy(newobj);
#ifdef ETCH_DEBUGALLOC
g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE); /* verify all memory freed */
CU_ASSERT_EQUAL(g_bytes_allocated, 0);
// start fresh for next test
memtable_clear();
#endif
}
static void test_primitive_int64(void)
{
int64 v = ((int64)(1)) << 63;
etch_int64* newobj = new_int64(v);
CU_ASSERT_PTR_NOT_NULL_FATAL(newobj);
CU_ASSERT_EQUAL(newobj->value,v);
etch_object_destroy(newobj);
#ifdef ETCH_DEBUGALLOC
g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE); /* verify all memory freed */
CU_ASSERT_EQUAL(g_bytes_allocated, 0);
// start fresh for next test
memtable_clear();
#endif
}
static void test_primitive_float(void)
{
float v = (float)(3.14159);
etch_float* newobj = new_float(v);
CU_ASSERT_PTR_NOT_NULL_FATAL(newobj);
CU_ASSERT_EQUAL(newobj->value,v);
etch_object_destroy(newobj);
#ifdef ETCH_DEBUGALLOC
g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE); /* verify all memory freed */
CU_ASSERT_EQUAL(g_bytes_allocated, 0);
// start fresh for next test
memtable_clear();
#endif
}
static void test_primitive_double(void)
{
double v = (1 << 31) + 3.14159;
etch_double* newobj = new_double(v);
CU_ASSERT_PTR_NOT_NULL_FATAL(newobj);
CU_ASSERT_EQUAL(newobj->value,v);
etch_object_destroy(newobj);
#ifdef ETCH_DEBUGALLOC
g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE); /* verify all memory freed */
CU_ASSERT_EQUAL(g_bytes_allocated, 0);
// start fresh for next test
memtable_clear();
#endif
}
static void test_primitive_string(void)
{
wchar_t* v = L"it works!";
etch_string* newobj = new_stringw(v);
CU_ASSERT_PTR_NOT_NULL_FATAL(newobj);
CU_ASSERT_EQUAL(wcscmp(v, newobj->v.valw), 0);
etch_object_destroy(newobj);
#ifdef ETCH_DEBUGALLOC
g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE); /* verify all memory freed */
CU_ASSERT_EQUAL(g_bytes_allocated, 0);
// start fresh for next test
memtable_clear();
#endif
}
/**
* test_nativearray_ctordtor()
* test that we can create and destroy an etch_nativearray with all memory accounted for
*/
static void test_nativearray_ctordtor(void)
{
etch_nativearray* bytearray_1x4 = new_etch_nativearray(CLASSID_ARRAY_BYTE, sizeof(byte), 1, 4, 0, 0);
CU_ASSERT_PTR_NOT_NULL_FATAL(bytearray_1x4);
etch_object_destroy(bytearray_1x4);
#ifdef ETCH_DEBUGALLOC
g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE); /* verify all memory freed */
CU_ASSERT_EQUAL(g_bytes_allocated, 0);
// start fresh for next test
memtable_clear();
#endif
}
/**
* test_nativearray_1x1x4()
* test that we can populate and access a 1-dimensional array of byte
*/
static void test_nativearray_1x1x4(void)
{
int i = 0, result = 0;
char x[4] = {'a','b','c','d'}, thisx = 0;
const int numdimensions = 1, itemcount = 4;
etch_nativearray* a = new_etch_nativearray
(CLASSID_ARRAY_BYTE, sizeof(byte), numdimensions, itemcount, 0, 0);
CU_ASSERT_PTR_NOT_NULL_FATAL(a);
for(i = 0; i < itemcount; i++) /* populate array */
{
result = a->put1(a, &x[i], i); /* insert value of i to ith slot */
CU_ASSERT_EQUAL(result, 0);
}
for(i = 0; i < itemcount; i++) /* read values out of array */
{
result = a->get1(a, &thisx, i); /* get value of ith slot into thisx */
CU_ASSERT_EQUAL(result, 0);
CU_ASSERT_EQUAL(x[i], thisx);
}
etch_object_destroy(a);
#ifdef ETCH_DEBUGALLOC
g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE); /* verify all memory freed */
CU_ASSERT_EQUAL(g_bytes_allocated, 0);
// start fresh for next test
memtable_clear();
#endif
}
/**
* test_nativearray_1x4x4()
* test that we can populate and access a 1-dimensional array of int
*/
static void test_nativearray_1x4x4(void)
{
int i = 0, j = 0, result = 0;
const int numdimensions = 1, itemcount = 4;
etch_nativearray* a = new_etch_nativearray
(CLASSID_ARRAY_INT32, sizeof(int), numdimensions, itemcount, 0, 0);
CU_ASSERT_PTR_NOT_NULL_FATAL(a);
for(i = 0; i < itemcount; i++) /* populate array */
{
result = a->put1(a, &i, i); /* insert value of i to ith slot */
CU_ASSERT_EQUAL(result, 0);
}
for(i = 0; i < itemcount; i++) /* read values out of array */
{
result = a->get1(a, &j, i); /* get value of ith slot into j */
CU_ASSERT_EQUAL(result, 0);
CU_ASSERT_EQUAL(i, j);
}
etch_object_destroy(a);
#ifdef ETCH_DEBUGALLOC
g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE); /* verify all memory freed */
CU_ASSERT_EQUAL(g_bytes_allocated, 0);
// start fresh for next test
memtable_clear();
#endif
}
/**
* test_nativearray_1xstruct()
* test that we can populate and access a 1-dimensional array of struct
*/
static void test_nativearray_1xstruct(void)
{
int i = 0, result = 0;
const int numdimensions = 1, itemcount = 4;
struct x { int n; char c; };
struct x xgot = {-1,'?'};
struct x xs[4] = { {0,'a'}, {1,'b'}, {2,'c'}, {3,'d'}, };
etch_nativearray* a = new_etch_nativearray
(CLASSID_ARRAY_STRUCT, sizeof(struct x), numdimensions, itemcount, 0, 0);
CU_ASSERT_PTR_NOT_NULL_FATAL(a);
for(i = 0; i < itemcount; i++) /* populate array */
{
result = a->put1(a, &xs[i], i); /* insert xs[i] to ith slot */
CU_ASSERT_EQUAL(result, 0);
}
for(i = 0; i < itemcount; i++) /* read values out of array */
{
result = a->get1(a, &xgot, i); /* get value of ith slot into xgot */
CU_ASSERT_EQUAL(result, 0);
result = memcmp(&xgot, &xs[i], sizeof(struct x));
CU_ASSERT_EQUAL(result, 0);
}
etch_object_destroy(a);
#ifdef ETCH_DEBUGALLOC
g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE); /* verify all memory freed */
CU_ASSERT_EQUAL(g_bytes_allocated, 0);
// start fresh for next test
memtable_clear();
#endif
}
/**
* test_nativearray_2x1x4()
* test that we can populate and access a 2-dimensional array of byte
*/
static void test_nativearray_2x1x4(void)
{
int i = 0, j = 0, result = 0;
char x[2][4] = { {'a','b','c','d'}, {'e','f','g','h'}, }, thisx = 0;
const int numdimensions = 2, dim0count = 4, dim1count = 2;
/* note when creating arrays, the dimensions are specified in reverse,
* low-order dimension (dim0) first, e.g., for x[2][3][4],
* dim0count is 4, dim1count is 3, dim2count is 2.
*/
etch_nativearray* a = new_etch_nativearray
(CLASSID_ARRAY_BYTE, sizeof(byte), numdimensions, dim0count, dim1count, 0);
CU_ASSERT_PTR_NOT_NULL_FATAL(a);
for(i = 0; i < dim1count; i++) /* populate array */
{
for(j = 0; j < dim0count; j++)
{ /* insert x[i][j] to array[i][j] */
result = a->put2(a, &x[i][j], i, j);
CU_ASSERT_EQUAL(result, 0);
}
}
for(i = 0; i < dim1count; i++) /* read array */
{
for(j = 0; j < dim0count; j++) /* read values out of array */
{ /* get array[i][j] into thisx */
result = a->get2(a, &thisx, i, j);
CU_ASSERT_EQUAL(result, 0);
CU_ASSERT_EQUAL(x[i][j], thisx);
}
}
etch_object_destroy(a);
#ifdef ETCH_DEBUGALLOC
g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE); /* verify all memory freed */
CU_ASSERT_EQUAL(g_bytes_allocated, 0);
// start fresh for next test
memtable_clear();
#endif
}
/**
* test_nativearray_3xstruct()
* test that we can populate and access a 3-dimensional array of struct
*/
static void test_nativearray_3xstruct(void)
{
int i = 0, j = 0, k = 0, result = 0;
struct x { int n; char c; };
struct x xgot = {-1,'?'};
struct x *xthis = 0;
struct x xs[2][3][4] =
{
{
{
{0,'a'}, {1,'b'}, {2,'c'}, {3,'d'},
},
{
{0,'e'}, {1,'f'}, {2,'g'}, {3,'h'},
},
{
{0,'i'}, {1,'j'}, {2,'k'}, {3,'l'},
},
},
{
{
{0,'m'}, {1,'n'}, {2,'o'}, {3,'p'},
},
{
{0,'q'}, {1,'r'}, {2,'s'}, {3,'t'},
},
{
{0,'u'}, {1,'v'}, {2,'w'}, {3,'x'},
},
},
};
const int numdimensions = 3, dim0count = 4, dim1count = 3, dim2count = 2;
etch_nativearray* a = new_etch_nativearray (CLASSID_ARRAY_STRUCT, sizeof(struct x),
numdimensions, dim0count, dim1count, dim2count);
CU_ASSERT_PTR_NOT_NULL_FATAL(a);
for(i = 0; i < dim2count; i++) /* write array */
{
for(j = 0; j < dim1count; j++)
{
for(k = 0; k < dim0count; k++)
{
result = a->put3(a, &xs[i][j][k], i, j, k);
CU_ASSERT_EQUAL(result, 0);
}
}
}
for(i = 0; i < dim2count; i++) /* read array */
{
for(j = 0; j < dim1count; j++)
{
for(k = 0; k < dim0count; k++)
{
result = a->get3(a, &xgot, i, j, k);
CU_ASSERT_EQUAL(result, 0);
xthis = &xs[i][j][k];
result = memcmp(&xgot, xthis, sizeof(struct x));
CU_ASSERT_EQUAL(result, 0);
}
}
}
etch_object_destroy(a);
#ifdef ETCH_DEBUGALLOC
g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE); /* verify all memory freed */
CU_ASSERT_EQUAL(g_bytes_allocated, 0);
// start fresh for next test
memtable_clear();
#endif
}
/**
* test_arrayfrom_2x1x4()
* test that we can access a static 2-dimensional array of byte.
* also validates that our array subscripting calculations match those of
* the C compiler, since we map and access an array mapped by the compiler.
* also validates that the etch_nativearray will not attempt to destroy
* the byte vector of an array created in this manner.
*/
static void test_arrayfrom_2x1x4(void)
{
int i = 0, j = 0, result = 0;
char x[2][4] = { {'a','b','c','d'}, {'e','f','g','h'}, }, thisx = 0;
const int numdimensions = 2, dim0count = 4, dim1count = 2;
etch_nativearray* a = new_etch_nativearray_from(&x, CLASSID_ARRAY_BYTE,
sizeof(byte), numdimensions, dim0count, dim1count, 0);
CU_ASSERT_PTR_NOT_NULL_FATAL(a);
for(i = 0; i < dim1count; i++) /* read array */
{
for(j = 0; j < dim0count; j++) /* read values out of array */
{ /* get array[i][j] into thisx */
result = a->get2(a, &thisx, i, j);
CU_ASSERT_EQUAL(result, 0);
CU_ASSERT_EQUAL(x[i][j], thisx);
}
}
etch_object_destroy(a);
#ifdef ETCH_DEBUGALLOC
g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE); /* verify all memory freed */
CU_ASSERT_EQUAL(g_bytes_allocated, 0);
// start fresh for next test
memtable_clear();
#endif
}
/**
* test_subarray()
* test that we can create a one-dimensional subarray from a 2-dimensional
* array of byte, and that all memory is accounted for.
*/
static void test_subarray(void)
{
int i = 0, result = 0;
char x[2][4] = { {'a','b','c','d'}, {'e','f','g','h'}, }, thisx = 0;
const int numdimensions = 2, dim0count = 4, dim1count = 2;
etch_nativearray *a0 = NULL, *a1 = NULL, *a2 = NULL;
etch_nativearray* a = new_etch_nativearray_from(&x, CLASSID_ARRAY_BYTE,
sizeof(byte), numdimensions, dim0count, dim1count, 0);
CU_ASSERT_PTR_NOT_NULL_FATAL(a);
a->content_obj_type = ETCHTYPEB_BYTE;
a->content_class_id = CLASSID_NONE; /* unwrapped content */
a0 = new_subarray(a, 0); /* test index 0 */
CU_ASSERT_PTR_NOT_NULL_FATAL(a0);
CU_ASSERT_EQUAL(a0->is_content_owned, FALSE);
CU_ASSERT_EQUAL(a0->numdims, a->numdims-1);
CU_ASSERT_EQUAL(a0->bytecount, a->bytecount/2);
CU_ASSERT_EQUAL(a0->itemsize, a->itemsize);
CU_ASSERT_EQUAL(a0->content_obj_type, a->content_obj_type);
CU_ASSERT_EQUAL(a0->content_class_id, a->content_class_id);
/* recall that dimension and dimsize are stored low-order
* dimension first, so dimension[0] and dimsize[0] are
* the same for byte x[2][4] as for x[4] */
CU_ASSERT_EQUAL(a0->dimension[0], a->dimension[0]);
CU_ASSERT_EQUAL(a0->dimsize[0], a->dimsize[0]);
for(i = 0; i < dim0count; i++)
{
result = a0->get1(a0, &thisx, i);
CU_ASSERT_EQUAL(result, 0);
CU_ASSERT_EQUAL(x[0][i], thisx);
}
a1 = new_subarray(a, 1); /* test index 1 */
CU_ASSERT_PTR_NOT_NULL_FATAL(a1);
CU_ASSERT_EQUAL(a1->is_content_owned, FALSE);
CU_ASSERT_EQUAL(a1->numdims, a->numdims-1);
CU_ASSERT_EQUAL(a1->bytecount, a->bytecount/2);
CU_ASSERT_EQUAL(a1->itemsize, a->itemsize);
CU_ASSERT_EQUAL(a1->content_obj_type, a->content_obj_type);
CU_ASSERT_EQUAL(a1->content_class_id, a->content_class_id);
/* recall that dimension and dimsize are stored low-order
* dimension first, so dimension[0] and dimsize[0] are
* the same for byte x[2][4] as for x[4] */
CU_ASSERT_EQUAL(a1->dimension[0], a->dimension[0]);
CU_ASSERT_EQUAL(a1->dimsize[0], a->dimsize[0]);
for(i = 0; i < dim0count; i++)
{
result = a1->get1(a1, &thisx, i);
CU_ASSERT_EQUAL(result, 0);
CU_ASSERT_EQUAL(x[1][i], thisx);
}
a2 = new_subarray(a, 2); /* test nonexistent index 2 */
CU_ASSERT_PTR_NULL(a2);
etch_object_destroy(a1);
etch_object_destroy(a0);
etch_object_destroy(a);
#ifdef ETCH_DEBUGALLOC
g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE); /* verify all memory freed */
CU_ASSERT_EQUAL(g_bytes_allocated, 0);
// start fresh for next test
memtable_clear();
#endif
}
/*
* test_if_busted_subarray()
* this test is here to debug something that was either broken in subarray,
* or that was not broken, but rather the validator test using it was broken.
* verdict: subarray itemsize was broken, is fixed.
*/
static void test_if_busted_subarray(void)
{
short x[2][3][4] =
{ { { 1,1,1,1, }, { 1,1,1,1, }, { 1,-1,32767, -32768, }, },
{ { 1,1,1,1, }, { 1,1,1,1, }, { 1,-1,0xfffe,0xffff, }, },
};
const int numdimensions = 3, dim0count = 4, dim1count = 3, dim2count = 2;
int i=0, j=0, k=0;
etch_nativearray* a1 = new_etch_nativearray_from(&x, CLASSID_ARRAY_INT16,
sizeof(short), numdimensions, dim0count, dim1count, dim2count);
a1->content_obj_type = ETCHTYPEB_INT16;
a1->content_class_id = CLASSID_NONE; /* unwrapped */
for(i = 0; i < dim2count; i++)
{
etch_nativearray* a2 = (etch_nativearray*) etch_nativearray_get_element(a1, i);
CU_ASSERT_EQUAL_FATAL(is_etch_nativearray(a2), TRUE);
CU_ASSERT_EQUAL_FATAL(a2->bytecount, a1->bytecount/a1->dimension[2]);
CU_ASSERT_EQUAL_FATAL(a2->numdims, a1->numdims-1);
CU_ASSERT_EQUAL_FATAL(a2->dimsize[0], a1->dimsize[0]);
CU_ASSERT_EQUAL_FATAL(a2->dimsize[1], a1->dimsize[1]);
CU_ASSERT_EQUAL_FATAL(a2->dimension[0],a1->dimension[0]);
CU_ASSERT_EQUAL_FATAL(a2->dimension[1],a1->dimension[1]);
CU_ASSERT_EQUAL_FATAL(a2->dimension[1],dim1count);
for(j = 0; j < dim1count; j++)
{
etch_nativearray* a3 = (etch_nativearray*) etch_nativearray_get_element(a2, j);
CU_ASSERT_EQUAL_FATAL(is_etch_nativearray(a3), TRUE);
CU_ASSERT_EQUAL_FATAL(a3->bytecount, a2->bytecount/a2->dimension[1]);
CU_ASSERT_EQUAL_FATAL(a3->numdims, a2->numdims-1);
CU_ASSERT_EQUAL_FATAL(a3->dimsize[0], a2->dimsize[0]);
CU_ASSERT_EQUAL_FATAL(a3->dimension[0],a2->dimension[0]);
CU_ASSERT_EQUAL_FATAL(a3->dimension[0],dim0count);
for(k = 0; k < dim0count; k++)
{
short n_expected = 0, n_actual = 0;
etch_int16* shortobj = (etch_int16*) etch_nativearray_get_element(a3, k);
CU_ASSERT_EQUAL_FATAL(is_etch_int16(shortobj), TRUE);
n_expected = x[i][j][k];
n_actual = shortobj->value;
CU_ASSERT_EQUAL_FATAL(n_expected, n_actual);
etch_object_destroy(shortobj);
}
etch_object_destroy(a3);
}
etch_object_destroy(a2);
}
etch_object_destroy(a1);
#ifdef ETCH_DEBUGALLOC
g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE); /* verify all memory freed */
CU_ASSERT_EQUAL(g_bytes_allocated, 0);
// start fresh for next test
memtable_clear();
#endif
}
/**
* test_get_element()
* test that we can get element[i] of a native array, and that element
* is another native array, or a wrapped etch object the same type as
* the array's content_obj_type and possibly content_class_id.
*/
static void test_get_element(void)
{
int i = 0;
char x[2][4] = { {'a','b','c','d'}, {'e','f','g','h'}, }, thisx = 0;
const int numdimensions = 2, dim0count = 4, dim1count = 2;
etch_nativearray *a1 = NULL;
etch_object* returnobj = NULL;
etch_byte* retbyteobj = NULL;
etch_nativearray* a = new_etch_nativearray_from(&x, CLASSID_ARRAY_BYTE,
sizeof(byte), numdimensions, dim0count, dim1count, 0);
CU_ASSERT_PTR_NOT_NULL_FATAL(a);
a->content_obj_type = ETCHTYPEB_BYTE;
a->content_class_id = CLASSID_NONE; /* unwrapped content */
/* get element[1] from the array, expecting a byte[4] native array */
returnobj = etch_nativearray_get_element(a, 1);
CU_ASSERT_EQUAL_FATAL(is_etch_nativearray(returnobj), TRUE);
a1 = (etch_nativearray*) returnobj;
CU_ASSERT_EQUAL(a1->is_content_owned, FALSE);
CU_ASSERT_EQUAL(a1->numdims, a->numdims-1);
CU_ASSERT_EQUAL(a1->bytecount, a->bytecount/2);
CU_ASSERT_EQUAL(a1->itemsize, a->itemsize);
CU_ASSERT_EQUAL(a1->content_obj_type, a->content_obj_type);
CU_ASSERT_EQUAL(a1->content_class_id, a->content_class_id);
CU_ASSERT_EQUAL(a1->dimension[0], a->dimension[0]);
CU_ASSERT_EQUAL(a1->dimsize[0], a->dimsize[0]);
for(i = 0; i < dim0count; i++)
{
/* get element[i] from the subarray, expecting an etch_byte object */
returnobj = etch_nativearray_get_element(a1, i);
CU_ASSERT_PTR_NOT_NULL_FATAL(returnobj);
CU_ASSERT_EQUAL_FATAL(((etch_object*)returnobj)->class_id, CLASSID_PRIMITIVE_BYTE);
retbyteobj = (etch_byte*) returnobj; /* verify that wrapped byte */
thisx = retbyteobj->value; /* matches original array */
CU_ASSERT_EQUAL(x[1][i], thisx);
etch_object_destroy(retbyteobj);
}
etch_object_destroy(a1);
etch_object_destroy(a);
#ifdef ETCH_DEBUGALLOC
g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE); /* verify all memory freed */
CU_ASSERT_EQUAL(g_bytes_allocated, 0);
// start fresh for next test
memtable_clear();
#endif
}
/**
* main
*/
//int wmain( int argc, wchar_t* argv[], wchar_t* envp[])
CU_pSuite test_etchobject_suite()
{
CU_pSuite ps = CU_add_suite("etchobject", init_suite, clean_suite);
CU_add_test(ps, "test primitive byte", test_primitive_byte);
CU_add_test(ps, "test primitive boolean", test_primitive_bool);
CU_add_test(ps, "test primitive int8", test_primitive_int8);
CU_add_test(ps, "test primitive int16", test_primitive_int16);
CU_add_test(ps, "test primitive int32", test_primitive_int32);
CU_add_test(ps, "test primitive int64", test_primitive_int64);
CU_add_test(ps, "test primitive float", test_primitive_float);
CU_add_test(ps, "test primitive double", test_primitive_double);
CU_add_test(ps, "test primitive string", test_primitive_string);
CU_add_test(ps, "test tri-level inheritance", test_inheritance);
CU_add_test(ps, "test clone and auto-construct superclass", test_clone);
CU_add_test(ps, "test native array ctor", test_nativearray_ctordtor);
CU_add_test(ps, "test 1-dim byte array", test_nativearray_1x1x4);
CU_add_test(ps, "test 1-dim int array", test_nativearray_1x4x4);
CU_add_test(ps, "test 1-dim struct array", test_nativearray_1xstruct);
CU_add_test(ps, "test 2-dim byte array", test_nativearray_2x1x4);
CU_add_test(ps, "test 3-dim struct array", test_nativearray_3xstruct);
CU_add_test(ps, "test static 2-dim byte array", test_arrayfrom_2x1x4);
CU_add_test(ps, "test subarray", test_subarray);
CU_add_test(ps, "test get array element", test_get_element);
CU_add_test(ps, "test 3-dim int16 subarray ", test_if_busted_subarray);
return ps;
}