Skip to content
This repository has been archived by the owner on Apr 18, 2023. It is now read-only.

Support for primitive return type method signatures #9

Merged
merged 4 commits into from
Dec 10, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and limitations under the License.

#import "DixieConstantChaosProvider.h"
#import "NSObject+DixieRunTimeHelper.h"

@interface DixieConstantChaosProvider()

Expand All @@ -31,7 +32,17 @@ +(instancetype) constant:(id)constant

-(void) chaosImplementationFor:(id)victim environment:(DixieCallEnvironment *)environment
{
environment.returnValue = self.constant;
if(isType(self.context.methodInfo.signature.methodReturnType, void) == NO)
{
if(isType(self.context.methodInfo.signature.methodReturnType, id) ||
strcmp(self.context.methodInfo.signature.methodReturnType, "@?") == 0)
{
environment.returnValue = (__bridge void *)(self.constant);
}
else{
environment.returnValue = [(NSObject *)self.constant originalValue];
}
}
}

@end
15 changes: 8 additions & 7 deletions Dixie/Dixie/ChaosProvider/DixieBaseChaosProvider.m
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,14 @@ -(IMP) chaos
environment:^(id victim, DixieCallEnvironment *environment) {

[self chaosImplementationFor:victim environment:environment];

[[DixieLogger defaultLogger] log:@"Puppet %@: %@ used %@ to return %@",
NSStringFromClass([victim class]),
NSStringFromSelector(self.context.methodInfo.selector),
[self class],
environment.returnValue];

if(isType(self.context.methodInfo.signature.methodReturnType, id))
{
[[DixieLogger defaultLogger] log:@"Puppet %@: %@ used %@ to return %@",
NSStringFromClass([victim class]),
NSStringFromSelector(self.context.methodInfo.selector),
[self class],
environment.returnValue];
}
}];
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,9 @@ -(IMP) chaos
return self.context.originalIMP;
}

-(void) chaosImplementationFor:(id)victim environment:(DixieCallEnvironment *)environment
{
[DixieRunTimeHelper callImplementation:self.context.originalIMP on:victim chaosContext:self.context environment:environment];
}

@end
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,6 @@ -(void) setContext:(DixieChaosContext *)context

-(void) chaosImplementationFor:(id)victim environment:(DixieCallEnvironment *)environment
{
environment.returnValue = [self.paramProvider parameter];
environment.returnValue = (__bridge void *)([self.paramProvider parameter]);
}
@end
2 changes: 1 addition & 1 deletion Dixie/Dixie/Runtime/DixieCallEnvironment.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
/**
* The return value of a method's implementation
*/
@property (nonatomic) id returnValue;
@property (nonatomic) void *returnValue;

/**
* Creates a DixieCallEnvironment with the arguments
Expand Down
2 changes: 2 additions & 0 deletions Dixie/Dixie/Runtime/DixieRunTimeHelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@

#define DixieMethodPrefix @"dixie_"

#define isType(typeEncoding, type2) (strcmp(typeEncoding, @encode(type2)) == 0)

/**
* Block type to describe a method's concrete implementation
*
Expand Down
116 changes: 60 additions & 56 deletions Dixie/Dixie/Runtime/DixieRunTimeHelper.m
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,6 @@
#import "DixieRunTimeHelper.h"
#import "NSObject+DixieRunTimeHelper.h"

#define isType(type1, type2) (strcmp(type1, @encode(type2)) == 0)

#define storeOriginal(object , type, original) \
({ \
object.originalValue = (void*)malloc(sizeof(type)); \
((type*)object.originalValue)[0] = original; \
}) \

@interface NSInvocation (PrivateHack)
- (void)invokeUsingIMP: (IMP)imp;
@end
Expand Down Expand Up @@ -74,47 +66,46 @@ +(IMP) implementationWithChaosContext:(DixieChaosContext*)chaosContext environme
*/
+(id) blockForSignature:(NSMethodSignature*)signature block:(DixieImplementationBlock)block
{
const char* rType = signature.methodReturnType;

if (isType(rType, void))
{
return ^void(id victim, ...){ \

va_list args;
va_start(args, victim);

NSArray* arguments = [self argumentsFor:signature originalArguments:args];

va_end(args);

DixieCallEnvironment* environment = [[DixieCallEnvironment alloc] initWithArguments:arguments];

block(victim, environment);
};
#define BLOCK_ID \
^id(id victim, ...){ \
va_list args; \
va_start(args, victim); \
\
NSArray* arguments = [self argumentsFor:signature originalArguments:args]; \
DixieCallEnvironment* environment = [[DixieCallEnvironment alloc] initWithArguments:arguments]; \
block(victim, environment); \
return environment.returnValue; \
}
else
{
return ^id (id victim, ...){ \

va_list args;
va_start(args, victim);

NSArray* arguments = [self argumentsFor:signature originalArguments:args];

va_end(args);

DixieCallEnvironment* environment = [[DixieCallEnvironment alloc] initWithArguments:arguments];

block(victim, environment);

return environment.returnValue;
};

#define BLOCK(TYPE) \
^TYPE(id victim, ...){ \
va_list args; \
va_start(args, victim); \
\
NSArray* arguments = [self argumentsFor:signature originalArguments:args]; \
DixieCallEnvironment* environment = [[DixieCallEnvironment alloc] initWithArguments:arguments]; \
block(victim, environment); \
return *(TYPE *)environment.returnValue; \
}

const char* rType = signature.methodReturnType;

if (isType(rType, void)) return BLOCK(void);
if (isType(rType, BOOL)) return BLOCK(BOOL);
if (isType(rType, int)) return BLOCK(int);
if (isType(rType, char)) return BLOCK(char);
if (isType(rType, double)) return BLOCK(double);
if (isType(rType, float)) return BLOCK(float);
if (isType(rType, long)) return BLOCK(long);
if (isType(rType, short)) return BLOCK(short);
if (isType(rType, unsigned int)) return BLOCK(unsigned int);

return BLOCK_ID;
}

/**
* Parses a variadic list into array of objects
@note The current solution handles only object,selector,BOOL and char types.
* Parses a variadic list into array of objects
@note The current solution handles only object,selector,BOOL and char types.
*
* @param signature The signature to determine the type of parameters in the variadic list
* @param arguments The variadic list
Expand All @@ -126,14 +117,16 @@ +(NSArray*) argumentsFor:(NSMethodSignature*)signature originalArguments:(va_lis
//Ignore self and _cmd
NSInteger numberOfParameters = signature.numberOfArguments-2;
NSMutableArray* parameters = [NSMutableArray arrayWithCapacity:numberOfParameters];
va_list iteratorList;
__va_copy(iteratorList, arguments);

for (NSInteger index = 0; index < numberOfParameters; index++) {

//Only read argument after self and _cmd
const char* argTyp = [signature getArgumentTypeAtIndex:index + 2];

//Convert to object
id parameter = [self objectFromNext:arguments type:argTyp];
id parameter = [self objectFromNext:iteratorList type:argTyp outputArgumentList:&iteratorList];

//Fill the unparsed value with NSNull
parameter = parameter ? :[NSNull null];
Expand All @@ -151,7 +144,7 @@ +(void) callImplementation:(IMP)implementation on:(id)puppet chaosContext:(Dixie

[invocation setTarget:puppet];
[invocation setSelector:chaosContext.methodInfo.selector];

//We are ignoring the index of self and _cmd
for (NSInteger i = 2; i < signature.numberOfArguments; i++) {

Expand All @@ -175,12 +168,20 @@ +(void) callImplementation:(IMP)implementation on:(id)puppet chaosContext:(Dixie
}

[invocation invokeUsingIMP:implementation];

if (!isType(chaosContext.methodInfo.signature.methodReturnType, void))
{
__unsafe_unretained id returnValue;
[invocation getReturnValue:&returnValue];
environment.returnValue = returnValue;
if(isType(chaosContext.methodInfo.signature.methodReturnType, id))
{
id returnValue;
[invocation getReturnValue:&returnValue];
environment.returnValue = (void*)CFBridgingRetain(returnValue);
}
else
{
void *returnValue = malloc(chaosContext.methodInfo.signature.methodReturnLength);
environment.returnValue = returnValue;
}
}
}

Expand All @@ -190,11 +191,12 @@ +(void) callImplementation:(IMP)implementation on:(id)puppet chaosContext:(Dixie
* @note We are using core foundation factories here, NSNumber, NSString might be swizzled
*
* @param arguments The variadic list
* @param argType the expected type of the next item
* @param argType The expected type of the next item
* @param ova_List The current state of the variadic list after the current value is read from it
*
* @return An NSObject subclass that represents the argument
*/
+(id) objectFromNext:(va_list)arguments type:(const char*)argType
+(NSObject *) objectFromNext:(va_list)arguments type:(const char*)argType outputArgumentList:(out void *)ova_List
{
NSObject* object;

Expand Down Expand Up @@ -280,13 +282,13 @@ +(id) objectFromNext:(va_list)arguments type:(const char*)argType
}
//Object
else if (strcmp(argType, "@") == 0 ||//NSObject
strcmp(argType, "no@") == 0 || //NSObject?
strcmp(argType, "@?") == 0 //Block
)
strcmp(argType, "no@") == 0 || //NSObject?
strcmp(argType, "@?") == 0 //Block
)
{
id data = va_arg(arguments, id);

object = data;
object = strcmp(argType, "@?") == 0 ? [data copy] : data;
}
//class
else if (isType(argType, Class))
Expand Down Expand Up @@ -317,6 +319,8 @@ +(id) objectFromNext:(va_list)arguments type:(const char*)argType
//Set the original encoding on the object
[object setEncoding:[NSString stringWithUTF8String:argType]];

ova_List = &arguments;

return object;
}

