Improve protocol tests and fix bugs.

Also add the new protocol_getProperties2 function.
main
David Chisnall 8 years ago
parent 8eb06a3b15
commit 0c9ee8b920

@ -4,26 +4,91 @@
#include <assert.h>
@protocol Test2 @end
@protocol Test3 @end
@protocol Test4 @end
void checkProtocolMethod(Protocol *p, SEL sel, BOOL isClass, BOOL isOptional)
{
struct objc_method_description d = protocol_getMethodDescription(p, sel, isClass, isOptional);
assert(sel_isEqual(d.name, sel));
assert(strcmp((d.types), "@:") == 0);
d = protocol_getMethodDescription(p, sel, !isClass, isOptional);
assert(d.name == NULL);
assert(d.types == NULL);
d = protocol_getMethodDescription(p, sel, isClass, !isOptional);
assert(d.name == NULL);
assert(d.types == NULL);
d = protocol_getMethodDescription(p, sel, !isClass, !isOptional);
assert(d.name == NULL);
assert(d.types == NULL);
}
int main(void)
{
Protocol *force_reference = @protocol(Test2);
Protocol *p = objc_allocateProtocol("Test");
protocol_addMethodDescription(p, @selector(someMethod), "@:", YES, NO);
protocol_addMethodDescription(p, @selector(someClassMethod), "@:", YES, NO);
protocol_addMethodDescription(p, @selector(someOptionalClassMethod), "@:", YES, YES);
protocol_addMethodDescription(p, @selector(someMethod), "@:", NO, NO);
protocol_addMethodDescription(p, @selector(someOtherMethod), "@:", NO, NO);
protocol_addMethodDescription(p, @selector(someOptionalMethod), "@:", NO, YES);
assert(objc_getProtocol("Test2"));
protocol_addProtocol(p, objc_getProtocol("Test2"));
objc_property_attribute_t attrs[] = { {"T", "@" }, {"V", "foo"} };
protocol_addProperty(p, "foo", attrs, 2, YES, YES);
protocol_addProtocol(p, @protocol(Test3));
// Check that this don't crash
protocol_addProtocol(p, NULL);
protocol_addProtocol(NULL, p);
protocol_addProtocol(NULL, NULL);
objc_property_attribute_t attrs[] = { {"T", "@" }, {"V", "optional"} };
protocol_addProperty(p, "optional", attrs, 2, NO, YES);
attrs[1].value = "required";
protocol_addProperty(p, "required", attrs, 2, YES, YES);
attrs[1].value = "required2";
protocol_addProperty(p, "required2", attrs, 2, YES, YES);
protocol_addProperty(p, "classOptional", attrs, 1, NO, NO);
protocol_addProperty(p, "classRequired", attrs, 1, YES, NO);
checkProtocolMethod(p, @selector(someClassMethod), YES, NO);
checkProtocolMethod(p, @selector(someOptionalClassMethod), YES, YES);
checkProtocolMethod(p, @selector(someMethod), NO, NO);
checkProtocolMethod(p, @selector(someOtherMethod), NO, NO);
checkProtocolMethod(p, @selector(someOptionalMethod), NO, YES);
objc_registerProtocol(p);
// Modifying protocols after they've been registered is not permitted.
protocol_addProtocol(p, @protocol(Test4));
protocol_addMethodDescription(p, @selector(someUnsupportedMethod), "@:", NO, NO);
protocol_addProperty(p, "classRequired2", attrs, 1, NO, NO);
Protocol *p1 = objc_getProtocol("Test");
assert(p == p1);
struct objc_method_description d = protocol_getMethodDescription(p1, @selector(someMethod), YES, NO);
assert(strcmp(sel_getName(d.name), "someMethod") == 0);
assert(strcmp((d.types), "@:") == 0);
checkProtocolMethod(p1, @selector(someClassMethod), YES, NO);
checkProtocolMethod(p1, @selector(someOptionalClassMethod), YES, YES);
checkProtocolMethod(p1, @selector(someMethod), NO, NO);
checkProtocolMethod(p1, @selector(someOtherMethod), NO, NO);
checkProtocolMethod(p1, @selector(someOptionalMethod), NO, YES);
// Added after the protocol was registered, shouldn't have been allowed.
struct objc_method_description d = protocol_getMethodDescription(p1, @selector(someUnsupportedMethod), NO, NO);
assert(d.name == NULL);
assert(d.types == NULL);
assert(protocol_conformsToProtocol(p1, objc_getProtocol("Test2")));
assert(protocol_conformsToProtocol(p1, objc_getProtocol("Test3")));
// Added after the protocol was registered, shouldn't have been allowed.
assert(!protocol_conformsToProtocol(p1, objc_getProtocol("Test4")));
unsigned int count;
objc_property_t *props = protocol_copyPropertyList(p1, &count);
protocol_copyPropertyList(p1, &count);
assert(count == 2);
protocol_copyPropertyList2(p1, &count, YES, YES);
assert(count == 2);
objc_property_t *props = protocol_copyPropertyList2(p1, &count, NO, YES);
assert(count == 1);
assert(strcmp("T@,Vfoo", property_getAttributes(*props)) == 0);
assert(strcmp("T@,Voptional", property_getAttributes(*props)) == 0);
//objc_copyProtocolList
return 0;
}

