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 SuperProps { id isa; int prop1; int prop2; } 
10@property int prop1;
11@property int prop2;
12@end
13@implementation SuperProps 
14@synthesize prop1;
15@synthesize prop2;
16@end
17
18@interface SubProps : SuperProps { int prop3; int prop4; }
19@property int prop3;
20@property int prop4;
21@end
22@implementation SubProps 
23@synthesize prop3;
24@synthesize prop4;
25@end
26
27OBJC_ROOT_CLASS
28@interface FourProps { int prop1; int prop2; int prop3; int prop4; }
29@property int prop1;
30@property int prop2;
31@property int prop3;
32@property int prop4;
33@end
34@implementation FourProps 
35@synthesize prop1;
36@synthesize prop2;
37@synthesize prop3;
38@synthesize prop4;
39@end
40
41OBJC_ROOT_CLASS
42@interface NoProps @end
43@implementation NoProps @end
44
45static int isNamed(objc_property_t p, const char *name)
46{
47    return (0 == strcmp(name, property_getName(p)));
48}
49
50int main()
51{
52    objc_property_t *props;
53    unsigned int count;
54    Class cls;
55
56    cls = objc_getClass("SubProps");
57    testassert(cls);
58
59    count = 100;
60    props = class_copyPropertyList(cls, &count);
61    testassert(props);
62    testassert(count == 2);
63    testassert((isNamed(props[0], "prop3")  &&  isNamed(props[1], "prop4"))  ||
64               (isNamed(props[1], "prop3")  &&  isNamed(props[0], "prop4")));
65    // props[] should be null-terminated
66    testassert(props[2] == NULL);
67    free(props);
68
69    cls = objc_getClass("SuperProps");
70    testassert(cls);
71
72    count = 100;
73    props = class_copyPropertyList(cls, &count);
74    testassert(props);
75    testassert(count == 2);
76    testassert((isNamed(props[0], "prop1")  &&  isNamed(props[1], "prop2"))  ||
77               (isNamed(props[1], "prop1")  &&  isNamed(props[0], "prop2")));
78    // props[] should be null-terminated
79    testassert(props[2] == NULL);
80    free(props);
81
82    // Check null-termination - this property list block would be 16 bytes
83    // if it weren't for the terminator
84    cls = objc_getClass("FourProps");
85    testassert(cls);
86
87    count = 100;
88    props = class_copyPropertyList(cls, &count);
89    testassert(props);
90    testassert(count == 4);
91    testassert(malloc_size(props) >= 5 * sizeof(objc_property_t));
92    testassert(props[3] != NULL);
93    testassert(props[4] == NULL);
94    free(props);
95
96    // Check NULL count parameter
97    props = class_copyPropertyList(cls, NULL);
98    testassert(props);
99    testassert(props[4] == NULL);
100    testassert(props[3] != NULL);
101    free(props);
102
103    // Check NULL class parameter
104    count = 100;
105    props = class_copyPropertyList(NULL, &count);
106    testassert(!props);
107    testassert(count == 0);
108    
109    // Check NULL class and count
110    props = class_copyPropertyList(NULL, NULL);
111    testassert(!props);
112
113    // Check class with no properties
114    cls = objc_getClass("NoProps");
115    testassert(cls);
116
117    count = 100;
118    props = class_copyPropertyList(cls, &count);
119    testassert(!props);
120    testassert(count == 0);
121
122    succeed(__FILE__);
123    return 0;
124}
125