Improve formatting of STAssertNil and STAssertNotNil macro output
| Originator: | quinntaylor | ||
| Number: | rdar://7681807 | Date Originated: | 2010-02-23 |
| Status: | Open | Resolved: | P3, NMOS |
| Product: | OCUnit | Product Version: | |
| Classification: | Enhancement | Reproducible: | Not Applicable |
The STAssertNil and STAssertNotNil macros are commonly used and very handy, but their output when an assertion fails leaves quite a bit to be desired. Here's an example of what such failures look like today:
- (void) testFAIL {
id bar = nil;
STAssertNil([NSObject new], nil);
STAssertNil(@"foo", nil);
STAssertNil(self, nil);
STAssertNotNil(bar, nil);
}
The errors that result from this test read as follows (trimmed for space):
error: -[SampleTest testFAIL] : "(([NSObject new]) == nil)" should be true.
error: -[SampleTest testFAIL] : "((@"foo") == nil)" should be true.
error: -[SampleTest testFAIL] : "((self) == nil)" should be true.
error: -[SampleTest testFAIL] : "((bar) != nil)" should be true.
These errors would be more intelligible and self-evident if they read more like this:
error: -[SampleTest testFAIL] : [NSObject new] should be nil.
error: -[SampleTest testFAIL] : @"foo" should be nil.
error: -[SampleTest testFAIL] : self should be nil.
error: -[SampleTest testFAIL] : bar should be non-nil.
The current error messages are produced using +failureInCondition:isTrue:inFile:atLine:withDescription: (the same NSException class method used by STAssertTrue and STAssertFalse) and wrap the expression text such that it looks vaguely like Lisp.
Adding a new class method (+failureInExpression:isNil:inFile:atLine:withDescription:) to NSException and slightly modifying the STAssertNil and STAssertNotNil macros makes these tests much more intelligible with minimal effort. I've attached a sample implementation (based on the old Sen:te source, as in <rdar://problem/7670449>) which I've verified to work with my existing unit tests.
------------ attachment included below for this report --------------
// NSException_SenTestFailure.h, add to @interface NSException(SenTestFailure)
+ (NSException *) failureInExpression:(NSString *)expression
isNil:(BOOL)isNil
inFile:(NSString *)filename
atLine:(int) lineNumber
withDescription:(NSString *) formatString, ...;
// NSException_SenTestFailure.m, add to @implementation NSException(SenTestFailure)
+ (NSException *) failureInExpression:(NSString *)expression
isNil:(BOOL)isNil
inFile:(NSString *)filename
atLine:(int) lineNumber
withDescription:(NSString *) formatString, ...
{
NSString *description;
if (formatString != nil) {
va_list argList;
va_start(argList, formatString);
description = [[[NSString alloc] initWithFormat:formatString
arguments:argList] autorelease];
va_end(argList);
} else {
description = @"";
}
NSString *reason = [NSString stringWithFormat:@"%@ should be %@. %@",
expression, (isNil ? @"nil" : @"non-nil"), description];
NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:
SenConditionFailure, SenFailureTypeKey,
expression, SenTestConditionKey,
filename, SenTestFilenameKey,
[NSNumber numberWithInt:lineNumber], SenTestLineNumberKey,
description, SenTestDescriptionKey,
nil];
return [self exceptionWithName:SenTestFailureException
reason:reason
userInfo:userInfo];
}
// SenTestCase_Macros.h, replace existing STAssertNil and STAssertNotNil macros
#define STAssertNil(a1, description, ...) \
do { \
@try {\
if ((a1) != nil) { \
[self failWithException:([NSException failureInExpression:[NSString stringWithUTF8String:#a1] \
isNil:YES \
inFile:[NSString stringWithUTF8String:__FILE__] \
atLine:__LINE__ \
withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)])]; \
} \
}\
@catch (id anException) {\
[self failWithException:([NSException failureInRaise:[NSString stringWithFormat:@"(%s) == nil fails", #a1] \
exception:anException \
inFile:[NSString stringWithUTF8String:__FILE__] \
atLine:__LINE__ \
withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)])]; \
}\
} while(0)
#define STAssertNotNil(a1, description, ...) \
do { \
@try {\
if ((a1) == nil) { \
[self failWithException:([NSException failureInExpression:[NSString stringWithUTF8String:#a1] \
isNil:NO \
inFile:[NSString stringWithUTF8String:__FILE__] \
atLine:__LINE__ \
withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)])]; \
} \
}\
@catch (id anException) {\
[self failWithException:([NSException failureInRaise:[NSString stringWithFormat:@"(%s) != nil fails", #a1] \
exception:anException \
inFile:[NSString stringWithUTF8String:__FILE__] \
atLine:__LINE__ \
withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)])]; \
}\
} while(0)
Comments
Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!