Expand Down
6 changes: 6 additions & 0 deletions Dixie/Dixie/Runtime/NSObject+DixieRunTimeHelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@

@import Foundation;

#define storeOriginal(object , type, original) \
({ \
object.originalValue = (void*)malloc(sizeof(type)); \
((type*)object.originalValue)[0] = original; \
}) \

/**
* Helper category on NSObject to store the original type encoding and value if the object was converted from non-object type
*/
Expand Down
35 changes: 34 additions & 1 deletion Dixie/DixieTests/Helpers/ChaosProviderTestClass.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,44 @@
// See the License for the specific language governing permissions and limitations under the License.

#import <Foundation/Foundation.h>
#import <CoreGraphics/CGGeometry.h>

typedef int(^TestBlockType)(double, BOOL);

@protocol ChaosProviderTestClassDelegate <NSObject>

-(BOOL) isItTrue;

@end

/*!
A class to test various method types
*/
@interface ChaosProviderTestClass : NSObject

- (id)returnValue;
@property (nonatomic, weak) id<ChaosProviderTestClassDelegate> testDelegate;

-(id) returnValue;
-(NSNumber*) numberFromInteger:(int)integer;
-(NSString*) variadicMethod:(id)key,... NS_REQUIRES_NIL_TERMINATION;
-(int) returnIntValue;

+(void) classDoNothing;
-(void) throwException;
-(void) doNothing;

-(void) setNumber:(int)number object:(NSNumber *)numberObj block:(dispatch_block_t)block;
-(void) setChar:(char)aChar frame:(CGRect)frame;

-(id) arg1:(NSNumber *)arg1 arg2:(NSInteger)arg2 arg3:(double)arg3 arg4:(float)arg4 arg5:(int)arg5 arg6:(int*)arg6 arg7:(BOOL)arg7 arg8:(char)arg8 arg9:(short)arg9 arg10:(long)arg10;
-(float) valueFrom:(double)doubleValue;
-(TestBlockType) block;

@end

@interface ChaosProviderTestClass(aCategory)

-(unsigned int) randomIntFrom:(int)k;

@end