1// TEST_CFLAGS -Wl,-no_objc_category_merging
2
3#include "test.h"
4#include "testroot.i"
5#include <string.h>
6#include <objc/runtime.h>
7
8static int state = 0;
9
10@interface Super : TestRoot @end
11@implementation Super
12-(void)instancemethod { fail("-instancemethod not overridden by category"); }
13+(void)method { fail("+method not overridden by category"); } 
14@end
15
16@interface Super (Category) @end
17@implementation Super (Category) 
18+(void)method { 
19    testprintf("in [Super(Category) method]\n"); 
20    testassert(self == [Super class]);
21    testassert(state == 0);
22    state = 1;
23}
24-(void)instancemethod { 
25    testprintf("in [Super(Category) instancemethod]\n"); 
26    testassert(object_getClass(self) == [Super class]);
27    testassert(state == 1);
28    state = 2;
29}
30@end
31
32@interface Super (PropertyCategory) 
33@property int i;
34@end
35@implementation Super (PropertyCategory) 
36- (int)i { return 0; }
37- (void)setI:(int)value { (void)value; }
38@end
39
40// rdar://5086110  memory smasher in category with class method and property
41@interface Super (r5086110) 
42@property int property5086110;
43@end
44@implementation Super (r5086110) 
45+(void)method5086110 { 
46    fail("method method5086110 called!");
47}
48- (int)property5086110 { fail("property5086110 called!"); return 0; }
49- (void)setProperty5086110:(int)value { fail("setProperty5086110 called!"); (void)value; }
50@end
51
52
53@interface PropertyClass : Super {
54    int q;
55}
56@property(readonly) int q;
57@end
58@implementation PropertyClass
59@synthesize q;
60@end
61
62@interface PropertyClass (PropertyCategory)
63@property int q;
64@end
65@implementation PropertyClass (PropertyCategory)
66@dynamic q;
67@end
68
69
70int main()
71{
72    // methods introduced by category
73    state = 0;
74    [Super method];
75    [[Super new] instancemethod];
76    testassert(state == 2);
77
78    // property introduced by category
79    objc_property_t p = class_getProperty([Super class], "i");
80    testassert(p);
81    testassert(0 == strcmp(property_getName(p), "i"));
82    testassert(property_getAttributes(p));
83
84    // methods introduced by category's property
85    Method m;
86    m = class_getInstanceMethod([Super class], @selector(i));
87    testassert(m);
88    m = class_getInstanceMethod([Super class], @selector(setI:));
89    testassert(m);
90
91    // class's property shadowed by category's property
92    objc_property_t *plist = class_copyPropertyList([PropertyClass class], NULL);
93    testassert(plist);
94    testassert(plist[0]);
95    testassert(0 == strcmp(property_getName(plist[0]), "q"));
96    testassert(0 == strcmp(property_getAttributes(plist[0]), "Ti,D"));
97    testassert(plist[1]);
98    testassert(0 == strcmp(property_getName(plist[1]), "q"));
99    testassert(0 == strcmp(property_getAttributes(plist[1]), "Ti,R,Vq"));
100    testassert(!plist[2]);
101    free(plist);
102    
103    succeed(__FILE__);
104}
105
106