X-Git-Url: https://git.saurik.com/apple/objc4.git/blobdiff_plain/7c0e6487d7b67b6bf6c632300ee4b74e8950b051..7af964d1562d70f51a8e9aca24215ac3d83d0624:/test/duplicateClass.m?ds=sidebyside diff --git a/test/duplicateClass.m b/test/duplicateClass.m new file mode 100644 index 0000000..794a46a --- /dev/null +++ b/test/duplicateClass.m @@ -0,0 +1,157 @@ +#include "test.h" +#include +#ifndef OBJC_NO_GC +#include +#include +#endif + +static int state; + +@protocol Proto ++class; +@end + +@interface Super { + id isa; + int i; +} +@property int i; +@end + +@implementation Super +@synthesize i; + ++(void)initialize { } ++class { return self; } ++new { return class_createInstance(self, 0); } +-(void)dealloc { object_dispose(self); } + ++(void)classMethod { + state = 1; +} + +-(void)instanceMethod { + state = 3; +} + +@end + + +@implementation Super (Category) + ++(void)classMethod { + state = 2; +} + +-(void)instanceMethod { + state = 4; +} + +@end + + +int main() +{ + Class clone; + Class cls; + Method *m1, *m2; + int i; + + cls = [Super class]; + clone = objc_duplicateClass(cls, "Super_copy", 0); +#ifndef OBJC_NO_GC + if (objc_collecting_enabled()) { + testassert(auto_zone_size(auto_zone(), clone)); + // objc_duplicateClass() doesn't duplicate the metaclass + // no: testassert(auto_zone_size(auto_zone(), clone->isa)); + } +#endif + + testassert(clone != cls); + testassert(clone->isa == cls->isa); + testassert(class_getSuperclass(clone) == class_getSuperclass(cls)); + testassert(class_getVersion(clone) == class_getVersion(cls)); + testassert(class_isMetaClass(clone) == class_isMetaClass(cls)); + testassert(class_getIvarLayout(clone) == class_getIvarLayout(cls)); + testassert(class_getWeakIvarLayout(clone) == class_getWeakIvarLayout(cls)); +#if !__OBJC2__ + testassert((clone->info & (CLS_CLASS|CLS_META)) == (cls->info & (CLS_CLASS|CLS_META))); +#endif + + // Check method list + + m1 = class_copyMethodList(cls, NULL); + m2 = class_copyMethodList(clone, NULL); + testassert(m1); + testassert(m2); + for (i = 0; m1[i] && m2[i]; i++) { + testassert(m1[i] != m2[i]); // method list must be deep-copied + testassert(method_getName(m1[i]) == method_getName(m2[i])); + testassert(method_getImplementation(m1[i]) == method_getImplementation(m2[i])); + testassert(method_getTypeEncoding(m1[i]) == method_getTypeEncoding(m2[i])); + } + testassert(m1[i] == NULL && m2[i] == NULL); + free(m1); + free(m2); + + // Check ivar list + Ivar *i1 = class_copyIvarList(cls, NULL); + Ivar *i2 = class_copyIvarList(clone, NULL); + testassert(i1); + testassert(i2); + for (i = 0; i1[i] && i2[i]; i++) { + testassert(i1[i] == i2[i]); // ivars are not deep-copied + } + testassert(i1[i] == NULL && i2[i] == NULL); + free(i1); + free(i2); + + // Check protocol list + Protocol **p1 = class_copyProtocolList(cls, NULL); + Protocol **p2 = class_copyProtocolList(clone, NULL); + testassert(p1); + testassert(p2); + for (i = 0; p1[i] && p2[i]; i++) { + testassert(p1[i] == p2[i]); // protocols are not deep-copied + } + testassert(p1[i] == NULL && p2[i] == NULL); + free(p1); + free(p2); + + // Check property list + objc_property_t *o1 = class_copyPropertyList(cls, NULL); + objc_property_t *o2 = class_copyPropertyList(clone, NULL); + testassert(o1); + testassert(o2); + for (i = 0; o1[i] && o2[i]; i++) { + testassert(o1[i] == o2[i]); // properties are not deep-copied + } + testassert(o1[i] == NULL && o2[i] == NULL); + free(o1); + free(o2); + + // Check method calls + + state = 0; + [cls classMethod]; + testassert(state == 2); + state = 0; + [clone classMethod]; + testassert(state == 2); + + // #4511660 Make sure category implementation is still the preferred one + id obj; + obj = [cls new]; + state = 0; + [obj instanceMethod]; + testassert(state == 4); + [obj dealloc]; + + obj = [clone new]; + state = 0; + [obj instanceMethod]; + testassert(state == 4); + [obj dealloc]; + + succeed(__FILE__); +}