/* ** OSSP xds - Extensible Data Serialization ** Copyright (c) 2001-2005 Ralf S. Engelschall ** Copyright (c) 2001-2005 The OSSP Project ** Copyright (c) 2001-2005 Cable & Wireless ** ** 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 #include #include #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 */