diff --git a/driver/js/include/driver/napi/jsc/jsc_ctx.h b/driver/js/include/driver/napi/jsc/jsc_ctx.h index 8f0975c28ab..d8d6e12e74f 100644 --- a/driver/js/include/driver/napi/jsc/jsc_ctx.h +++ b/driver/js/include/driver/napi/jsc/jsc_ctx.h @@ -127,8 +127,7 @@ class JSCCtx : public Ctx { virtual std::shared_ptr CreateObject() override; virtual std::shared_ptr CreateNumber(double number) override; virtual std::shared_ptr CreateBoolean(bool b) override; - virtual std::shared_ptr CreateString( - const string_view& string) override; + virtual std::shared_ptr CreateString(const string_view& string) override; virtual std::shared_ptr CreateUndefined() override; virtual std::shared_ptr CreateNull() override; virtual std::shared_ptr CreateObject(const std::unordered_map< diff --git a/framework/ios/base/bridge/HippyBridge.mm b/framework/ios/base/bridge/HippyBridge.mm index 0f5c1b5f81c..022b9e72e8c 100644 --- a/framework/ios/base/bridge/HippyBridge.mm +++ b/framework/ios/base/bridge/HippyBridge.mm @@ -787,8 +787,7 @@ - (void)actuallyInvokeAndProcessModule:(NSString *)module method:(NSString *)met - (void)dispatchBlock:(dispatch_block_t)block queue:(dispatch_queue_t)queue { if (HippyJSThread == queue) { [_javaScriptExecutor executeBlockOnJavaScriptQueue:block]; - } - else { + } else { dispatch_async(queue, block); } } diff --git a/framework/ios/utils/NSObject+CtxValue.mm b/framework/ios/utils/NSObject+CtxValue.mm index 00cf1ab915f..c7177eeade8 100644 --- a/framework/ios/utils/NSObject+CtxValue.mm +++ b/framework/ios/utils/NSObject+CtxValue.mm @@ -152,20 +152,17 @@ id ObjectFromCtxValue(CtxPtr context, CtxValuePtr value) { if (context->IsString(value)) { footstone::string_view view; if (context->GetValueString(value, &view)) { - view = footstone::StringViewUtils::ConvertEncoding(view, footstone::string_view::Encoding::Utf16); + view = footstone::StringViewUtils::CovertToUtf16(view, view.encoding()); footstone::string_view::u16string &u16String = view.utf16_value(); - NSString *string = - [NSString stringWithCharacters:(const unichar *)u16String.c_str() length:u16String.length()]; + NSString *string = [NSString stringWithCharacters:(const unichar *)u16String.c_str() length:u16String.length()]; return string; } - } - else if (context->IsNumber(value)) { + } else if (context->IsNumber(value)) { double number = 0; if (context->GetValueNumber(value, &number)) { return @(number); } - } - else if (context->IsArray(value)) { + } else if (context->IsArray(value)) { uint32_t length = context->GetArrayLength(value); NSMutableArray *array = [NSMutableArray arrayWithCapacity:length]; for (uint32_t index = 0; index < length; index++) { @@ -183,8 +180,7 @@ id ObjectFromCtxValue(CtxPtr context, CtxValuePtr value) { if (context->GetByteBuffer(value, &bytes, length, type)) { return [NSData dataWithBytes:bytes length:length]; } - } - else if (context->IsObject(value)) { + } else if (context->IsObject(value)) { std::unordered_map map; if (context->GetEntriesFromObject(value, map)) { NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithCapacity:map.size()]; @@ -194,17 +190,19 @@ id ObjectFromCtxValue(CtxPtr context, CtxValuePtr value) { if (!flag) { continue; } - const auto &u16String = footstone::StringViewUtils::CovertToUtf16(string_view, string_view.encoding()).utf16_value(); - NSString *string = [NSString stringWithCharacters:(const unichar *)u16String.c_str() length:u16String.length()]; + // Note that reference value (const auto &) cannot be used directly here, + // since the temporary string_view object will destruct the uft16 value. + // a wrong example is: + // const auto &u16Str = footstone::StringViewUtils::CovertToUtf16(string_view, string_view.encoding()).utf16_value(); + string_view = footstone::StringViewUtils::CovertToUtf16(string_view, string_view.encoding()); + footstone::string_view::u16string &u16Str = string_view.utf16_value(); + NSString *string = [NSString stringWithCharacters:(const unichar *)u16Str.c_str() length:u16Str.length()]; auto &value = it.second; id obj = ObjectFromCtxValue(context, value); [dictionary setObject:obj forKey:string]; } return [dictionary copy]; } - } - else { - } return [NSNull null]; } diff --git a/tests/ios/HippyCtxValueConvertTest.mm b/tests/ios/HippyCtxValueConvertTest.mm new file mode 100644 index 00000000000..040def8b410 --- /dev/null +++ b/tests/ios/HippyCtxValueConvertTest.mm @@ -0,0 +1,134 @@ +/*! + * iOS SDK + * + * Tencent is pleased to support the open source community by making + * Hippy available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#import +#import +#import +#include "driver/engine.h" +#include "driver/vm/js_vm.h" +#include "driver/napi/js_ctx.h" + + +@interface HippyCtxValueConvertTest : XCTestCase + +/// hippy vm for test +@property (nonatomic, assign) std::shared_ptr vm; +/// context for test +@property (nonatomic, assign) std::shared_ptr context; + +@end + +@implementation HippyCtxValueConvertTest + +- (void)setUp { + _vm = hippy::CreateVM(std::make_shared()); + _context = _vm->CreateContext(); +} + +- (void)tearDown { + // nop +} + +- (void)testCtxStringToNSString { + std::shared_ptr ctxStr = _context->CreateString(u"shouldIgnoreLatestLogin"); + id ocObj = ObjectFromCtxValue(_context, ctxStr); + XCTAssert([ocObj isEqualToString:@"shouldIgnoreLatestLogin"]); +} + +- (void)testCtxObjectToNSDictionary { + const char *testKey = "MyVeryVeryLongStringKeyForUnitTest"; + std::shared_ptr ctxStr = _context->CreateString(u"myTestVeryLongStringValue"); + std::unordered_map> map = { {testKey , ctxStr} }; + std::shared_ptr ctxValue = _context->CreateObject(map); + id ocObj = ObjectFromCtxValue(_context, ctxValue); + XCTAssert([ocObj isKindOfClass:NSDictionary.class]); + XCTAssertTrue([[((NSDictionary *)ocObj) objectForKey:@(testKey)] isEqualToString:@"myTestVeryLongStringValue"]); +} + +// NSString +- (void)testNSStringToCtxValue { + NSString *testOCString = @"Hello Hippy"; + CtxValuePtr ctxValue = [testOCString convertToCtxValue:_context]; + XCTAssert(_context->IsString(ctxValue)); + XCTAssert([ObjectFromCtxValue(_context, ctxValue) isEqualToString:testOCString]); +} + +// NSNumber +- (void)testNSNumberToCtxValue { + NSNumber *testOCNumber = @42; + CtxValuePtr ctxValue = [testOCNumber convertToCtxValue:_context]; + XCTAssert(_context->IsNumber(ctxValue)); + XCTAssertTrue([ObjectFromCtxValue(_context, ctxValue) isEqualToNumber:testOCNumber]); +} + +// NSArray +- (void)testNSArrayToCtxValue { + NSArray *testOCArray = @[@"Hello", @42, @YES]; + CtxValuePtr ctxValue = [testOCArray convertToCtxValue:_context]; + XCTAssert(_context->IsArray(ctxValue)); + XCTAssert([ObjectFromCtxValue(_context, ctxValue) isEqualToArray:testOCArray]); +} + +// NSDictionary +- (void)testNSDictionaryToCtxValue { + NSDictionary *testOCDict = @{@"key1": @"value1", @"key2": @42}; + CtxValuePtr ctxValue = [testOCDict convertToCtxValue:_context]; + XCTAssert(_context->IsObject(ctxValue)); + XCTAssert([ObjectFromCtxValue(_context, ctxValue) isEqualToDictionary:testOCDict]); +} + +// NSData +- (void)testNSDataToCtxValue { + NSData *testOCData = [@"Hello Hippy" dataUsingEncoding:NSUTF8StringEncoding]; + CtxValuePtr ctxValue = [testOCData convertToCtxValue:_context]; + XCTAssert(_context->IsByteBuffer(ctxValue)); + XCTAssert([ObjectFromCtxValue(_context, ctxValue) isEqualToData:testOCData]); +} + +// NSNull +- (void)testNSNullToCtxValue { + NSNull *testOCNull = [NSNull null]; + CtxValuePtr ctxValue = [testOCNull convertToCtxValue:_context]; + XCTAssert(_context->IsNull(ctxValue)); + XCTAssert([ObjectFromCtxValue(_context, ctxValue) isKindOfClass:[NSNull class]]); +} + +// NSError +- (void)testNSErrorToCtxValue { + NSError *testOCError = [NSError errorWithDomain:@"com.example" code:42 userInfo:nil]; + CtxValuePtr ctxValue = [testOCError convertToCtxValue:_context]; + XCTAssert(_context->IsString(ctxValue)); // NSErrors are converted as string + NSString *resultDesc = ObjectFromCtxValue(_context, ctxValue); + XCTAssert([resultDesc isKindOfClass:[NSString class]]); + XCTAssertEqualObjects(resultDesc, testOCError.description); +} + +// NSURL +- (void)testNSURLToCtxValue { + NSURL *testOCURL = [NSURL URLWithString:@"https://www.example.com"]; + CtxValuePtr ctxValue = [testOCURL convertToCtxValue:_context]; + XCTAssert(_context->IsString(ctxValue)); // Assuming URLs are converted to strings + XCTAssert([ObjectFromCtxValue(_context, ctxValue) isEqualToString:[testOCURL absoluteString]]); +} + +@end