1// TEST_CONFIG
2
3#include "test.h"
4#include <string.h>
5#include <malloc/malloc.h>
6#include <objc/objc-runtime.h>
7
8OBJC_ROOT_CLASS
9@interface SuperIvars { 
10    id isa;
11    int ivar1;
12    int ivar2;
13} @end
14@implementation SuperIvars @end
15
16@interface SubIvars : SuperIvars { 
17    int ivar3;
18    int ivar4;
19} @end
20@implementation SubIvars @end
21
22OBJC_ROOT_CLASS
23@interface FourIvars {
24    int ivar1;
25    int ivar2;
26    int ivar3;
27    int ivar4;
28} @end
29@implementation FourIvars @end
30
31OBJC_ROOT_CLASS
32@interface NoIvars { } @end
33@implementation NoIvars @end
34
35static int isNamed(Ivar iv, const char *name)
36{
37    return (0 == strcmp(name, ivar_getName(iv)));
38}
39
40int main()
41{
42    Ivar *ivars;
43    unsigned int count;
44    Class cls;
45
46    cls = objc_getClass("SubIvars");
47    testassert(cls);
48
49    count = 100;
50    ivars = class_copyIvarList(cls, &count);
51    testassert(ivars);
52    testassert(count == 2);
53    testassert(isNamed(ivars[0], "ivar3"));
54    testassert(isNamed(ivars[1], "ivar4"));
55    // ivars[] should be null-terminated
56    testassert(ivars[2] == NULL);
57    free(ivars);
58
59    cls = objc_getClass("SuperIvars");
60    testassert(cls);
61
62    count = 100;
63    ivars = class_copyIvarList(cls, &count);
64    testassert(ivars);
65    testassert(count == 3);
66    testassert(isNamed(ivars[0], "isa"));
67    testassert(isNamed(ivars[1], "ivar1"));
68    testassert(isNamed(ivars[2], "ivar2"));
69    // ivars[] should be null-terminated
70    testassert(ivars[3] == NULL);
71    free(ivars);
72
73    // Check null-termination - this ivar list block would be 16 bytes
74    // if it weren't for the terminator
75    cls = objc_getClass("FourIvars");
76    testassert(cls);
77
78    count = 100;
79    ivars = class_copyIvarList(cls, &count);
80    testassert(ivars);
81    testassert(count == 4);
82    testassert(malloc_size(ivars) >= 5 * sizeof(Ivar));
83    testassert(ivars[3] != NULL);
84    testassert(ivars[4] == NULL);
85    free(ivars);
86
87    // Check NULL count parameter
88    ivars = class_copyIvarList(cls, NULL);
89    testassert(ivars);
90    testassert(ivars[4] == NULL);
91    testassert(ivars[3] != NULL);
92    free(ivars);
93
94    // Check NULL class parameter
95    count = 100;
96    ivars = class_copyIvarList(NULL, &count);
97    testassert(!ivars);
98    testassert(count == 0);
99    
100    // Check NULL class and count
101    ivars = class_copyIvarList(NULL, NULL);
102    testassert(!ivars);
103
104    // Check class with no ivars
105    cls = objc_getClass("NoIvars");
106    testassert(cls);
107
108    count = 100;
109    ivars = class_copyIvarList(cls, &count);
110    testassert(!ivars);
111    testassert(count == 0);
112
113    succeed(__FILE__);
114    return 0;
115}
116