@ -715,12 +715,20 @@ struct objc_method_description *protocol_copyMethodDescriptionList(Protocol *p,
BOOL isRequiredMethod, BOOL isInstanceMethod, unsigned int *count);
/**
* Returns an array of property metadata values, with the number being stored
* in the variable pointed to by the last argument. The caller is responsible
* for freeing the returned array.
* Returns an array of required instance properties, with the number being
* stored in the variable pointed to by the last argument. The caller is
* responsible for freeing the returned array.
*/
objc_property_t *protocol_copyPropertyList(Protocol *p, unsigned int *count);
/**
* Returns an array of properties specified by this class, with the number
* being stored in the variable pointed to by the last argument. The caller is
* responsible for freeing the returned array.
*/
objc_property_t *protocol_copyPropertyList2(Protocol *p, unsigned int *count,
BOOL isRequiredProperty, BOOL isInstanceProperty);
/**
* Returns an array of protocols that this protocol conforms to, with the
* number of protocols in the array being returned via the last argument. The

@ -391,23 +391,28 @@ Protocol*__unsafe_unretained* protocol_copyProtocolList(Protocol *p, unsigned in
return out;
}
objc_property_t *protocol_copyPropertyList(Protocol *p,
unsigned int *outCount)
objc_property_t *protocol_copyPropertyList2(Protocol *p, unsigned int *outCount,
BOOL isRequiredProperty, BOOL isInstanceProperty)
{
struct objc_property_list *properties =
isInstanceProperty ?
(isRequiredProperty ? p->properties : p->optional_properties) :
(isRequiredProperty ? p->class_properties : p->optional_class_properties);
if (NULL == p) { return NULL; }
if (!protocol_hasOptionalMethodsAndProperties(p))
// If it's an old protocol, it won't have any of the other options.
if (!isRequiredProperty && !isInstanceProperty &&
!protocol_hasOptionalMethodsAndProperties(p))
{
return NULL;
}
struct objc_property_list *properties = p->properties;
unsigned int count = 0;
if (NULL != properties)
if (properties == NULL)
{
count = properties->count;
return NULL;
}
if (NULL != p->optional_properties)
unsigned int count = 0;
for (struct objc_property_list *l=properties ; l!=NULL ; l=l->next)
{
count += p->optional_properties->count;
count += properties->count;
}
if (0 == count)
{
@ -415,25 +420,23 @@ objc_property_t *protocol_copyPropertyList(Protocol *p,
}
objc_property_t *list = calloc(sizeof(objc_property_t), count);
unsigned int out = 0;
if (properties)
{
for (int i=0 ; i<properties->count ; i++)
{
list[out++] = property_at_index(properties, i);
}
}
properties = p->optional_properties;
if (properties)
for (struct objc_property_list *l=properties ; l!=NULL ; l=l->next)
{
for (int i=0 ; i<properties->count ; i++)
for (int i=0 ; i<l->count ; i++)
{
list[out++] = property_at_index(properties, i);
list[out++] = property_at_index(l, i);
}
}
*outCount = count;
return list;
}
objc_property_t *protocol_copyPropertyList(Protocol *p,
unsigned int *outCount)
{
return protocol_copyPropertyList2(p, outCount, YES, YES);
}
objc_property_t protocol_getProperty(Protocol *p,
const char *name,
BOOL isRequiredProperty,
@ -658,7 +661,6 @@ void protocol_addProtocol(Protocol *aProtocol, Protocol *addition)
aProtocol->protocol_list->count++;
aProtocol->protocol_list = realloc(aProtocol->protocol_list, sizeof(struct objc_property_list) +
aProtocol->protocol_list->count * sizeof(Protocol*));
aProtocol->protocol_list->count = 1;
}
aProtocol->protocol_list->list[aProtocol->protocol_list->count-1] = (Protocol*)addition;
}
@ -672,15 +674,10 @@ void protocol_addProperty(Protocol *aProtocol,
if ((NULL == aProtocol) || (NULL == name)) { return; }
if (incompleteProtocolClass() != aProtocol->isa) { return; }
if (!isInstanceProperty) { return; }
struct objc_property_list **listPtr;
if (isRequiredProperty)
{
listPtr = &aProtocol->properties;
}
else
{
listPtr = &aProtocol->optional_properties;
}
struct objc_property_list **listPtr =
isInstanceProperty ?
(isRequiredProperty ? &aProtocol->properties : &aProtocol->optional_properties) :
(isRequiredProperty ? &aProtocol->class_properties : &aProtocol->optional_class_properties);
if (NULL == *listPtr)
{
*listPtr = calloc(1, sizeof(struct objc_property_list) + sizeof(struct objc_property));

Loading…
Cancel
Save