pushpull: new module.
[ccan] / ccan / pushpull / test / run.c
1 #include <ccan/pushpull/pushpull.h>
2 /* Include the C files directly. */
3 #include <ccan/pushpull/push.c>
4 #include <ccan/pushpull/pull.c>
5 #include <ccan/tap/tap.h>
6
7 struct foo {
8         uint64_t vu64;
9         uint32_t vu32;
10         uint16_t vu16;
11         uint8_t vu8;
12         unsigned char vuchar;
13         int64_t vs64;
14         int32_t vs32;
15         int16_t vs16;
16         int8_t vs8;
17         char vchar;
18         char bytes[100];
19 };
20
21 static void *fail_reallocfn(void *ptr, size_t size)
22 {
23         return NULL;
24 }
25
26 static bool push_foo(char **p, size_t *len, const struct foo *foo)
27 {
28         return push_u64(p, len, foo->vu64) &&
29                 push_u32(p, len, foo->vu32) &&
30                 push_u16(p, len, foo->vu16) &&
31                 push_u8(p, len, foo->vu8) &&
32                 push_uchar(p, len, foo->vuchar) &&
33                 push_s64(p, len, foo->vs64) &&
34                 push_s32(p, len, foo->vs32) &&
35                 push_s16(p, len, foo->vs16) &&
36                 push_s8(p, len, foo->vs8) &&
37                 push_char(p, len, foo->vchar) &&
38                 push_bytes(p, len, foo->bytes, sizeof(foo->bytes));
39 }
40
41 static bool pull_foo(const char **p, size_t *len, struct foo *foo)
42 {
43         int ret;
44
45         ret = pull_u64(p, len, &foo->vu64) +
46                 pull_u32(p, len, &foo->vu32) +
47                 pull_u16(p, len, &foo->vu16) +
48                 pull_u8(p, len, &foo->vu8) +
49                 pull_uchar(p, len, &foo->vuchar) +
50                 pull_s64(p, len, &foo->vs64) +
51                 pull_s32(p, len, &foo->vs32) +
52                 pull_s16(p, len, &foo->vs16) +
53                 pull_s8(p, len, &foo->vs8) +
54                 pull_char(p, len, &foo->vchar) +
55                 pull_bytes(p, len, foo->bytes, sizeof(foo->bytes));
56
57         if (ret != 11)
58                 ok1(len == 0 && *p == NULL);
59         return ret == 11;
60 }
61
62 static bool foo_equal(const struct foo *f1, const struct foo *f2)
63 {
64         return f1->vu64 == f2->vu64 &&
65                 f1->vu32 == f2->vu32 &&
66                 f1->vu16 == f2->vu16 &&
67                 f1->vu8 == f2->vu8 &&
68                 f1->vuchar == f2->vuchar &&
69                 f1->vs64 == f2->vs64 &&
70                 f1->vs32 == f2->vs32 &&
71                 f1->vs16 == f2->vs16 &&
72                 f1->vs8 == f2->vs8 &&
73                 f1->vchar == f2->vchar &&
74                 memcmp(f1->bytes, f2->bytes, sizeof(f1->bytes)) == 0;
75 }
76
77 int main(void)
78 {
79         char *buffer;
80         const char *p;
81         size_t len, left;
82         struct foo *foo, *foo2;
83
84         /* This is how many tests you plan to run */
85         plan_tests(17);
86
87         /* Valgrind will make sure we don't read padding! */
88         foo = malloc(sizeof(*foo));
89         foo->vu64 = 0x01020304050607ULL;
90         foo->vu32 = 0x08090a0b;
91         foo->vu16 = 0x0c0d;
92         foo->vu8 = 0x0e;
93         foo->vuchar = 0x0f;
94         foo->vs64 = -0x1011121314151617LL;
95         foo->vs32 = -0x18191a1b;
96         foo->vs16 = -0x1c1d;
97         foo->vs8 = -0x1e;
98         foo->vchar = -0x1f;
99         memset(foo->bytes, 0x20, sizeof(foo->bytes));
100         strcpy(foo->bytes, "This is a test");
101
102         buffer = malloc(1);
103         len = 0;
104         ok1(push_foo(&buffer, &len, foo));
105         ok1(len <= sizeof(*foo));
106
107         /* Triggers valgrind's uninitialized value warning */
108         ok1(!memchr(buffer, 0x21, len));
109
110         p = buffer;
111         left = len;
112         foo2 = malloc(sizeof(*foo2));
113         ok1(pull_foo(&p, &left, foo2));
114         ok1(left == 0);
115         ok1(p == buffer + len);
116         ok1(foo_equal(foo, foo2));
117
118         /* Too-small for pull, it should fail and set ptr/len to 0 */
119         p = buffer;
120         left = 0;
121         ok1(!pull_u64(&p, &left, &foo2->vu64));
122         ok1(p == NULL && left == 0);
123         /* Shouldn't change field! */
124         ok1(foo_equal(foo, foo2));
125
126         left = 7;
127         ok1(!pull_u64(&p, &left, &foo2->vu64));
128         ok1(p == NULL && left == 0);
129         /* Shouldn't change field! */
130         ok1(foo_equal(foo, foo2));
131
132         /* Discard should work. */
133         left = len;
134         ok1(pull_bytes(&p, &left, NULL, sizeof(foo->bytes)));
135         ok1(left == len - sizeof(foo->bytes));
136
137         /* Push failures should be clean. */
138         push_set_realloc(fail_reallocfn);
139         p = buffer;
140         left = len;
141         ok1(!push_u64(&buffer, &left, foo->vu64));
142         ok1(p == buffer && left == len);
143
144         free(buffer);
145         free(foo);
146         free(foo2);
147
148         /* This exits depending on whether all tests passed */
149         return exit_status();
150 }