tal: allow notifiers on NULL.
[ccan] / ccan / tal / test / run-notifier.c
1 #include <ccan/tal/tal.h>
2 #include <ccan/tal/tal.c>
3 #include <ccan/tap/tap.h>
4
5 static enum tal_notify_type expect;
6 static void *expect_info;
7 static char *ctx;
8 static unsigned int notified1, notified2, notified_null;
9
10 /* Make sure we always move on resize. */
11 static void *my_realloc(void *old, size_t size)
12 {
13         void *new = realloc(old, size);
14         if (new == old) {
15                 void *p = malloc(size);
16                 memcpy(p, old, size);
17                 free(old);
18                 new = p;
19         }
20         return new;
21 }
22
23 static void notify1(char *p, enum tal_notify_type notify, void *info)
24 {
25         ok1(p == ctx);
26         ok1(notify == expect);
27         if (expect_info == &expect_info)
28                 expect_info = info;
29         else
30                 ok1(info == expect_info);
31         notified1++;
32 }
33
34 static void notify2(char *ctx UNNEEDED,
35                     enum tal_notify_type notify UNNEEDED,
36                     void *info UNNEEDED)
37 {
38         notified2++;
39 }
40
41 static void notify_null(void *p, enum tal_notify_type notify, void *info)
42 {
43         ok1(p == NULL);
44         ok1(notify == expect);
45         if (expect_info == &expect_info)
46                 expect_info = info;
47         else
48                 ok1(info == expect_info);
49         notified_null++;
50 }
51
52 static bool seen_move, seen_resize;
53 static void resize_notifier(char *p, enum tal_notify_type notify, void *info)
54 {
55         if (notify == TAL_NOTIFY_MOVE) {
56                 ok1(!seen_move);
57                 ok1(!seen_resize);
58                 ok1(info == ctx);
59                 ok1(p != ctx);
60                 ctx = p;
61                 seen_move = true;
62         } else if (notify == TAL_NOTIFY_RESIZE) {
63                 ok1(!seen_resize);
64                 ok1(seen_move);
65                 ok1(p == ctx);
66                 ok1((size_t)info == 100);
67                 seen_resize = true;
68         } else
69                 fail("Unexpected notifier %i", notify);
70 }
71
72 int main(void)
73 {
74         char *child, *new_ctx;
75
76         plan_tests(65);
77
78         ctx = tal(NULL, char);
79         ok1(tal_add_notifier(ctx, 511, notify1));
80         ok1(notified1 == 0);
81         ok1(notified2 == 0);
82
83         expect = TAL_NOTIFY_STEAL;
84         expect_info = NULL;
85         ok1(tal_steal(NULL, ctx) == ctx);
86         ok1(notified1 == 1);
87
88         expect = TAL_NOTIFY_ADD_NOTIFIER;
89         expect_info = notify2;
90         ok1(tal_add_notifier(ctx, TAL_NOTIFY_RENAME|TAL_NOTIFY_ADD_NOTIFIER
91                              |TAL_NOTIFY_DEL_NOTIFIER, notify2));
92         ok1(notified1 == 2);
93         ok1(notified2 == 0);
94
95         expect = TAL_NOTIFY_RENAME;
96         expect_info = (char *)"newname";
97         ok1(tal_set_name(ctx, (char *)expect_info));
98         ok1(notified1 == 3);
99         ok1(notified2 == 1);
100
101         expect = TAL_NOTIFY_DEL_NOTIFIER;
102         expect_info = notify2;
103         ok1(tal_del_notifier(ctx, notify2));
104         ok1(notified1 == 4);
105         ok1(notified2 == 1);
106
107         /* Failed delete should not call notifier! */
108         expect = TAL_NOTIFY_DEL_NOTIFIER;
109         expect_info = notify2;
110         ok1(!tal_del_notifier(ctx, notify2));
111         ok1(notified1 == 4);
112         ok1(notified2 == 1);
113
114         expect = TAL_NOTIFY_ADD_CHILD;
115         expect_info = &expect_info;
116         child = tal(ctx, char);
117         ok1(notified1 == 5);
118         ok1(notified2 == 1);
119         ok1(expect_info == child);
120
121         expect = TAL_NOTIFY_DEL_CHILD;
122         expect_info = child;
123         tal_free(child);
124         ok1(notified1 == 6);
125         ok1(notified2 == 1);
126
127         expect = TAL_NOTIFY_FREE;
128         expect_info = ctx;
129         tal_free(ctx);
130         ok1(notified1 == 7);
131         ok1(notified2 == 1);
132
133         /* Notifiers on NULL work, too. */
134         ok1(tal_add_notifier(NULL, TAL_NOTIFY_ADD_CHILD|TAL_NOTIFY_DEL_CHILD,
135                              notify_null));
136         expect = TAL_NOTIFY_ADD_CHILD;
137         expect_info = &expect_info;
138         child = tal(NULL, char);
139         ok1(notified_null == 1);
140
141         expect = TAL_NOTIFY_DEL_CHILD;
142         expect_info = child;
143         tal_free(child);
144         ok1(notified_null == 2);
145         ok1(tal_del_notifier(NULL, notify_null));
146
147         tal_set_backend(NULL, my_realloc, NULL, NULL);
148         ctx = new_ctx = tal(NULL, char);
149         ok1(tal_add_notifier(new_ctx, 511, resize_notifier));
150         ok1(tal_resize(&new_ctx, 100));
151         ok1(seen_move);
152         ok1(seen_resize);
153         tal_del_notifier(new_ctx, resize_notifier);
154         tal_free(new_ctx);
155
156         tal_cleanup();
157         return exit_status();
158 }