react-native-macos/packages/rn-tester/RNTesterUnitTests/RCTModuleMethodTests.mm

295 строки
8.7 KiB
Plaintext

/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <React/RCTUIKit.h> // [macOS]
#import <XCTest/XCTest.h>
#import <React/RCTBridgeModule.h>
#import <React/RCTLog.h>
#import <React/RCTModuleMethod.h>
static BOOL RCTLogsError(void (^block)(void))
{
__block BOOL loggedError = NO;
RCTPerformBlockWithLogFunction(
block,
^(RCTLogLevel level,
__unused RCTLogSource source,
__unused NSString *fileName,
__unused NSNumber *lineNumber,
__unused NSString *message) {
loggedError = (level == RCTLogLevelError);
});
return loggedError;
}
@interface RCTModuleMethodTests : XCTestCase <RCTBridgeModule>
@end
@implementation RCTModuleMethodTests {
CGRect _s;
}
static RCTModuleMethod *buildDefaultMethodWithMethodSignature(const char *methodSignature)
{
// This leaks a RCTMethodInfo, but it's a test, so...
RCTMethodInfo *methodInfo = new RCTMethodInfo{.objcName = methodSignature, .isSync = NO};
return [[RCTModuleMethod alloc] initWithExportedMethod:methodInfo moduleClass:[RCTModuleMethodTests class]];
}
static RCTModuleMethod *buildSyncMethodWithMethodSignature(const char *methodSignature)
{
// This leaks a RCTMethodInfo, but it's a test, so...
RCTMethodInfo *methodInfo = new RCTMethodInfo{.objcName = methodSignature, .isSync = YES};
return [[RCTModuleMethod alloc] initWithExportedMethod:methodInfo moduleClass:[RCTModuleMethodTests class]];
}
+ (NSString *)moduleName
{
return nil;
}
- (void)doFoo
{
}
- (void)doFooWithBar:(__unused NSString *)bar
{
}
- (id)echoString:(NSString *)input
{
return input;
}
- (id)methodThatReturnsNil
{
return nil;
}
- (void)openURL:(NSURL *)URL resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject
{
}
- (void)openURL:(NSURL *)URL callback:(RCTResponseSenderBlock)callback
{
}
- (id)methodThatCallsCallbackWithArg:(NSString *)input callback:(RCTResponseSenderBlock)callback
{
callback(@[ input ]);
return nil;
}
- (void)testNonnull
{
const char *methodSignature = "doFooWithBar:(nonnull NSString *)bar";
RCTModuleMethod *method = buildDefaultMethodWithMethodSignature(methodSignature);
XCTAssertFalse(RCTLogsError(^{
[method invokeWithBridge:nil module:self arguments:@[ @"Hello World" ]];
}));
XCTAssertTrue(RCTLogsError(^{
[method invokeWithBridge:nil module:self arguments:@[ [NSNull null] ]];
}));
}
- (void)doFooWithNumber:(__unused NSNumber *)n
{
}
- (void)doFooWithDouble:(__unused double)n
{
}
- (void)doFooWithInteger:(__unused NSInteger)n
{
}
- (void)doFooWithCGRect:(CGRect)s
{
_s = s;
}
- (void)doFoo:(__unused NSString *)foo
{
}
- (void)testNumbersNonnull
{
{
// Specifying an NSNumber param without nonnull isn't allowed
XCTAssertTrue(RCTLogsError(^{
const char *methodSignature = "doFooWithNumber:(NSNumber *)n";
RCTModuleMethod *method = buildDefaultMethodWithMethodSignature(methodSignature);
// Invoke method to trigger parsing
[method invokeWithBridge:nil module:self arguments:@[ @1 ]];
}));
}
{
const char *methodSignature = "doFooWithNumber:(nonnull NSNumber *)n";
RCTModuleMethod *method = buildDefaultMethodWithMethodSignature(methodSignature);
XCTAssertTrue(RCTLogsError(^{
[method invokeWithBridge:nil module:self arguments:@[ [NSNull null] ]];
}));
}
{
const char *methodSignature = "doFooWithDouble:(double)n";
RCTModuleMethod *method = buildDefaultMethodWithMethodSignature(methodSignature);
XCTAssertTrue(RCTLogsError(^{
[method invokeWithBridge:nil module:self arguments:@[ [NSNull null] ]];
}));
}
{
const char *methodSignature = "doFooWithInteger:(NSInteger)n";
RCTModuleMethod *method = buildDefaultMethodWithMethodSignature(methodSignature);
XCTAssertTrue(RCTLogsError(^{
[method invokeWithBridge:nil module:self arguments:@[ [NSNull null] ]];
}));
}
}
- (void)testStructArgument
{
const char *methodSignature = "doFooWithCGRect:(CGRect)s";
RCTModuleMethod *method = buildDefaultMethodWithMethodSignature(methodSignature);
CGRect r = CGRectMake(10, 20, 30, 40);
[method invokeWithBridge:nil module:self arguments:@[ @[ @10, @20, @30, @40 ] ]];
XCTAssertTrue(CGRectEqualToRect(r, _s));
}
- (void)testWhitespaceTolerance
{
const char *methodSignature = "doFoo : \t (NSString *)foo";
__block RCTModuleMethod *method;
XCTAssertFalse(RCTLogsError(^{
method = buildDefaultMethodWithMethodSignature(methodSignature);
}));
XCTAssertEqualObjects(@(method.JSMethodName), @"doFoo");
XCTAssertFalse(RCTLogsError(^{
[method invokeWithBridge:nil module:self arguments:@[ @"bar" ]];
}));
}
- (void)testFunctionType
{
{
const char *methodSignature = "doFoo";
RCTModuleMethod *method = buildDefaultMethodWithMethodSignature(methodSignature);
XCTAssertTrue(method.functionType == RCTFunctionTypeNormal);
XCTAssertFalse(
RCTLogsError(^{
// Invoke method to trigger parsing
__unused SEL selector = method.selector;
}),
@"Unexpected error when parsing normal function");
}
{
const char *methodSignature = "openURL:(NSURL *)URL callback:(RCTResponseSenderBlock)callBack";
RCTModuleMethod *method = buildDefaultMethodWithMethodSignature(methodSignature);
XCTAssertTrue(method.functionType == RCTFunctionTypeNormal);
XCTAssertFalse(
RCTLogsError(^{
// Invoke method to trigger parsing
__unused SEL selector = method.selector;
}),
@"Unexpected error when parsing normal function with callback");
}
{
const char *methodSignature =
"openURL:(NSURL *)URL resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject";
RCTModuleMethod *method = buildDefaultMethodWithMethodSignature(methodSignature);
XCTAssertTrue(method.functionType == RCTFunctionTypePromise);
XCTAssertFalse(
RCTLogsError(^{
// Invoke method to trigger parsing
__unused SEL selector = method.selector;
}),
@"Unexpected error when parsing promise function");
}
{
const char *methodSignature = "echoString:(NSString *)input";
RCTModuleMethod *method = buildSyncMethodWithMethodSignature(methodSignature);
XCTAssertTrue(method.functionType == RCTFunctionTypeSync);
XCTAssertFalse(
RCTLogsError(^{
// Invoke method to trigger parsing
__unused SEL selector = method.selector;
}),
@"Unexpected error when parsing sync function");
}
{
const char *methodSignature =
"methodThatCallsCallbackWithArg:(NSString *)input callback:(RCTResponseSenderBlock)callback";
RCTModuleMethod *method = buildSyncMethodWithMethodSignature(methodSignature);
XCTAssertTrue(method.functionType == RCTFunctionTypeSync);
XCTAssertFalse(
RCTLogsError(^{
// Invoke method to trigger parsing
__unused SEL selector = method.selector;
}),
@"Unexpected error when parsing sync function with callback");
}
}
- (void)testReturnsValueForSyncFunction
{
{
const char *methodSignature = "echoString:(NSString *)input";
RCTModuleMethod *method = buildSyncMethodWithMethodSignature(methodSignature);
id result = [method invokeWithBridge:nil module:self arguments:@[ @"Test String Value" ]];
XCTAssertEqualObjects(result, @"Test String Value");
}
{
const char *methodSignature = "methodThatReturnsNil";
RCTModuleMethod *method = buildSyncMethodWithMethodSignature(methodSignature);
id result = [method invokeWithBridge:nil module:self arguments:@[]];
XCTAssertNil(result);
}
}
- (void)testReturnsNilForDefaultFunction
{
const char *methodSignature = "doFoo";
RCTModuleMethod *method = buildDefaultMethodWithMethodSignature(methodSignature);
id result = [method invokeWithBridge:nil module:self arguments:@[]];
XCTAssertNil(result);
}
- (void)testReturnTypeForSyncFunction
{
{
const char *methodSignature = "methodThatReturnsNil";
RCTModuleMethod *method = buildSyncMethodWithMethodSignature(methodSignature);
XCTAssertFalse(
RCTLogsError(^{
// Invoke method to trigger parsing
__unused SEL selector = method.selector;
}),
@"Unexpected error when parsing sync function with (id) return type");
}
{
const char *methodSignature = "doFoo";
RCTModuleMethod *method = buildSyncMethodWithMethodSignature(methodSignature);
XCTAssertTrue(
RCTLogsError(^{
// Invoke method to trigger parsing
__unused SEL selector = method.selector;
}),
@"Failed to trigger an error when parsing sync function with non-(id) return type");
}
}
@end