dd6abff4dc6f7a0678bb3055305330382516143e
[ccan] / ccan / tal / test / run-allocfail.c
1 #include <ccan/tal/tal.h>
2 #include <ccan/tal/tal.c>
3 #include <ccan/tap/tap.h>
4
5 static int alloc_count, when_to_fail, err_count;
6 static bool stealing;
7
8 static void *failing_alloc(size_t len)
9 {
10         if (alloc_count++ == when_to_fail)
11                 return NULL;
12         /* once we've failed once, it shouldn't ask again (steal can though). */
13         assert(stealing || alloc_count <= when_to_fail);
14
15         return malloc(len);
16 }
17
18 static void nofail_on_error(const char *msg)
19 {
20         diag("ERROR: %s", msg);
21         err_count++;
22 }
23
24 static void destroy_p(void *p)
25 {
26 }
27
28 int main(void)
29 {
30         void *p, *c1, *c2;
31         bool success;
32
33         plan_tests(21);
34
35         tal_set_backend(failing_alloc, NULL, NULL, nofail_on_error);
36
37         /* Fail at each possible point in an allocation. */
38         when_to_fail = err_count = 0;
39         do {
40                 alloc_count = 0;
41                 p = tal(NULL, char);
42                 when_to_fail++;
43         } while (!p);
44         ok1(alloc_count >= 1);
45         ok1(when_to_fail > 1);
46         ok1(err_count == when_to_fail - 1);
47
48         /* Do it again. */
49         when_to_fail = err_count = 0;
50         do {
51                 alloc_count = 0;
52                 c1 = tal(p, char);
53                 when_to_fail++;
54         } while (!c1);
55         ok1(alloc_count >= 1);
56         ok1(when_to_fail > 1);
57         ok1(err_count == when_to_fail - 1);
58
59         /* Now for second child. */
60         when_to_fail = err_count = 0;
61         do {
62                 alloc_count = 0;
63                 c2 = tal(p, char);
64                 when_to_fail++;
65         } while (!c2);
66         ok1(alloc_count >= 1);
67         ok1(when_to_fail > 1);
68         /* Note: adding a child will fall through if group alloc fails. */
69         ok1 (err_count == when_to_fail - 1 || err_count == when_to_fail);
70
71         /* Now while adding a destructor. */
72         when_to_fail = err_count = 0;
73         do {
74                 alloc_count = 0;
75                 success = tal_add_destructor(p, destroy_p);
76                 when_to_fail++;
77         } while (!success);
78         ok1(alloc_count >= 1);
79         ok1(when_to_fail > 1);
80         ok1(err_count == when_to_fail - 1);
81
82         /* Now while adding a name. */
83         when_to_fail = err_count = 0;
84         do {
85                 const char name[] = "some name";
86                 alloc_count = 0;
87                 success = tal_set_name(p, name);
88                 when_to_fail++;
89         } while (!success);
90         ok1(alloc_count >= 1);
91         ok1(when_to_fail > 1);
92         ok1(err_count == when_to_fail - 1);
93
94         /* Now while stealing. */
95         stealing = true;
96         when_to_fail = err_count = 0;
97         do {
98                 alloc_count = 0;
99                 success = tal_steal(c2, c1) != NULL;
100                 when_to_fail++;
101         } while (!success);
102         ok1(alloc_count >= 1);
103         ok1(when_to_fail > 1);
104         ok1(err_count == when_to_fail - 1);
105
106         /* Now stealing with more children (more coverage). */
107         when_to_fail = 1000;
108         (void)tal(p, char);
109         c1 = tal(p, char);
110         c2 = tal(p, char);
111         (void)tal(p, char);
112
113         /* Now steal again. */
114         when_to_fail = err_count = 0;
115         do {
116                 alloc_count = 0;
117                 success = tal_steal(c2, c1) != NULL;
118                 when_to_fail++;
119         } while (!success);
120         ok1(alloc_count >= 1);
121         ok1(when_to_fail > 1);
122         ok1(err_count == when_to_fail - 1);
123
124         tal_free(p);
125         return exit_status();
126 }