123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155 |
- // TEST_CFLAGS -Wl,-no_objc_category_merging
- #include "test.h"
- #include "testroot.i"
- #include <malloc/malloc.h>
- #include <objc/runtime.h>
- @interface SuperMethods : TestRoot { } @end
- @implementation SuperMethods
- +(BOOL)SuperMethodClass { return NO; }
- +(BOOL)SuperMethodClass2 { return NO; }
- -(BOOL)SuperMethodInstance { return NO; }
- -(BOOL)SuperMethodInstance2 { return NO; }
- @end
- @interface SubMethods : SuperMethods { } @end
- @implementation SubMethods
- +(BOOL)SubMethodClass { return NO; }
- +(BOOL)SubMethodClass2 { return NO; }
- -(BOOL)SubMethodInstance { return NO; }
- -(BOOL)SubMethodInstance2 { return NO; }
- @end
- @interface SuperMethods (Category) @end
- @implementation SuperMethods (Category)
- +(BOOL)SuperMethodClass { return YES; }
- +(BOOL)SuperMethodClass2 { return YES; }
- -(BOOL)SuperMethodInstance { return YES; }
- -(BOOL)SuperMethodInstance2 { return YES; }
- @end
- @interface SubMethods (Category) @end
- @implementation SubMethods (Category)
- +(BOOL)SubMethodClass { return YES; }
- +(BOOL)SubMethodClass2 { return YES; }
- -(BOOL)SubMethodInstance { return YES; }
- -(BOOL)SubMethodInstance2 { return YES; }
- @end
- @interface FourMethods : TestRoot @end
- @implementation FourMethods
- -(void)one { }
- -(void)two { }
- -(void)three { }
- -(void)four { }
- @end
- @interface NoMethods : TestRoot @end
- @implementation NoMethods @end
- static void checkReplacement(Method *list, const char *name)
- {
- Method first = NULL, second = NULL;
- SEL sel = sel_registerName(name);
- int i;
- testassert(list);
- // Find the methods. There should be two.
- for (i = 0; list[i]; i++) {
- if (method_getName(list[i]) == sel) {
- if (!first) first = list[i];
- else if (!second) second = list[i];
- else testassert(0);
- }
- }
- // Call the methods. The first should be the category (returns YES).
- BOOL isCat;
- isCat = ((BOOL(*)(id, Method))method_invoke)(NULL, first);
- testassert(isCat);
- isCat = ((BOOL(*)(id, Method))method_invoke)(NULL, second);
- testassert(! isCat);
- }
- int main()
- {
- // Class SubMethods has not yet been touched, so runtime must attach
- // the lazy categories
- Method *methods;
- unsigned int count;
- Class cls;
- cls = objc_getClass("SubMethods");
- testassert(cls);
- testprintf("calling class_copyMethodList(SubMethods) (should be unmethodized)\n");
- count = 100;
- methods = class_copyMethodList(cls, &count);
- testassert(methods);
- testassert(count == 4);
- // methods[] should be null-terminated
- testassert(methods[4] == NULL);
- // Class and category methods may be mixed in the method list thanks
- // to linker / shared cache sorting, but a category's replacement should
- // always precede the class's implementation.
- checkReplacement(methods, "SubMethodInstance");
- checkReplacement(methods, "SubMethodInstance2");
- free(methods);
- testprintf("calling class_copyMethodList(SubMethods(meta)) (should be unmethodized)\n");
- count = 100;
- methods = class_copyMethodList(object_getClass(cls), &count);
- testassert(methods);
- testassert(count == 4);
- // methods[] should be null-terminated
- testassert(methods[4] == NULL);
- // Class and category methods may be mixed in the method list thanks
- // to linker / shared cache sorting, but a category's replacement should
- // always precede the class's implementation.
- checkReplacement(methods, "SubMethodClass");
- checkReplacement(methods, "SubMethodClass2");
- free(methods);
- // Check null-termination - this method list block would be 16 bytes
- // if it weren't for the terminator
- count = 100;
- cls = objc_getClass("FourMethods");
- methods = class_copyMethodList(cls, &count);
- testassert(methods);
- testassert(count == 4);
- testassert(malloc_size(methods) >= (4+1) * sizeof(Method));
- testassert(methods[3] != NULL);
- testassert(methods[4] == NULL);
- free(methods);
- // Check NULL count parameter
- methods = class_copyMethodList(cls, NULL);
- testassert(methods);
- testassert(methods[4] == NULL);
- testassert(methods[3] != NULL);
- free(methods);
- // Check NULL class parameter
- count = 100;
- methods = class_copyMethodList(NULL, &count);
- testassert(!methods);
- testassert(count == 0);
-
- // Check NULL class and count
- methods = class_copyMethodList(NULL, NULL);
- testassert(!methods);
- // Check class with no methods
- count = 100;
- cls = objc_getClass("NoMethods");
- methods = class_copyMethodList(cls, &count);
- testassert(!methods);
- testassert(count == 0);
- succeed(__FILE__);
- }
|