Home | History | Annotate | Download | only in OCMock
      1 //---------------------------------------------------------------------------------------
      2 //  $Id$
      3 //  Copyright (c) 2006-2009 by Mulle Kybernetik. See License file for details.
      4 //---------------------------------------------------------------------------------------
      5 
      6 #import "NSInvocation+OCMAdditions.h"
      7 
      8 
      9 @implementation NSInvocation(OCMAdditions)
     10 
     11 - (id)getArgumentAtIndexAsObject:(int)argIndex
     12 {
     13 	const char* argType;
     14 	
     15 	argType = [[self methodSignature] getArgumentTypeAtIndex:argIndex];
     16 	while(strchr("rnNoORV", argType[0]) != NULL)
     17 		argType += 1;
     18 	
     19 	if((strlen(argType) > 1) && (strchr("{^", argType[0]) == NULL) && (strcmp("@?", argType) != 0))
     20 		[NSException raise:NSInvalidArgumentException format:@"Cannot handle argument type '%s'.", argType];
     21 	
     22 	switch (argType[0]) 
     23 	{
     24 		case '#':
     25 		case '@': 
     26 		{
     27 			id value;
     28 			[self getArgument:&value atIndex:argIndex];
     29 			return value;
     30 		}
     31 		case ':':
     32  		{
     33  			SEL s = (SEL)0;
     34  			[self getArgument:&s atIndex:argIndex];
     35  			id value = NSStringFromSelector(s);
     36  			return value;
     37  		}
     38 		case 'i': 
     39 		{
     40 			int value;
     41 			[self getArgument:&value atIndex:argIndex];
     42 			return [NSNumber numberWithInt:value];
     43 		}	
     44 		case 's':
     45 		{
     46 			short value;
     47 			[self getArgument:&value atIndex:argIndex];
     48 			return [NSNumber numberWithShort:value];
     49 		}	
     50 		case 'l':
     51 		{
     52 			long value;
     53 			[self getArgument:&value atIndex:argIndex];
     54 			return [NSNumber numberWithLong:value];
     55 		}	
     56 		case 'q':
     57 		{
     58 			long long value;
     59 			[self getArgument:&value atIndex:argIndex];
     60 			return [NSNumber numberWithLongLong:value];
     61 		}	
     62 		case 'c':
     63 		{
     64 			char value;
     65 			[self getArgument:&value atIndex:argIndex];
     66 			return [NSNumber numberWithChar:value];
     67 		}	
     68 		case 'C':
     69 		{
     70 			unsigned char value;
     71 			[self getArgument:&value atIndex:argIndex];
     72 			return [NSNumber numberWithUnsignedChar:value];
     73 		}	
     74 		case 'I':
     75 		{
     76 			unsigned int value;
     77 			[self getArgument:&value atIndex:argIndex];
     78 			return [NSNumber numberWithUnsignedInt:value];
     79 		}	
     80 		case 'S':
     81 		{
     82 			unsigned short value;
     83 			[self getArgument:&value atIndex:argIndex];
     84 			return [NSNumber numberWithUnsignedShort:value];
     85 		}	
     86 		case 'L':
     87 		{
     88 			unsigned long value;
     89 			[self getArgument:&value atIndex:argIndex];
     90 			return [NSNumber numberWithUnsignedLong:value];
     91 		}	
     92 		case 'Q':
     93 		{
     94 			unsigned long long value;
     95 			[self getArgument:&value atIndex:argIndex];
     96 			return [NSNumber numberWithUnsignedLongLong:value];
     97 		}	
     98 		case 'f':
     99 		{
    100 			float value;
    101 			[self getArgument:&value atIndex:argIndex];
    102 			return [NSNumber numberWithFloat:value];
    103 		}	
    104 		case 'd':
    105 		{
    106 			double value;
    107 			[self getArgument:&value atIndex:argIndex];
    108 			return [NSNumber numberWithDouble:value];
    109 		}	
    110 		case 'B':
    111 		{
    112 			bool value;
    113 			[self getArgument:&value atIndex:argIndex];
    114 			return [NSNumber numberWithBool:value];
    115 		}
    116 		case '^':
    117         {
    118             void *value = NULL;
    119             [self getArgument:&value atIndex:argIndex];
    120             return [NSValue valueWithPointer:value];
    121         }
    122 		case '{': // structure
    123 		{
    124 			NSUInteger maxArgSize = [[self methodSignature] frameLength];
    125 			NSMutableData *argumentData = [[[NSMutableData alloc] initWithLength:maxArgSize] autorelease];
    126 			[self getArgument:[argumentData mutableBytes] atIndex:argIndex];
    127 			return [NSValue valueWithBytes:[argumentData bytes] objCType:argType];
    128 		}       
    129 			
    130 	}
    131 	[NSException raise:NSInvalidArgumentException format:@"Argument type '%s' not supported", argType];
    132 	return nil;
    133 }
    134 
    135 - (NSString *)invocationDescription
    136 {
    137 	NSMethodSignature *methodSignature = [self methodSignature];
    138 	NSUInteger numberOfArgs = [methodSignature numberOfArguments];
    139 	
    140 	if (numberOfArgs == 2)
    141 		return NSStringFromSelector([self selector]);
    142 	
    143 	NSArray *selectorParts = [NSStringFromSelector([self selector]) componentsSeparatedByString:@":"];
    144 	NSMutableString *description = [[NSMutableString alloc] init];
    145 	unsigned int i;
    146 	for(i = 2; i < numberOfArgs; i++)
    147 	{
    148 		[description appendFormat:@"%@%@:", (i > 2 ? @" " : @""), [selectorParts objectAtIndex:(i - 2)]];
    149 		[description appendString:[self argumentDescriptionAtIndex:i]];
    150 	}
    151 	
    152 	return [description autorelease];
    153 }
    154 
    155 - (NSString *)argumentDescriptionAtIndex:(int)argIndex
    156 {
    157 	const char *argType = [[self methodSignature] getArgumentTypeAtIndex:argIndex];
    158 	if(strchr("rnNoORV", argType[0]) != NULL)
    159 		argType += 1;
    160 
    161 	switch(*argType)
    162 	{
    163 		case '@':	return [self objectDescriptionAtIndex:argIndex];
    164 		case 'B':	return [self boolDescriptionAtIndex:argIndex];
    165 		case 'c':	return [self charDescriptionAtIndex:argIndex];
    166 		case 'C':	return [self unsignedCharDescriptionAtIndex:argIndex];
    167 		case 'i':	return [self intDescriptionAtIndex:argIndex];
    168 		case 'I':	return [self unsignedIntDescriptionAtIndex:argIndex];
    169 		case 's':	return [self shortDescriptionAtIndex:argIndex];
    170 		case 'S':	return [self unsignedShortDescriptionAtIndex:argIndex];
    171 		case 'l':	return [self longDescriptionAtIndex:argIndex];
    172 		case 'L':	return [self unsignedLongDescriptionAtIndex:argIndex];
    173 		case 'q':	return [self longLongDescriptionAtIndex:argIndex];
    174 		case 'Q':	return [self unsignedLongLongDescriptionAtIndex:argIndex];
    175 		case 'd':	return [self doubleDescriptionAtIndex:argIndex];
    176 		case 'f':	return [self floatDescriptionAtIndex:argIndex];
    177 		// Why does this throw EXC_BAD_ACCESS when appending the string?
    178 		//	case NSObjCStructType: return [self structDescriptionAtIndex:index];
    179 		case '^':	return [self pointerDescriptionAtIndex:argIndex];
    180 		case '*':	return [self cStringDescriptionAtIndex:argIndex];
    181 		case ':':	return [self selectorDescriptionAtIndex:argIndex];
    182 		default:	return [@"<??" stringByAppendingString:@">"];  // avoid confusion with trigraphs...
    183 	}
    184 	
    185 }
    186 
    187 
    188 - (NSString *)objectDescriptionAtIndex:(int)anInt
    189 {
    190 	id object;
    191 	
    192 	[self getArgument:&object atIndex:anInt];
    193 	if (object == nil)
    194 		return @"nil";
    195 	else if(![object isProxy] && [object isKindOfClass:[NSString class]])
    196 		return [NSString stringWithFormat:@"@\"%@\"", [object description]];
    197 	else
    198 		return [object description];
    199 }
    200 
    201 - (NSString *)boolDescriptionAtIndex:(int)anInt
    202 {
    203 	bool value;
    204 
    205 	[self getArgument:&value atIndex:anInt];
    206 	return value ? @"YES" : @"NO";
    207 }
    208 
    209 - (NSString *)charDescriptionAtIndex:(int)anInt
    210 {
    211 	unsigned char buffer[128];
    212 	memset(buffer, 0x0, 128);
    213 	
    214 	[self getArgument:&buffer atIndex:anInt];
    215 	
    216 	// If there's only one character in the buffer, and it's 0 or 1, then we have a BOOL
    217 	if (buffer[1] == '\0' && (buffer[0] == 0 || buffer[0] == 1))
    218 		return [NSString stringWithFormat:@"%@", (buffer[0] == 1 ? @"YES" : @"NO")];
    219 	else
    220 		return [NSString stringWithFormat:@"'%c'", *buffer];
    221 }
    222 
    223 - (NSString *)unsignedCharDescriptionAtIndex:(int)anInt
    224 {
    225 	unsigned char buffer[128];
    226 	memset(buffer, 0x0, 128);
    227 	
    228 	[self getArgument:&buffer atIndex:anInt];
    229 	return [NSString stringWithFormat:@"'%c'", *buffer];
    230 }
    231 
    232 - (NSString *)intDescriptionAtIndex:(int)anInt
    233 {
    234 	int intValue;
    235 	
    236 	[self getArgument:&intValue atIndex:anInt];
    237 	return [NSString stringWithFormat:@"%d", intValue];
    238 }
    239 
    240 - (NSString *)unsignedIntDescriptionAtIndex:(int)anInt
    241 {
    242 	unsigned int intValue;
    243 	
    244 	[self getArgument:&intValue atIndex:anInt];
    245 	return [NSString stringWithFormat:@"%d", intValue];
    246 }
    247 
    248 - (NSString *)shortDescriptionAtIndex:(int)anInt
    249 {
    250 	short shortValue;
    251 	
    252 	[self getArgument:&shortValue atIndex:anInt];
    253 	return [NSString stringWithFormat:@"%hi", shortValue];
    254 }
    255 
    256 - (NSString *)unsignedShortDescriptionAtIndex:(int)anInt
    257 {
    258 	unsigned short shortValue;
    259 	
    260 	[self getArgument:&shortValue atIndex:anInt];
    261 	return [NSString stringWithFormat:@"%hu", shortValue];
    262 }
    263 
    264 - (NSString *)longDescriptionAtIndex:(int)anInt
    265 {
    266 	long longValue;
    267 	
    268 	[self getArgument:&longValue atIndex:anInt];
    269 	return [NSString stringWithFormat:@"%ld", longValue];
    270 }
    271 
    272 - (NSString *)unsignedLongDescriptionAtIndex:(int)anInt
    273 {
    274 	unsigned long longValue;
    275 	
    276 	[self getArgument:&longValue atIndex:anInt];
    277 	return [NSString stringWithFormat:@"%lu", longValue];
    278 }
    279 
    280 - (NSString *)longLongDescriptionAtIndex:(int)anInt
    281 {
    282 	long long longLongValue;
    283 	
    284 	[self getArgument:&longLongValue atIndex:anInt];
    285 	return [NSString stringWithFormat:@"%qi", longLongValue];
    286 }
    287 
    288 - (NSString *)unsignedLongLongDescriptionAtIndex:(int)anInt
    289 {
    290 	unsigned long long longLongValue;
    291 	
    292 	[self getArgument:&longLongValue atIndex:anInt];
    293 	return [NSString stringWithFormat:@"%qu", longLongValue];
    294 }
    295 
    296 - (NSString *)doubleDescriptionAtIndex:(int)anInt;
    297 {
    298 	double doubleValue;
    299 	
    300 	[self getArgument:&doubleValue atIndex:anInt];
    301 	return [NSString stringWithFormat:@"%f", doubleValue];
    302 }
    303 
    304 - (NSString *)floatDescriptionAtIndex:(int)anInt
    305 {
    306 	float floatValue;
    307 	
    308 	[self getArgument:&floatValue atIndex:anInt];
    309 	return [NSString stringWithFormat:@"%f", floatValue];
    310 }
    311 
    312 - (NSString *)structDescriptionAtIndex:(int)anInt;
    313 {
    314 	void *buffer;
    315 	
    316 	[self getArgument:&buffer atIndex:anInt];
    317 	return [NSString stringWithFormat:@":(struct)%p", buffer];
    318 }
    319 
    320 - (NSString *)pointerDescriptionAtIndex:(int)anInt
    321 {
    322 	void *buffer;
    323 	
    324 	[self getArgument:&buffer atIndex:anInt];
    325 	return [NSString stringWithFormat:@"%p", buffer];
    326 }
    327 
    328 - (NSString *)cStringDescriptionAtIndex:(int)anInt
    329 {
    330 	char buffer[128];
    331 	
    332 	memset(buffer, 0x0, 128);
    333 	
    334 	[self getArgument:&buffer atIndex:anInt];
    335 	return [NSString stringWithFormat:@"\"%s\"", buffer];
    336 }
    337 
    338 - (NSString *)selectorDescriptionAtIndex:(int)anInt
    339 {
    340 	SEL selectorValue;
    341 	
    342 	[self getArgument:&selectorValue atIndex:anInt];
    343 	return [NSString stringWithFormat:@"@selector(%@)", NSStringFromSelector(selectorValue)];
    344 }
    345 
    346 @end
    347