]>
Commit | Line | Data |
---|---|---|
1 | // TEST_CFLAGS -Wno-deprecated-declarations -Wl,-no_objc_category_merging | |
2 | ||
3 | #include "test.h" | |
4 | #include "testroot.i" | |
5 | #include <objc/runtime.h> | |
6 | ||
7 | static int state; | |
8 | ||
9 | @protocol Proto | |
10 | +(void)classMethod; | |
11 | -(void)instanceMethod; | |
12 | @end | |
13 | ||
14 | @interface Super : TestRoot <Proto> { | |
15 | int i; | |
16 | } | |
17 | @property int i; | |
18 | @end | |
19 | ||
20 | @implementation Super | |
21 | @synthesize i; | |
22 | ||
23 | +(void)classMethod { | |
24 | state = 1; | |
25 | } | |
26 | ||
27 | -(void)instanceMethod { | |
28 | state = 3; | |
29 | } | |
30 | ||
31 | @end | |
32 | ||
33 | ||
34 | #if __clang__ | |
35 | #pragma clang diagnostic push | |
36 | #pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation" | |
37 | #endif | |
38 | ||
39 | @implementation Super (Category) | |
40 | ||
41 | +(void)classMethod { | |
42 | state = 2; | |
43 | } | |
44 | ||
45 | -(void)instanceMethod { | |
46 | state = 4; | |
47 | } | |
48 | ||
49 | @end | |
50 | ||
51 | #if __clang__ | |
52 | #pragma clang diagnostic pop | |
53 | #endif | |
54 | ||
55 | ||
56 | int main() | |
57 | { | |
58 | Class clone; | |
59 | Class cls; | |
60 | Method *m1, *m2; | |
61 | int i; | |
62 | ||
63 | cls = [Super class]; | |
64 | clone = objc_duplicateClass(cls, "Super_copy", 0); | |
65 | ||
66 | testassert(clone != cls); | |
67 | testassert(object_getClass(clone) == object_getClass(cls)); | |
68 | testassert(class_getSuperclass(clone) == class_getSuperclass(cls)); | |
69 | testassert(class_getVersion(clone) == class_getVersion(cls)); | |
70 | testassert(class_isMetaClass(clone) == class_isMetaClass(cls)); | |
71 | testassert(class_getIvarLayout(clone) == class_getIvarLayout(cls)); | |
72 | testassert(class_getWeakIvarLayout(clone) == class_getWeakIvarLayout(cls)); | |
73 | ||
74 | // Check method list | |
75 | ||
76 | m1 = class_copyMethodList(cls, NULL); | |
77 | m2 = class_copyMethodList(clone, NULL); | |
78 | testassert(m1); | |
79 | testassert(m2); | |
80 | for (i = 0; m1[i] && m2[i]; i++) { | |
81 | testassert(m1[i] != m2[i]); // method list must be deep-copied | |
82 | testassert(method_getName(m1[i]) == method_getName(m2[i])); | |
83 | testassert(method_getImplementation(m1[i]) == method_getImplementation(m2[i])); | |
84 | testassert(method_getTypeEncoding(m1[i]) == method_getTypeEncoding(m2[i])); | |
85 | } | |
86 | testassert(m1[i] == NULL && m2[i] == NULL); | |
87 | free(m1); | |
88 | free(m2); | |
89 | ||
90 | // Check ivar list | |
91 | Ivar *i1 = class_copyIvarList(cls, NULL); | |
92 | Ivar *i2 = class_copyIvarList(clone, NULL); | |
93 | testassert(i1); | |
94 | testassert(i2); | |
95 | for (i = 0; i1[i] && i2[i]; i++) { | |
96 | testassert(i1[i] == i2[i]); // ivars are not deep-copied | |
97 | } | |
98 | testassert(i1[i] == NULL && i2[i] == NULL); | |
99 | free(i1); | |
100 | free(i2); | |
101 | ||
102 | // Check protocol list | |
103 | Protocol * __unsafe_unretained *p1 = class_copyProtocolList(cls, NULL); | |
104 | Protocol * __unsafe_unretained *p2 = class_copyProtocolList(clone, NULL); | |
105 | testassert(p1); | |
106 | testassert(p2); | |
107 | for (i = 0; p1[i] && p2[i]; i++) { | |
108 | testassert(p1[i] == p2[i]); // protocols are not deep-copied | |
109 | } | |
110 | testassert(p1[i] == NULL && p2[i] == NULL); | |
111 | free(p1); | |
112 | free(p2); | |
113 | ||
114 | // Check property list | |
115 | objc_property_t *o1 = class_copyPropertyList(cls, NULL); | |
116 | objc_property_t *o2 = class_copyPropertyList(clone, NULL); | |
117 | testassert(o1); | |
118 | testassert(o2); | |
119 | for (i = 0; o1[i] && o2[i]; i++) { | |
120 | testassert(o1[i] == o2[i]); // properties are not deep-copied | |
121 | } | |
122 | testassert(o1[i] == NULL && o2[i] == NULL); | |
123 | free(o1); | |
124 | free(o2); | |
125 | ||
126 | // Check method calls | |
127 | ||
128 | state = 0; | |
129 | [cls classMethod]; | |
130 | testassert(state == 2); | |
131 | state = 0; | |
132 | [clone classMethod]; | |
133 | testassert(state == 2); | |
134 | ||
135 | // #4511660 Make sure category implementation is still the preferred one | |
136 | id obj; | |
137 | obj = [cls new]; | |
138 | state = 0; | |
139 | [obj instanceMethod]; | |
140 | testassert(state == 4); | |
141 | RELEASE_VAR(obj); | |
142 | ||
143 | obj = [clone new]; | |
144 | state = 0; | |
145 | [obj instanceMethod]; | |
146 | testassert(state == 4); | |
147 | RELEASE_VAR(obj); | |
148 | ||
149 | succeed(__FILE__); | |
150 | } |