diff options
Diffstat (limited to 'ccan/tal/test')
| -rw-r--r-- | ccan/tal/test/run-allocfail.c | 153 | ||||
| -rw-r--r-- | ccan/tal/test/run-array.c | 48 | ||||
| -rw-r--r-- | ccan/tal/test/run-count.c | 92 | ||||
| -rw-r--r-- | ccan/tal/test/run-destructor.c | 68 | ||||
| -rw-r--r-- | ccan/tal/test/run-destructor2.c | 38 | ||||
| -rw-r--r-- | ccan/tal/test/run-expand.c | 33 | ||||
| -rw-r--r-- | ccan/tal/test/run-free.c | 29 | ||||
| -rw-r--r-- | ccan/tal/test/run-groups-grow.c | 48 | ||||
| -rw-r--r-- | ccan/tal/test/run-iter.c | 53 | ||||
| -rw-r--r-- | ccan/tal/test/run-named-debug.c | 35 | ||||
| -rw-r--r-- | ccan/tal/test/run-named-nolabels.c | 31 | ||||
| -rw-r--r-- | ccan/tal/test/run-named.c | 34 | ||||
| -rw-r--r-- | ccan/tal/test/run-notifier.c | 133 | ||||
| -rw-r--r-- | ccan/tal/test/run-overflow.c | 99 | ||||
| -rw-r--r-- | ccan/tal/test/run-resizez.c | 27 | ||||
| -rw-r--r-- | ccan/tal/test/run-steal.c | 41 | ||||
| -rw-r--r-- | ccan/tal/test/run-take.c | 57 | ||||
| -rw-r--r-- | ccan/tal/test/run-test-backend.c | 80 | ||||
| -rw-r--r-- | ccan/tal/test/run.c | 61 |
19 files changed, 1160 insertions, 0 deletions
diff --git a/ccan/tal/test/run-allocfail.c b/ccan/tal/test/run-allocfail.c new file mode 100644 index 0000000..97cba9f --- /dev/null +++ b/ccan/tal/test/run-allocfail.c @@ -0,0 +1,153 @@ +#include <ccan/tal/tal.h> +#include <ccan/tal/tal.c> +#include <ccan/tap/tap.h> + +static int alloc_count, when_to_fail, err_count; +static bool stealing; + +static void *failing_alloc(size_t len) +{ + if (alloc_count++ == when_to_fail) + return NULL; + /* once we've failed once, it shouldn't ask again (steal can though). */ + assert(stealing || alloc_count <= when_to_fail); + + return malloc(len); +} + +static void *failing_realloc(void *p, size_t len) +{ + if (alloc_count++ == when_to_fail) + return NULL; + + return realloc(p, len); +} + + +static void nofail_on_error(const char *msg) +{ + diag("ERROR: %s", msg); + err_count++; +} + +static void destroy_p(void *p UNNEEDED) +{ +} + +int main(void) +{ + char *p, *c1, *c2; + bool success; + + plan_tests(25); + + tal_set_backend(failing_alloc, failing_realloc, NULL, nofail_on_error); + + /* Fail at each possible point in an allocation. */ + when_to_fail = err_count = 0; + do { + alloc_count = 0; + p = tal(NULL, char); + when_to_fail++; + } while (!p); + ok1(alloc_count >= 1); + ok1(when_to_fail > 1); + ok1(err_count == when_to_fail - 1); + + /* Do it again. */ + when_to_fail = err_count = 0; + do { + alloc_count = 0; + c1 = tal(p, char); + when_to_fail++; + } while (!c1); + ok1(alloc_count >= 1); + ok1(when_to_fail > 1); + ok1(err_count == when_to_fail - 1); + + /* Now during resize. */ + c2 = c1; + when_to_fail = err_count = 0; + for (;;) { + alloc_count = 0; + if (tal_resize(&c1, 100)) + break; + /* Failing alloc will not change pointer. */ + ok1(c1 == c2); + when_to_fail++; + }; + ok1(alloc_count == 1); + ok1(when_to_fail == 1); + ok1(err_count == 1); + /* Make sure it's really resized. */ + memset(c1, 1, 100); + + /* Now for second child. */ + when_to_fail = err_count = 0; + do { + alloc_count = 0; + c2 = tal(p, char); + when_to_fail++; + } while (!c2); + ok1(alloc_count >= 1); + ok1(when_to_fail > 1); + /* Note: adding a child will fall through if group alloc fails. */ + ok1 (err_count == when_to_fail - 1 || err_count == when_to_fail); + + /* Now while adding a destructor. */ + when_to_fail = err_count = 0; + do { + alloc_count = 0; + success = tal_add_destructor(p, destroy_p); + when_to_fail++; + } while (!success); + ok1(alloc_count >= 1); + ok1(when_to_fail > 1); + ok1(err_count == when_to_fail - 1); + + /* Now while adding a name. */ + when_to_fail = err_count = 0; + do { + const char name[] = "some name"; + alloc_count = 0; + success = tal_set_name(p, name); + when_to_fail++; + } while (!success); + ok1(alloc_count >= 1); + ok1(when_to_fail > 1); + ok1(err_count == when_to_fail - 1); + + /* Now while stealing. */ + stealing = true; + when_to_fail = err_count = 0; + do { + alloc_count = 0; + success = tal_steal(c2, c1) != NULL; + when_to_fail++; + } while (!success); + ok1(alloc_count >= 1); + ok1(when_to_fail > 1); + ok1(err_count == when_to_fail - 1); + + /* Now stealing with more children (more coverage). */ + when_to_fail = 1000; + (void)tal(p, char); + c1 = tal(p, char); + c2 = tal(p, char); + (void)tal(p, char); + + /* Now steal again. */ + when_to_fail = err_count = 0; + do { + alloc_count = 0; + success = tal_steal(c2, c1) != NULL; + when_to_fail++; + } while (!success); + ok1(alloc_count >= 1); + ok1(when_to_fail > 1); + ok1(err_count == when_to_fail - 1); + + tal_free(p); + tal_cleanup(); + return exit_status(); +} diff --git a/ccan/tal/test/run-array.c b/ccan/tal/test/run-array.c new file mode 100644 index 0000000..5cab66e --- /dev/null +++ b/ccan/tal/test/run-array.c @@ -0,0 +1,48 @@ +#include <ccan/tal/tal.h> +#include <ccan/tal/tal.c> +#include <ccan/tap/tap.h> + +int main(void) +{ + char *parent, *c[4]; + int i; + + plan_tests(11); + + parent = tal(NULL, char); + ok1(parent); + + /* Zeroing allocations. */ + for (i = 0; i < 4; i++) { + c[i] = talz(parent, char); + ok1(*c[i] == '\0'); + tal_free(c[i]); + } + + /* Array allocation. */ + for (i = 0; i < 4; i++) { + c[i] = tal_arr(parent, char, 4); + strcpy(c[i], "abc"); + tal_free(c[i]); + } + + /* Zeroing array allocation. */ + for (i = 0; i < 4; i++) { + c[i] = tal_arrz(parent, char, 4); + ok1(!c[i][0] && !c[i][1] && !c[i][2] && !c[i][3]); + strcpy(c[i], "abc"); + tal_free(c[i]); + } + + /* Resizing. */ + c[0] = tal_arrz(parent, char, 4); + ok1(tal_resize(&c[0], 6)); + strcpy(c[0], "hello"); + tal_free(c[0]); + ok1(tal_first(parent) == NULL); + + tal_free(parent); + + tal_cleanup(); + return exit_status(); +} diff --git a/ccan/tal/test/run-count.c b/ccan/tal/test/run-count.c new file mode 100644 index 0000000..33049b9 --- /dev/null +++ b/ccan/tal/test/run-count.c @@ -0,0 +1,92 @@ +#include <ccan/tal/tal.h> +#include <ccan/tal/tal.c> +#include <ccan/tap/tap.h> + +static bool move; +#define ALIGN (sizeof(void *)*2) + +static void *my_alloc(size_t len) +{ + char *ret = malloc(len + ALIGN); + memcpy(ret, &len, sizeof(len)); + return ret + ALIGN; +} + +static void my_free(void *p) +{ + if (p) + free((char *)p - ALIGN); +} + +static void *my_realloc(void *old, size_t new_size) +{ + char *ret; + + /* Test what happens if we always move */ + if (move) { + size_t old_size = *(size_t *)((char *)old - ALIGN); + ret = my_alloc(new_size); + memcpy(ret, old, old_size > new_size ? new_size : old_size); + my_free(old); + } else { + ret = realloc((char *)old - ALIGN, new_size + ALIGN); + memcpy(ret, &new_size, sizeof(new_size)); + ret += ALIGN; + } + return ret; +} + +int main(void) +{ + char *p1, *p2; + unsigned int i; + + tal_set_backend(my_alloc, my_realloc, my_free, NULL); + + plan_tests(2 + 19 * 3); + + p1 = NULL; + ok1(tal_len(p1) == 0); + ok1(tal_count(p1) == 0); + + for (i = 0; i < 3; i++) { + move = i; + + p1 = tal(NULL, char); + ok1(p1); + ok1(tal_count(p1) == 0); + + p2 = tal_arr(p1, char, 1); + ok1(p2); + ok1(tal_count(p2) == 1); + ok1(tal_resize(&p2, 2)); + ok1(tal_count(p2) == 2); + ok1(tal_check(NULL, NULL)); + tal_free(p2); + + /* Resize twice. */ + p2 = tal_arrz(p1, char, 7); + ok1(p2); + ok1(tal_count(p2) == 7); + ok1(tal_check(NULL, NULL)); + tal_resize(&p2, 20); + ok1(p2); + ok1(tal_check(NULL, NULL)); + ok1(tal_count(p2) == 20); + /* Tickles non-moving logic, as we do not update bounds. */ + if (i == 2) + move = false; + tal_resize(&p2, 300); + ok1(p2); + ok1(tal_check(NULL, NULL)); + ok1(tal_count(p2) == 300); + ok1(tal_resize(&p2, 0)); + ok1(tal_count(p2) == 0); + ok1(tal_check(NULL, NULL)); + tal_free(p2); + tal_free(p1); + } + + tal_cleanup(); + return exit_status(); +} diff --git a/ccan/tal/test/run-destructor.c b/ccan/tal/test/run-destructor.c new file mode 100644 index 0000000..7183f7c --- /dev/null +++ b/ccan/tal/test/run-destructor.c @@ -0,0 +1,68 @@ +#include <ccan/tal/tal.h> +#include <ccan/tal/tal.c> +#include <ccan/tap/tap.h> + +static char *parent, *child; +static int destroy_count; + +/* Parent gets destroyed first. */ +static void destroy_parent(char *p) +{ + ok1(p == parent); + ok1(destroy_count == 0); + /* Can still access child. */ + *child = '1'; + destroy_count++; +} + +static void destroy_child(char *p) +{ + ok1(p == child); + ok1(destroy_count == 1); + /* Can still access parent (though destructor has been called). */ + *parent = '1'; + destroy_count++; +} + +static void destroy_inc(char *p UNNEEDED) +{ + destroy_count++; +} + +int main(void) +{ + char *child2; + + plan_tests(18); + + destroy_count = 0; + parent = tal(NULL, char); + child = tal(parent, char); + ok1(tal_add_destructor(parent, destroy_parent)); + ok1(tal_add_destructor(child, destroy_child)); + tal_free(parent); + ok1(destroy_count == 2); + + destroy_count = 0; + parent = tal(NULL, char); + child = tal(parent, char); + ok1(tal_add_destructor(parent, destroy_parent)); + ok1(tal_add_destructor(child, destroy_child)); + ok1(tal_del_destructor(child, destroy_child)); + tal_free(parent); + ok1(destroy_count == 1); + + destroy_count = 0; + parent = tal(NULL, char); + child = tal(parent, char); + child2 = tal(parent, char); + ok1(tal_add_destructor(parent, destroy_inc)); + ok1(tal_add_destructor(parent, destroy_inc)); + ok1(tal_add_destructor(child, destroy_inc)); + ok1(tal_add_destructor(child2, destroy_inc)); + tal_free(parent); + ok1(destroy_count == 4); + + tal_cleanup(); + return exit_status(); +} diff --git a/ccan/tal/test/run-destructor2.c b/ccan/tal/test/run-destructor2.c new file mode 100644 index 0000000..a92f07f --- /dev/null +++ b/ccan/tal/test/run-destructor2.c @@ -0,0 +1,38 @@ +#include <ccan/tal/tal.h> +#include <ccan/tal/tal.c> +#include <ccan/tap/tap.h> + +static void destroy_inc(char *p UNNEEDED, int *destroy_count) +{ + (*destroy_count)++; +} + +static void destroy_dec(char *p UNNEEDED, int *destroy_count) +{ + (*destroy_count)--; +} + +int main(void) +{ + char *p; + int destroy_count1 = 0, destroy_count2 = 0; + + plan_tests(10); + + p = tal(NULL, char); + /* Del must match both fn and arg. */ + ok1(tal_add_destructor2(p, destroy_inc, &destroy_count1)); + ok1(!tal_del_destructor2(p, destroy_inc, &destroy_count2)); + ok1(!tal_del_destructor2(p, destroy_dec, &destroy_count1)); + ok1(tal_del_destructor2(p, destroy_inc, &destroy_count1)); + ok1(!tal_del_destructor2(p, destroy_inc, &destroy_count1)); + + ok1(tal_add_destructor2(p, destroy_inc, &destroy_count1)); + ok1(tal_add_destructor2(p, destroy_dec, &destroy_count2)); + ok1(tal_free(p) == NULL); + ok1(destroy_count1 == 1); + ok1(destroy_count2 == -1); + + tal_cleanup(); + return exit_status(); +} diff --git a/ccan/tal/test/run-expand.c b/ccan/tal/test/run-expand.c new file mode 100644 index 0000000..841735f --- /dev/null +++ b/ccan/tal/test/run-expand.c @@ -0,0 +1,33 @@ +#include <ccan/tal/tal.h> +#include <ccan/tal/tal.c> +#include <ccan/tap/tap.h> + +int main(void) +{ + int *a; + const int arr[] = { 1, 2 }; + + plan_tests(13); + + a = tal_arrz(NULL, int, 1); + ok1(a); + + ok1(tal_expand(&a, arr, 2)); + ok1(tal_count(a) == 3); + ok1(a[0] == 0); + ok1(a[1] == 1); + ok1(a[2] == 2); + + ok1(tal_expand(&a, take(tal_arrz(NULL, int, 1)), 1)); + ok1(tal_count(a) == 4); + ok1(a[0] == 0); + ok1(a[1] == 1); + ok1(a[2] == 2); + ok1(a[3] == 0); + ok1(tal_first(NULL) == a && !tal_next(a) && !tal_first(a)); + + tal_free(a); + + tal_cleanup(); + return exit_status(); +} diff --git a/ccan/tal/test/run-free.c b/ccan/tal/test/run-free.c new file mode 100644 index 0000000..37d03cd --- /dev/null +++ b/ccan/tal/test/run-free.c @@ -0,0 +1,29 @@ +#include <ccan/tal/tal.h> +#include <ccan/tal/tal.c> +#include <ccan/tap/tap.h> + +static void destroy_errno(char *p UNNEEDED) +{ + /* Errno restored for all the destructors. */ + ok1(errno == EINVAL); + errno = ENOENT; +} + +int main(void) +{ + char *p; + + plan_tests(5); + + p = tal(NULL, char); + ok1(tal_add_destructor(p, destroy_errno)); + ok1(tal_add_destructor(p, destroy_errno)); + + /* Errno save/restored across free. */ + errno = EINVAL; + tal_free(p); + ok1(errno == EINVAL); + + tal_cleanup(); + return exit_status(); +} diff --git a/ccan/tal/test/run-groups-grow.c b/ccan/tal/test/run-groups-grow.c new file mode 100644 index 0000000..ea379c0 --- /dev/null +++ b/ccan/tal/test/run-groups-grow.c @@ -0,0 +1,48 @@ +#define CCAN_TAL_DEBUG +#include <ccan/tal/tal.h> +#include <ccan/tal/tal.c> +#include <ccan/tap/tap.h> + +static size_t num_allocated; + +static void *alloc_account(size_t len) +{ + num_allocated++; + return malloc(len); +} + +static void free_account(void *p) +{ + num_allocated--; + return free(p); +} + +#define NUM_ALLOCS 1000 + +int main(void) +{ + void *p, *c[NUM_ALLOCS]; + int i; + size_t allocated_after_first; + + plan_tests(1); + + tal_set_backend(alloc_account, NULL, free_account, NULL); + + p = tal(NULL, char); + c[0] = tal(p, char); + + allocated_after_first = num_allocated; + for (i = 1; i < NUM_ALLOCS; i++) + c[i] = tal(p, char); + + /* Now free them all. */ + for (i = 0; i < NUM_ALLOCS; i++) + tal_free(c[i]); + + /* We can expect some residue from having any child, but limited! */ + ok1(num_allocated <= allocated_after_first); + tal_free(p); + tal_cleanup(); + return exit_status(); +} diff --git a/ccan/tal/test/run-iter.c b/ccan/tal/test/run-iter.c new file mode 100644 index 0000000..5992172 --- /dev/null +++ b/ccan/tal/test/run-iter.c @@ -0,0 +1,53 @@ +#include <ccan/tal/tal.h> +#include <ccan/tal/tal.c> +#include <ccan/tap/tap.h> + +#define NUM 1000 + +static int set_children(const tal_t *parent, char val) +{ + char *iter; + int num = 0; + + for (iter = tal_first(parent); iter; iter = tal_next(iter)) { + ok1(*iter == '0'); + *iter = val; + num++; + num += set_children(iter, val); + } + return num; +} + +static void check_children(const tal_t *parent, char val) +{ + const char *iter; + + for (iter = tal_first(parent); iter; iter = tal_next(iter)) { + ok1(*iter == val); + check_children(iter, val); + } +} + +int main(void) +{ + char *p[NUM] = { NULL }; + int i; + + plan_tests(NUM + 1 + NUM); + + /* Create a random tree */ + for (i = 0; i < NUM; i++) { + p[i] = tal(p[rand() % (i + 1)], char); + *p[i] = '0'; + } + + i = set_children(NULL, '1'); + ok1(i == NUM); + + check_children(NULL, '1'); + for (i = NUM-1; i >= 0; i--) + tal_free(p[i]); + + tal_cleanup(); + return exit_status(); +} diff --git a/ccan/tal/test/run-named-debug.c b/ccan/tal/test/run-named-debug.c new file mode 100644 index 0000000..679e6ec --- /dev/null +++ b/ccan/tal/test/run-named-debug.c @@ -0,0 +1,35 @@ +#define CCAN_TAL_DEBUG +#include <ccan/tal/tal.h> +#include <ccan/tal/tal.c> +#include <ccan/tap/tap.h> + +int main(void) +{ + int *p; + char name[] = "test name"; + + plan_tests(6); + + p = tal(NULL, int); + ok1(strcmp(tal_name(p), __FILE__ ":13:int") == 0); + + tal_set_name(p, "some literal"); + ok1(strcmp(tal_name(p), "some literal") == 0); + + tal_set_name(p, name); + ok1(strcmp(tal_name(p), name) == 0); + /* You can't reuse my pointer though! */ + ok1(tal_name(p) != name); + + tal_set_name(p, "some other literal"); + ok1(strcmp(tal_name(p), "some other literal") == 0); + + tal_free(p); + + p = tal_arr(NULL, int, 2); + ok1(strcmp(tal_name(p), __FILE__ ":29:int[]") == 0); + tal_free(p); + + tal_cleanup(); + return exit_status(); +} diff --git a/ccan/tal/test/run-named-nolabels.c b/ccan/tal/test/run-named-nolabels.c new file mode 100644 index 0000000..fc7b81f --- /dev/null +++ b/ccan/tal/test/run-named-nolabels.c @@ -0,0 +1,31 @@ +#define CCAN_TAL_NO_LABELS +#include <ccan/tal/tal.h> +#include <ccan/tal/tal.c> +#include <ccan/tap/tap.h> + +int main(void) +{ + int *p; + char name[] = "test name"; + + plan_tests(5); + + p = tal(NULL, int); + ok1(tal_name(p) == NULL); + + tal_set_name(p, "some literal"); + ok1(strcmp(tal_name(p), "some literal") == 0); + + tal_set_name(p, name); + ok1(strcmp(tal_name(p), name) == 0); + /* You can't reuse my pointer though! */ + ok1(tal_name(p) != name); + + tal_set_name(p, "some other literal"); + ok1(strcmp(tal_name(p), "some other literal") == 0); + + tal_free(p); + + tal_cleanup(); + return exit_status(); +} diff --git a/ccan/tal/test/run-named.c b/ccan/tal/test/run-named.c new file mode 100644 index 0000000..d6275ac --- /dev/null +++ b/ccan/tal/test/run-named.c @@ -0,0 +1,34 @@ +#include <ccan/tal/tal.h> +#include <ccan/tal/tal.c> +#include <ccan/tap/tap.h> + +int main(void) +{ + int *p; + char name[] = "test name"; + + plan_tests(6); + + p = tal(NULL, int); + ok1(strcmp(tal_name(p), "int") == 0); + + tal_set_name(p, "some literal"); + ok1(strcmp(tal_name(p), "some literal") == 0); + + tal_set_name(p, name); + ok1(strcmp(tal_name(p), name) == 0); + /* You can't reuse my pointer though! */ + ok1(tal_name(p) != name); + + tal_set_name(p, "some other literal"); + ok1(strcmp(tal_name(p), "some other literal") == 0); + + tal_free(p); + + p = tal_arr(NULL, int, 2); + ok1(strcmp(tal_name(p), "int[]") == 0); + tal_free(p); + + tal_cleanup(); + return exit_status(); +} diff --git a/ccan/tal/test/run-notifier.c b/ccan/tal/test/run-notifier.c new file mode 100644 index 0000000..3820444 --- /dev/null +++ b/ccan/tal/test/run-notifier.c @@ -0,0 +1,133 @@ +#include <ccan/tal/tal.h> +#include <ccan/tal/tal.c> +#include <ccan/tap/tap.h> + +static enum tal_notify_type expect; +static void *expect_info; +static char *ctx; +static unsigned int notified1, notified2; + +/* Make sure we always move on resize. */ +static void *my_realloc(void *old, size_t size) +{ + void *new = realloc(old, size); + if (new == old) { + void *p = malloc(size); + memcpy(p, old, size); + free(old); + new = p; + } + return new; +} + +static void notify1(char *p UNNEEDED, enum tal_notify_type notify, void *info) +{ + ok1(ctx == ctx); + ok1(notify == expect); + if (expect_info == &expect_info) + expect_info = info; + else + ok1(info == expect_info); + notified1++; +} + +static void notify2(char *ctx UNNEEDED, + enum tal_notify_type notify UNNEEDED, + void *info UNNEEDED) +{ + notified2++; +} + +static bool seen_move, seen_resize; +static void resize_notifier(char *p, enum tal_notify_type notify, void *info) +{ + if (notify == TAL_NOTIFY_MOVE) { + ok1(!seen_move); + ok1(!seen_resize); + ok1(info == ctx); + ok1(p != ctx); + ctx = p; + seen_move = true; + } else if (notify == TAL_NOTIFY_RESIZE) { + ok1(!seen_resize); + ok1(seen_move); + ok1(p == ctx); + ok1((size_t)info == 100); + seen_resize = true; + } else + fail("Unexpected notifier %i", notify); +} + +int main(void) +{ + char *child, *new_ctx; + + plan_tests(56); + + ctx = tal(NULL, char); + ok1(tal_add_notifier(ctx, 511, notify1)); + ok1(notified1 == 0); + ok1(notified2 == 0); + + expect = TAL_NOTIFY_STEAL; + expect_info = NULL; + ok1(tal_steal(NULL, ctx) == ctx); + ok1(notified1 == 1); + + expect = TAL_NOTIFY_ADD_NOTIFIER; + expect_info = notify2; + ok1(tal_add_notifier(ctx, TAL_NOTIFY_RENAME|TAL_NOTIFY_ADD_NOTIFIER + |TAL_NOTIFY_DEL_NOTIFIER, notify2)); + ok1(notified1 == 2); + ok1(notified2 == 0); + + expect = TAL_NOTIFY_RENAME; + expect_info = (char *)"newname"; + ok1(tal_set_name(ctx, (char *)expect_info)); + ok1(notified1 == 3); + ok1(notified2 == 1); + + expect = TAL_NOTIFY_DEL_NOTIFIER; + expect_info = notify2; + ok1(tal_del_notifier(ctx, notify2)); + ok1(notified1 == 4); + ok1(notified2 == 1); + + /* Failed delete should not call notifier! */ + expect = TAL_NOTIFY_DEL_NOTIFIER; + expect_info = notify2; + ok1(!tal_del_notifier(ctx, notify2)); + ok1(notified1 == 4); + ok1(notified2 == 1); + + expect = TAL_NOTIFY_ADD_CHILD; + expect_info = &expect_info; + child = tal(ctx, char); + ok1(notified1 == 5); + ok1(notified2 == 1); + ok1(expect_info == child); + + expect = TAL_NOTIFY_DEL_CHILD; + expect_info = child; + tal_free(child); + ok1(notified1 == 6); + ok1(notified2 == 1); + + expect = TAL_NOTIFY_FREE; + expect_info = ctx; + tal_free(ctx); + ok1(notified1 == 7); + ok1(notified2 == 1); + + tal_set_backend(NULL, my_realloc, NULL, NULL); + ctx = new_ctx = tal(NULL, char); + ok1(tal_add_notifier(new_ctx, 511, resize_notifier)); + ok1(tal_resize(&new_ctx, 100)); + ok1(seen_move); + ok1(seen_resize); + tal_del_notifier(new_ctx, resize_notifier); + tal_free(new_ctx); + + tal_cleanup(); + return exit_status(); +} diff --git a/ccan/tal/test/run-overflow.c b/ccan/tal/test/run-overflow.c new file mode 100644 index 0000000..d1919c1 --- /dev/null +++ b/ccan/tal/test/run-overflow.c @@ -0,0 +1,99 @@ +#include <ccan/tal/tal.h> +#include <ccan/tal/tal.c> +#include <ccan/tap/tap.h> + +static int error_count; + +static void my_error(const char *msg UNNEEDED) +{ + error_count++; +} + +int main(void) +{ + void *p; + int *pi, *origpi; + char *cp; + + plan_tests(30); + + tal_set_backend(NULL, NULL, NULL, my_error); + + p = tal_arr(NULL, int, (size_t)-1); + ok1(!p); + ok1(error_count == 1); + + p = tal_arr(NULL, char, (size_t)-2); + ok1(!p); + ok1(error_count == 2); + + /* Now try overflow cases for tal_dup. */ + error_count = 0; + origpi = tal_arr(NULL, int, 100); + ok1(origpi); + ok1(error_count == 0); + pi = tal_dup_arr(NULL, int, origpi, (size_t)-1, 0); + ok1(!pi); + ok1(error_count == 1); + pi = tal_dup_arr(NULL, int, origpi, 0, (size_t)-1); + ok1(!pi); + ok1(error_count == 2); + + pi = tal_dup_arr(NULL, int, origpi, (size_t)-1UL / sizeof(int), + (size_t)-1UL / sizeof(int)); + ok1(!pi); + ok1(error_count == 3); + /* This will still overflow when tal_hdr is added. */ + pi = tal_dup_arr(NULL, int, origpi, (size_t)-1UL / sizeof(int) / 2, + (size_t)-1UL / sizeof(int) / 2); + ok1(!pi); + ok1(error_count == 4); + ok1(tal_first(NULL) == origpi && !tal_next(origpi) && !tal_first(origpi)); + tal_free(origpi); + + /* Now, check that with taltk() we free old one on failure. */ + origpi = tal_arr(NULL, int, 100); + error_count = 0; + pi = tal_dup_arr(NULL, int, take(origpi), (size_t)-1, 0); + ok1(!pi); + ok1(error_count == 1); + + origpi = tal_arr(NULL, int, 100); + error_count = 0; + pi = tal_dup_arr(NULL, int, take(origpi), 0, (size_t)-1); + ok1(!pi); + ok1(error_count == 1); + ok1(!tal_first(NULL)); + + origpi = tal_arr(NULL, int, 100); + error_count = 0; + pi = tal_dup_arr(NULL, int, take(origpi), (size_t)-1UL / sizeof(int), + (size_t)-1UL / sizeof(int)); + ok1(!pi); + ok1(error_count == 1); + ok1(!tal_first(NULL)); + + origpi = tal_arr(NULL, int, 100); + error_count = 0; + /* This will still overflow when tal_hdr is added. */ + pi = tal_dup_arr(NULL, int, take(origpi), (size_t)-1UL / sizeof(int) / 2, + (size_t)-1UL / sizeof(int) / 2); + ok1(!pi); + ok1(error_count == 1); + ok1(!tal_first(NULL)); + + /* Overflow on expand addition. */ + cp = tal_arr(p, char, 100); + ok1(!tal_expand(&cp, NULL, (size_t)-99UL)); + ok1(error_count == 2); + tal_free(cp); + + /* Overflow when multiplied by size */ + origpi = tal_arr(NULL, int, 100); + ok1(!tal_expand(&origpi, NULL, (size_t)-1UL / sizeof(int))); + ok1(error_count == 3); + tal_free(origpi); + + tal_cleanup(); + return exit_status(); +} diff --git a/ccan/tal/test/run-resizez.c b/ccan/tal/test/run-resizez.c new file mode 100644 index 0000000..ddf6682 --- /dev/null +++ b/ccan/tal/test/run-resizez.c @@ -0,0 +1,27 @@ +#include <ccan/tal/tal.h> +#include <ccan/tal/tal.c> +#include <ccan/tap/tap.h> + +int main(void) +{ + char *parent, *c; + int i; + + plan_tests(1 + 3 * 100 + 98); + + parent = tal(NULL, char); + ok1(parent); + + for (i = 0; i < 100; i++) { + c = tal_arr(parent, char, 1); + ok1(tal_resizez(&c, i)); + ok1(tal_count(c) == i); + ok1(tal_parent(c) == parent); + if (i > 1) + ok1(c[i-1] == '\0'); + } + tal_free(parent); + + tal_cleanup(); + return exit_status(); +} diff --git a/ccan/tal/test/run-steal.c b/ccan/tal/test/run-steal.c new file mode 100644 index 0000000..36251cb --- /dev/null +++ b/ccan/tal/test/run-steal.c @@ -0,0 +1,41 @@ +#include <ccan/tal/tal.h> +#include <ccan/tal/tal.c> +#include <ccan/tap/tap.h> + +int main(void) +{ + char *p[5]; + unsigned int i; + + plan_tests(9); + + p[0] = tal(NULL, char); + for (i = 1; i < 5; i++) + p[i] = tal(p[i-1], char); + + tal_check(NULL, "check"); + /* Steal node with no children. */ + ok1(tal_steal(p[0], p[4]) == p[4]); + tal_check(NULL, "check"); + /* Noop steal. */ + ok1(tal_steal(p[0], p[4]) == p[4]); + tal_check(NULL, "check"); + /* Steal with children. */ + ok1(tal_steal(p[0], p[1]) == p[1]); + tal_check(NULL, "check"); + /* Noop steal. */ + ok1(tal_steal(p[0], p[1]) == p[1]); + tal_check(NULL, "check"); + /* Steal from direct child. */ + ok1(tal_steal(p[0], p[2]) == p[2]); + tal_check(NULL, "check"); + + ok1(tal_parent(p[1]) == p[0]); + ok1(tal_parent(p[2]) == p[0]); + ok1(tal_parent(p[3]) == p[2]); + ok1(tal_parent(p[4]) == p[0]); + tal_free(p[0]); + + tal_cleanup(); + return exit_status(); +} diff --git a/ccan/tal/test/run-take.c b/ccan/tal/test/run-take.c new file mode 100644 index 0000000..d93304e --- /dev/null +++ b/ccan/tal/test/run-take.c @@ -0,0 +1,57 @@ +#include <ccan/tal/tal.h> +#include <ccan/tal/tal.c> +#include <ccan/tap/tap.h> + +int main(void) +{ + char *parent, *c; + + plan_tests(21); + + /* We can take NULL. */ + ok1(take(NULL) == NULL); + ok1(is_taken(NULL)); + ok1(taken(NULL)); /* Undoes take() */ + ok1(!is_taken(NULL)); + ok1(!taken(NULL)); + + parent = tal(NULL, char); + ok1(parent); + + ok1(take(parent) == parent); + ok1(is_taken(parent)); + ok1(taken(parent)); /* Undoes take() */ + ok1(!is_taken(parent)); + ok1(!taken(parent)); + + c = tal(parent, char); + *c = 'h'; + c = tal_dup(parent, char, take(c)); + ok1(c[0] == 'h'); + ok1(tal_parent(c) == parent); + + c = tal_dup_arr(parent, char, take(c), 1, 2); + ok1(c[0] == 'h'); + strcpy(c, "hi"); + ok1(tal_parent(c) == parent); + + /* dup must reparent child. */ + c = tal_dup(NULL, char, take(c)); + ok1(c[0] == 'h'); + ok1(tal_parent(c) == NULL); + + /* No leftover allocations. */ + tal_free(c); + ok1(tal_first(parent) == NULL); + + tal_free(parent); + ok1(!taken_any()); + + /* NULL pass-through. */ + c = NULL; + ok1(tal_dup_arr(NULL, char, take(c), 5, 5) == NULL); + ok1(!taken_any()); + + tal_cleanup(); + return exit_status(); +} diff --git a/ccan/tal/test/run-test-backend.c b/ccan/tal/test/run-test-backend.c new file mode 100644 index 0000000..ebcd811 --- /dev/null +++ b/ccan/tal/test/run-test-backend.c @@ -0,0 +1,80 @@ +#include <stdlib.h> +#include <stdbool.h> + +/* Make sure it always uses our allocation/resize/free fns! */ +static bool my_alloc_called; + +static void *my_alloc(size_t len) +{ + my_alloc_called = true; + return (char *)malloc(len + 16) + 16; +} + +static void my_free(void *p) +{ + if (p) + free((char *)p - 16); +} + +static void *my_realloc(void *old, size_t new_size) +{ + return (char *)realloc((char *)old - 16, new_size + 16) + 16; +} + +#define free ((void (*)(void *))abort) +#define malloc ((void *(*)(size_t))abort) +#define realloc ((void *(*)(void *, size_t))abort) + +#include <ccan/tal/tal.h> +#include <ccan/tal/tal.c> +#include <ccan/tap/tap.h> + +#define NUM_ALLOCS 1000 + +static void destroy_p(void *p UNNEEDED) +{ +} + +int main(void) +{ + void *p, *c[NUM_ALLOCS]; + int i; + char *name; + + /* Mostly we rely on the allocator (or valgrind) crashing. */ + plan_tests(1); + + tal_set_backend(my_alloc, my_realloc, my_free, NULL); + + p = tal(NULL, char); + ok1(my_alloc_called); + + /* Adding properties makes us allocated. */ + tal_add_destructor(p, destroy_p); + + tal_set_name(p, "test"); + name = tal_arr(NULL, char, 6); + strcpy(name, "test2"); + tal_set_name(p, name); + /* makes us free old name */ + tal_set_name(p, name); + tal_free(name); + + /* Add lots of children. */ + for (i = 0; i < NUM_ALLOCS; i++) + c[i] = tal(p, char); + + /* Now steal a few. */ + for (i = 1; i < NUM_ALLOCS / 2; i++) + tal_steal(c[0], c[i]); + + /* Now free individual ones.. */ + for (i = NUM_ALLOCS / 2; i < NUM_ALLOCS; i++) + tal_free(c[i]); + + /* Finally, free the parent. */ + tal_free(p); + + tal_cleanup(); + return exit_status(); +} diff --git a/ccan/tal/test/run.c b/ccan/tal/test/run.c new file mode 100644 index 0000000..4931099 --- /dev/null +++ b/ccan/tal/test/run.c @@ -0,0 +1,61 @@ +#include <ccan/tal/tal.h> +#include <ccan/tal/tal.c> +#include <ccan/tap/tap.h> + +int main(void) +{ + char *parent, *c[4], *p; + int i, j; + + plan_tests(14); + + /* tal_free(NULL) works. */ + ok1(tal_free(NULL) == NULL); + + parent = tal(NULL, char); + ok1(parent); + ok1(tal_parent(parent) == NULL); + ok1(tal_parent(NULL) == NULL); + + for (i = 0; i < 4; i++) + c[i] = tal(parent, char); + + for (i = 0; i < 4; i++) + ok1(tal_parent(c[i]) == parent); + + /* Iteration test. */ + i = 0; + for (p = tal_first(parent); p; p = tal_next(p)) { + *p = '1'; + i++; + } + ok1(i == 4); + ok1(*c[0] == '1'); + ok1(*c[1] == '1'); + ok1(*c[2] == '1'); + ok1(*c[3] == '1'); + + /* Free parent. */ + ok1(tal_free(parent) == NULL); + + parent = tal(NULL, char); + + /* Test freeing in every order */ + for (i = 0; i < 4; i++) { + for (j = 0; j < 4; j++) + c[j] = tal(parent, char); + + tal_free(c[i]); + debug_tal(to_tal_hdr(parent)); + tal_free(c[(i+1) % 4]); + debug_tal(to_tal_hdr(parent)); + tal_free(c[(i+2) % 4]); + debug_tal(to_tal_hdr(parent)); + tal_free(c[(i+3) % 4]); + debug_tal(to_tal_hdr(parent)); + } + tal_free(parent); + + tal_cleanup(); + return exit_status(); +} |
