Add utility methods for enabling high quality error messages
Summary: These helper functions will be used by the ObjC generated code for support on commands. This is an example of what that code might look like and how these functions will be used. ``` - (void)handleCommand:(NSString const *)commandName args:(NSArray const *)args { if ([commandName isEqualToString:@"scrollTo"]) { if ([args count] != 2) { RCTLogError( @"%@ command %@ received %d arguments, expected %d.", @"ScrollView", @"scrollTo", (int)[args count], 2); return; } NSObject *arg0 = args[0]; if (!RCTValidateTypeOfViewCommandArgument(arg0, [NSNumber class], @"number", @"ScrollView", @"scrollTo", @"1st")) { return; } int x = [(NSNumber *)arg0 intValue]; NSObject *arg1 = args[1]; if (!RCTValidateTypeOfViewCommandArgument(arg1, [NSNumber class], @"number", @"ScrollView", @"scrollTo", @"2nd")) { return; } int y = [(NSNumber *)arg1 intValue]; [self scrollTo:x y:y]; } else if ([commandName isEqualToString:@"scrollToEnd"]) { if ([args count] != 0) { RCTLogError( @"%@ command %@ received %d arguments, expected %d.", @"ScrollView", @"scrollToEnd", (int)[args count], 0); return; } [self scrollToEnd]; } } ``` Reviewed By: JoshuaGross Differential Revision: D16474117 fbshipit-source-id: 2bb9f01d7c97cc59e9373b7759021c65980fcc0e
This commit is contained in:
Родитель
a24a9b9946
Коммит
91681016e8
|
@ -0,0 +1,64 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
*/
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
#import <React/RCTLog.h>
|
||||
#import <React/RCTUtils.h>
|
||||
|
||||
static NSString * RCTLogsError(void (^block)(void))
|
||||
{
|
||||
__block NSString* loggedMessage = @"";
|
||||
__block BOOL loggedError = NO;
|
||||
RCTPerformBlockWithLogFunction(block, ^(RCTLogLevel level,
|
||||
__unused RCTLogSource source,
|
||||
__unused NSString *fileName,
|
||||
__unused NSNumber *lineNumber,
|
||||
NSString *message) {
|
||||
loggedError = (level == RCTLogLevelError);
|
||||
loggedMessage = message;
|
||||
});
|
||||
if (loggedError) {
|
||||
return loggedMessage;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
@interface RCTUtilsTests : XCTestCase
|
||||
|
||||
@end
|
||||
|
||||
@implementation RCTUtilsTests
|
||||
|
||||
- (void)testRCTHumanReadableType
|
||||
{
|
||||
XCTAssertEqualObjects(RCTHumanReadableType(@"str"), @"string");
|
||||
XCTAssertEqualObjects(RCTHumanReadableType([NSNumber numberWithInt:4]), @"number");
|
||||
|
||||
// If we could detect that this was definitely a boolean and not a number that would be ideal
|
||||
// That seems difficult in ObjC though
|
||||
XCTAssertEqualObjects(RCTHumanReadableType(@(YES)), @"boolean or number");
|
||||
XCTAssertEqualObjects(RCTHumanReadableType(@(NO)), @"boolean or number");
|
||||
// These ideally would just say number
|
||||
XCTAssertEqualObjects(RCTHumanReadableType([NSNumber numberWithInt:0]), @"boolean or number");
|
||||
XCTAssertEqualObjects(RCTHumanReadableType([NSNumber numberWithInt:1]), @"boolean or number");
|
||||
}
|
||||
|
||||
- (void)testRCTValidateTypeOfViewCommandArgument
|
||||
{
|
||||
XCTAssertEqualObjects(RCTLogsError(^{
|
||||
RCTValidateTypeOfViewCommandArgument(@"str", [NSNumber class], @"number", @"ScrollView", @"scrollTo", @"2nd");
|
||||
}), @"ScrollView command scrollTo received 2nd argument of type string, expected number.");
|
||||
|
||||
XCTAssertEqualObjects(RCTLogsError(^{
|
||||
RCTValidateTypeOfViewCommandArgument(@"str", [NSString class], @"string", @"ScrollView", @"scrollTo", @"1st");
|
||||
}), nil);
|
||||
}
|
||||
|
||||
@end
|
|
@ -147,6 +147,9 @@ RCT_EXTERN NSString *RCTColorToHexString(CGColorRef color);
|
|||
// Get standard localized string (if it exists)
|
||||
RCT_EXTERN NSString *RCTUIKitLocalizedString(NSString *string);
|
||||
|
||||
// Get a human readable type string from an NSObject. For example NSString becomes string
|
||||
RCT_EXTERN NSString *RCTHumanReadableType(NSObject *obj);
|
||||
|
||||
// URL manipulation
|
||||
RCT_EXTERN NSString *__nullable RCTGetURLQueryParam(NSURL *__nullable URL, NSString *param);
|
||||
RCT_EXTERN NSURL *__nullable RCTURLByReplacingQueryParam(NSURL *__nullable URL, NSString *param, NSString *__nullable value);
|
||||
|
@ -156,4 +159,6 @@ RCT_EXTERN NSString *RCTDropReactPrefixes(NSString *s);
|
|||
|
||||
RCT_EXTERN BOOL RCTUIManagerTypeForTagIsFabric(NSNumber *reactTag);
|
||||
|
||||
RCT_EXTERN BOOL RCTValidateTypeOfViewCommandArgument(NSObject *obj, id expectedClass, NSString const * expectedType, NSString const *componentName, NSString const * commandName, NSString const * argPos);
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
|
@ -894,6 +894,22 @@ NSString *RCTUIKitLocalizedString(NSString *string)
|
|||
return UIKitBundle ? [UIKitBundle localizedStringForKey:string value:string table:nil] : string;
|
||||
}
|
||||
|
||||
NSString *RCTHumanReadableType(NSObject *obj)
|
||||
{
|
||||
if ([obj isKindOfClass:[NSString class]]) {
|
||||
return @"string";
|
||||
} else if ([obj isKindOfClass:[NSNumber class]]) {
|
||||
int intVal = [(NSNumber *)obj intValue];
|
||||
if(intVal == 0 || intVal == 1) {
|
||||
return @"boolean or number";
|
||||
}
|
||||
|
||||
return @"number";
|
||||
} else {
|
||||
return NSStringFromClass([obj class]);
|
||||
}
|
||||
}
|
||||
|
||||
NSString *__nullable RCTGetURLQueryParam(NSURL *__nullable URL, NSString *param)
|
||||
{
|
||||
RCTAssertParam(param);
|
||||
|
@ -965,3 +981,21 @@ RCT_EXTERN BOOL RCTUIManagerTypeForTagIsFabric(NSNumber *reactTag)
|
|||
// See https://github.com/facebook/react/pull/12587
|
||||
return [reactTag integerValue] % 2 == 0;
|
||||
}
|
||||
|
||||
RCT_EXTERN BOOL RCTValidateTypeOfViewCommandArgument(NSObject *obj, id expectedClass, NSString const * expectedType, NSString const *componentName, NSString const * commandName, NSString const * argPos)
|
||||
{
|
||||
if (![obj isKindOfClass:expectedClass]) {
|
||||
NSString *kindOfClass = RCTHumanReadableType(obj);
|
||||
|
||||
RCTLogError(
|
||||
@"%@ command %@ received %@ argument of type %@, expected %@.",
|
||||
componentName,
|
||||
commandName,
|
||||
argPos,
|
||||
kindOfClass,
|
||||
expectedType);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче