diff options
Diffstat (limited to 'common/tests/test_alloc.c')
-rw-r--r-- | common/tests/test_alloc.c | 501 |
1 files changed, 501 insertions, 0 deletions
diff --git a/common/tests/test_alloc.c b/common/tests/test_alloc.c new file mode 100644 index 0000000..9e08213 --- /dev/null +++ b/common/tests/test_alloc.c @@ -0,0 +1,501 @@ +/* + * Copyright (c) 2007,2009-2014 by Internet Systems Consortium, Inc. ("ISC") + * + * We test the functions provided in alloc.c here. These are very + * basic functions, and it is very important that they work correctly. + * + * You can see two different styles of testing: + * + * - In the first, we have a single test for each function that tests + * all of the possible ways it can operate. (This is the case for + * the buffer tests.) + * + * - In the second, we have a separate test for each of the ways a + * function can operate. (This is the case for the data_string + * tests.) + * + * The advantage of a single test per function is that you have fewer + * tests, and less duplicated and extra code. The advantage of having + * a separate test is that each test is simpler. Plus if you need to + * allow certain tests to fail for some reason (known bugs that are + * hard to fix for example), then + */ + +/** @TODO: dmalloc() test */ + +#include "config.h" +#include <atf-c.h> +#include "dhcpd.h" + +static const char* checkString (struct data_string* ds, const char *src); + +ATF_TC(buffer_allocate); + +ATF_TC_HEAD(buffer_allocate, tc) { + atf_tc_set_md_var(tc, "descr", "buffer_allocate basic test"); +} + +ATF_TC_BODY(buffer_allocate, tc) { + struct buffer *buf = 0; + + /* + * Check a 0-length buffer. + */ + buf = NULL; + if (!buffer_allocate(&buf, 0, MDL)) { + atf_tc_fail("failed on 0-len buffer"); + } + if (!buffer_dereference(&buf, MDL)) { + atf_tc_fail("buffer_dereference() failed"); + } + if (buf != NULL) { + atf_tc_fail("buffer_dereference() did not NULL-out buffer"); + } + + /* + * Check an actual buffer. + */ + buf = NULL; + if (!buffer_allocate(&buf, 100, MDL)) { + atf_tc_fail("failed on allocate 100 bytes\n"); + } + if (!buffer_dereference(&buf, MDL)) { + atf_tc_fail("buffer_dereference() failed"); + } + if (buf != NULL) { + atf_tc_fail("buffer_dereference() did not NULL-out buffer"); + } + + /* + * Okay, we're happy. + */ + atf_tc_pass(); +} + +ATF_TC(buffer_reference); + +ATF_TC_HEAD(buffer_reference, tc) { + atf_tc_set_md_var(tc, "descr", "buffer_reference basic test"); +} + +ATF_TC_BODY(buffer_reference, tc) { + + struct buffer *a, *b; + + /* + * Create a buffer. + */ + a = NULL; + if (!buffer_allocate(&a, 100, MDL)) { + atf_tc_fail("failed on allocate 100 bytes"); + } + + /** + * Confirm buffer_reference() doesn't work if we pass in NULL. + * + * @TODO: we should confirm we get an error message here. + */ + if (buffer_reference(NULL, a, MDL)) { + atf_tc_fail("succeeded on an error input"); + } + + /** + * @TODO: we should confirm we get an error message if we pass + * a non-NULL target. + */ + + /* + * Confirm we work under normal circumstances. + */ + b = NULL; + if (!buffer_reference(&b, a, MDL)) { + atf_tc_fail("buffer_reference() failed"); + } + + if (b != a) { + atf_tc_fail("incorrect pointer returned"); + } + + if (b->refcnt != 2) { + atf_tc_fail("incorrect refcnt"); + } + + /* + * Clean up. + */ + if (!buffer_dereference(&b, MDL)) { + atf_tc_fail("buffer_dereference() failed"); + } + if (!buffer_dereference(&a, MDL)) { + atf_tc_fail("buffer_dereference() failed"); + } + +} + + +ATF_TC(buffer_dereference); + +ATF_TC_HEAD(buffer_dereference, tc) { + atf_tc_set_md_var(tc, "descr", "buffer_dereference basic test"); +} + +ATF_TC_BODY(buffer_dereference, tc) { + struct buffer *a, *b; + + /** + * Confirm buffer_dereference() doesn't work if we pass in NULL. + * + * TODO: we should confirm we get an error message here. + */ + if (buffer_dereference(NULL, MDL)) { + atf_tc_fail("succeeded on an error input"); + } + + /** + * Confirm buffer_dereference() doesn't work if we pass in + * a pointer to NULL. + * + * @TODO: we should confirm we get an error message here. + */ + a = NULL; + if (buffer_dereference(&a, MDL)) { + atf_tc_fail("succeeded on an error input"); + } + + /* + * Confirm we work under normal circumstances. + */ + a = NULL; + if (!buffer_allocate(&a, 100, MDL)) { + atf_tc_fail("failed on allocate"); + } + if (!buffer_dereference(&a, MDL)) { + atf_tc_fail("buffer_dereference() failed"); + } + if (a != NULL) { + atf_tc_fail("non-null buffer after buffer_dereference()"); + } + + /** + * Confirm we get an error from negative refcnt. + * + * @TODO: we should confirm we get an error message here. + */ + a = NULL; + if (!buffer_allocate(&a, 100, MDL)) { + atf_tc_fail("failed on allocate"); + } + b = NULL; + if (!buffer_reference(&b, a, MDL)) { + atf_tc_fail("buffer_reference() failed"); + } + a->refcnt = 0; /* purposely set to invalid value */ + if (buffer_dereference(&a, MDL)) { + atf_tc_fail("buffer_dereference() succeeded on error input"); + } + a->refcnt = 2; + if (!buffer_dereference(&b, MDL)) { + atf_tc_fail("buffer_dereference() failed"); + } + if (!buffer_dereference(&a, MDL)) { + atf_tc_fail("buffer_dereference() failed"); + } +} + +ATF_TC(data_string_forget); + +ATF_TC_HEAD(data_string_forget, tc) { + atf_tc_set_md_var(tc, "descr", "data_string_forget basic test"); +} + +ATF_TC_BODY(data_string_forget, tc) { + struct buffer *buf; + struct data_string a; + const char *str = "Lorem ipsum dolor sit amet turpis duis."; + + /* + * Create the string we want to forget. + */ + memset(&a, 0, sizeof(a)); + a.len = strlen(str); + buf = NULL; + if (!buffer_allocate(&buf, a.len, MDL)) { + atf_tc_fail("out of memory"); + } + if (!buffer_reference(&a.buffer, buf, MDL)) { + atf_tc_fail("buffer_reference() failed"); + } + a.data = a.buffer->data; + memcpy(a.buffer->data, str, a.len); + + /* + * Forget and confirm we've forgotten. + */ + data_string_forget(&a, MDL); + + if (a.len != 0) { + atf_tc_fail("incorrect length"); + } + + if (a.data != NULL) { + atf_tc_fail("incorrect data"); + } + if (a.terminated) { + atf_tc_fail("incorrect terminated"); + } + if (a.buffer != NULL) { + atf_tc_fail("incorrect buffer"); + } + if (buf->refcnt != 1) { + atf_tc_fail("too many references to buf"); + } + + /* + * Clean up buffer. + */ + if (!buffer_dereference(&buf, MDL)) { + atf_tc_fail("buffer_reference() failed"); + } +} + +ATF_TC(data_string_forget_nobuf); + +ATF_TC_HEAD(data_string_forget_nobuf, tc) { + atf_tc_set_md_var(tc, "descr", "data_string_forget test, " + "data_string without buffer"); +} + +ATF_TC_BODY(data_string_forget_nobuf, tc) { + struct data_string a; + const char *str = "Lorem ipsum dolor sit amet massa nunc."; + + /* + * Create the string we want to forget. + */ + memset(&a, 0, sizeof(a)); + a.len = strlen(str); + a.data = (const unsigned char *)str; + a.terminated = 1; + + /* + * Forget and confirm we've forgotten. + */ + data_string_forget(&a, MDL); + + if (a.len != 0) { + atf_tc_fail("incorrect length"); + } + if (a.data != NULL) { + atf_tc_fail("incorrect data"); + } + if (a.terminated) { + atf_tc_fail("incorrect terminated"); + } + if (a.buffer != NULL) { + atf_tc_fail("incorrect buffer"); + } +} + +ATF_TC(data_string_copy); + +ATF_TC_HEAD(data_string_copy, tc) { + atf_tc_set_md_var(tc, "descr", "data_string_copy basic test"); +} + +ATF_TC_BODY(data_string_copy, tc) { + struct data_string a, b; + const char *str = "Lorem ipsum dolor sit amet orci aliquam."; + + /* + * Create the string we want to copy. + */ + memset(&a, 0, sizeof(a)); + a.len = strlen(str); + if (!buffer_allocate(&a.buffer, a.len, MDL)) { + atf_tc_fail("out of memory"); + } + a.data = a.buffer->data; + memcpy(a.buffer->data, str, a.len); + + /* + * Copy the string, and confirm it works. + */ + memset(&b, 0, sizeof(b)); + data_string_copy(&b, &a, MDL); + + if (b.len != a.len) { + atf_tc_fail("incorrect length"); + } + if (b.data != a.data) { + atf_tc_fail("incorrect data"); + } + if (b.terminated != a.terminated) { + atf_tc_fail("incorrect terminated"); + } + if (b.buffer != a.buffer) { + atf_tc_fail("incorrect buffer"); + } + + /* + * Clean up. + */ + data_string_forget(&b, MDL); + data_string_forget(&a, MDL); +} + +ATF_TC(data_string_copy_nobuf); + +ATF_TC_HEAD(data_string_copy_nobuf, tc) { + atf_tc_set_md_var(tc, "descr", "data_string_copy test, " + "data_string without buffer"); +} + +ATF_TC_BODY(data_string_copy_nobuf, tc) { + struct data_string a, b; + const char *str = "Lorem ipsum dolor sit amet cras amet."; + + /* + * Create the string we want to copy. + */ + memset(&a, 0, sizeof(a)); + a.len = strlen(str); + a.data = (const unsigned char *)str; + a.terminated = 1; + + /* + * Copy the string, and confirm it works. + */ + memset(&b, 0, sizeof(b)); + data_string_copy(&b, &a, MDL); + + if (b.len != a.len) { + atf_tc_fail("incorrect length"); + } + if (b.data != a.data) { + atf_tc_fail("incorrect data"); + } + if (b.terminated != a.terminated) { + atf_tc_fail("incorrect terminated"); + } + if (b.buffer != a.buffer) { + atf_tc_fail("incorrect buffer"); + } + + /* + * Clean up. + */ + data_string_forget(&b, MDL); + data_string_forget(&a, MDL); + +} + + +ATF_TC(data_string_new); + +ATF_TC_HEAD(data_string_new, tc) { + atf_tc_set_md_var(tc, "descr", "data_string_new test, " + "exercises data_string_new function"); +} + +ATF_TC_BODY(data_string_new, tc) { + struct data_string new_string; + const char *src = "Really? Latin? ... geeks"; + int len_arg = 0; + const char *error; + + /* Case 1: Call with an invalid data_string pointer, should fail */ + if (data_string_new(NULL, src, len_arg, MDL)) { + atf_tc_fail("case 1: call should have failed"); + } + + /* Case 2: Passing in NULL src should fail */ + if (data_string_new(&new_string, NULL, 10, MDL)) { + atf_tc_fail("case 2: did not return success"); + } + + /* Case 3: Call with valid params, length includes NULL */ + len_arg = strlen(src) + 1; + if (data_string_new(&new_string, src, len_arg, MDL) == 0) { + atf_tc_fail("case 3: did not return success"); + } + + error = checkString(&new_string, src); + ATF_REQUIRE_MSG((error == NULL), "case 3: %s", error); + data_string_forget(&new_string, MDL); + + + /* Case 4: Call with valid params, length does not include NULL */ + len_arg = 7; + if (data_string_new(&new_string, src, len_arg, MDL) == 0) { + atf_tc_fail("case 4: did not return success"); + } + + error = checkString(&new_string, "Really?"); + ATF_REQUIRE_MSG((error == NULL), "case 4: %s", error); + data_string_forget(&new_string, MDL); + + + /* Case 5: Call with valid params, source string is "" */ + len_arg = 0; + if (data_string_new(&new_string, "", len_arg, MDL) == 0) { + atf_tc_fail("case 5: did not return success"); + } + + error = checkString(&new_string, ""); + ATF_REQUIRE_MSG((error == NULL), "case 4: %s", error); + data_string_forget(&new_string, MDL); + + +} + +/* Helper function which tests validity of a data_string +* +* Verifies that the given data_string contains a null-terminated string +* equal to a given string. +* +* \param string data_string to test +* \param src text content string should contain +* \return returns NULL if data_string is validate or an error message +* describing why it is invalid +*/ +const char* checkString (struct data_string* string, + const char* src) { + int src_len = strlen(src); + + if (string->buffer == NULL) { + return ("buffer is NULL"); + } + + if (string->data != string->buffer->data) { + return ("data not set to buffer->data"); + } + + if (string->len != src_len) { + return ("len is wrong "); + } + + if (string->terminated != 1) { + return ("terminated flag not set"); + } + + if (memcmp(string->data, src, src_len + 1)) { + return ("data content wrong"); + } + + return (NULL); +} + + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, buffer_allocate); + ATF_TP_ADD_TC(tp, buffer_reference); + ATF_TP_ADD_TC(tp, buffer_dereference); + ATF_TP_ADD_TC(tp, data_string_forget); + ATF_TP_ADD_TC(tp, data_string_forget_nobuf); + ATF_TP_ADD_TC(tp, data_string_copy); + ATF_TP_ADD_TC(tp, data_string_copy_nobuf); + ATF_TP_ADD_TC(tp, data_string_new); + + return (atf_no_error()); +} |