Merge "lpc10: Avoid compiler warning when DONT_OPTIMIZE/COMPILE_DOUBLE."
[asterisk/asterisk.git] / tests / test_stringfields.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2009, Mark Michelson
5  *
6  * Mark Michelson <mmmichelson@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief String fields test
22  *
23  * \author\verbatim Mark Michelson <mmichelson@digium.com> \endverbatim
24  *
25  * Test module for string fields API
26  * \ingroup tests
27  */
28
29 /*** MODULEINFO
30         <depend>TEST_FRAMEWORK</depend>
31         <support_level>core</support_level>
32  ***/
33
34 #include "asterisk.h"
35 #include "asterisk/module.h"
36 #include "asterisk/stringfields.h"
37 #include "asterisk/cli.h"
38 #include "asterisk/utils.h"
39 #include "asterisk/test.h"
40
41 AST_TEST_DEFINE(string_field_test)
42 {
43         const char *address_holder;
44         struct ast_string_field_pool *field_pool1;
45         struct ast_string_field_pool *field_pool2;
46         struct ast_string_field_pool *field_pool3;
47         static const char LONG_STRING[] = "A professional panoramic photograph of the majestic elephant bathing itself and its young by the shores of the raging Mississippi River";
48
49         struct {
50                 AST_DECLARE_STRING_FIELDS (
51                         AST_STRING_FIELD(string1);
52                 );
53                 AST_STRING_FIELD_EXTENDED(string2);
54         } test_struct;
55
56         struct {
57                 AST_DECLARE_STRING_FIELDS (
58                         AST_STRING_FIELD(string1);
59                         AST_STRING_FIELD(string2);
60                 );
61                 AST_STRING_FIELD_EXTENDED(string3);
62         } test_struct2;
63
64         switch (cmd) {
65         case TEST_INIT:
66                 info->name = "string_field_test";
67                 info->category = "/main/utils/";
68                 info->summary = "Test stringfield operations";
69                 info->description =
70                         "This tests the stringfield API";
71                 return AST_TEST_NOT_RUN;
72         case TEST_EXECUTE:
73                 break;
74         }
75
76         memset(&test_struct, 0, sizeof(test_struct));
77         memset(&test_struct2, 0, sizeof(test_struct));
78
79         ast_test_status_update(test, "First things first. Let's see if we can actually allocate string fields\n");
80
81         if (ast_string_field_init(&test_struct, 32)) {
82                 ast_test_status_update(test, "Failure to initialize string fields. They are totally messed up\n");
83                 return AST_TEST_FAIL;
84         } else {
85                 ast_test_status_update(test, "All right! Successfully allocated! Now let's get down to business\n");
86         }
87         ast_string_field_init_extended(&test_struct, string2);
88
89         ast_test_status_update(test,"We're going to set some string fields and perform some checks\n");
90
91         ast_string_field_set(&test_struct, string1, "elephant");
92         ast_string_field_set(&test_struct, string2, "hippopotamus");
93
94         ast_test_status_update(test, "First we're going to make sure that the strings are actually set to what we expect\n");
95
96         if (strcmp(test_struct.string1, "elephant")) {
97                 ast_test_status_update(test, "We were expecting test_struct.string1 to have 'elephant' but it has %s\n", test_struct.string1);
98                 goto error;
99         } else {
100                 ast_test_status_update(test, "test_struct.string1 appears to be all clear. It has '%s' and that's what we expect\n", test_struct.string1);
101         }
102
103         if (strcmp(test_struct.string2, "hippopotamus")) {
104                 ast_test_status_update(test, "We were expecting test_struct.string2 to have 'hippopotamus' but it has %s\n", test_struct.string2);
105                 goto error;
106         } else {
107                 ast_test_status_update(test, "test_struct.string2 appears to be all clear. It has '%s' and that's what we expect\n", test_struct.string2);
108         }
109
110         ast_test_status_update(test, "Now let's make sure that our recorded capacities for these strings is what we expect\n");
111
112         if (AST_STRING_FIELD_ALLOCATION(test_struct.string1) != strlen("elephant") + 1) {
113                 ast_test_status_update(test, "string1 has allocation area of %hu but we expect %lu\n",
114                                 AST_STRING_FIELD_ALLOCATION(test_struct.string1), (unsigned long) strlen("elephant") + 1);
115                 goto error;
116         } else {
117                 ast_test_status_update(test, "string1 has the allocation area we expect: %hu\n", AST_STRING_FIELD_ALLOCATION(test_struct.string1));
118         }
119
120         if (AST_STRING_FIELD_ALLOCATION(test_struct.string2) != strlen("hippopotamus") + 1) {
121                 ast_test_status_update(test, "string2 has allocation area of %hu but we expect %lu\n",
122                                 AST_STRING_FIELD_ALLOCATION(test_struct.string2), (unsigned long) strlen("hippopotamus") + 1);
123                 goto error;
124         } else {
125                 ast_test_status_update(test, "string2 has the allocation area we expect: %hu\n", AST_STRING_FIELD_ALLOCATION(test_struct.string2));
126         }
127
128         ast_test_status_update(test, "Now we're going to shrink string1 and see if it's in the same place in memory\n");
129
130         address_holder = test_struct.string1;
131         ast_string_field_set(&test_struct, string1, "rhino");
132
133         if (strcmp(test_struct.string1, "rhino")) {
134                 ast_test_status_update(test, "string1 has the wrong value in it. We want 'rhino' but it has '%s'\n", test_struct.string1);
135                 goto error;
136         } else {
137                 ast_test_status_update(test, "string1 successfully was changed to '%s'\n", test_struct.string1);
138         }
139
140         if (address_holder != test_struct.string1) {
141                 ast_test_status_update(test, "We shrunk string1, but it moved?!\n");
142                 goto error;
143         } else {
144                 ast_test_status_update(test, "Shrinking string1 allowed it to stay in the same place in memory\n");
145         }
146
147         if (AST_STRING_FIELD_ALLOCATION(test_struct.string1) != strlen("elephant") + 1) {
148                 ast_test_status_update(test, "The allocation amount changed when we shrunk the string...\n");
149                 goto error;
150         } else {
151                 ast_test_status_update(test, "Shrinking string1 did not change its allocation area (This is a good thing)\n");
152         }
153
154         ast_test_status_update(test, "Next, let's increase it a little but not all the way to its original size\n");
155
156         address_holder = test_struct.string1;
157         ast_string_field_set(&test_struct, string1, "mammoth");
158
159         if (strcmp(test_struct.string1, "mammoth")) {
160                 ast_test_status_update(test, "string1 has the wrong value in it. We want 'mammoth' but it has '%s'\n", test_struct.string1);
161                 goto error;
162         } else {
163                 ast_test_status_update(test, "string1 successfully was changed to '%s'\n", test_struct.string1);
164         }
165
166         if (address_holder != test_struct.string1) {
167                 ast_test_status_update(test, "We expanded string1, but it moved?!\n");
168                 goto error;
169         } else {
170                 ast_test_status_update(test, "Expanding string1 allowed it to stay in the same place in memory\n");
171         }
172
173         if (AST_STRING_FIELD_ALLOCATION(test_struct.string1) != strlen("elephant") + 1) {
174                 ast_test_status_update(test, "The allocation amount changed when we expanded the string...\n");
175                 goto error;
176         } else {
177                 ast_test_status_update(test, "Expanding string1 did not change its allocation area (This is a good thing)\n");
178         }
179
180         ast_test_status_update(test, "Cool, now let's bring it back to its original size and see what happens\n");
181
182         ast_string_field_set(&test_struct, string1, "elephant");
183
184         if (strcmp(test_struct.string1, "elephant")) {
185                 ast_test_status_update(test, "string1 has the wrong value in it. We want 'elephant' but it has '%s'\n", test_struct.string1);
186                 goto error;
187         } else {
188                 ast_test_status_update(test, "string1 successfully changed to '%s'\n", test_struct.string1);
189         }
190
191         if (address_holder != test_struct.string1) {
192                 ast_test_status_update(test, "We restored string1 to its original size, but it moved?!\n");
193                 goto error;
194         } else {
195                 ast_test_status_update(test, "Restoring string1 did not cause it to move (This is a good thing)\n");
196         }
197
198         if (AST_STRING_FIELD_ALLOCATION(test_struct.string1) != strlen("elephant") + 1) {
199                 ast_test_status_update(test, "The allocation amount changed when we re-expanded the string...\n");
200                 goto error;
201         } else {
202                 ast_test_status_update(test, "The allocation amount for string1 is still holding steady\n");
203         }
204
205         ast_test_status_update(test, "All right, now we're going to expand string 2. It should stay in place since it was the last string allocated in this pool\n");
206
207         address_holder = test_struct.string2;
208         ast_string_field_set(&test_struct, string2, "hippopotamus face");
209
210         if (strcmp(test_struct.string2, "hippopotamus face")) {
211                 ast_test_status_update(test, "string2 has the wrong value. We want 'hippopotamus face' but it has '%s'\n", test_struct.string2);
212                 goto error;
213         } else {
214                 ast_test_status_update(test, "string2 successfully changed to '%s'\n", test_struct.string2);
215         }
216
217         if (AST_STRING_FIELD_ALLOCATION(test_struct.string2) != strlen("hippopotamus face") + 1) {
218                 ast_test_status_update(test, "The allocation amount is incorrect for string2. We expect %lu but it has %d\n",
219                                 (unsigned long) strlen("hippopotamus face"), AST_STRING_FIELD_ALLOCATION(test_struct.string2) + 1);
220                 goto error;
221         } else {
222                 ast_test_status_update(test, "The allocation amount successfully increased for string2 when it grew\n");
223         }
224
225         if (test_struct.string2 != address_holder) {
226                 ast_test_status_update(test, "string2 has moved, but it should not have since it had room to grow\n");
227                 goto error;
228         } else {
229                 ast_test_status_update(test, "string2 stayed in place when it grew. Good job!\n");
230         }
231
232         ast_test_status_update(test, "Now we're going to set string1 to a very long string so that a new string field pool must be allocated\n");
233
234         address_holder = test_struct.string1;
235         ast_string_field_set(&test_struct, string1, LONG_STRING);
236
237         if (strcmp(test_struct.string1, LONG_STRING)) {
238                 ast_test_status_update(test, "We were expecting string1 to be '%s'\nbut it was actually '%s'\n", LONG_STRING, test_struct.string1);
239                 goto error;
240         } else {
241                 ast_test_status_update(test, "string1 successfully changed to '%s'\n", test_struct.string1);
242         }
243
244         if (address_holder == test_struct.string1) {
245                 ast_test_status_update(test, "Uh oh, string1 didn't move when we set it to a long value\n");
246                 goto error;
247         } else {
248                 ast_test_status_update(test, "Good. Setting string1 to a long value caused it to change addresses\n");
249         }
250
251         if (AST_STRING_FIELD_ALLOCATION(test_struct.string1) != strlen(LONG_STRING) + 1) {
252                 ast_test_status_update(test, "The string field allocation for string1 indicates a length of %hu instead of the expected %lu\n",
253                                 AST_STRING_FIELD_ALLOCATION(test_struct.string1), (unsigned long) strlen(LONG_STRING) + 1);
254                 goto error;
255         } else {
256                 ast_test_status_update(test, "The stored allocation size of string1 is what we expect\n");
257         }
258
259         ast_string_field_init(&test_struct2, 32);
260         ast_test_status_update(test, "Now using a totally separate area of memory we're going to test a basic pool freeing scenario\n");
261         ast_string_field_init_extended(&test_struct2, string3);
262
263
264         ast_string_field_set(&test_struct2, string1, "first");
265         ast_string_field_set(&test_struct2, string2, "second");
266         ast_string_field_set(&test_struct2, string3, "third");
267
268         /* This string is 208 characters long, which will surely exceed the initial pool size */
269         ast_string_field_set(&test_struct2, string1, "Expanded first string to create new pool-----------------------------------------------------------------------------------------------------------------------------------------------------------------------");
270         /* Pool size at this point is 976, so 1000 chars should do it */
271         ast_string_field_set(&test_struct2, string2, "Expanded second string to create new pool----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
272
273         field_pool3 = test_struct2.__field_mgr_pool;
274         field_pool2 = test_struct2.__field_mgr_pool->prev;
275         field_pool1 = test_struct2.__field_mgr_pool->prev->prev;
276
277         if(field_pool3->prev != field_pool2 || field_pool2->prev != field_pool1) {
278                 ast_test_status_update(test, "Pools are not linked properly!\n");
279                 goto error;
280         } else {
281                 ast_test_status_update(test, "Three different pools are linked as expected.\n");
282         }
283
284         ast_string_field_set(&test_struct2, string1, NULL);
285         if (test_struct2.string1 != __ast_string_field_empty || field_pool3->prev != field_pool1) {
286                 ast_test_status_update(test, "Things did not work out when removing the middle pool!\n");
287                 goto error;
288         } else {
289                 ast_test_status_update(test, "After removing a pool the remaining two are linked as expected.\n");
290         }
291
292         ast_string_field_free_memory(&test_struct2);
293         ast_string_field_free_memory(&test_struct);
294         return AST_TEST_PASS;
295
296 error:
297         ast_string_field_free_memory(&test_struct);
298         ast_string_field_free_memory(&test_struct2);
299         return AST_TEST_FAIL;
300 }
301
302 struct test_struct {
303         int foo;
304         AST_DECLARE_STRING_FIELDS (
305                 AST_STRING_FIELD(string1);
306         );
307         int foo2;
308         AST_STRING_FIELD_EXTENDED(string2);
309 };
310
311 AST_TEST_DEFINE(string_field_aggregate_test)
312 {
313         enum ast_test_result_state res = AST_TEST_PASS;
314         struct test_struct *inst1 = NULL;
315         struct test_struct *inst2 = NULL;
316         struct test_struct *inst3 = NULL;
317         struct test_struct *inst4 = NULL;
318
319         switch (cmd) {
320         case TEST_INIT:
321                 info->name = "string_field_aggregate_test";
322                 info->category = "/main/utils/";
323                 info->summary = "Test stringfield aggregate operations";
324                 info->description =
325                         "This tests the structure comparison and copy macros of the stringfield API";
326                 return AST_TEST_NOT_RUN;
327         case TEST_EXECUTE:
328                 break;
329         }
330
331         inst1 = ast_calloc_with_stringfields(1, struct test_struct, 32);
332         if (!inst1) {
333                 ast_test_status_update(test, "Unable to allocate structure 1!\n");
334                 res = AST_TEST_FAIL;
335                 goto error;
336         }
337         ast_string_field_init_extended(inst1, string2);
338
339         inst2 = ast_calloc_with_stringfields(1, struct test_struct, 32);
340         if (!inst2) {
341                 ast_test_status_update(test, "Unable to allocate structure 2!\n");
342                 res = AST_TEST_FAIL;
343                 goto error;
344         }
345         ast_string_field_init_extended(inst2, string2);
346
347         inst3 = ast_calloc_with_stringfields(1, struct test_struct, 32);
348         if (!inst3) {
349                 ast_test_status_update(test, "Unable to allocate structure 3!\n");
350                 res = AST_TEST_FAIL;
351                 goto error;
352         }
353         ast_string_field_init_extended(inst3, string2);
354
355         inst4 = ast_calloc_with_stringfields(1, struct test_struct, 32);
356         if (!inst4) {
357                 ast_test_status_update(test, "Unable to allocate structure 4!\n");
358                 res = AST_TEST_FAIL;
359                 goto error;
360         }
361         ast_string_field_init_extended(inst4, string2);
362
363
364         ast_string_field_set(inst1, string1, "foo");
365         ast_string_field_set(inst1, string2, "bar");
366         inst1->foo = 1;
367
368         ast_string_field_ptr_set_by_fields(inst2->__field_mgr_pool, inst2->__field_mgr, &inst2->string2, "bar");
369         ast_string_field_ptr_set_by_fields(inst2->__field_mgr_pool, inst2->__field_mgr, &inst2->string1, "foo");
370         inst2->foo = 2;
371
372         if (inst3->__field_mgr.embedded_pool->prev) {
373                 ast_test_status_update(test, "Structure 3 embedded pool should not have a previous pool!\n");
374                 res = AST_TEST_FAIL;
375                 goto error;
376         }
377
378         ast_string_field_set(inst3, string1, "foo");
379
380         if (inst3->__field_mgr.embedded_pool != inst3->__field_mgr_pool) {
381                 ast_test_status_update(test, "Structure 3 embedded pool should have been the current pool!\n");
382                 res = AST_TEST_FAIL;
383                 goto error;
384         }
385
386         if (inst3->__field_mgr.embedded_pool->prev) {
387                 ast_test_status_update(test, "Structure 3 embedded pool should not have a previous pool!\n");
388                 res = AST_TEST_FAIL;
389                 goto error;
390         }
391
392         ast_test_status_update(test, "Structures 3 embedded pool initialized successfully.\n");
393
394         /* Exhaust the embedded pool */
395         ast_string_field_set(inst3, string2, "baz 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890");
396         inst3->foo = 3;
397
398         if (inst3->__field_mgr_pool == inst3->__field_mgr.embedded_pool) {
399                 ast_test_status_update(test, "Structure 3 embedded pool should not have been the current pool!\n");
400                 res = AST_TEST_FAIL;
401                 goto error;
402         }
403
404         if (inst3->__field_mgr.embedded_pool != inst3->__field_mgr_pool->prev) {
405                 ast_test_status_update(test, "Structure 3 embedded pool should be the current pool's previous!\n");
406                 res = AST_TEST_FAIL;
407                 goto error;
408         }
409
410         ast_test_status_update(test, "Structures 3 additional pool initialized successfully.\n");
411
412         ast_string_field_set(inst4, string1, "faz");
413         /* Exhaust the embedded pool */
414         ast_string_field_set(inst4, string2, "baz 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890");
415         inst4->foo = 4;
416
417         if (ast_string_fields_cmp(inst1, inst2)) {
418                 ast_test_status_update(test, "Structures 1/2 should be equal!\n");
419                 res = AST_TEST_FAIL;
420                 goto error;
421         } else {
422                 ast_test_status_update(test, "Structures 1/2 are equal as expected.\n");
423         }
424
425         if (!ast_string_fields_cmp(inst1, inst3)) {
426                 ast_test_status_update(test, "Structures 1/3 should be different!\n");
427                 res = AST_TEST_FAIL;
428                 goto error;
429         } else {
430                 ast_test_status_update(test, "Structures 1/3 are different as expected.\n");
431         }
432
433         if (!ast_string_fields_cmp(inst2, inst3)) {
434                 ast_test_status_update(test, "Structures 2/3 should be different!\n");
435                 res = AST_TEST_FAIL;
436                 goto error;
437         } else {
438                 ast_test_status_update(test, "Structures 2/3 are different as expected.\n");
439         }
440
441         if (!ast_string_fields_cmp(inst3, inst4)) {
442                 ast_test_status_update(test, "Structures 3/4 should be different!\n");
443                 res = AST_TEST_FAIL;
444                 goto error;
445         } else {
446                 ast_test_status_update(test, "Structures 3/4 are different as expected.\n");
447         }
448
449         if (ast_string_fields_copy(inst1, inst3)) {
450                 ast_test_status_update(test, "Copying from structure 3 to structure 1 failed!\n");
451                 res = AST_TEST_FAIL;
452                 goto error;
453         } else {
454                 ast_test_status_update(test, "Copying from structure 3 to structure 1 succeeded!\n");
455         }
456
457         /* inst1 and inst3 should now be equal and inst1 should no longer be equal to inst2 */
458         if (ast_string_fields_cmp(inst1, inst3)) {
459                 ast_test_status_update(test, "Structures 1/3 should be equal!\n");
460                 res = AST_TEST_FAIL;
461                 goto error;
462         } else {
463                 ast_test_status_update(test, "Structures 1/3 are equal as expected.\n");
464         }
465
466         if (!ast_string_fields_cmp(inst1, inst2)) {
467                 ast_test_status_update(test, "Structures 1/2 should be different!\n");
468                 res = AST_TEST_FAIL;
469         } else {
470                 ast_test_status_update(test, "Structures 1/2 are different as expected.\n");
471         }
472
473         ast_test_status_update(test, "Reset but don't free.\n");
474
475         ast_string_field_init(inst1, AST_STRINGFIELD_RESET);
476         ast_string_field_init(inst2, AST_STRINGFIELD_RESET);
477         ast_string_field_init(inst3, AST_STRINGFIELD_RESET);
478         ast_string_field_init(inst4, AST_STRINGFIELD_RESET);
479
480         if (ast_string_fields_cmp(inst1, inst2)) {
481                 ast_test_status_update(test, "Structures 1/2 should be the same (empty)!\n");
482                 res = AST_TEST_FAIL;
483         } else {
484                 ast_test_status_update(test, "Structures 1/2 are the same (empty) as expected.\n");
485         }
486
487         if (inst4->__field_mgr.embedded_pool != inst4->__field_mgr_pool) {
488                 ast_test_status_update(test, "Structure 4 embedded pool should have been the current pool!\n");
489                 res = AST_TEST_FAIL;
490                 goto error;
491         } else {
492                 ast_test_status_update(test, "Structure 4 embedded pool is the current pool as expected.\n");
493         }
494
495         if (inst4->__field_mgr.embedded_pool->prev) {
496                 ast_test_status_update(test, "Structure 4 embedded pool should not have a previous pool!\n");
497                 res = AST_TEST_FAIL;
498                 goto error;
499         } else {
500                 ast_test_status_update(test, "Structure 4 embedded pool does not have a previous as expected.\n");
501         }
502
503 error:
504         ast_string_field_free_memory(inst1);
505         ast_free(inst1);
506         ast_string_field_free_memory(inst2);
507         ast_free(inst2);
508         ast_string_field_free_memory(inst3);
509         ast_free(inst3);
510         ast_string_field_free_memory(inst4);
511         ast_free(inst4);
512
513         return res;
514 }
515
516 static int unload_module(void)
517 {
518         AST_TEST_UNREGISTER(string_field_aggregate_test);
519         AST_TEST_UNREGISTER(string_field_test);
520         return 0;
521 }
522
523 static int load_module(void)
524 {
525         AST_TEST_REGISTER(string_field_test);
526         AST_TEST_REGISTER(string_field_aggregate_test);
527         return AST_MODULE_LOAD_SUCCESS;
528 }
529
530 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "String Fields Test");