3
* test_alloc.c - test suite for nih/alloc.c
5
* Copyright Ā© 2009 Scott James Remnant <scott@netsplit.com>.
6
* Copyright Ā© 2009 Canonical Ltd.
8
* This program is free software; you can redistribute it and/or modify
9
* it under the terms of the GNU General Public License version 2, as
10
* published by the Free Software Foundation.
12
* This program is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU General Public License for more details.
17
* You should have received a copy of the GNU General Public License along
18
* with this program; if not, write to the Free Software Foundation, Inc.,
19
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28
#include <nih/macros.h>
29
#include <nih/alloc.h>
34
malloc_null (size_t size)
45
TEST_FUNCTION ("nih_new");
47
/* Check that nih_new works if we don't give it a parent, the block
48
* should be allocated with the size of the type given.
50
TEST_FEATURE ("with no parent");
51
ptr1 = nih_new (NULL, int);
53
TEST_ALLOC_SIZE (ptr1, sizeof (int));
54
TEST_ALLOC_ORPHAN (ptr1);
57
/* Check that nih_new works if we do give a parent. */
58
TEST_FEATURE ("with parent");
59
ptr2 = nih_new (ptr1, char);
61
TEST_ALLOC_SIZE (ptr2, sizeof (char));
62
TEST_ALLOC_PARENT (ptr2, ptr1);
67
/* Check that nih_new returns NULL if allocation fails. */
68
TEST_FEATURE ("with failed allocation");
69
__nih_malloc = malloc_null;
70
ptr1 = nih_new (NULL, int);
71
__nih_malloc = malloc;
73
TEST_EQ_P (ptr1, NULL);
82
TEST_FUNCTION ("nih_alloc");
84
/* Check allocation remembers the size, and is possible without
87
TEST_FEATURE ("with no parent");
88
ptr1 = nih_alloc (NULL, 8096);
89
memset (ptr1, 'x', 8096);
91
TEST_ALLOC_SIZE (ptr1, 8096);
92
TEST_ALLOC_ORPHAN (ptr1);
95
/* Check that allocation with a parent remembers the parent */
96
TEST_FEATURE ("with a parent");
97
ptr2 = nih_alloc (ptr1, 10);
98
memset (ptr2, 'x', 10);
100
TEST_ALLOC_SIZE (ptr2, 10);
101
TEST_ALLOC_PARENT (ptr2, ptr1);
106
/* Check that nih_alloc returns NULL if allocation fails. */
107
TEST_FEATURE ("with failed allocation");
108
__nih_malloc = malloc_null;
109
ptr1 = nih_new (NULL, int);
110
__nih_malloc = malloc;
112
TEST_EQ_P (ptr1, NULL);
117
realloc_null (void * ptr,
130
TEST_FUNCTION ("nih_realloc");
132
/* Check that nih_realloc behaves like nih_alloc if the pointer is
133
* NULL (it should, in fact, just call it)
135
TEST_FEATURE ("as nih_alloc");
136
ptr1 = nih_realloc (NULL, NULL, 4096);
137
memset (ptr1, 'x', 4096);
139
TEST_ALLOC_SIZE (ptr1, 4096);
140
TEST_ALLOC_ORPHAN (ptr1);
145
/* Check that nih_realloc works if the block doesn't have a parent.
147
TEST_FEATURE ("with no parent");
148
ptr1 = nih_alloc (NULL, 4096);
149
memset (ptr1, 'x', 4096);
151
ptr1 = nih_realloc (ptr1, NULL, 8096);
152
memset (ptr1, 'x', 8096);
154
TEST_ALLOC_SIZE (ptr1, 8096);
155
TEST_ALLOC_ORPHAN (ptr1);
158
/* Check that nih_realloc works if the block has a parent, the size
159
* should change but the parent should remain the same.
161
TEST_FEATURE ("with a parent");
162
ptr2 = nih_alloc (ptr1, 5);
163
memset (ptr2, 'x', 5);
165
ptr2 = nih_realloc (ptr2, ptr1, 10);
166
memset (ptr2, 'x', 10);
168
TEST_ALLOC_SIZE (ptr2, 10);
169
TEST_ALLOC_PARENT (ptr2, ptr1);
174
/* Check that nih_realloc works if the block being reallocated has
175
* a child. This is fiddly as they need their parent pointers
178
TEST_FEATURE ("with a child");
179
ptr1 = nih_alloc (NULL, 128);
180
memset (ptr1, 'x', 128);
182
ptr2 = nih_alloc (ptr1, 512);
183
memset (ptr2, 'x', 512);
185
ptr3 = nih_realloc (ptr1, NULL, 1024);
186
memset (ptr3, 'x', 1024);
188
TEST_ALLOC_PARENT (ptr2, ptr3);
193
/* Check that nih_realloc returns NULL and doesn't alter the block
194
* if the allocator fails.
196
TEST_FEATURE ("with failing realloc");
197
ptr1 = nih_alloc (NULL, 10);
199
memset (ptr1, 'x', 10);
201
__nih_realloc = realloc_null;
202
ptr2 = nih_realloc (ptr1, NULL, 200);
203
__nih_realloc = realloc;
205
TEST_EQ_P (ptr2, NULL);
206
TEST_ALLOC_SIZE (ptr1, 10);
212
static int destructor_was_called;
215
destructor_called (void *ptr)
217
destructor_was_called++;
222
static int child_destructor_was_called;
225
child_destructor_called (void *ptr)
227
child_destructor_was_called++;
232
typedef struct child {
237
typedef struct parent {
243
static void *list_head_ptr = NULL;
244
static int list_head_free = FALSE;
247
my_list_head_malloc (size_t size)
249
list_head_ptr = malloc (size);
250
list_head_free = FALSE;
251
return list_head_ptr;
255
my_list_head_free (void *ptr)
257
if (ptr == list_head_ptr)
258
list_head_free = TRUE;
263
child_destructor_test (Child *child)
265
TEST_FALSE (list_head_free);
278
TEST_FUNCTION ("nih_free");
280
/* Check that nih_free works if the block has no parent. The
281
* destructor should get called and nih_free should return that
284
TEST_FEATURE ("with no parent");
285
ptr1 = nih_alloc (NULL, 10);
286
nih_alloc_set_destructor (ptr1, destructor_called);
287
destructor_was_called = 0;
288
ret = nih_free (ptr1);
290
TEST_TRUE (destructor_was_called);
294
/* Check that nih_free works if the block has a parent. The
295
* destructor should get called and nih_free should return that
298
TEST_FEATURE ("with parent");
299
ptr2 = nih_alloc (NULL, 20);
301
ptr1 = nih_alloc (ptr2, 10);
302
nih_alloc_set_destructor (ptr1, destructor_called);
303
destructor_was_called = 0;
304
ret = nih_free (ptr1);
306
TEST_TRUE (destructor_was_called);
312
/* Check that the destructor on any children also gets called, which
313
* is as good a indication as any that the children are being freed.
315
TEST_FEATURE ("with destructor on child");
316
ptr1 = nih_alloc (NULL, 10);
317
ptr2 = nih_alloc (ptr1, 10);
318
nih_alloc_set_destructor (ptr2, child_destructor_called);
319
child_destructor_was_called = 0;
320
ret = nih_free (ptr1);
322
TEST_TRUE (child_destructor_was_called);
326
/* Check that both destructors on parent and children are called,
327
* and that the return value from nih_free is that of the parent's.
329
TEST_FEATURE ("with child and destructors");
330
ptr1 = nih_alloc (NULL, 10);
331
ptr2 = nih_alloc (ptr1, 10);
332
nih_alloc_set_destructor (ptr1, destructor_called);
333
nih_alloc_set_destructor (ptr2, child_destructor_called);
334
destructor_was_called = 0;
335
child_destructor_was_called = 0;
336
ret = nih_free (ptr1);
338
TEST_TRUE (destructor_was_called);
339
TEST_TRUE (child_destructor_was_called);
343
/* Check that a child of an object may be included in a sibling
344
* linked list allocated earlier. At the point the child destructor
345
* is called, the sibling must not have been freed otherwise it
346
* cannot cut itself out.
348
TEST_FEATURE ("with child in older sibling list");
349
parent = nih_new (NULL, Parent);
351
__nih_malloc = my_list_head_malloc;
352
parent->list = nih_new (parent, NihList);
353
nih_list_init (parent->list);
354
__nih_malloc = malloc;
356
parent->child = nih_new (parent, Child);
357
nih_list_init (&parent->child->entry);
359
nih_list_add (parent->list, &parent->child->entry);
360
nih_alloc_set_destructor (parent->child, child_destructor_test);
362
__nih_free = my_list_head_free;
367
/* Check that a child of an object may be included in a sibling
368
* linked list allocated later. At the point the child destructor
369
* is called, the sibling must not have been freed otherwise it
370
* cannot cut itself out.
372
TEST_FEATURE ("with child in younger sibling list");
373
parent = nih_new (NULL, Parent);
375
parent->child = nih_new (parent, Child);
376
nih_list_init (&parent->child->entry);
378
__nih_malloc = my_list_head_malloc;
379
parent->list = nih_new (parent, NihList);
380
nih_list_init (parent->list);
381
__nih_malloc = malloc;
383
nih_list_add (parent->list, &parent->child->entry);
384
nih_alloc_set_destructor (parent->child, child_destructor_test);
386
__nih_free = my_list_head_free;
399
TEST_FUNCTION ("nih_discard");
401
/* Check that nih_discard works if the block has no parent, freeing
402
* the object. The destructor should get called and nih_discard
403
* should return that return value.
405
TEST_FEATURE ("with no parent");
406
ptr1 = nih_alloc (NULL, 10);
407
nih_alloc_set_destructor (ptr1, destructor_called);
408
destructor_was_called = 0;
409
ret = nih_discard (ptr1);
411
TEST_TRUE (destructor_was_called);
415
/* Check that nih_discard does nothing it the block has a parent.
417
TEST_FEATURE ("with parent");
418
ptr2 = nih_alloc (NULL, 20);
420
ptr1 = nih_alloc (ptr2, 10);
421
nih_alloc_set_destructor (ptr1, destructor_called);
422
destructor_was_called = 0;
423
ret = nih_discard (ptr1);
425
TEST_FALSE (destructor_was_called);
431
/* Check that the destructor on any children also gets called, which
432
* is as good a indication as any that the children are being freed.
434
TEST_FEATURE ("with destructor on child");
435
ptr1 = nih_alloc (NULL, 10);
436
ptr2 = nih_alloc (ptr1, 10);
437
nih_alloc_set_destructor (ptr2, child_destructor_called);
438
child_destructor_was_called = 0;
439
ret = nih_discard (ptr1);
441
TEST_TRUE (child_destructor_was_called);
445
/* Check that both destructors on parent and children are called,
446
* and that the return value from nih_discard is that of the parent's.
448
TEST_FEATURE ("with child and destructors");
449
ptr1 = nih_alloc (NULL, 10);
450
ptr2 = nih_alloc (ptr1, 10);
451
nih_alloc_set_destructor (ptr1, destructor_called);
452
nih_alloc_set_destructor (ptr2, child_destructor_called);
453
destructor_was_called = 0;
454
child_destructor_was_called = 0;
455
ret = nih_discard (ptr1);
457
TEST_TRUE (destructor_was_called);
458
TEST_TRUE (child_destructor_was_called);
470
TEST_FUNCTION ("nih_ref");
473
/* Check that we can add a reference to an object that has no
476
TEST_FEATURE ("with no existing parent");
477
ptr1 = nih_alloc (NULL, 100);
478
memset (ptr1, 'x', 100);
480
ptr2 = nih_alloc (NULL, 100);
481
memset (ptr2, 'y', 100);
483
nih_ref (ptr1, ptr2);
485
TEST_ALLOC_PARENT (ptr1, ptr2);
490
/* Check that we can add a reference to an object that already has
491
* a parent, and that both shall be parents afterwards.
493
TEST_FEATURE ("with existing parent");
494
ptr1 = nih_alloc (NULL, 100);
495
memset (ptr1, 'x', 100);
497
ptr2 = nih_alloc (ptr1, 100);
498
memset (ptr2, 'y', 100);
500
ptr3 = nih_alloc (NULL, 100);
501
memset (ptr2, 'z', 100);
503
nih_ref (ptr2, ptr3);
505
TEST_ALLOC_PARENT (ptr2, ptr1);
506
TEST_ALLOC_PARENT (ptr2, ptr3);
519
TEST_FUNCTION ("nih_unref");
522
/* Check that we can remove a reference from an object with multiple
523
* parents, which means the object will not be freed.
525
TEST_FEATURE ("with multiple parents");
526
ptr1 = nih_alloc (NULL, 100);
527
memset (ptr1, 'x', 100);
529
ptr2 = nih_alloc (ptr1, 100);
530
memset (ptr2, 'y', 100);
532
ptr3 = nih_alloc (NULL, 100);
533
memset (ptr2, 'z', 100);
535
nih_ref (ptr2, ptr3);
537
nih_alloc_set_destructor (ptr2, destructor_called);
538
destructor_was_called = 0;
540
nih_unref (ptr2, ptr1);
542
TEST_FALSE (destructor_was_called);
543
TEST_ALLOC_PARENT (ptr2, ptr3);
549
/* Check that when we remove the last reference from an object,
550
* the object is freed.
552
TEST_FEATURE ("with last parent");
553
ptr1 = nih_alloc (NULL, 100);
554
memset (ptr1, 'x', 100);
556
ptr2 = nih_alloc (ptr1, 100);
557
memset (ptr2, 'y', 100);
559
nih_alloc_set_destructor (ptr2, destructor_called);
560
destructor_was_called = 0;
562
nih_unref (ptr2, ptr1);
564
TEST_TRUE (destructor_was_called);
577
TEST_FUNCTION ("nih_alloc_parent");
580
/* Check that nih_alloc_parent returns TRUE when the passed object
581
* is a child of the passed parent.
583
TEST_FEATURE ("with child and parent");
584
ptr1 = nih_alloc (NULL, 10);
585
ptr2 = nih_alloc (ptr1, 10);
587
TEST_TRUE (nih_alloc_parent (ptr2, ptr1));
592
/* Check that nih_alloc_parent returns TRUE when the passed object
593
* has a parent and NULL is passed.
595
TEST_FEATURE ("with child and NULL");
596
ptr1 = nih_alloc (NULL, 10);
597
ptr2 = nih_alloc (ptr1, 10);
599
TEST_TRUE (nih_alloc_parent (ptr2, ptr1));
604
/* Check that nih_alloc_parent returns FALSE when the passed object
605
* is a child but not of the passed parent.
607
TEST_FEATURE ("with child and wrong parent");
608
ptr1 = nih_alloc (NULL, 10);
609
ptr2 = nih_alloc (ptr1, 10);
610
ptr3 = nih_alloc (NULL, 10);
612
TEST_FALSE (nih_alloc_parent (ptr2, ptr3));
618
/* Check that nih_alloc_parent returns FALSE when the passed object
621
TEST_FEATURE ("with orphan");
622
ptr1 = nih_alloc (NULL, 10);
623
ptr2 = nih_alloc (NULL, 10);
625
TEST_FALSE (nih_alloc_parent (ptr2, ptr1));
631
/* Check that nih_alloc_parent returns FALSE when the passed object
632
* is an orphan and NULL is passed.
634
TEST_FEATURE ("with orphan and NULL");
635
ptr1 = nih_alloc (NULL, 10);
637
TEST_FALSE (nih_alloc_parent (ptr1, NULL));
649
TEST_GROUP ("nih_local");
652
/* Make sure that when a variable goes out of scope, it's freed. */
653
TEST_FEATURE ("with variable going out of scope");
657
ptr = nih_alloc (NULL, 100);
659
nih_alloc_set_destructor (ptr, destructor_called);
660
destructor_was_called = 0;
663
TEST_TRUE (destructor_was_called);
666
/* Make sure that if a variable is referenced while in scope, it
669
TEST_FEATURE ("with referenced variable");
670
parent = nih_alloc (NULL, 100);
675
ptr = nih_alloc (NULL, 100);
676
nih_ref (ptr, parent);
679
nih_alloc_set_destructor (ptr, destructor_called);
680
destructor_was_called = 0;
683
TEST_FALSE (destructor_was_called);
684
TEST_ALLOC_PARENT (_ptr, parent);
689
/* Make sure we don't need to allocate the variable. */
690
TEST_FEATURE ("with NULL variable");
692
nih_local void *ptr = NULL;