From a39aea7ba53f5a4bc3c9baf809556e98dd6224a5 Mon Sep 17 00:00:00 2001 From: Roustem Karimov Date: Fri, 13 Jul 2012 01:05:01 -0400 Subject: [PATCH] Adding stub:withBlock: method to Mock objects. It let's you implement any method on the Mock object with a block. --- Kiwi.xcodeproj/project.pbxproj | 12 ++ Kiwi/KWMock.h | 1 + Kiwi/KWMock.m | 12 ++ Kiwi/KWStub.h | 3 + Kiwi/KWStub.m | 29 +++ Kiwi/NSInvocation+OCMAdditions.h | 34 ++++ Kiwi/NSInvocation+OCMAdditions.m | 337 +++++++++++++++++++++++++++++++ 7 files changed, 428 insertions(+) create mode 100644 Kiwi/NSInvocation+OCMAdditions.h create mode 100644 Kiwi/NSInvocation+OCMAdditions.m diff --git a/Kiwi.xcodeproj/project.pbxproj b/Kiwi.xcodeproj/project.pbxproj index 4855abc7..100e356b 100755 --- a/Kiwi.xcodeproj/project.pbxproj +++ b/Kiwi.xcodeproj/project.pbxproj @@ -388,6 +388,10 @@ A3EB8065131EA574001860F5 /* KWHamrestMatchingAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = A352EA0D12EDC6F20049C691 /* KWHamrestMatchingAdditions.m */; }; A3FABFAF13CBB187002003F7 /* KiwiBlockMacros.h in Headers */ = {isa = PBXBuildFile; fileRef = A3FABFAE13CBB187002003F7 /* KiwiBlockMacros.h */; settings = {ATTRIBUTES = (Public, ); }; }; ADBF4B031511C6B300784E9E /* KWAny.h in Headers */ = {isa = PBXBuildFile; fileRef = F5FC83B611B100B100BF98A7 /* KWAny.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B36B276415AFD5120056C31D /* NSInvocation+OCMAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = B36B276215AFD5120056C31D /* NSInvocation+OCMAdditions.h */; }; + B36B276515AFD5120056C31D /* NSInvocation+OCMAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = B36B276215AFD5120056C31D /* NSInvocation+OCMAdditions.h */; }; + B36B276615AFD5120056C31D /* NSInvocation+OCMAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = B36B276315AFD5120056C31D /* NSInvocation+OCMAdditions.m */; }; + B36B276715AFD5120056C31D /* NSInvocation+OCMAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = B36B276315AFD5120056C31D /* NSInvocation+OCMAdditions.m */; }; C922D1DA1580438300995B43 /* KWStringContainsMatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = C922D1D81580438300995B43 /* KWStringContainsMatcher.m */; }; C922D1DD158045FC00995B43 /* KWStringContainsMatcherTest.m in Sources */ = {isa = PBXBuildFile; fileRef = C922D1DC158045FC00995B43 /* KWStringContainsMatcherTest.m */; }; C922D1DE1580484300995B43 /* KWStringContainsMatcher.h in Headers */ = {isa = PBXBuildFile; fileRef = C922D1D71580438300995B43 /* KWStringContainsMatcher.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -668,6 +672,8 @@ A3CB75E0144C3479002D1F7A /* KWExampleSuite.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KWExampleSuite.h; sourceTree = ""; }; A3CB75E1144C3479002D1F7A /* KWExampleSuite.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KWExampleSuite.m; sourceTree = ""; }; A3FABFAE13CBB187002003F7 /* KiwiBlockMacros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KiwiBlockMacros.h; sourceTree = ""; }; + B36B276215AFD5120056C31D /* NSInvocation+OCMAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSInvocation+OCMAdditions.h"; sourceTree = ""; }; + B36B276315AFD5120056C31D /* NSInvocation+OCMAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSInvocation+OCMAdditions.m"; sourceTree = ""; }; C922D1D71580438300995B43 /* KWStringContainsMatcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KWStringContainsMatcher.h; sourceTree = ""; }; C922D1D81580438300995B43 /* KWStringContainsMatcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KWStringContainsMatcher.m; sourceTree = ""; }; C922D1DC158045FC00995B43 /* KWStringContainsMatcherTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KWStringContainsMatcherTest.m; sourceTree = ""; }; @@ -1180,6 +1186,8 @@ F5BDB7A511C0C04200DD3474 /* KWWorkarounds.m */, F52CD2A7115E1E760038A6A2 /* NSInvocation+KiwiAdditions.h */, F52CD2A8115E1E760038A6A2 /* NSInvocation+KiwiAdditions.m */, + B36B276215AFD5120056C31D /* NSInvocation+OCMAdditions.h */, + B36B276315AFD5120056C31D /* NSInvocation+OCMAdditions.m */, F5015B6D1158398E002E9A98 /* NSMethodSignature+KiwiAdditions.h */, F5015B6E1158398E002E9A98 /* NSMethodSignature+KiwiAdditions.m */, F5B3FDC41178B15E00ECF9E8 /* NSNumber+KiwiAdditions.h */, @@ -1420,6 +1428,7 @@ 832C837A157263B300F160D5 /* KWCaptureSpy.h in Headers */, C922D1EA15805AEB00995B43 /* KWStringPrefixMatcher.h in Headers */, C922D1EB15805AF000995B43 /* KWStringContainsMatcher.h in Headers */, + B36B276515AFD5120056C31D /* NSInvocation+OCMAdditions.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1515,6 +1524,7 @@ 4B45D6BD1548765800793B1E /* KWCaptureSpy.h in Headers */, C922D1DE1580484300995B43 /* KWStringContainsMatcher.h in Headers */, C922D1DF1580487700995B43 /* KWStringPrefixMatcher.h in Headers */, + B36B276415AFD5120056C31D /* NSInvocation+OCMAdditions.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1782,6 +1792,7 @@ 832C83C2157263B300F160D5 /* KWCaptureSpy.m in Sources */, C922D1E915805ADC00995B43 /* KWStringPrefixMatcher.m in Sources */, C922D1EC15805AF600995B43 /* KWStringContainsMatcher.m in Sources */, + B36B276715AFD5120056C31D /* NSInvocation+OCMAdditions.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1880,6 +1891,7 @@ 4B45D6BE1548765800793B1E /* KWCaptureSpy.m in Sources */, C922D1DA1580438300995B43 /* KWStringContainsMatcher.m in Sources */, C922D1E715805ADB00995B43 /* KWStringPrefixMatcher.m in Sources */, + B36B276615AFD5120056C31D /* NSInvocation+OCMAdditions.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Kiwi/KWMock.h b/Kiwi/KWMock.h index fb5ed27d..0e7e4bee 100644 --- a/Kiwi/KWMock.h +++ b/Kiwi/KWMock.h @@ -59,6 +59,7 @@ #pragma mark Stubbing Methods - (void)stub:(SEL)aSelector; +- (void)stub:(SEL)aSelector withBlock:(id (^)(NSArray *params))block; - (void)stub:(SEL)aSelector withArguments:(id)firstArgument, ...; - (void)stub:(SEL)aSelector andReturn:(id)aValue; - (void)stub:(SEL)aSelector andReturn:(id)aValue withArguments:(id)firstArgument, ...; diff --git a/Kiwi/KWMock.m b/Kiwi/KWMock.m index da20d339..c759c968 100644 --- a/Kiwi/KWMock.m +++ b/Kiwi/KWMock.m @@ -217,6 +217,11 @@ - (void)stub:(SEL)aSelector { [self stubMessagePattern:messagePattern andReturn:nil]; } +- (void)stub:(SEL)aSelector withBlock:(id (^)(NSArray *params))block { + KWMessagePattern *messagePattern = [KWMessagePattern messagePatternWithSelector:aSelector]; + [self stubMessagePattern:messagePattern withBlock:block]; +} + - (void)stub:(SEL)aSelector withArguments:(id)firstArgument, ... { va_list argumentList; va_start(argumentList, firstArgument); @@ -259,6 +264,13 @@ - (void)stubMessagePattern:(KWMessagePattern *)aMessagePattern andReturn:(id)aVa [self.stubs addObject:stub]; } +- (void)stubMessagePattern:(KWMessagePattern *)aMessagePattern withBlock:(id (^)(NSArray *params))block { + [self expectMessagePattern:aMessagePattern]; + [self removeStubWithMessagePattern:aMessagePattern]; + KWStub *stub = [KWStub stubWithMessagePattern:aMessagePattern block:block]; + [self.stubs addObject:stub]; +} + - (void)stubMessagePattern:(KWMessagePattern *)aMessagePattern andReturn:(id)aValue times:(id)times afterThatReturn:(id)aSecondValue { [self expectMessagePattern:aMessagePattern]; [self removeStubWithMessagePattern:aMessagePattern]; diff --git a/Kiwi/KWStub.h b/Kiwi/KWStub.h index 8f1fb1e0..f7428434 100644 --- a/Kiwi/KWStub.h +++ b/Kiwi/KWStub.h @@ -15,6 +15,7 @@ id returnValueTimes; int returnedValueTimes; id secondValue; + id (^block)(NSArray *params); } #pragma mark - @@ -22,10 +23,12 @@ - (id)initWithMessagePattern:(KWMessagePattern *)aMessagePattern; - (id)initWithMessagePattern:(KWMessagePattern *)aMessagePattern value:(id)aValue; +- (id)initWithMessagePattern:(KWMessagePattern *)aMessagePattern block:(id (^)(NSArray *params))aBlock; - (id)initWithMessagePattern:(KWMessagePattern *)aMessagePattern value:(id)aValue times:(id)times afterThatReturn:(id)aSecondValue; + (id)stubWithMessagePattern:(KWMessagePattern *)aMessagePattern; + (id)stubWithMessagePattern:(KWMessagePattern *)aMessagePattern value:(id)aValue; ++ (id)stubWithMessagePattern:(KWMessagePattern *)aMessagePattern block:(id (^)(NSArray *params))aBlock; + (id)stubWithMessagePattern:(KWMessagePattern *)aMessagePattern value:(id)aValue times:(id)times afterThatReturn:(id)aSecondValue; #pragma mark - diff --git a/Kiwi/KWStub.m b/Kiwi/KWStub.m index bb9a2bb2..688c4cd6 100644 --- a/Kiwi/KWStub.m +++ b/Kiwi/KWStub.m @@ -10,6 +10,8 @@ #import "KWStringUtilities.h" #import "KWValue.h" +#import "NSInvocation+OCMAdditions.h" + @implementation KWStub #pragma mark - @@ -28,6 +30,15 @@ - (id)initWithMessagePattern:(KWMessagePattern *)aMessagePattern value:(id)aValu return self; } +- (id)initWithMessagePattern:(KWMessagePattern *)aMessagePattern block:(id (^)(NSArray *params))aBlock { + if ((self = [super init])) { + messagePattern = [aMessagePattern retain]; + block = [aBlock copy]; + } + + return self; +} + - (id)initWithMessagePattern:(KWMessagePattern *)aMessagePattern value:(id)aValue times:(id)times afterThatReturn:(id)aSecondValue { if ((self = [super init])) { messagePattern = [aMessagePattern retain]; @@ -47,6 +58,10 @@ + (id)stubWithMessagePattern:(KWMessagePattern *)aMessagePattern value:(id)aValu return [[[self alloc] initWithMessagePattern:aMessagePattern value:aValue] autorelease]; } ++ (id)stubWithMessagePattern:(KWMessagePattern *)aMessagePattern block:(id (^)(NSArray *params))aBlock { + return [[[self alloc] initWithMessagePattern:aMessagePattern block:aBlock] autorelease]; +} + + (id)stubWithMessagePattern:(KWMessagePattern *)aMessagePattern value:(id)aValue times:(id)times afterThatReturn:(id)aSecondValue { return [[[self alloc] initWithMessagePattern:aMessagePattern value:aValue times:times afterThatReturn:aSecondValue] autorelease]; } @@ -56,6 +71,7 @@ - (void)dealloc { [value release]; [returnValueTimes release]; [secondValue release]; + [block release]; [super dealloc]; } @@ -160,6 +176,19 @@ - (void)writeObjectValueToInvocationReturnValue:(NSInvocation *)anInvocation { - (BOOL)processInvocation:(NSInvocation *)anInvocation { if (![self.messagePattern matchesInvocation:anInvocation]) return NO; + + if (block) { + NSUInteger numberOfArguments = [[anInvocation methodSignature] numberOfArguments]; + NSMutableArray *params = [NSMutableArray arrayWithCapacity:(numberOfArguments-2)]; + for (NSUInteger i = 2; i < numberOfArguments; ++i) { + id param = [anInvocation getArgumentAtIndexAsObject:i]; + [params addObject:param]; + } + + value = block(params); + + [params removeAllObjects]; // We don't want these objects to be in autorelease pool + } if (self.value == nil) [self writeZerosToInvocationReturnValue:anInvocation]; diff --git a/Kiwi/NSInvocation+OCMAdditions.h b/Kiwi/NSInvocation+OCMAdditions.h new file mode 100644 index 00000000..04f22cd6 --- /dev/null +++ b/Kiwi/NSInvocation+OCMAdditions.h @@ -0,0 +1,34 @@ +//--------------------------------------------------------------------------------------- +// $Id$ +// Copyright (c) 2006-2009 by Mulle Kybernetik. See License file for details. +//--------------------------------------------------------------------------------------- + +#import + +@interface NSInvocation(OCMAdditions) + +- (id)getArgumentAtIndexAsObject:(int)argIndex; + +- (NSString *)invocationDescription; + +- (NSString *)argumentDescriptionAtIndex:(int)argIndex; + +- (NSString *)objectDescriptionAtIndex:(int)anInt; +- (NSString *)charDescriptionAtIndex:(int)anInt; +- (NSString *)unsignedCharDescriptionAtIndex:(int)anInt; +- (NSString *)intDescriptionAtIndex:(int)anInt; +- (NSString *)unsignedIntDescriptionAtIndex:(int)anInt; +- (NSString *)shortDescriptionAtIndex:(int)anInt; +- (NSString *)unsignedShortDescriptionAtIndex:(int)anInt; +- (NSString *)longDescriptionAtIndex:(int)anInt; +- (NSString *)unsignedLongDescriptionAtIndex:(int)anInt; +- (NSString *)longLongDescriptionAtIndex:(int)anInt; +- (NSString *)unsignedLongLongDescriptionAtIndex:(int)anInt; +- (NSString *)doubleDescriptionAtIndex:(int)anInt; +- (NSString *)floatDescriptionAtIndex:(int)anInt; +- (NSString *)structDescriptionAtIndex:(int)anInt; +- (NSString *)pointerDescriptionAtIndex:(int)anInt; +- (NSString *)cStringDescriptionAtIndex:(int)anInt; +- (NSString *)selectorDescriptionAtIndex:(int)anInt; + +@end diff --git a/Kiwi/NSInvocation+OCMAdditions.m b/Kiwi/NSInvocation+OCMAdditions.m new file mode 100644 index 00000000..41579583 --- /dev/null +++ b/Kiwi/NSInvocation+OCMAdditions.m @@ -0,0 +1,337 @@ +//--------------------------------------------------------------------------------------- +// $Id$ +// Copyright (c) 2006-2009 by Mulle Kybernetik. See License file for details. +//--------------------------------------------------------------------------------------- + +#import "NSInvocation+OCMAdditions.h" + + +@implementation NSInvocation(OCMAdditions) + +- (id)getArgumentAtIndexAsObject:(int)argIndex +{ + const char* argType; + + argType = [[self methodSignature] getArgumentTypeAtIndex:argIndex]; + while(strchr("rnNoORV", argType[0]) != NULL) + argType += 1; + + if((strlen(argType) > 1) && (strchr("{^", argType[0]) == NULL) && (strcmp("@?", argType) != 0)) + [NSException raise:NSInvalidArgumentException format:@"Cannot handle argument type '%s'.", argType]; + + switch (argType[0]) + { + case '#': + case '@': + { + id value; + [self getArgument:&value atIndex:argIndex]; + return value; + } + case ':': + { + SEL s = (SEL)0; + [self getArgument:&s atIndex:argIndex]; + id value = NSStringFromSelector(s); + return value; + } + case 'i': + { + int value; + [self getArgument:&value atIndex:argIndex]; + return [NSNumber numberWithInt:value]; + } + case 's': + { + short value; + [self getArgument:&value atIndex:argIndex]; + return [NSNumber numberWithShort:value]; + } + case 'l': + { + long value; + [self getArgument:&value atIndex:argIndex]; + return [NSNumber numberWithLong:value]; + } + case 'q': + { + long long value; + [self getArgument:&value atIndex:argIndex]; + return [NSNumber numberWithLongLong:value]; + } + case 'c': + { + char value; + [self getArgument:&value atIndex:argIndex]; + return [NSNumber numberWithChar:value]; + } + case 'C': + { + unsigned char value; + [self getArgument:&value atIndex:argIndex]; + return [NSNumber numberWithUnsignedChar:value]; + } + case 'I': + { + unsigned int value; + [self getArgument:&value atIndex:argIndex]; + return [NSNumber numberWithUnsignedInt:value]; + } + case 'S': + { + unsigned short value; + [self getArgument:&value atIndex:argIndex]; + return [NSNumber numberWithUnsignedShort:value]; + } + case 'L': + { + unsigned long value; + [self getArgument:&value atIndex:argIndex]; + return [NSNumber numberWithUnsignedLong:value]; + } + case 'Q': + { + unsigned long long value; + [self getArgument:&value atIndex:argIndex]; + return [NSNumber numberWithUnsignedLongLong:value]; + } + case 'f': + { + float value; + [self getArgument:&value atIndex:argIndex]; + return [NSNumber numberWithFloat:value]; + } + case 'd': + { + double value; + [self getArgument:&value atIndex:argIndex]; + return [NSNumber numberWithDouble:value]; + } + case 'B': + { + bool value; + [self getArgument:&value atIndex:argIndex]; + return [NSNumber numberWithBool:value]; + } + case '^': + { + void *value = NULL; + [self getArgument:&value atIndex:argIndex]; + return [NSValue valueWithPointer:value]; + } + case '{': // structure + { + NSUInteger maxArgSize = [[self methodSignature] frameLength]; + NSMutableData *argumentData = [[[NSMutableData alloc] initWithLength:maxArgSize] autorelease]; + [self getArgument:[argumentData mutableBytes] atIndex:argIndex]; + return [NSValue valueWithBytes:[argumentData bytes] objCType:argType]; + } + + } + [NSException raise:NSInvalidArgumentException format:@"Argument type '%s' not supported", argType]; + return nil; +} + +- (NSString *)invocationDescription +{ + NSMethodSignature *methodSignature = [self methodSignature]; + NSUInteger numberOfArgs = [methodSignature numberOfArguments]; + + if (numberOfArgs == 2) + return NSStringFromSelector([self selector]); + + NSArray *selectorParts = [NSStringFromSelector([self selector]) componentsSeparatedByString:@":"]; + NSMutableString *description = [[NSMutableString alloc] init]; + unsigned int i; + for(i = 2; i < numberOfArgs; i++) + { + [description appendFormat:@"%@%@:", (i > 2 ? @" " : @""), [selectorParts objectAtIndex:(i - 2)]]; + [description appendString:[self argumentDescriptionAtIndex:i]]; + } + + return [description autorelease]; +} + +- (NSString *)argumentDescriptionAtIndex:(int)argIndex +{ + const char *argType = [[self methodSignature] getArgumentTypeAtIndex:argIndex]; + if(strchr("rnNoORV", argType[0]) != NULL) + argType += 1; + + switch(*argType) + { + case '@': return [self objectDescriptionAtIndex:argIndex]; + case 'c': return [self charDescriptionAtIndex:argIndex]; + case 'C': return [self unsignedCharDescriptionAtIndex:argIndex]; + case 'i': return [self intDescriptionAtIndex:argIndex]; + case 'I': return [self unsignedIntDescriptionAtIndex:argIndex]; + case 's': return [self shortDescriptionAtIndex:argIndex]; + case 'S': return [self unsignedShortDescriptionAtIndex:argIndex]; + case 'l': return [self longDescriptionAtIndex:argIndex]; + case 'L': return [self unsignedLongDescriptionAtIndex:argIndex]; + case 'q': return [self longLongDescriptionAtIndex:argIndex]; + case 'Q': return [self unsignedLongLongDescriptionAtIndex:argIndex]; + case 'd': return [self doubleDescriptionAtIndex:argIndex]; + case 'f': return [self floatDescriptionAtIndex:argIndex]; + // Why does this throw EXC_BAD_ACCESS when appending the string? + // case NSObjCStructType: return [self structDescriptionAtIndex:index]; + case '^': return [self pointerDescriptionAtIndex:argIndex]; + case '*': return [self cStringDescriptionAtIndex:argIndex]; + case ':': return [self selectorDescriptionAtIndex:argIndex]; + default: return [@""]; // avoid confusion with trigraphs... + } + +} + + +- (NSString *)objectDescriptionAtIndex:(int)anInt +{ + id object; + + [self getArgument:&object atIndex:anInt]; + if (object == nil) + return @"nil"; + else if(![object isProxy] && [object isKindOfClass:[NSString class]]) + return [NSString stringWithFormat:@"@\"%@\"", [object description]]; + else + return [object description]; +} + +- (NSString *)charDescriptionAtIndex:(int)anInt +{ + unsigned char buffer[128]; + memset(buffer, 0x0, 128); + + [self getArgument:&buffer atIndex:anInt]; + + // If there's only one character in the buffer, and it's 0 or 1, then we have a BOOL + if (buffer[1] == '\0' && (buffer[0] == 0 || buffer[0] == 1)) + return [NSString stringWithFormat:@"%@", (buffer[0] == 1 ? @"YES" : @"NO")]; + else + return [NSString stringWithFormat:@"'%c'", *buffer]; +} + +- (NSString *)unsignedCharDescriptionAtIndex:(int)anInt +{ + unsigned char buffer[128]; + memset(buffer, 0x0, 128); + + [self getArgument:&buffer atIndex:anInt]; + return [NSString stringWithFormat:@"'%c'", *buffer]; +} + +- (NSString *)intDescriptionAtIndex:(int)anInt +{ + int intValue; + + [self getArgument:&intValue atIndex:anInt]; + return [NSString stringWithFormat:@"%d", intValue]; +} + +- (NSString *)unsignedIntDescriptionAtIndex:(int)anInt +{ + unsigned int intValue; + + [self getArgument:&intValue atIndex:anInt]; + return [NSString stringWithFormat:@"%d", intValue]; +} + +- (NSString *)shortDescriptionAtIndex:(int)anInt +{ + short shortValue; + + [self getArgument:&shortValue atIndex:anInt]; + return [NSString stringWithFormat:@"%hi", shortValue]; +} + +- (NSString *)unsignedShortDescriptionAtIndex:(int)anInt +{ + unsigned short shortValue; + + [self getArgument:&shortValue atIndex:anInt]; + return [NSString stringWithFormat:@"%hu", shortValue]; +} + +- (NSString *)longDescriptionAtIndex:(int)anInt +{ + long longValue; + + [self getArgument:&longValue atIndex:anInt]; + return [NSString stringWithFormat:@"%ld", longValue]; +} + +- (NSString *)unsignedLongDescriptionAtIndex:(int)anInt +{ + unsigned long longValue; + + [self getArgument:&longValue atIndex:anInt]; + return [NSString stringWithFormat:@"%lu", longValue]; +} + +- (NSString *)longLongDescriptionAtIndex:(int)anInt +{ + long long longLongValue; + + [self getArgument:&longLongValue atIndex:anInt]; + return [NSString stringWithFormat:@"%qi", longLongValue]; +} + +- (NSString *)unsignedLongLongDescriptionAtIndex:(int)anInt +{ + unsigned long long longLongValue; + + [self getArgument:&longLongValue atIndex:anInt]; + return [NSString stringWithFormat:@"%qu", longLongValue]; +} + +- (NSString *)doubleDescriptionAtIndex:(int)anInt; +{ + double doubleValue; + + [self getArgument:&doubleValue atIndex:anInt]; + return [NSString stringWithFormat:@"%f", doubleValue]; +} + +- (NSString *)floatDescriptionAtIndex:(int)anInt +{ + float floatValue; + + [self getArgument:&floatValue atIndex:anInt]; + return [NSString stringWithFormat:@"%f", floatValue]; +} + +- (NSString *)structDescriptionAtIndex:(int)anInt; +{ + void *buffer; + + [self getArgument:&buffer atIndex:anInt]; + return [NSString stringWithFormat:@":(struct)%p", buffer]; +} + +- (NSString *)pointerDescriptionAtIndex:(int)anInt +{ + void *buffer; + + [self getArgument:&buffer atIndex:anInt]; + return [NSString stringWithFormat:@"%p", buffer]; +} + +- (NSString *)cStringDescriptionAtIndex:(int)anInt +{ + char buffer[128]; + + memset(buffer, 0x0, 128); + + [self getArgument:&buffer atIndex:anInt]; + return [NSString stringWithFormat:@"\"%s\"", buffer]; +} + +- (NSString *)selectorDescriptionAtIndex:(int)anInt +{ + SEL selectorValue; + + [self getArgument:&selectorValue atIndex:anInt]; + return [NSString stringWithFormat:@"@selector(%@)", NSStringFromSelector(selectorValue)]; +} + +@end