Fix RCTAssert logic

This commit is contained in:
Nick Lockwood 2015-08-07 06:06:17 -07:00
parent 1d452f3e4d
commit 3cef3010e6
2 changed files with 70 additions and 28 deletions

View File

@ -14,13 +14,13 @@
/**
* The default error domain to be used for React errors.
*/
extern NSString *const RCTErrorDomain;
RCT_EXTERN NSString *const RCTErrorDomain;
/**
* A block signature to be used for custom assertion handling.
*/
typedef void (^RCTAssertFunction)(
BOOL condition,
NSString *condition,
NSString *fileName,
NSNumber *lineNumber,
NSString *function,
@ -30,12 +30,18 @@ typedef void (^RCTAssertFunction)(
/**
* This is the main assert macro that you should use.
*/
#define RCTAssert(condition, ...) do { BOOL pass = ((condition) != 0); \
if (RCT_NSASSERT && !pass) { [[NSAssertionHandler currentHandler] handleFailureInFunction:@(__func__) \
file:@(__FILE__) lineNumber:__LINE__ description:__VA_ARGS__]; } \
_RCTAssertFormat(pass, __FILE__, __LINE__, __func__, __VA_ARGS__); \
#define RCTAssert(condition, ...) do { \
if ((condition) == 0) { \
_RCTAssertFormat(#condition, __FILE__, __LINE__, __func__, __VA_ARGS__); \
if (RCT_NSASSERT) { \
[[NSAssertionHandler currentHandler] handleFailureInFunction:@(__func__) \
file:@(__FILE__) lineNumber:__LINE__ description:__VA_ARGS__]; \
} \
} \
} while (false)
RCT_EXTERN void _RCTAssertFormat(BOOL, const char *, int, const char *, NSString *, ...) NS_FORMAT_FUNCTION(5,6);
RCT_EXTERN void _RCTAssertFormat(
const char *, const char *, int, const char *, NSString *, ...
) NS_FORMAT_FUNCTION(5,6);
/**
* Convenience macro for asserting that a parameter is non-nil/non-zero.
@ -64,6 +70,13 @@ RCT_EXTERN RCTAssertFunction RCTGetAssertFunction(void);
*/
RCT_EXTERN void RCTAddAssertFunction(RCTAssertFunction assertFunction);
/**
* This method temporarily overrides the assert function while performing the
* specified block. This is useful for testing purposes (to detect if a given
* function asserts something) or to suppress or override assertions temporarily.
*/
RCT_EXTERN void RCTPerformBlockWithAssertFunction(void (^block)(void), RCTAssertFunction assertFunction);
/**
* Get the current thread's name (or the current queue, if in debug mode)
*/

View File

@ -11,6 +11,8 @@
NSString *const RCTErrorDomain = @"RCTErrorDomain";
static NSString *const RCTAssertFunctionStack = @"RCTAssertFunctionStack";
RCTAssertFunction RCTCurrentAssertFunction = nil;
NSException *_RCTNotImplementedException(SEL, Class);
@ -22,26 +24,6 @@ NSException *_RCTNotImplementedException(SEL cmd, Class cls)
reason:msg userInfo:nil];
}
void _RCTAssertFormat(
BOOL condition,
const char *fileName,
int lineNumber,
const char *function,
NSString *format, ...)
{
if (RCTCurrentAssertFunction) {
va_list args;
va_start(args, format);
NSString *message = [[NSString alloc] initWithFormat:format arguments:args];
va_end(args);
RCTCurrentAssertFunction(
condition, @(fileName), @(lineNumber), @(function), message
);
}
}
void RCTSetAssertFunction(RCTAssertFunction assertFunction)
{
RCTCurrentAssertFunction = assertFunction;
@ -56,7 +38,7 @@ void RCTAddAssertFunction(RCTAssertFunction assertFunction)
{
RCTAssertFunction existing = RCTCurrentAssertFunction;
if (existing) {
RCTCurrentAssertFunction = ^(BOOL condition,
RCTCurrentAssertFunction = ^(NSString *condition,
NSString *fileName,
NSNumber *lineNumber,
NSString *function,
@ -70,6 +52,34 @@ void RCTAddAssertFunction(RCTAssertFunction assertFunction)
}
}
/**
* returns the topmost stacked assert function for the current thread, which
* may not be the same as the current value of RCTCurrentAssertFunction.
*/
static RCTAssertFunction RCTGetLocalAssertFunction()
{
NSMutableDictionary *threadDictionary = [NSThread currentThread].threadDictionary;
NSArray *functionStack = threadDictionary[RCTAssertFunctionStack];
RCTAssertFunction assertFunction = [functionStack lastObject];
if (assertFunction) {
return assertFunction;
}
return RCTCurrentAssertFunction;
}
void RCTPerformBlockWithAssertFunction(void (^block)(void), RCTAssertFunction assertFunction)
{
NSMutableDictionary *threadDictionary = [NSThread currentThread].threadDictionary;
NSMutableArray *functionStack = threadDictionary[RCTAssertFunctionStack];
if (!functionStack) {
functionStack = [[NSMutableArray alloc] init];
threadDictionary[RCTAssertFunctionStack] = functionStack;
}
[functionStack addObject:assertFunction];
block();
[functionStack removeLastObject];
}
NSString *RCTCurrentThreadName(void)
{
NSThread *thread = [NSThread currentThread];
@ -84,3 +94,22 @@ NSString *RCTCurrentThreadName(void)
}
return threadName;
}
void _RCTAssertFormat(
const char *condition,
const char *fileName,
int lineNumber,
const char *function,
NSString *format, ...)
{
RCTAssertFunction assertFunction = RCTGetLocalAssertFunction();
if (assertFunction) {
va_list args;
va_start(args, format);
NSString *message = [[NSString alloc] initWithFormat:format arguments:args];
va_end(args);
assertFunction(@(condition), @(fileName), @(lineNumber), @(function), message);
}
}