log framework
[protos/libecoli.git] / lib / ecoli_test.c
1 /*
2  * Copyright (c) 2016, Olivier MATZ <zer0@droids-corp.org>
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  *     * Redistributions of source code must retain the above copyright
8  *       notice, this list of conditions and the following disclaimer.
9  *     * Redistributions in binary form must reproduce the above copyright
10  *       notice, this list of conditions and the following disclaimer in the
11  *       documentation and/or other materials provided with the distribution.
12  *     * Neither the name of the University of California, Berkeley nor the
13  *       names of its contributors may be used to endorse or promote products
14  *       derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <string.h>
31
32 #include <ecoli_log.h>
33 #include <ecoli_malloc.h>
34 #include <ecoli_test.h>
35 #include <ecoli_tk.h>
36
37 static struct ec_test_list test_list = TAILQ_HEAD_INITIALIZER(test_list);
38
39 /* register a driver */
40 void ec_test_register(struct ec_test *test)
41 {
42         TAILQ_INSERT_TAIL(&test_list, test, next);
43 }
44
45 int ec_test_check_tk_parse(const struct ec_tk *tk, const char *input,
46         const char *expected)
47 {
48         struct ec_parsed_tk *p;
49         const char *s;
50         int ret = -1;
51
52         p = ec_tk_parse(tk, input);
53         s = ec_parsed_tk_to_string(p);
54         if (s == NULL && expected == NULL)
55                 ret = 0;
56         else if (s != NULL && expected != NULL &&
57                 !strcmp(s, expected))
58                 ret = 0;
59
60         if (expected == NULL && ret != 0)
61                 ec_log(EC_LOG_ERR, "tk should not match but matches <%s>\n", s);
62         if (expected != NULL && ret != 0)
63                 ec_log(EC_LOG_ERR, "tk should match <%s> but matches <%s>\n",
64                         expected, s);
65
66         ec_parsed_tk_free(p);
67
68         return ret;
69 }
70
71 int ec_test_check_tk_complete(const struct ec_tk *tk, const char *input,
72         const char *expected)
73 {
74         struct ec_completed_tk *p;
75         const char *s;
76         int ret = -1;
77
78         p = ec_tk_complete(tk, input);
79         s = ec_completed_tk_smallest_start(p);
80         if (s == NULL && expected == NULL)
81                 ret = 0;
82         else if (s != NULL && expected != NULL &&
83                 !strcmp(s, expected))
84                 ret = 0;
85
86         if (expected == NULL && ret != 0)
87                 ec_log(EC_LOG_ERR,
88                         "tk should not complete but completes with <%s>\n", s);
89         if (expected != NULL && ret != 0)
90                 ec_log(EC_LOG_ERR,
91                         "tk should complete with <%s> but completes with <%s>\n",
92                         expected, s);
93
94         ec_completed_tk_free(p);
95
96         return ret;
97 }
98
99 TAILQ_HEAD(debug_alloc_hdr_list, debug_alloc_hdr);
100 static struct debug_alloc_hdr_list debug_alloc_hdr_list =
101         TAILQ_HEAD_INITIALIZER(debug_alloc_hdr_list);
102
103 struct debug_alloc_hdr {
104         TAILQ_ENTRY(debug_alloc_hdr) next;
105         const char *file;
106         unsigned int line;
107         size_t size;
108         unsigned int cookie;
109 };
110
111 static void *debug_malloc(size_t size, const char *file, unsigned int line)
112 {
113         struct debug_alloc_hdr *hdr;
114         size_t new_size = size + sizeof(*hdr) + sizeof(unsigned int);
115         void *ret;
116
117         hdr = malloc(new_size);
118         if (hdr == NULL) {
119                 ret = NULL;
120         } else {
121                 hdr->file = file;
122                 hdr->line = line;
123                 hdr->size = size;
124                 hdr->cookie = 0x12345678;
125                 TAILQ_INSERT_TAIL(&debug_alloc_hdr_list, hdr, next);
126                 ret = hdr + 1;
127         }
128
129         ec_log(EC_LOG_INFO, "%s:%d: info: malloc(%zd) -> %p\n",
130                 file, line, size, ret);
131
132         return ret;
133 }
134
135 static void debug_free(void *ptr, const char *file, unsigned int line)
136 {
137         struct debug_alloc_hdr *hdr, *h;
138
139         (void)file;
140         (void)line;
141
142         ec_log(EC_LOG_INFO, "%s:%d: info: free(%p)\n", file, line, ptr);
143
144         if (ptr == NULL)
145                 return;
146
147         hdr = (ptr - sizeof(*hdr));
148         if (hdr->cookie != 0x12345678) {
149                 ec_log(EC_LOG_ERR, "%s:%d: error: free(%p): bad start cookie\n",
150                         file, line, ptr);
151                 abort();
152         }
153
154         TAILQ_FOREACH(h, &debug_alloc_hdr_list, next) {
155                 if (h == hdr)
156                         break;
157         }
158
159         if (h == NULL) {
160                 ec_log(EC_LOG_ERR, "%s:%d: error: free(%p): bad ptr\n",
161                         file, line, ptr);
162                 abort();
163         }
164
165         TAILQ_REMOVE(&debug_alloc_hdr_list, hdr, next);
166         free(hdr);
167 }
168
169 void *debug_realloc(void *ptr, size_t size, const char *file, unsigned int line)
170 {
171         struct debug_alloc_hdr *hdr = (ptr - sizeof(*hdr));
172         struct debug_alloc_hdr *h;
173         size_t new_size = size + sizeof(*hdr) + sizeof(unsigned int);
174         void *ret;
175
176         if (ptr != NULL) {
177                 if (hdr->cookie != 0x12345678) {
178                         ec_log(EC_LOG_ERR, "%s:%d: error: realloc(%p): bad start cookie\n",
179                                 file, line, ptr);
180                         abort();
181                 }
182
183                 TAILQ_FOREACH(h, &debug_alloc_hdr_list, next) {
184                         if (h == hdr)
185                                 break;
186                 }
187
188                 if (h == NULL) {
189                         ec_log(EC_LOG_ERR, "%s:%d: error: realloc(%p): bad ptr\n",
190                                 file, line, ptr);
191                         abort();
192                 }
193
194                 TAILQ_REMOVE(&debug_alloc_hdr_list, h, next);
195                 hdr = realloc(hdr, new_size);
196                 if (hdr == NULL) {
197                         TAILQ_INSERT_TAIL(&debug_alloc_hdr_list, h, next);
198                         ret = NULL;
199                 } else {
200                         ret = hdr + 1;
201                 }
202         } else {
203                 hdr = realloc(NULL, new_size);
204                 if (hdr == NULL)
205                         ret = NULL;
206                 else
207                         ret= hdr + 1;
208         }
209
210         if (hdr != NULL) {
211                 hdr->file = file;
212                 hdr->line = line;
213                 hdr->size = size;
214                 hdr->cookie = 0x12345678;
215                 TAILQ_INSERT_TAIL(&debug_alloc_hdr_list, hdr, next);
216         }
217
218         ec_log(EC_LOG_INFO, "%s:%d: info: realloc(%p, %zd) -> %p\n",
219                 file, line, ptr, size, ret);
220
221         return ret;
222 }
223
224 void debug_alloc_dump(void)
225 {
226         struct debug_alloc_hdr *hdr;
227
228         TAILQ_FOREACH(hdr, &debug_alloc_hdr_list, next) {
229                 ec_log(EC_LOG_ERR, "%s:%d: error: memory leak size=%zd ptr=%p\n",
230                         hdr->file, hdr->line, hdr->size, hdr + 1);
231         }
232 }
233
234 /* XXX todo */
235 /* int ec_test_check_tk_complete_list(const struct ec_tk *tk, */
236 /*      const char *input, ...) */
237
238 int ec_test_all(void)
239 {
240         struct ec_test *test;
241         int ret = 0;
242
243         TAILQ_INIT(&debug_alloc_hdr_list);
244
245         /* register a new malloc to trac memleaks */
246         if (ec_malloc_register(debug_malloc, debug_free, debug_realloc) < 0) {
247                 ec_log(EC_LOG_ERR, "cannot register new malloc\n");
248                 return -1;
249         }
250
251         TAILQ_FOREACH(test, &test_list, next) {
252                 if (test->test() == 0) {
253                         ec_log(EC_LOG_INFO, "== test %-20s success\n",
254                                 test->name);
255                 } else {
256                         ec_log(EC_LOG_INFO, "== test %-20s failed\n",
257                                 test->name);
258                         ret = -1;
259                 }
260         }
261
262         ec_malloc_unregister();
263         debug_alloc_dump();
264
265         return ret;
266 }