ossp-pkg/xds/xds_test_lib.c
/*
** OSSP xds - Extensible Data Serialization
** Copyright (c) 2001-2005 Ralf S. Engelschall <rse@engelschall.com>
** Copyright (c) 2001-2005 The OSSP Project <http://www.ossp.org/>
** Copyright (c) 2001-2005 Cable & Wireless <http://www.cw.com/>
**
** This file is part of OSSP xds, an extensible data serialization
** library which can be found at http://www.ossp.org/pkg/lib/xds/.
**
** Permission to use, copy, modify, and distribute this software for
** any purpose with or without fee is hereby granted, provided that
** the above copyright notice and this permission notice appear in all
** copies.
**
** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
** USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
** OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
** SUCH DAMAGE.
**
** xds_test_lib.c: test suite for library framework
*/
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include "xds_p.h"
#ifdef XDS_TEST_XDS_CORE
int main(int argc, char *argv[])
{
xds_t *ctx[50];
size_t i;
/* Open a bunch of contextes and close them again. */
for (i = 0; i < sizeof (ctx) / sizeof (xds_t *); ++i) {
if (i % 2 == 0)
xds_init(&ctx[i], XDS_ENCODE);
else
xds_init(&ctx[i], XDS_DECODE);
if (ctx[i] == 0) {
printf("Failed to initialize xds context: i = %d\n", i);
return 1;
}
}
for (i = 0; i < sizeof (ctx) / sizeof (xds_t *); ++i)
xds_destroy(ctx[i]);
#ifdef NDEBUG
/* Check how the library deals with errorneous arguments. */
if (xds_init(NULL, (xds_mode_t)42) != NULL || errno != EINVAL) {
printf
("Called xds_init() with invalid mode but didn't get EINVAL.\n");
return 1;
}
/* Call xds_destroy() with an invalid context and see whether we survive
that. */
xds_destroy(NULL);
#endif
/* Everything went fine. */
return 0;
}
#endif /* XDS_TEST_XDS_CORE */
#ifdef XDS_TEST_XDS_REGISTER
static int dummy_engine(xds_t *xds, void *engine_context,
void *buffer, size_t buffer_size,
size_t *used_buffer_size, va_list *args)
{
return 0;
}
int main(int argc, char *argv[])
{
const char *test_names[] = {
"foo",
"bar",
"zarah",
"caesar",
"claus",
"heinz",
};
size_t test_names_len = sizeof (test_names) / sizeof (char *);
xds_t *xds;
size_t i;
/* Create context. */
if (xds_init(&xds, XDS_ENCODE) != XDS_OK) {
printf("Failed to initialize XDS context.\n");
return 1;
}
/* Register the dummy callback under an invalid name to see whether the
routine fails correctly. */
if (xds_register(xds, "abcdefh1230#", &dummy_engine, NULL) !=
XDS_ERR_INVALID_ARG) {
printf
("xds_register() illegally accepted an invalid name for the engine.\n");
return 1;
}
/* Register the dummy callback under multiple names. */
for (i = 0; i < test_names_len; ++i) {
if (xds_register(xds, test_names[i], &dummy_engine, NULL) != XDS_OK) {
printf("Failed to register engine for '%s'.\n", test_names[i]);
return 1;
}
}
/* Register the callback again, overwriting an existing entry. */
if (xds_register(xds, "claus", &dummy_engine, NULL) != XDS_OK) {
printf("Failed to re-register engine for 'claus'.\n");
return 1;
}
/* Ensure that everything is in alphabetical order. */
for (i = 1; i < xds->engines_len; ++i) {
assert(xds->engines[i - 1].name != NULL);
assert(xds->engines[i].name != NULL);
if (strcmp(xds->engines[i - 1].name, xds->engines[i].name) >= 0) {
printf("xds->engines is not in alphabetical order!\n");
exit(1);
}
}
/* Try to remove an unknown entry. */
if (xds_unregister(xds, "abacadabra") != XDS_ERR_UNKNOWN_ENGINE) {
printf("xds_unregister() succeeded at removing 'abacadabra' even though it is not there.\n");
exit(1);
}
/* Remove an entry from the middle. */
if (xds_unregister(xds, test_names[test_names_len / 2]) != XDS_OK) {
printf("xds_unregister() failed to remove '%s'.\n",
test_names[test_names_len / 2]);
exit(1);
}
/* Remove the last entry. */
assert(test_names_len > 0);
if (xds_unregister(xds, test_names[test_names_len - 1]) != XDS_OK) {
printf("xds_unregister() failed to remove '%s'.\n",
test_names[test_names_len - 1]);
exit(1);
}
/* Remove the first entry. */
if (xds_unregister(xds, test_names[0]) != XDS_OK) {
printf("xds_unregister() failed to remove '%s'.\n", test_names[0]);
exit(1);
}
/* Clean up. */
xds_destroy(xds);
/* Everything went fine. */
return 0;
}
#endif /* XDS_TEST_XDS_REGISTER */
#ifdef XDS_TEST_XDS_SETBUFFER
static int dummy_engine(xds_t *xds, void *engine_context,
void *buffer, size_t buffer_size,
size_t *used_buffer_size, va_list *args)
{
assert(xds != NULL);
assert(buffer != NULL);
assert(buffer_size != 0);
assert(used_buffer_size != NULL);
assert(args != NULL);
if (buffer_size < 64)
return XDS_ERR_OVERFLOW;
else
*used_buffer_size = 64;
memset(buffer, 'a', 64);
return XDS_OK;
}
int main(int argc, char *argv[])
{
xds_t *xds;
char *buffer;
size_t buffer_size;
/* Create XDS context. */
if (xds_init(&xds, XDS_ENCODE) != XDS_OK) {
printf("Failed to initialize XDS context.\n");
return 1;
}
/* Register the callback. */
if (xds_register(xds, "dummy", &dummy_engine, NULL) != XDS_OK) {
printf("Failed to register my encoding engine.\n");
return 1;
}
/* Give the library a buffer of 32 byte, call the engine once, get the
buffer back and see whether it has been enlarged or not. */
buffer_size = 32;
buffer = malloc(buffer_size);
if (buffer == NULL) {
printf("Failed to allocate my memory.\n");
return 1;
}
if (xds_setbuffer(xds, XDS_GIFT, buffer, buffer_size) != XDS_OK) {
printf("xds_setbuffer() failed!\n");
return 1;
}
if (xds_encode(xds, "dummy") != XDS_OK) {
printf("xds_encode() failed!\n");
return 1;
}
if (xds_getbuffer(xds, XDS_GIFT, (void **)&buffer, &buffer_size) != XDS_OK) {
printf("xds_getbuffer() failed!\n");
return 1;
}
if (buffer_size < 64) {
printf("xds_encode() did not enlarge the buffer after processing the callback\n");
printf("even though all capacity was used up!\n");
return 1;
}
/* Loan the library a buffer we own, call the engine once to exceed the
buffer's capacity and check, whether the library returns the correct
error code. */
buffer = malloc(32);
if (buffer == NULL) {
printf("Failed to allocate my memory.\n");
return 1;
}
buffer_size = 32;
if (xds_setbuffer(xds, XDS_LOAN, buffer, buffer_size) != XDS_OK) {
printf("xds_setbuffer() failed!\n");
return 1;
}
if (xds_encode(xds, "dummy") != XDS_ERR_OVERFLOW) {
printf("xds_encode() was supposed to fail with XDS_ERR_OVERFLOW!\n");
return 1;
}
free(buffer);
/* Clean up. */
xds_destroy(xds);
/* Everything went fine. */
return 0;
}
#endif /* XDS_TEST_XDS_SETBUFFER */
#ifdef XDS_TEST_XDS_GETBUFFER
static int dummy_engine(xds_t *xds, void *engine_context,
void *buffer, size_t buffer_size,
size_t *used_buffer_size, va_list *args)
{
if (buffer_size < 6)
return XDS_ERR_OVERFLOW;
else
*used_buffer_size = 6;
memmove(buffer, "Hallo!", 6);
return XDS_OK;
}
int main(int argc, char *argv[])
{
xds_t *xds;
char *old;
size_t old_len;
char *new;
size_t new_len;
/* Create XDS context. */
if (xds_init(&xds, XDS_ENCODE) != XDS_OK) {
printf("Failed to initialize XDS context.\n");
return 1;
}
/* Register the dummy callback under multiple names. */
if (xds_register(xds, "text", &dummy_engine, (void *)42) != XDS_OK) {
printf("Failed to register my encoding engine.\n");
return 1;
}
/* Encode something, then flush the buffer by calling xds_getbuffer(),
then encode something new and verify that the old buffer hasn't ben
overwritten and that the new one contains the correct string. */
if (xds_encode(xds, "text text") != XDS_OK) {
printf("xds_encode() failed!\n");
return 1;
}
if (xds_getbuffer(xds, XDS_GIFT, (void **)&old, &old_len) != XDS_OK) {
printf("xds_getbuffer() failed for the first buffer!\n");
return 1;
}
if (xds_encode(xds, "text") != XDS_OK) {
printf("xds_encode() failed!\n");
return 1;
}
if (xds_getbuffer(xds, XDS_GIFT, (void **)&new, &new_len) != XDS_OK) {
printf("xds_getbuffer() failed for the second buffer!\n");
return 1;
}
if ((memcmp(old, "Hallo!Hallo!", 12) != 0 || old_len != 12) &&
(memcmp(new, "Hallo!", 6) != 0 || new_len != 6)) {
printf("xds_encode() did not yield the expected result.\n");
return 1;
}
free(old);
free(new);
/* Encode somthing, then get the buffer via XDS_LOAN and verify the
contents. Encode something new and compare the new content with what
we expect. */
if (xds_encode(xds, "text text") != XDS_OK) {
printf("xds_encode() failed!\n");
return 1;
}
if (xds_getbuffer(xds, XDS_LOAN, (void **)&old, &old_len) != XDS_OK) {
printf("xds_getbuffer() failed for the first buffer!\n");
return 1;
}
if (memcmp(old, "Hallo!Hallo!", 12) != 0 || old_len != 12) {
printf("xds_encode() did not yield the expected result.\n");
return 1;
}
if (xds_encode(xds, "text") != XDS_OK) {
printf("xds_encode() failed!\n");
return 1;
}
if (xds_getbuffer(xds, XDS_LOAN, (void **)&new, &new_len) != XDS_OK) {
printf("xds_getbuffer() failed for the second buffer!\n");
return 1;
}
if (old != new) {
printf
("xds_encode() allocated a new buffer even though we used XDS_LOAN.\n");
return 1;
}
if (memcmp(new, "Hallo!", 6) != 0 || new_len != 6) {
printf("xds_encode() did not yield the expected result.\n");
return 1;
}
/* Clean up. */
xds_destroy(xds);
/* Everything went fine. */
return 0;
}
#endif /* XDS_TEST_XDS_GETBUFFER */
#ifdef XDS_TEST_XDS_ENCODE
static int dummy_engine(xds_t *xds, void *engine_context,
void *buffer, size_t buffer_size,
size_t *used_buffer_size, va_list *args)
{
if (xds == NULL) {
printf("XDS context isn't passed through to registered engine.\n");
exit(1);
}
if (engine_context != (void *)42) {
printf("Engine context isn't passed through to registered engine.\n");
exit(1);
}
if (buffer == NULL) {
printf("Buffer passed to engine is NULL.\n");
exit(1);
}
if (buffer_size == 0) {
printf("buffer_size passed to engine is zero!\n");
exit(1);
}
if (used_buffer_size == NULL) {
printf("used_buffer_size pointer passed to engine is NULL!\n");
exit(1);
}
if (args == NULL) {
printf("args pointer passed to engine is NULL!\n");
exit(1);
}
*used_buffer_size = 6;
if (buffer_size < 6)
return XDS_ERR_OVERFLOW;
memmove(buffer, "Hallo ", 6);
return XDS_OK;
}
int main(int argc, char *argv[])
{
xds_t *xds;
/* Create XDS context. */
if (xds_init(&xds, XDS_ENCODE) != XDS_OK) {
printf("Failed to initialize XDS context.\n");
return 1;
}
/* Register the dummy callback under multiple names. */
if (xds_register(xds, "int", &dummy_engine, (void *)42) != XDS_OK ||
xds_register(xds, "float", &dummy_engine, (void *)42) != XDS_OK ||
xds_register(xds, "double", &dummy_engine, (void *)42) != XDS_OK ||
xds_register(xds, "text", &dummy_engine, (void *)42) != XDS_OK) {
printf("Failed to register my encoding engines.\n");
return 1;
}
/* Let's go and encode something. */
if (xds_encode(xds, "int:text double double float") != XDS_OK) {
printf("xds_encode() failed!\n");
return 1;
}
if (memcmp(xds->buffer, "Hallo Hallo Hallo Hallo Hallo ", 30) != 0) {
printf("xds_encode() did not yield the expected result.\n");
return 1;
}
/* Clean up. */
xds_destroy(xds);
/* Everything went fine. */
return 0;
}
#endif /* XDS_TEST_XDS_ENCODE */
#ifdef XDS_TEST_XDS_DECODE
static int dummy_engine(xds_t *xds, void *engine_context,
void *buffer, size_t buffer_size,
size_t *used_buffer_size, va_list *args)
{
if (xds == NULL) {
printf("XDS context isn't passed through to registered engine.\n");
exit(1);
}
if (engine_context != (void *)42) {
printf("Engine context isn't passed through to registered engine.\n");
exit(1);
}
if (buffer == NULL) {
printf("Buffer passed to engine is NULL.\n");
exit(1);
}
if (buffer_size == 0) {
printf("Buffer size passed to engine is zero!\n");
exit(1);
}
if (used_buffer_size == NULL) {
printf("used_buffer_size passed to engine is zero!\n");
exit(1);
}
if (args == NULL) {
printf("args pointer passed to engine is NULL!\n");
exit(1);
}
if (buffer_size < 6) {
printf("The buffer is too small; can't verify my encoded string.\n");
exit(1);
}
if (memcmp(buffer, "Hallo!", 6) != 0) {
printf("The contents of the decode buffer are not what we expected.\n");
exit(1);
}
*used_buffer_size = 6;
return XDS_OK;
}
int main(int argc, char *argv[])
{
xds_t *xds;
char buffer[] = "Hallo!Hallo!Hallo!";
/* Create XDS context. */
if (xds_init(&xds, XDS_DECODE) != XDS_OK) {
printf("Failed to initialize XDS context.\n");
return 1;
}
/* Register the dummy callback under multiple names. */
if (xds_register(xds, "text", &dummy_engine, (void *)42) != XDS_OK) {
printf("Failed to register my decoding engines.\n");
return 1;
}
/* Decode the buffer and have the callback report when something is wrong. */
if (xds_setbuffer(xds, XDS_LOAN, buffer, sizeof (buffer) - 1) != XDS_OK) {
printf("xds_decode() failed!");
return 1;
}
if (xds_decode(xds, "text::text text") != XDS_OK) {
printf("xds_decode() failed!");
return 1;
}
/* Clean up. */
xds_destroy(xds);
/* Everything went fine. */
return 0;
}
#endif /* XDS_TEST_XDS_DECODE */
#ifdef XDS_TEST_XDS_ENGINE_RESTART
static int dummy_engine(xds_t *xds, void *engine_context,
void *buffer, size_t buffer_size,
size_t *used_buffer_size, va_list *args)
{
if (xds == NULL) {
printf("XDS context isn't passed through to registered engine.\n");
exit(1);
}
if (engine_context != (void *)42) {
printf("Engine context isn't passed through to registered engine.\n");
exit(1);
}
if (buffer == NULL) {
printf("Buffer passed to engine is NULL.\n");
exit(1);
}
if (buffer_size == 0) {
printf("Buffer size passed to engine is zero!\n");
exit(1);
}
if (used_buffer_size == NULL) {
printf("used_buffer_size pointer passed to engine is NULL!\n");
exit(1);
}
if (args == NULL) {
printf("args pointer passed to engine is NULL!\n");
exit(1);
}
if (va_arg(*args, int) != 42) {
printf("The varadic argument is not what the engine expected!\n");
exit(1);
}
if (buffer_size < 64)
return XDS_ERR_OVERFLOW;
else
*used_buffer_size = 64;
return XDS_OK;
}
int main(int argc, char *argv[])
{
xds_t *xds;
char *buffer;
size_t buffer_size;
/* Create an XDS context and set a buffer that's too small for the first
encode() call. Then call encode() with two parameters: the one the
engine is expecting and a different one after that. The engine will
complain if it sees the second value -- what would mean that the args
parameter was not resetted to the original value before the engine is
restarted after buffer enlargement. */
if (xds_init(&xds, XDS_ENCODE) != XDS_OK) {
printf("Failed to initialize XDS context.\n");
return 1;
}
if (xds_register(xds, "int", &dummy_engine, (void *)42) != XDS_OK) {
printf("Failed to register my encoding engines.\n");
return 1;
}
buffer = malloc(32);
if (buffer == NULL) {
printf("malloc() failed!\n");
return 1;
}
buffer_size = 32;
if (xds_setbuffer(xds, XDS_GIFT, buffer, buffer_size) != XDS_OK) {
printf("xds_setbuffer() failed!\n");
return 1;
}
if (xds_encode(xds, "int", 42, 13) != XDS_OK) {
printf("xds_encode() failed!");
return 1;
}
xds_destroy(xds);
return 0;
}
#endif /* XDS_TEST_XDS_ENGINE_RESTART */
#ifdef XDS_TEST_XDS_MYSTRUCT
struct mystruct {
xds_int32_t small;
xds_uint32_t positive;
};
static int encode_mystruct_engine(xds_t *xds, void *engine_context,
void *buffer, size_t buffer_size,
size_t *used_buffer_size, va_list *args)
{
struct mystruct *ms;
assert(xds != NULL);
assert(buffer != NULL);
assert(buffer_size != 0);
assert(used_buffer_size != NULL);
assert(args != NULL);
ms = va_arg(*args, struct mystruct *);
return xds_encode(xds, "int32 uint32", ms->small, ms->positive);
}
static int decode_mystruct_engine(xds_t *xds, void *engine_context,
void *buffer, size_t buffer_size,
size_t *used_buffer_size, va_list *args)
{
struct mystruct *ms;
assert(xds != NULL);
assert(buffer != NULL);
assert(buffer_size != 0);
assert(used_buffer_size != NULL);
assert(args != NULL);
ms = va_arg(*args, struct mystruct *);
return xds_decode(xds, "int32 uint32", &(ms->small), &(ms->positive));
}
int main(int argc, char *argv[])
{
xds_t *xds;
char *buffer;
size_t buffer_size;
struct mystruct ms, new_ms;
ms.small = -0x1234567;
ms.positive = 42;
/* Encode our copy of mystruct using our encoding callback. Then get a
the buffer and destroy the context again. */
if (xds_init(&xds, XDS_ENCODE) != XDS_OK) {
printf("Failed to initialize XDS context.\n");
return 1;
}
if ( xds_register(xds, "mystruct", &encode_mystruct_engine, NULL) != XDS_OK
|| xds_register(xds, "int32", &xdr_encode_int32, NULL) != XDS_OK
|| xds_register(xds, "uint32", &xdr_encode_uint32, NULL) != XDS_OK) {
printf("Failed to register my encoding engines.\n");
return 1;
}
buffer_size = 4;
buffer = malloc(buffer_size);
if (buffer == NULL) {
printf("Failed to allocate memory for buffer.\n");
return 1;
}
if (xds_setbuffer(xds, XDS_GIFT, buffer, buffer_size) != XDS_OK) {
printf("xds_setbuffer() failed!\n");
return 1;
}
if (xds_encode(xds, "mystruct", &ms) != XDS_OK) {
printf("xds_encode() failed!\n");
return 1;
}
if (xds->buffer_capacity <= buffer_size) {
printf("Buffer should have been enlarged after xds_encode()!\n");
return 1;
}
if (xds_getbuffer(xds, XDS_GIFT, (void **)&buffer, &buffer_size) !=
XDS_OK) {
printf("xds_getbuffer() failed!\n");
return 1;
}
xds_destroy(xds);
/* Now create a decoding context and decode the whole thing again. */
if (xds_init(&xds, XDS_DECODE) != XDS_OK) {
printf("Failed to initialize XDS context.\n");
return 1;
}
if (xds_register(xds, "mystruct", &decode_mystruct_engine, NULL) != XDS_OK
|| xds_register(xds, "int32", &xdr_decode_int32, NULL) != XDS_OK
|| xds_register(xds, "uint32", &xdr_decode_uint32, NULL) != XDS_OK) {
printf("Failed to register my decoding engines.\n");
return 1;
}
if (xds_setbuffer(xds, XDS_GIFT, buffer, buffer_size) != XDS_OK) {
printf("xds_setbuffer() failed!\n");
return 1;
}
if (xds_decode(xds, "mystruct", &new_ms) != XDS_OK) {
printf("xds_decode() failed!\n");
return 1;
}
xds_destroy(xds);
/* Both structures must be identical. */
if (ms.small != new_ms.small
|| ms.positive != new_ms.positive) {
printf("Decoded data does not match the original!\n");
return 1;
}
/* Everything went fine. */
return 0;
}
#endif /* XDS_TEST_XDS_MYSTRUCT */