diff --git a/frameworks/js/napi/inputmethodability/BUILD.gn b/frameworks/js/napi/inputmethodability/BUILD.gn index 31622c658b02128d970608bff9b98849bddbc0a7..21e7ea5096976ac5a0e06f50f90d502d1d0acd54 100644 --- a/frameworks/js/napi/inputmethodability/BUILD.gn +++ b/frameworks/js/napi/inputmethodability/BUILD.gn @@ -95,7 +95,6 @@ ohos_shared_library("inputmethodengine") { "napi:ace_napi", "window_manager:libwm_lite", "resource_management:global_resmgr", - "samgr:samgr_proxy", "ability_runtime:app_context", ] diff --git a/frameworks/js/napi/inputmethodability/js_text_input_client_engine.cpp b/frameworks/js/napi/inputmethodability/js_text_input_client_engine.cpp index 7a5589f709a2192c549799870645961c39482315..82a96b3ff2ecc90038aa559ab57e2ca9615c9ceb 100644 --- a/frameworks/js/napi/inputmethodability/js_text_input_client_engine.cpp +++ b/frameworks/js/napi/inputmethodability/js_text_input_client_engine.cpp @@ -523,6 +523,7 @@ napi_value JsTextInputClientEngine::InsertTextSync(napi_env env, napi_callback_i HandleParamCheckFailure(env)); PARAM_CHECK_RETURN(env, JsUtil::GetValue(env, argv[0], text), "text covert failed!", TYPE_NONE, HandleParamCheckFailure(env)); + IMSA_HILOGD("insert text, text: %{private}s.", text.c_str()); int32_t ret = InputMethodAbility::GetInstance().InsertText(text); if (ret != ErrorCode::NO_ERROR) { JsUtils::ThrowException(env, JsUtils::Convert(ret), "failed to insert text!", TYPE_NONE); diff --git a/frameworks/js/napi/inputmethodability/panel_listener_impl.cpp b/frameworks/js/napi/inputmethodability/panel_listener_impl.cpp index 3a57d65fefde75e2df1fce3c7371251edfaa641d..20c4578f10d369f77e1e48839b14cc03ad6ba01f 100644 --- a/frameworks/js/napi/inputmethodability/panel_listener_impl.cpp +++ b/frameworks/js/napi/inputmethodability/panel_listener_impl.cpp @@ -22,7 +22,7 @@ namespace OHOS { namespace MiscServices { std::shared_ptr PanelListenerImpl::instance_{ nullptr }; std::mutex PanelListenerImpl::listenerMutex_; -constexpr uint8_t SIE_CHANGE_PARAM_COUNT = 2; +constexpr uint8_t SIZE_CHANGE_PARAM_COUNT = 2; std::shared_ptr PanelListenerImpl::GetInstance() { if (instance_ == nullptr) { @@ -135,7 +135,7 @@ void PanelListenerImpl::OnSizeChange( keyboardArea.right); auto task = [entry]() { auto getWindowSizeParams = [entry](napi_env env, napi_value *args, uint8_t argc) -> bool { - if (argc < SIE_CHANGE_PARAM_COUNT) { + if (argc < SIZE_CHANGE_PARAM_COUNT) { return false; } napi_value windowSize = JsWindowSize::Write(env, entry->size); @@ -145,7 +145,7 @@ void PanelListenerImpl::OnSizeChange( return true; }; // 2 means 'sizeChange' has 2 params - JsCallbackHandler::Traverse({ entry->cbCopy }, { SIE_CHANGE_PARAM_COUNT, getWindowSizeParams }); + JsCallbackHandler::Traverse({ entry->cbCopy }, { SIZE_CHANGE_PARAM_COUNT, getWindowSizeParams }); }; eventHandler->PostTask(task, event, 0, AppExecFwk::EventQueue::Priority::VIP); } diff --git a/frameworks/native/inputmethod_ability/include/input_method_ability.h b/frameworks/native/inputmethod_ability/include/input_method_ability.h index 754919b208fb5811c1e7ecde939bda9b45b46306..a31a016f99ce3be300fe7e51cfc97e6926b96e52 100644 --- a/frameworks/native/inputmethod_ability/include/input_method_ability.h +++ b/frameworks/native/inputmethod_ability/include/input_method_ability.h @@ -116,6 +116,7 @@ public: int32_t IsCapacitySupport(int32_t capacity, bool &isSupport); AttachOptions GetAttachOptions(); int32_t HandleKeyEventResult(uint64_t cbId, bool consumeResult, const sptr &channelObject); + void RemoveDeathRecipient(); public: /* called from TaskManager worker thread */ diff --git a/frameworks/native/inputmethod_ability/src/input_method_ability.cpp b/frameworks/native/inputmethod_ability/src/input_method_ability.cpp index 127c3fca9e0045fc8a8949443d0538c75cdf01c5..34970ed653b0d17874fe88db6fac82a870d53201 100644 --- a/frameworks/native/inputmethod_ability/src/input_method_ability.cpp +++ b/frameworks/native/inputmethod_ability/src/input_method_ability.cpp @@ -1972,5 +1972,24 @@ int32_t InputMethodAbility::HandleKeyEventResult( auto channel = std::make_shared(channelObject); return channel->HandleKeyEventResult(cbId, consumeResult); } + +void InputMethodAbility::RemoveDeathRecipient() +{ + std::lock_guard lock(abilityLock_); + if (abilityManager_ == nullptr || deathRecipient_ == nullptr) { + IMSA_HILOGE("abilityManager_ or deathRecipient_ is nullptr"); + return; + } + + auto remoteObject = abilityManager_->AsObject(); + if (remoteObject == nullptr) { + IMSA_HILOGE("remoteObject is nullptr"); + return; + } + + if (!remoteObject->RemoveDeathRecipient(deathRecipient_)) { + IMSA_HILOGE("RemoveDeathRecipient failed"); + } +} } // namespace MiscServices } // namespace OHOS \ No newline at end of file diff --git a/frameworks/native/inputmethod_controller/src/input_method_controller.cpp b/frameworks/native/inputmethod_controller/src/input_method_controller.cpp index 4ba7568266398a56c8009e7f8ed5ede0d4c22b55..5a2fd62cc437911aa1a3b13247e9c99d05d65c4e 100644 --- a/frameworks/native/inputmethod_controller/src/input_method_controller.cpp +++ b/frameworks/native/inputmethod_controller/src/input_method_controller.cpp @@ -68,13 +68,6 @@ InputMethodController::InputMethodController() } InputMethodController::~InputMethodController() { } -#ifdef OHOS_IMF_TEST -void InputMethodController::SetImsaProxyForTest(sptr proxy) -{ - std::lock_guard autoLock(abilityLock_); - abilityManager_ = proxy; -} -#endif // OHOS_IMF_TEST sptr InputMethodController::GetInstance() { diff --git a/frameworks/ndk/src/inputmethod_inputmethod_proxy_capi.cpp b/frameworks/ndk/src/inputmethod_inputmethod_proxy_capi.cpp index dacf3afadeea34f0265fb1a6bdb99528ae161c38..b0e2f2e60ac0f001a8f04e4059485b686d0c5c41 100644 --- a/frameworks/ndk/src/inputmethod_inputmethod_proxy_capi.cpp +++ b/frameworks/ndk/src/inputmethod_inputmethod_proxy_capi.cpp @@ -60,10 +60,16 @@ InputMethod_ErrorCode OH_InputMethodProxy_ShowTextInput( InputMethod_InputMethodProxy *inputMethodProxy, InputMethod_AttachOptions *options) { auto errCode = IsValidInputMethodProxy(inputMethodProxy); - if (errCode != IME_ERR_OK || options == nullptr) { + if (errCode != IME_ERR_OK) { IMSA_HILOGE("invalid state, errCode=%{public}d", errCode); return errCode; } + + if (options == nullptr) { + IMSA_HILOGE("options is nullptr"); + return IME_ERR_PARAMCHECK; + } + AttachOptions attachOptions; attachOptions.isShowKeyboard = options->showKeyboard; attachOptions.requestKeyboardReason = diff --git a/interfaces/inner_api/inputmethod_controller/BUILD.gn b/interfaces/inner_api/inputmethod_controller/BUILD.gn index b18b0bde25518c17f7be63b807e6dc799d081661..29c881e904001a971a31167faa3a11ec84d76cf3 100644 --- a/interfaces/inner_api/inputmethod_controller/BUILD.gn +++ b/interfaces/inner_api/inputmethod_controller/BUILD.gn @@ -418,12 +418,6 @@ ohos_static_library("inputmethod_client_static") { "samgr:samgr_proxy", ] - if (testonly) { - defines = [ - "OHOS_IMF_TEST" - ] - } - client_output_values = get_target_outputs(":input_client_interface") sources += filter_include(client_output_values, [ diff --git a/interfaces/inner_api/inputmethod_controller/include/input_method_controller.h b/interfaces/inner_api/inputmethod_controller/include/input_method_controller.h index 1ea657d0d5a69e01b25261407c1185b19d9c47bd..18b8a61953a9db04d5c6ee7f4e30f0564f7bb475 100644 --- a/interfaces/inner_api/inputmethod_controller/include/input_method_controller.h +++ b/interfaces/inner_api/inputmethod_controller/include/input_method_controller.h @@ -993,11 +993,8 @@ public: IMF_API int32_t RegisterWindowScaleCallbackHandler(WindowScaleCallback&& callback); void HandleKeyEventResult(uint64_t cbId, bool consumeResult); - -#ifdef OHOS_IMF_TEST - void SetImsaProxyForTest(sptr proxy); -#endif // OHOS_IMF_TEST private: + friend class MockInputMethodSystemAbilityProxy; InputMethodController(); ~InputMethodController(); diff --git a/services/adapter/settings_data_provider/include/numkey_apps_manager.h b/services/adapter/settings_data_provider/include/numkey_apps_manager.h index ec2d1f938d9e9493df3fe2dd37efb5e67882e089..9da77af0ba5f3458fcf395396869ad2fa3fe3eb8 100644 --- a/services/adapter/settings_data_provider/include/numkey_apps_manager.h +++ b/services/adapter/settings_data_provider/include/numkey_apps_manager.h @@ -56,6 +56,7 @@ class NumkeyAppsManager { public: static NumkeyAppsManager &GetInstance(); int32_t Init(int32_t userId); + void Release(); bool NeedAutoNumKeyInput(int32_t userId, const std::string &bundleName); int32_t OnUserSwitched(int32_t userId); int32_t OnUserRemoved(int32_t userId); diff --git a/services/adapter/settings_data_provider/src/numkey_apps_manager.cpp b/services/adapter/settings_data_provider/src/numkey_apps_manager.cpp index e6977738563ececec4c5035cb496f46561bb7942..7ebd43a9f484cc524b03c17f44c2e61d591df1cc 100644 --- a/services/adapter/settings_data_provider/src/numkey_apps_manager.cpp +++ b/services/adapter/settings_data_provider/src/numkey_apps_manager.cpp @@ -34,7 +34,7 @@ NumkeyAppsManager &NumkeyAppsManager::GetInstance() return numkeyAppsManager; } // LCOV_EXCL_START -NumkeyAppsManager::~NumkeyAppsManager() +void NumkeyAppsManager::Release() { if (observers_.empty()) { return; @@ -50,6 +50,8 @@ NumkeyAppsManager::~NumkeyAppsManager() } } +NumkeyAppsManager::~NumkeyAppsManager() { } + int32_t NumkeyAppsManager::Init(int32_t userId) { IMSA_HILOGI("start, userId: %{public}d", userId); diff --git a/services/include/ime_info_inquirer.h b/services/include/ime_info_inquirer.h index 54d7ae8be21645f420ffa546e0d54b81cab3080d..319fc3f49c4970bf828a97a7ed819db3da08ef69 100644 --- a/services/include/ime_info_inquirer.h +++ b/services/include/ime_info_inquirer.h @@ -92,6 +92,7 @@ public: bool IsProxyIme(int32_t callingUid); bool IsSpecialSaUid(int32_t callingUid); void InitSystemConfig(); + void InitDynamicStartImeCfg(); SystemConfig GetSystemConfig(); ImeNativeCfg GetDefaultIme(); std::string GetSystemSpecialIme(); @@ -149,6 +150,7 @@ private: FullImeInfo &imeInfo, bool needBrief = false); SystemConfig systemConfig_; + std::vector dynamicStartImeList_; bool IsTempInputMethod(const OHOS::AppExecFwk::ExtensionAbilityInfo &extInfo); }; } // namespace MiscServices diff --git a/services/include/sys_cfg_parser.h b/services/include/sys_cfg_parser.h index 664f7c1d3fdda77042138e44179a86c6211c668a..5b64d2b1cf06cb2c60859d7b853355b35cbcaa5e 100644 --- a/services/include/sys_cfg_parser.h +++ b/services/include/sys_cfg_parser.h @@ -35,8 +35,7 @@ struct SystemConfig : public Serializable { std::unordered_set specialSaUidList; std::unordered_set defaultImeScreenList; std::unordered_set supportedCapacityList; - std::string dynamicStartImeSysParam; - std::string dynamicStartImeValue; + bool Unmarshal(cJSON *node) override { GetValue(node, GET_NAME(systemInputMethodConfigAbility), systemInputMethodConfigAbility); @@ -54,8 +53,6 @@ struct SystemConfig : public Serializable { GetValue(node, GET_NAME(specialSaUidList), specialSaUidList); GetValue(node, GET_NAME(defaultImeScreenList), defaultImeScreenList); GetValue(node, GET_NAME(supportedCapacityList), supportedCapacityList); - GetValue(node, GET_NAME(dynamicStartImeSysParam), dynamicStartImeSysParam); - GetValue(node, GET_NAME(dynamicStartImeValue), dynamicStartImeValue); return true; } }; @@ -92,6 +89,31 @@ struct InputTypeCfg : public Serializable { } }; +struct DynamicStartImeCfgItem : public Serializable { + std::string sysParam; + std::string value; + DynamicStartImeCfgItem(const std::string &sysParam = "", const std::string &value = "") + { + this->sysParam = sysParam; + this->value = value; + } + + bool Unmarshal(cJSON *node) override + { + auto ret = GetValue(node, GET_NAME(sysParam), sysParam); + ret = GetValue(node, GET_NAME(value), value) && ret; + return ret; + } +}; + +struct DynamicStartImeCfg : public Serializable { + std::vector dynamicStartImeCfgList; + bool Unmarshal(cJSON *node) override + { + return GetValue(node, GET_NAME(dynamicStartImeCfgList), dynamicStartImeCfgList); + } +}; + struct SysPanelAdjust : public Serializable { std::vector style; int32_t top = 0; @@ -161,6 +183,7 @@ public: static bool ParsePanelAdjust(std::vector &sysPanelAdjust); static bool ParseDefaultFullIme(std::vector &defaultFullImeList); static bool ParseIgnoreSysPanelAdjust(IgnoreSysPanelAdjust &ignoreSysPanelAdjust); + static bool ParseDynamicStartImeCfg(std::vector &dynamicStartImeCfgList); private: static std::string GetSysCfgContent(const std::string &key); diff --git a/services/src/ime_info_inquirer.cpp b/services/src/ime_info_inquirer.cpp index cf11e4990331a4d673d91a6aaa1e4dd9bb30dc66..307281c0d328264f16a162d54421026cca64b173 100644 --- a/services/src/ime_info_inquirer.cpp +++ b/services/src/ime_info_inquirer.cpp @@ -58,6 +58,14 @@ void ImeInfoInquirer::InitSystemConfig() } } +void ImeInfoInquirer::InitDynamicStartImeCfg() +{ + if (!SysCfgParser::ParseDynamicStartImeCfg(dynamicStartImeList_)) { + IMSA_HILOGW("not found dynamic start ime cfg"); + dynamicStartImeList_.clear(); + } +} + bool ImeInfoInquirer::IsEnableAppAgent() { return systemConfig_.enableAppAgentFeature; @@ -1239,11 +1247,20 @@ bool ImeInfoInquirer::IsRestrictedDefaultImeByDisplay(uint64_t displayId) bool ImeInfoInquirer::IsDynamicStartIme() { - if (systemConfig_.dynamicStartImeSysParam.empty()) { + if (dynamicStartImeList_.empty()) { + IMSA_HILOGI("dynamic start ime cfg is empty"); return false; } - std::string value = system::GetParameter(systemConfig_.dynamicStartImeSysParam, ""); - return value == systemConfig_.dynamicStartImeValue; + + for (auto &dynamicStartIme : dynamicStartImeList_) { + std::string value = system::GetParameter(dynamicStartIme.sysParam, ""); + if (value == dynamicStartIme.value) { + IMSA_HILOGI("dynamic start ime cfg is matched"); + return true; + } + } + IMSA_HILOGI("dynamic start ime cfg is not matched"); + return false; } bool ImeInfoInquirer::GetCompatibleDeviceType( diff --git a/services/src/input_method_system_ability.cpp b/services/src/input_method_system_ability.cpp index 694bcb94ff63ec9cb25e26a7e9abc3cbd59cc40b..50d2ad770597583f6813d34f4621ddc6d42cd83a 100644 --- a/services/src/input_method_system_ability.cpp +++ b/services/src/input_method_system_ability.cpp @@ -387,6 +387,7 @@ int32_t InputMethodSystemAbility::Init() IMSA_HILOGI("publish success"); state_ = ServiceRunningState::STATE_RUNNING; ImeInfoInquirer::GetInstance().InitSystemConfig(); + ImeInfoInquirer::GetInstance().InitDynamicStartImeCfg(); ImeStateManagerFactory::GetInstance().SetDynamicStartIme(ImeInfoInquirer::GetInstance().IsDynamicStartIme()); #endif InitMonitors(); @@ -425,6 +426,7 @@ void InputMethodSystemAbility::OnStop() serviceHandler_ = nullptr; state_ = ServiceRunningState::STATE_NOT_START; Memory::MemMgrClient::GetInstance().NotifyProcessStatus(getpid(), 1, 0, INPUT_METHOD_SYSTEM_ABILITY_ID); + NumkeyAppsManager::GetInstance().Release(); SettingsDataUtils::GetInstance().Release(); } // LCOV_EXCL_STOP diff --git a/services/src/sys_cfg_parser.cpp b/services/src/sys_cfg_parser.cpp index bead0887a08cb7957389f58170c429706c4bca5a..292824bb8c0a173a56c7f0ef50ba356710ca7e75 100644 --- a/services/src/sys_cfg_parser.cpp +++ b/services/src/sys_cfg_parser.cpp @@ -46,6 +46,22 @@ bool SysCfgParser::ParseInputType(std::vector &inputType) return ret; } +bool SysCfgParser::ParseDynamicStartImeCfg(std::vector &dynamicStartImeCfgList) +{ + auto content = GetSysCfgContent(GET_NAME(dynamicStartImeCfgList)); + if (content.empty()) { + IMSA_HILOGW("dynamic start ime cfg content is empty"); + return false; + } + + DynamicStartImeCfg dynamicStartImeCfg; + auto ret = dynamicStartImeCfg.Unmarshall(content); + if (ret) { + dynamicStartImeCfgList = dynamicStartImeCfg.dynamicStartImeCfgList; + } + return ret; +} + bool SysCfgParser::ParsePanelAdjust(std::vector &sysPanelAdjust) { auto content = GetSysCfgContent(GET_NAME(sysPanelAdjust)); diff --git a/test/unittest/cpp_test/BUILD.gn b/test/unittest/cpp_test/BUILD.gn index 10bd24d5456e98c76131d00180e5c8723402daaa..bc2f2ee7c91d3755f08701fa05f07e1c5ea364ec 100644 --- a/test/unittest/cpp_test/BUILD.gn +++ b/test/unittest/cpp_test/BUILD.gn @@ -1119,6 +1119,7 @@ ohos_unittest("JsonOperateTest") { "input:libmmi-client", "ipc:ipc_single", "resource_management:global_resmgr", + "init:libbegetutil", ] } @@ -1246,6 +1247,7 @@ ohos_unittest("ImeControllerCpaiTest") { sources = [ "src/inputmethod_controller_capi_test.cpp", "src/native_text_changed_listener_test.cpp", + "mock/mock_input_method_system_ability_proxy.cpp", ] configs = [ "${inputmethod_path}/interfaces/inner_api/inputmethod_ability:inputmethod_ability_native_public_config" ] @@ -1256,10 +1258,6 @@ ohos_unittest("ImeControllerCpaiTest") { "${inputmethod_path}/test/unittest/cpp_test/mock", ] - defines = [ - "OHOS_IMF_TEST" - ] - deps = [ "${inputmethod_path}/frameworks/ndk:ohinputmethod_static", "${inputmethod_path}/interfaces/inner_api/inputmethod_controller:inputmethod_client_static", @@ -1403,6 +1401,7 @@ ohos_unittest("OnDemandStartStopSaTest") { "hilog:libhilog", "ipc:ipc_single", "samgr:samgr_proxy", + "googletest:gmock", ] } diff --git a/test/unittest/cpp_test/mock/mock_input_method_system_ability_proxy.cpp b/test/unittest/cpp_test/mock/mock_input_method_system_ability_proxy.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bd47f6138728fdc0922d8a0c2c0209e84a292979 --- /dev/null +++ b/test/unittest/cpp_test/mock/mock_input_method_system_ability_proxy.cpp @@ -0,0 +1,35 @@ +/* +* Copyright (c) 2025 Huawei Device Co., Ltd. +* 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. +*/ +#include "mock_input_method_system_ability_proxy.h" + +namespace OHOS { +namespace MiscServices { +using namespace testing::ext; +using namespace testing; +MockInputMethodSystemAbilityProxy::MockInputMethodSystemAbilityProxy() : InputMethodSystemAbilityProxy(nullptr) +{ +} +void MockInputMethodSystemAbilityProxy::SetImsaProxyForTest( + sptr controller, sptr proxy) +{ + if (controller == nullptr) { + IMSA_HILOGE("MockInputMethodSystemAbilityProxy::SetImsaProxyForTest: controller is nullptr"); + return; + } + std::lock_guard autoLock(controller->abilityLock_); + controller->abilityManager_ = proxy; +} +} +} \ No newline at end of file diff --git a/test/unittest/cpp_test/mock/mock_input_method_system_ability_proxy.h b/test/unittest/cpp_test/mock/mock_input_method_system_ability_proxy.h index c2063be0931a0c7544fcfa7f0ed2ead859c40ea9..e0457463715f634f5caffb828da749c0ce240c30 100644 --- a/test/unittest/cpp_test/mock/mock_input_method_system_ability_proxy.h +++ b/test/unittest/cpp_test/mock/mock_input_method_system_ability_proxy.h @@ -1,33 +1,35 @@ /* -* Copyright (c) 2025 Huawei Device Co., Ltd. -* 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. -*/ + * Copyright (c) 2025 Huawei Device Co., Ltd. + * 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. + */ #ifndef MOCK_INPUT_METHOD_SYSTEM_ABILITY_PROXY_H #define MOCK_INPUT_METHOD_SYSTEM_ABILITY_PROXY_H #include +#include "input_method_controller.h" #include "input_method_system_ability_proxy.h" -#include "mock_iremote_object.h" namespace OHOS { namespace MiscServices { class MockInputMethodSystemAbilityProxy : public InputMethodSystemAbilityProxy { public: - MockInputMethodSystemAbilityProxy() : InputMethodSystemAbilityProxy(nullptr) { }; - MOCK_METHOD(int32_t, StartInput, - (const InputClientInfoInner &inputClientInfoInner, std::vector> &agents, - std::vector &imeInfos), - (override)); - MOCK_METHOD(int32_t, ReleaseInput, (const sptr &client, uint32_t sessionId), (override)); + MockInputMethodSystemAbilityProxy(); + static void SetImsaProxyForTest(sptr controller, sptr proxy); + MOCK_METHOD3(StartInput, + int32_t(const InputClientInfoInner &, std::vector> &, std::vector &)); + MOCK_METHOD2(ReleaseInput, int32_t(const sptr &, uint32_t)); + MOCK_METHOD0(ShowCurrentInputDeprecated, int32_t()); + MOCK_METHOD3(ShowInput, int32_t(const sptr &, uint32_t, int32_t)); + MOCK_METHOD0(HideCurrentInputDeprecated, int32_t()); }; } // namespace MiscServices } // namespace OHOS diff --git a/test/unittest/cpp_test/mock/mock_iremote_object.h b/test/unittest/cpp_test/mock/mock_iremote_object.h index 85852f2489f378f7c1b97d2ab8b7bcc0ba5b856c..8b55ab6ebb679a6d3b08c0f91b047bf4905a2548 100644 --- a/test/unittest/cpp_test/mock/mock_iremote_object.h +++ b/test/unittest/cpp_test/mock/mock_iremote_object.h @@ -15,68 +15,32 @@ #ifndef IMF_MOCK_IREMOTE_OBJECT_H #define IMF_MOCK_IREMOTE_OBJECT_H -#include "iremote_broker.h" +#include + #include "iremote_object.h" namespace OHOS { +namespace MiscServices { class MockIRemoteObject : public IRemoteObject { public: MockIRemoteObject() : IRemoteObject(u"mock_i_remote_object") { } - ~MockIRemoteObject() { } + MOCK_METHOD(int, SendRequest, (uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option)); + MOCK_METHOD(bool, IsProxyObject, (), (const, override)); + MOCK_METHOD(bool, CheckObjectLegality, (), (const, override)); + MOCK_METHOD(bool, AddDeathRecipient, (const sptr &recipient), (override)); + MOCK_METHOD(bool, RemoveDeathRecipient, (const sptr &recipient), (override)); + MOCK_METHOD(bool, Marshalling, (Parcel & parcel), (const, override)); + MOCK_METHOD(sptr, AsInterface, (), (override)); + MOCK_METHOD(int, Dump, (int fd, const std::vector &args), (override)); + MOCK_METHOD(int32_t, GetObjectRefCount, (), (override)); - int32_t GetObjectRefCount() override - { - return 0; - } - - int SendRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override - { - (void)code; - (void)data; - (void)reply; - (void)option; - return 0; - } - - bool IsProxyObject() const override - { - return true; - } - - bool CheckObjectLegality() const override - { - return true; - } - - bool AddDeathRecipient(const sptr &recipient) override - { - (void)recipient; - return true; - } - - bool RemoveDeathRecipient(const sptr &recipient) override - { - (void)recipient; - return true; - } - - bool Marshalling(Parcel &parcel) const override - { - (void)parcel; - return true; - } - - sptr AsInterface() override - { - return nullptr; - } - - int Dump(int fd, const std::vector &args) override + std::u16string GetObjectDescriptor() const { - (void)fd; - return 0; + std::u16string descriptor = std::u16string(); + return descriptor; } }; +} } // namespace OHOS #endif // IMF_MOCK_IREMOTE_OBJECT_H \ No newline at end of file diff --git a/test/unittest/cpp_test/src/ime_proxy_agent_ime_test.cpp b/test/unittest/cpp_test/src/ime_proxy_agent_ime_test.cpp index b4c005dd46d4c836ee8041213b16a684a5f4b4e0..1b8e053f456382dd249617f72136ef9a6f4e2fd3 100644 --- a/test/unittest/cpp_test/src/ime_proxy_agent_ime_test.cpp +++ b/test/unittest/cpp_test/src/ime_proxy_agent_ime_test.cpp @@ -46,6 +46,8 @@ public: static void SetUpTestCase(void) { IMSA_HILOGI("ImeProxyAgentImeTest::SetUpTestCase"); + // To increase the coverage of abnormal branches + InputMethodAbility::GetInstance().RemoveDeathRecipient(); TddUtil::StorageSelfTokenID(); TddUtil::InitWindow(false); imc_ = InputMethodController::GetInstance(); @@ -69,6 +71,10 @@ public: IMSA_HILOGI("ImeProxyAgentImeTest::TearDownTestCase"); TddUtil::DestroyWindow(); TddUtil::RestoreSelfTokenID(); + InputMethodAbility::GetInstance().RemoveDeathRecipient(); + if (imc_ != nullptr) { + imc_->Reset(); + } TddUtil::KillImsaProcess(); } void SetUp() diff --git a/test/unittest/cpp_test/src/input_method_message_handler_test.cpp b/test/unittest/cpp_test/src/input_method_message_handler_test.cpp index b8f110233bdc08e23143fcdf810ec61a3b9eb901..235717dcfcb3301c8f9750b121af44a7d2b7b650 100644 --- a/test/unittest/cpp_test/src/input_method_message_handler_test.cpp +++ b/test/unittest/cpp_test/src/input_method_message_handler_test.cpp @@ -1453,6 +1453,7 @@ HWTEST_F(InputMethodMessageHandlerTest, testRecvMessageCapi_003, TestSize.Level1 EXPECT_EQ(ret, IME_ERR_OK); auto messageHanlderProxy = OH_MessageHandlerProxy_Create(); EXPECT_EQ(IME_ERR_OK, OH_MessageHandlerProxy_SetOnTerminatedFunc(messageHanlderProxy, OnTerminatedFuncNew)); + EXPECT_EQ(OH_InputMethodProxy_RecvMessage(imeProxy, messageHanlderProxy), IME_ERR_NULL_POINTER); EXPECT_EQ(IME_ERR_OK, OH_MessageHandlerProxy_SetOnMessageFunc(messageHanlderProxy, OnMessageFunc)); ret = OH_InputMethodProxy_RecvMessage(imeProxy, messageHanlderProxy); EXPECT_EQ(ret, IME_ERR_OK); diff --git a/test/unittest/cpp_test/src/inputmethod_controller_capi_test.cpp b/test/unittest/cpp_test/src/inputmethod_controller_capi_test.cpp index e5a5fb9406979a1bdd86350dc9981e8aa63cfa74..52f4e19bf08b020aea5adb49c882db2135eaa646 100644 --- a/test/unittest/cpp_test/src/inputmethod_controller_capi_test.cpp +++ b/test/unittest/cpp_test/src/inputmethod_controller_capi_test.cpp @@ -17,16 +17,72 @@ #include "string_ex.h" #include "global.h" -#include "native_inputmethod_types.h" -#include "mock_input_method_system_ability_proxy.h" #include "input_method_controller.h" +#include "mock_input_method_system_ability_proxy.h" +#include "mock_iremote_object.h" +#include "native_inputmethod_types.h" using namespace testing::ext; using namespace OHOS; using namespace OHOS::MiscServices; using namespace testing; -class InputMethodControllerCapiTest : public testing::Test { }; -namespace { + +namespace OHOS { +namespace MiscServices { +class InputMethodControllerCapiTest : public testing::Test { +public: + static void SetUpTestSuite() + { + systemAbilityProxyMock_ = new (std::nothrow) NiceMock(); + ASSERT_NE(systemAbilityProxyMock_, nullptr); + MockInputMethodSystemAbilityProxy::SetImsaProxyForTest( + InputMethodController::GetInstance(), systemAbilityProxyMock_); + + textEditorProxy_ = OH_TextEditorProxy_Create(); + ASSERT_NE(nullptr, textEditorProxy_); + ConstructTextEditorProxy(textEditorProxy_); + + attachOptions_ = OH_AttachOptions_Create(true); + ASSERT_NE(nullptr, attachOptions_); + + ON_CALL(*systemAbilityProxyMock_, StartInput(_, _, _)) + .WillByDefault(Invoke([](const InputClientInfoInner &info, vector> &agents, + vector &imeInfos) { + sptr iremoteObject = new (std::nothrow) NiceMock(); + EXPECT_NE(iremoteObject, nullptr); + agents.emplace_back(iremoteObject); + BindImeInfo imeinfo; + imeInfos.push_back(imeinfo); + return ErrorCode::NO_ERROR; + })); + } + + static void TearDownTestSuite() + { + MockInputMethodSystemAbilityProxy::SetImsaProxyForTest(InputMethodController::GetInstance(), nullptr); + if (textEditorProxy_ != nullptr) { + OH_TextEditorProxy_Destroy(textEditorProxy_); + textEditorProxy_ = nullptr; + } + + if (attachOptions_ != nullptr) { + OH_AttachOptions_Destroy(attachOptions_); + attachOptions_ = nullptr; + } + + systemAbilityProxyMock_ = nullptr; + } + + static void ConstructTextEditorProxy(InputMethod_TextEditorProxy *textEditorProxy); + + static InputMethod_TextEditorProxy *textEditorProxy_; + static InputMethod_AttachOptions *attachOptions_; + static sptr systemAbilityProxyMock_; +}; + +InputMethod_TextEditorProxy *InputMethodControllerCapiTest::textEditorProxy_ = nullptr; +InputMethod_AttachOptions *InputMethodControllerCapiTest::attachOptions_ = nullptr; +sptr InputMethodControllerCapiTest::systemAbilityProxyMock_ = nullptr; /** * @tc.name: TestCursorInfo_001 * @tc.desc: create and destroy TestCursorInfo success @@ -199,7 +255,7 @@ int32_t SetPreviewTextFunc( return 0; } void FinishTextPreviewFunc(InputMethod_TextEditorProxy *proxy) { } -static void ConstructTextEditorProxy(InputMethod_TextEditorProxy *textEditorProxy) +void InputMethodControllerCapiTest::ConstructTextEditorProxy(InputMethod_TextEditorProxy *textEditorProxy) { EXPECT_EQ(IME_ERR_OK, OH_TextEditorProxy_SetGetTextConfigFunc(textEditorProxy, GetTextConfigFunc)); EXPECT_EQ(IME_ERR_OK, OH_TextEditorProxy_SetInsertTextFunc(textEditorProxy, InsertTextFunc)); @@ -311,6 +367,42 @@ HWTEST_F(InputMethodControllerCapiTest, AttachOptions_001, TestSize.Level0) OH_AttachOptions_Destroy(options); } +/** + * @tc.name: CreateAndDestroyAttachOptionsWithRequestKeyboardReason_success + * @tc.desc: create and destroy AttachOptions success + * @tc.type: FUNC + */ +HWTEST_F(InputMethodControllerCapiTest, CreateAndDestroyAttachOptionsWithRequestKeyboardReason_success, TestSize.Level0) +{ + auto options = OH_AttachOptions_CreateWithRequestKeyboardReason( + true, InputMethod_RequestKeyboardReason::IME_REQUEST_REASON_NONE); + ASSERT_NE(nullptr, options); + + int32_t requestKeyboardReason = -1; + EXPECT_EQ(IME_ERR_NULL_POINTER, OH_AttachOptions_GetRequestKeyboardReason(options, nullptr)); + EXPECT_EQ(IME_ERR_NULL_POINTER, OH_AttachOptions_GetRequestKeyboardReason(nullptr, &requestKeyboardReason)); + + EXPECT_EQ(IME_ERR_OK, OH_AttachOptions_GetRequestKeyboardReason(options, &requestKeyboardReason)); + EXPECT_EQ(requestKeyboardReason, InputMethod_RequestKeyboardReason::IME_REQUEST_REASON_NONE); + OH_AttachOptions_Destroy(options); +} + +/** + * @tc.name: GetRequestKeyboardReasonWithNull_fail + * @tc.desc: get request keyboard reason with null fail + * @tc.type: FUNC + */ +HWTEST_F(InputMethodControllerCapiTest, GetRequestKeyboardReasonWithNull_fail, TestSize.Level0) +{ + auto options = OH_AttachOptions_CreateWithRequestKeyboardReason( + true, InputMethod_RequestKeyboardReason::IME_REQUEST_REASON_NONE); + ASSERT_NE(nullptr, options); + + EXPECT_EQ(IME_ERR_NULL_POINTER, OH_AttachOptions_GetRequestKeyboardReason(options, nullptr)); + EXPECT_EQ(IME_ERR_NULL_POINTER, OH_AttachOptions_GetRequestKeyboardReason(nullptr, nullptr)); + OH_AttachOptions_Destroy(options); +} + /** * @tc.name: TextAvoidInfo_001 * @tc.desc: create and destroy TextAvoidInfo success @@ -1380,6 +1472,57 @@ HWTEST_F(InputMethodControllerCapiTest, OH_InputMethodProxy_ShowKeyboard_001, Te EXPECT_EQ(ret, IME_ERR_NULL_POINTER); } +/** + * @tc.name: ShowKeyboardTest_SUCCESS + * @tc.desc: show keyboard success after attach + * @tc.type: FUNC + */ +HWTEST_F(InputMethodControllerCapiTest, ShowKeyboardTest_SUCCESS, TestSize.Level0) +{ + InputMethod_InputMethodProxy *inputMethodProxy = nullptr; + EXPECT_EQ(IME_ERR_OK, OH_InputMethodController_Attach(textEditorProxy_, attachOptions_, &inputMethodProxy)); + + auto ret = OH_InputMethodProxy_ShowKeyboard(inputMethodProxy); + EXPECT_EQ(ret, IME_ERR_OK); + + EXPECT_EQ(IME_ERR_OK, OH_InputMethodController_Detach(inputMethodProxy)); +} + +/** + * @tc.name: ShowTextInput_SUCCESS + * @tc.desc: show text input success after attach + * @tc.type: FUNC + */ +HWTEST_F(InputMethodControllerCapiTest, ShowTextInput_SUCCESS, TestSize.Level0) +{ + InputMethod_InputMethodProxy *inputMethodProxy = nullptr; + EXPECT_EQ(IME_ERR_OK, OH_InputMethodController_Attach(textEditorProxy_, attachOptions_, &inputMethodProxy)); + + auto ret = OH_InputMethodProxy_ShowTextInput(inputMethodProxy, attachOptions_); + EXPECT_EQ(ret, IME_ERR_OK); + + EXPECT_EQ(IME_ERR_OK, OH_InputMethodController_Detach(inputMethodProxy)); +} + +/** + * @tc.name: ShowTextInputWithNullOptions_fail + * @tc.desc: show text input with invalid param fail after attach + * @tc.type: FUNC + */ +HWTEST_F(InputMethodControllerCapiTest, ShowTextInputWithNullOptions_fail, TestSize.Level0) +{ + InputMethod_InputMethodProxy *inputMethodProxy = nullptr; + EXPECT_EQ(IME_ERR_OK, OH_InputMethodController_Attach(textEditorProxy_, attachOptions_, &inputMethodProxy)); + + auto ret = OH_InputMethodProxy_ShowTextInput(inputMethodProxy, nullptr); + EXPECT_EQ(ret, IME_ERR_PARAMCHECK); + + ret = OH_InputMethodProxy_ShowTextInput(nullptr, attachOptions_); + EXPECT_EQ(ret, IME_ERR_NULL_POINTER); + + EXPECT_EQ(IME_ERR_OK, OH_InputMethodController_Detach(inputMethodProxy)); +} + /** * @tc.name: OH_InputMethodProxy_HideKeyboard_001 * @tc.desc: input parameters is nullptr @@ -1391,6 +1534,22 @@ HWTEST_F(InputMethodControllerCapiTest, OH_InputMethodProxy_HideKeyboard_001, Te EXPECT_EQ(ret, IME_ERR_NULL_POINTER); } +/** + * @tc.name: HideKeyboard_SUCCESS + * @tc.desc: hide keyboard success + * @tc.type: FUNC + */ +HWTEST_F(InputMethodControllerCapiTest, HideKeyboard_SUCCESS, TestSize.Level0) +{ + InputMethod_InputMethodProxy *inputMethodProxy = nullptr; + EXPECT_EQ(IME_ERR_OK, OH_InputMethodController_Attach(textEditorProxy_, attachOptions_, &inputMethodProxy)); + + auto ret = OH_InputMethodProxy_HideKeyboard(inputMethodProxy); + EXPECT_EQ(ret, IME_ERR_OK); + + EXPECT_EQ(IME_ERR_OK, OH_InputMethodController_Detach(inputMethodProxy)); +} + /** * @tc.name: OH_InputMethodProxy_NotifySelectionChange_001 * @tc.desc: input parameters is nullptr @@ -1405,6 +1564,56 @@ HWTEST_F(InputMethodControllerCapiTest, OH_InputMethodProxy_NotifySelectionChang EXPECT_EQ(ret, IME_ERR_NULL_POINTER); } +/** + * @tc.name: NotifySelectionChangeWithNullText_FAIL + * @tc.desc: input parameters is nullptr + * @tc.type: FUNC + */ +HWTEST_F(InputMethodControllerCapiTest, NotifySelectionChangeWithNullText_FAIL, TestSize.Level0) +{ + InputMethod_InputMethodProxy *inputMethodProxy = nullptr; + EXPECT_EQ(IME_ERR_OK, OH_InputMethodController_Attach(textEditorProxy_, attachOptions_, &inputMethodProxy)); + size_t length = 0; + int start = 0; + int end = 0; + auto ret = OH_InputMethodProxy_NotifySelectionChange(inputMethodProxy, nullptr, length, start, end); + EXPECT_EQ(ret, IME_ERR_NULL_POINTER); + + EXPECT_EQ(IME_ERR_OK, OH_InputMethodController_Detach(inputMethodProxy)); +} + +/** + * @tc.name: NotifySelectionChangeWithInvalidLength_FAIL + * @tc.desc: input parameters is nullptr + * @tc.type: FUNC + */ +HWTEST_F(InputMethodControllerCapiTest, NotifySelectionChangeWithInvalidLength_FAIL, TestSize.Level0) +{ + InputMethod_InputMethodProxy *inputMethodProxy = nullptr; + EXPECT_EQ(IME_ERR_OK, OH_InputMethodController_Attach(textEditorProxy_, attachOptions_, &inputMethodProxy)); + char16_t text[] = u"1234"; + auto ret = OH_InputMethodProxy_NotifySelectionChange(inputMethodProxy, text, MAX_TEXT_LENGTH + 1, 0, 0); + EXPECT_EQ(ret, IME_ERR_PARAMCHECK); + + EXPECT_EQ(IME_ERR_OK, OH_InputMethodController_Detach(inputMethodProxy)); +} + +/** + * @tc.name: NotifySelectionChange_SUCCESS + * @tc.desc: NotifySelectionChange success + * @tc.type: FUNC + */ +HWTEST_F(InputMethodControllerCapiTest, NotifySelectionChange_SUCCESS, TestSize.Level0) +{ + InputMethod_InputMethodProxy *inputMethodProxy = nullptr; + EXPECT_EQ(IME_ERR_OK, OH_InputMethodController_Attach(textEditorProxy_, attachOptions_, &inputMethodProxy)); + char16_t text[] = u"1234"; + auto ret = OH_InputMethodProxy_NotifySelectionChange(inputMethodProxy, text, 4, 0, 0); + EXPECT_EQ(ret, IME_ERR_OK); + + EXPECT_EQ(IME_ERR_OK, OH_InputMethodController_Detach(inputMethodProxy)); +} + /** * @tc.name: OH_InputMethodProxy_NotifyConfigurationChange_001 * @tc.desc: input parameters is nullptr @@ -1418,6 +1627,63 @@ HWTEST_F(InputMethodControllerCapiTest, OH_InputMethodProxy_NotifyConfigurationC EXPECT_EQ(ret, IME_ERR_NULL_POINTER); } +/** + * @tc.name: NotifyConfigurationChange_SUCCESS + * @tc.desc: notify configuration change success + * @tc.type: FUNC + */ +HWTEST_F(InputMethodControllerCapiTest, NotifyConfigurationChange_SUCCESS, TestSize.Level0) +{ + InputMethod_InputMethodProxy *inputMethodProxy = nullptr; + EXPECT_EQ(IME_ERR_OK, OH_InputMethodController_Attach(textEditorProxy_, attachOptions_, &inputMethodProxy)); + + InputMethod_EnterKeyType enterKey = IME_ENTER_KEY_UNSPECIFIED; + InputMethod_TextInputType expInput = IME_TEXT_INPUT_TYPE_NUMBER_DECIMAL; + auto ret = OH_InputMethodProxy_NotifyConfigurationChange(inputMethodProxy, enterKey, expInput); + EXPECT_EQ(ret, IME_ERR_OK); + + EXPECT_EQ(IME_ERR_OK, OH_InputMethodController_Detach(inputMethodProxy)); +} + +/** + * @tc.name: NotifyCursorUpdate_SUCCESS + * @tc.desc: notify cursor update success + * @tc.type: FUNC + */ +HWTEST_F(InputMethodControllerCapiTest, NotifyCursorUpdate_SUCCESS, TestSize.Level0) +{ + InputMethod_InputMethodProxy *inputMethodProxy = nullptr; + EXPECT_EQ(IME_ERR_OK, OH_InputMethodController_Attach(textEditorProxy_, attachOptions_, &inputMethodProxy)); + + double left = 0; + double top = 1.0; + double width = 2.0; + double height = 3.0; + InputMethod_CursorInfo *cursorInfo = OH_CursorInfo_Create(left, top, width, height); + EXPECT_NE(cursorInfo, nullptr); + auto ret = OH_InputMethodProxy_NotifyCursorUpdate(inputMethodProxy, cursorInfo); + EXPECT_EQ(ret, IME_ERR_OK); + OH_CursorInfo_Destroy(cursorInfo); + + EXPECT_EQ(IME_ERR_OK, OH_InputMethodController_Detach(inputMethodProxy)); +} + +/** + * @tc.name: NotifyCursorUpdateWithNullCursorInfo_FAIL + * @tc.desc: notify cursor update with null cursorInfo fail + * @tc.type: FUNC + */ +HWTEST_F(InputMethodControllerCapiTest, NotifyCursorUpdateWithNullCursorInfo_FAIL, TestSize.Level0) +{ + InputMethod_InputMethodProxy *inputMethodProxy = nullptr; + EXPECT_EQ(IME_ERR_OK, OH_InputMethodController_Attach(textEditorProxy_, attachOptions_, &inputMethodProxy)); + + auto ret = OH_InputMethodProxy_NotifyCursorUpdate(inputMethodProxy, nullptr); + EXPECT_EQ(ret, IME_ERR_NULL_POINTER); + + EXPECT_EQ(IME_ERR_OK, OH_InputMethodController_Detach(inputMethodProxy)); +} + /** * @tc.name: OH_InputMethodProxy_NotifyCursorUpdate_001 * @tc.desc: input parameters is nullptr @@ -1430,10 +1696,12 @@ HWTEST_F(InputMethodControllerCapiTest, OH_InputMethodProxy_NotifyCursorUpdate_0 double width = 2.0; double height = 3.0; InputMethod_CursorInfo *cursorInfo = OH_CursorInfo_Create(left, top, width, height); + EXPECT_NE(cursorInfo, nullptr); auto ret = OH_InputMethodProxy_NotifyCursorUpdate(nullptr, nullptr); EXPECT_EQ(ret, IME_ERR_NULL_POINTER); ret = OH_InputMethodProxy_NotifyCursorUpdate(nullptr, cursorInfo); EXPECT_EQ(ret, IME_ERR_NULL_POINTER); + OH_CursorInfo_Destroy(cursorInfo); } /** @@ -1456,6 +1724,64 @@ HWTEST_F(InputMethodControllerCapiTest, OH_InputMethodProxy_SendPrivateCommand_0 EXPECT_EQ(ret, IME_ERR_NULL_POINTER); } +/** + * @tc.name: SendPrivateCommandWithInvalidCommandCount_FAIL + * @tc.desc: input parameters is invalid + * @tc.type: FUNC + */ +HWTEST_F(InputMethodControllerCapiTest, SendPrivateCommandWithInvalidCommandCount_FAIL, TestSize.Level0) +{ + InputMethod_InputMethodProxy *inputMethodProxy = nullptr; + EXPECT_EQ(IME_ERR_OK, OH_InputMethodController_Attach(textEditorProxy_, attachOptions_, &inputMethodProxy)); + + InputMethod_PrivateCommand *privateCommand[MAX_SYS_PRIVATE_COMMAND_COUNT + 1] = { nullptr }; + auto ret = + OH_InputMethodProxy_SendPrivateCommand(inputMethodProxy, privateCommand, MAX_SYS_PRIVATE_COMMAND_COUNT + 1); + EXPECT_EQ(ret, IME_ERR_PARAMCHECK); + + size_t size = 1; + ret = OH_InputMethodProxy_SendPrivateCommand(inputMethodProxy, privateCommand, size); + EXPECT_EQ(ret, IME_ERR_NULL_POINTER); + + EXPECT_EQ(IME_ERR_OK, OH_InputMethodController_Detach(inputMethodProxy)); +} + +/** + * @tc.name: SendPrivateCommandWithNullCommand_FAIL + * @tc.desc: input parameters is invalid + * @tc.type: FUNC + */ +HWTEST_F(InputMethodControllerCapiTest, SendPrivateCommandWithNullCommand_FAIL, TestSize.Level0) +{ + InputMethod_InputMethodProxy *inputMethodProxy = nullptr; + EXPECT_EQ(IME_ERR_OK, OH_InputMethodController_Attach(textEditorProxy_, attachOptions_, &inputMethodProxy)); + + auto ret = OH_InputMethodProxy_SendPrivateCommand(inputMethodProxy, nullptr, 0); + EXPECT_EQ(ret, IME_ERR_NULL_POINTER); + + EXPECT_EQ(IME_ERR_OK, OH_InputMethodController_Detach(inputMethodProxy)); +} + +/** + * @tc.name: SendPrivateCommand_SUCCESS + * @tc.desc: send private command success + * @tc.type: FUNC + */ +HWTEST_F(InputMethodControllerCapiTest, SendPrivateCommand_SUCCESS, TestSize.Level0) +{ + InputMethod_InputMethodProxy *inputMethodProxy = nullptr; + EXPECT_EQ(IME_ERR_OK, OH_InputMethodController_Attach(textEditorProxy_, attachOptions_, &inputMethodProxy)); + + char key[] = "example key"; + size_t keyLength = strlen(key); + InputMethod_PrivateCommand *privateCommand[] = { OH_PrivateCommand_Create(key, keyLength) }; + auto ret = OH_InputMethodProxy_SendPrivateCommand(inputMethodProxy, privateCommand, 1); + EXPECT_EQ(ret, IME_ERR_OK); + + OH_PrivateCommand_Destroy(privateCommand[0]); + EXPECT_EQ(IME_ERR_OK, OH_InputMethodController_Detach(inputMethodProxy)); +} + /** * @tc.name: TestAttachWithNullParam_001 * @tc.desc: input parameters is nullptr @@ -1530,15 +1856,16 @@ HWTEST_F(InputMethodControllerCapiTest, TestAttachWithNorrmalParam_001, TestSize auto options = OH_AttachOptions_Create(true); EXPECT_NE(nullptr, options); InputMethod_InputMethodProxy *inputMethodProxy = nullptr; - EXPECT_EQ(IME_ERR_IMCLIENT, OH_InputMethodController_Attach(textEditorProxy, options, &inputMethodProxy)); - EXPECT_EQ(IME_ERR_IMCLIENT, OH_InputMethodController_Attach(textEditorProxy, options, &inputMethodProxy)); + EXPECT_EQ(IME_ERR_OK, OH_InputMethodController_Attach(textEditorProxy, options, &inputMethodProxy)); + EXPECT_EQ(IME_ERR_OK, OH_InputMethodController_Attach(textEditorProxy, options, &inputMethodProxy)); auto textEditorProxy2 = OH_TextEditorProxy_Create(); EXPECT_NE(nullptr, textEditorProxy2); ConstructTextEditorProxy(textEditorProxy2); - EXPECT_EQ(IME_ERR_IMCLIENT, OH_InputMethodController_Attach(textEditorProxy2, options, &inputMethodProxy)); - OH_TextEditorProxy_Destroy(textEditorProxy2); + EXPECT_EQ(IME_ERR_OK, OH_InputMethodController_Attach(textEditorProxy2, options, &inputMethodProxy)); + OH_InputMethodController_Detach(inputMethodProxy); + OH_TextEditorProxy_Destroy(textEditorProxy2); OH_AttachOptions_Destroy(options); OH_TextEditorProxy_Destroy(textEditorProxy); } @@ -1564,7 +1891,9 @@ HWTEST_F(InputMethodControllerCapiTest, TestAttachWithPlaceholderAndAbility_001, OH_TextEditorProxy_SetGetTextConfigFunc(textEditorProxy2, fnGetTextConfigFunc); InputMethod_InputMethodProxy *inputMethodProxy = nullptr; auto ret = OH_InputMethodController_Attach(textEditorProxy2, options, &inputMethodProxy); - EXPECT_NE(ret, IME_ERR_OK); + EXPECT_EQ(ret, IME_ERR_OK); + + OH_InputMethodController_Detach(inputMethodProxy); OH_TextEditorProxy_Destroy(textEditorProxy2); OH_AttachOptions_Destroy(options); } @@ -1806,4 +2135,75 @@ HWTEST_F(InputMethodControllerCapiTest, OH_TextConfig_SetAbilityName_004, TestSi IMSA_HILOGI("outLen:%{public}zu,out:%{public}s, utf8len:%{public}zu", outLen, utf8Out.c_str(), utf8Out.size()); OH_TextConfig_Destroy(config); } -} // namespace \ No newline at end of file + +/** + * @tc.name: SetOnTerminatedFuncWithNull_FAIL + * @tc.desc: GetOnTerminatedFunc with null fail. + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(InputMethodControllerCapiTest, SetOnTerminatedFuncWithNull_FAIL, TestSize.Level0) +{ + auto proxy = OH_MessageHandlerProxy_Create(); + EXPECT_NE(proxy, nullptr); + + EXPECT_EQ(IME_ERR_NULL_POINTER, OH_MessageHandlerProxy_SetOnTerminatedFunc(nullptr, nullptr)); + EXPECT_EQ(IME_ERR_NULL_POINTER, OH_MessageHandlerProxy_SetOnTerminatedFunc(proxy, nullptr)); + + OH_MessageHandlerProxy_Destroy(proxy); + OH_MessageHandlerProxy_Destroy(nullptr); +} + +/** + * @tc.name: GetOnTerminatedFuncWithNull_FAIL + * @tc.desc: GetOnTerminatedFunc with null fail. + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(InputMethodControllerCapiTest, GetOnTerminatedFuncWithNull_FAIL, TestSize.Level0) +{ + auto proxy = OH_MessageHandlerProxy_Create(); + EXPECT_NE(proxy, nullptr); + + EXPECT_EQ(IME_ERR_NULL_POINTER, OH_MessageHandlerProxy_GetOnTerminatedFunc(nullptr, nullptr)); + EXPECT_EQ(IME_ERR_NULL_POINTER, OH_MessageHandlerProxy_GetOnTerminatedFunc(proxy, nullptr)); + + OH_MessageHandlerProxy_Destroy(proxy); +} + +/** + * @tc.name: SetOnMessageFuncWithNull_FAIL + * @tc.desc: GetOnTerminatedFunc with null fail. + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(InputMethodControllerCapiTest, SetOnMessageFuncWithNull_FAIL, TestSize.Level0) +{ + auto proxy = OH_MessageHandlerProxy_Create(); + EXPECT_NE(proxy, nullptr); + + EXPECT_EQ(IME_ERR_NULL_POINTER, OH_MessageHandlerProxy_SetOnMessageFunc(nullptr, nullptr)); + EXPECT_EQ(IME_ERR_NULL_POINTER, OH_MessageHandlerProxy_SetOnMessageFunc(proxy, nullptr)); + + OH_MessageHandlerProxy_Destroy(proxy); + OH_MessageHandlerProxy_Destroy(nullptr); +} + +/** + * @tc.name: GetOnMessageFuncWithNull_FAIL + * @tc.desc: GetOnTerminatedFunc with null fail. + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(InputMethodControllerCapiTest, GetOnMessageFuncWithNull_FAIL, TestSize.Level0) +{ + auto proxy = OH_MessageHandlerProxy_Create(); + EXPECT_NE(proxy, nullptr); + + EXPECT_EQ(IME_ERR_NULL_POINTER, OH_MessageHandlerProxy_GetOnMessageFunc(nullptr, nullptr)); + EXPECT_EQ(IME_ERR_NULL_POINTER, OH_MessageHandlerProxy_GetOnMessageFunc(proxy, nullptr)); + + OH_MessageHandlerProxy_Destroy(proxy); +} +} // namespace MiscServices +} // namespace OHOS \ No newline at end of file diff --git a/test/unittest/cpp_test/src/json_operate_test.cpp b/test/unittest/cpp_test/src/json_operate_test.cpp index 19c3e5634609041563e3972aabf360e0614e9e43..259e031c85957c98f38bda7afac80b40920585b7 100644 --- a/test/unittest/cpp_test/src/json_operate_test.cpp +++ b/test/unittest/cpp_test/src/json_operate_test.cpp @@ -23,6 +23,8 @@ #include #include +#include "parameters.h" + using namespace testing; using namespace testing::ext; namespace OHOS { @@ -77,7 +79,26 @@ public: static void SetUpTestCase() { } static void TearDownTestCase() { } void SetUp() { } - void TearDown() { } + void TearDown() + { + ClearTestParameters(); + } + // Helper function: Set system parameter + void SetSystemParameter(const std::string &key, const std::string &value) + { + system::SetParameter(key, value); + testParameters_.push_back(key); + } + + // Helper function: Clear test parameters + void ClearTestParameters() + { + for (const auto ¶m : testParameters_) { + system::SetParameter(param, ""); + } + testParameters_.clear(); + } + std::vector testParameters_; // Tracks parameter keys set during testing }; /** @@ -386,31 +407,291 @@ HWTEST_F(JsonOperateTest, testGetResMgr, TestSize.Level1) } /** - * @tc.name: testIsDynamicStartIme - * @tc.desc: test IsDynamicStartIme + * @tc.name: IsDynamicStartIme_EmptyDynamicList_ReturnFalse + * @tc.desc: Verify IsDynamicStartIme() returns false when dynamic start list is empty + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(JsonOperateTest, IsDynamicStartIme_EmptyDynamicList_ReturnFalse, TestSize.Level0) +{ + // Preparation: Set empty dynamic start configuration list + auto instance = ImeInfoInquirer::GetInstance(); + instance.dynamicStartImeList_ = {}; + + // Execution + bool result = instance.IsDynamicStartIme(); + + // Verification + EXPECT_FALSE(result); +} + +/** + * @tc.name: IsDynamicStartIme_NoMatchingParameter_ReturnFalse + * @tc.desc: Verify IsDynamicStartIme() returns false when no matching system parameter exists + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(JsonOperateTest, IsDynamicStartIme_NoMatchingParameter_ReturnFalse, TestSize.Level0) +{ + // Preparation: Configuration list contains one rule + auto instance = ImeInfoInquirer::GetInstance(); + instance.InitDynamicStartImeCfg(); + std::vector testList = { + { "ime.dynamic.start", "true" } + }; + instance.dynamicStartImeList_ = testList; + + // Set non-matching system parameter + SetSystemParameter("ime.dynamic.start", "false"); + + // Execution + bool result = instance.IsDynamicStartIme(); + + // Verification + EXPECT_FALSE(result); +} + +/** + * @tc.name: IsDynamicStartIme_OneMatchingParameter_ReturnTrue + * @tc.desc: Verify IsDynamicStartIme() returns true when there's one matching parameter + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(JsonOperateTest, IsDynamicStartIme_OneMatchingParameter_ReturnTrue, TestSize.Level0) +{ + // Preparation: Configuration list contains one matching rule + auto instance = ImeInfoInquirer::GetInstance(); + instance.dynamicStartImeList_ = { + { "ime.enable.dynamic", "1" } + }; + + // Set matching system parameter + SetSystemParameter("ime.enable.dynamic", "1"); + + // Execution + bool result = instance.IsDynamicStartIme(); + + // Verification + EXPECT_TRUE(result); +} + +/** + * @tc.name: IsDynamicStartIme_MultiRulesOneMatching_ReturnTrue + * @tc.desc: Verify IsDynamicStartIme() returns true when one of multiple rules matches * @tc.type: FUNC * @tc.require: */ -HWTEST_F(JsonOperateTest, testIsDynamicStartIme, TestSize.Level1) +HWTEST_F(JsonOperateTest, IsDynamicStartIme_MultiRulesOneMatching_ReturnTrue, TestSize.Level0) { - IMSA_HILOGI("JsonOperateTest testIsDynamicStartIme START"); + // Preparation: Configuration list contains multiple rules auto instance = ImeInfoInquirer::GetInstance(); - // dynamicStartImeSysParam is empty - auto ret = instance.IsDynamicStartIme(); - EXPECT_FALSE(false); + instance.dynamicStartImeList_ = { + { "ime.condition1", "ok" }, // No match + { "ime.condition2", "yes" } // Match + }; + + // Set system parameters + SetSystemParameter("ime.condition1", "no"); + SetSystemParameter("ime.condition2", "yes"); + + // Execution + bool result = instance.IsDynamicStartIme(); + + // Verification + EXPECT_TRUE(result); +} + +/** + * @tc.name: IsDynamicStartIme_EmptyValueMatch_ReturnTrue + * @tc.desc: Verify IsDynamicStartIme() returns true when empty values match + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(JsonOperateTest, IsDynamicStartIme_EmptyValueMatch_ReturnTrue, TestSize.Level0) +{ + // Preparation: Configuration rule contains empty value + auto instance = ImeInfoInquirer::GetInstance(); + instance.dynamicStartImeList_ = { + { "ime.empty.value", "" } + }; + + // Set empty string system parameter (matching) + SetSystemParameter("ime.empty.value", ""); + + // Execution + bool result = instance.IsDynamicStartIme(); + + // Verification + EXPECT_TRUE(result); +} + +/** + * @tc.name: DynamicStartImeUnmarshal_NormalCase_MultiEntries + * @tc.desc: DynamicStartImeUnmarshal_NormalCase_MultiEntries + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(JsonOperateTest, DynamicStartImeUnmarshal_NormalCase_MultiEntries, TestSize.Level0) +{ + const std::string jsonStr = R"( + { + "dynamicStartImeCfgList": [ + { "sysParam": "param1", "value": "value1" }, + { "sysParam": "param2", "value": "value2" } + ] + } + )"; + cJSON *node = cJSON_Parse(jsonStr.c_str()); + ASSERT_NE(node, nullptr) << "JSON parse failed."; + + DynamicStartImeCfg cfg; + bool ret = cfg.Unmarshal(node); + + EXPECT_TRUE(ret); + EXPECT_EQ(cfg.dynamicStartImeCfgList.size(), 2); + EXPECT_EQ(cfg.dynamicStartImeCfgList[0].sysParam, "param1"); + EXPECT_EQ(cfg.dynamicStartImeCfgList[0].value, "value1"); + EXPECT_EQ(cfg.dynamicStartImeCfgList[1].sysParam, "param2"); + EXPECT_EQ(cfg.dynamicStartImeCfgList[1].value, "value2"); + cJSON_Delete(node); +} + +/** + * @tc.name: DynamicStartImeUnmarshal_NormalCase_EmptyList + * @tc.desc: DynamicStartImeUnmarshal_NormalCase_EmptyList + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(JsonOperateTest, DynamicStartImeUnmarshal_NormalCase_EmptyList, TestSize.Level0) +{ + const std::string jsonStr = R"( + { + "dynamicStartImeCfgList": [] + } + )"; + cJSON *node = cJSON_Parse(jsonStr.c_str()); + ASSERT_NE(node, nullptr) << "JSON parse failed."; + + DynamicStartImeCfg cfg; + bool ret = cfg.Unmarshal(node); - // dynamicStartImeValue is empty - instance.systemConfig_.dynamicStartImeSysParam = "123"; - ret = instance.IsDynamicStartIme(); EXPECT_TRUE(ret); + EXPECT_TRUE(cfg.dynamicStartImeCfgList.empty()); + + cJSON_Delete(node); +} + +/** + * @tc.name: DynamicStartImeUnmarshal_AbnormalCase_MissingField + * @tc.desc: DynamicStartImeUnmarshal_AbnormalCase_MissingField + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(JsonOperateTest, DynamicStartImeUnmarshal_AbnormalCase_MissingField, TestSize.Level0) +{ + const std::string jsonStr = R"( + { + "otherField": "test" + } + )"; + cJSON *node = cJSON_Parse(jsonStr.c_str()); + ASSERT_NE(node, nullptr) << "JSON parse failed."; + + DynamicStartImeCfg cfg; + bool ret = cfg.Unmarshal(node); - // dynamicStartImeValue is default - instance.systemConfig_.dynamicStartImeValue = "default"; - ret = instance.IsDynamicStartIme(); EXPECT_FALSE(ret); + EXPECT_TRUE(cfg.dynamicStartImeCfgList.empty()); + + cJSON_Delete(node); +} + +/** + * @tc.name: DynamicStartImeUnmarshal_AbnormalCase_InvalidType + * @tc.desc: DynamicStartImeUnmarshal_AbnormalCase_InvalidType + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(JsonOperateTest, DynamicStartImeUnmarshal_AbnormalCase_InvalidType, TestSize.Level0) +{ + const std::string jsonStr = R"( + { + "dynamicStartImeCfgList": "not an array" + } + )"; + cJSON *node = cJSON_Parse(jsonStr.c_str()); + ASSERT_NE(node, nullptr) << "JSON parse failed."; + + DynamicStartImeCfg cfg; + bool ret = cfg.Unmarshal(node); + + EXPECT_FALSE(ret); + EXPECT_TRUE(cfg.dynamicStartImeCfgList.empty()); + + cJSON_Delete(node); +} + +/** + * @tc.name: DynamicStartImeUnmarshal_AbnormalCase_InvalidEntry + * @tc.desc: DynamicStartImeUnmarshal_AbnormalCase_InvalidEntry + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(JsonOperateTest, DynamicStartImeUnmarshal_AbnormalCase_InvalidEntry, TestSize.Level0) +{ + const std::string jsonStr = R"( + { + "dynamicStartImeCfgList": [ + { "sysParam": "param1", "value": "value1" }, + { "sysParam": "param2" } + ] + } + )"; + cJSON *node = cJSON_Parse(jsonStr.c_str()); + ASSERT_NE(node, nullptr) << "JSON parse failed."; + + DynamicStartImeCfg cfg; + bool ret = cfg.Unmarshal(node); + + EXPECT_FALSE(ret); + EXPECT_EQ(cfg.dynamicStartImeCfgList.size(), 2); + EXPECT_EQ(cfg.dynamicStartImeCfgList[0].sysParam, "param1"); + EXPECT_EQ(cfg.dynamicStartImeCfgList[0].value, "value1"); + EXPECT_EQ(cfg.dynamicStartImeCfgList[1].sysParam, "param2"); + EXPECT_EQ(cfg.dynamicStartImeCfgList[1].value, ""); + cJSON_Delete(node); +} + +/** + * @tc.name: DynamicStartImeUnmarshal_BoundaryCase_EmptyValues + * @tc.desc: DynamicStartImeUnmarshal_BoundaryCase_EmptyValues + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(JsonOperateTest, DynamicStartImeUnmarshal_BoundaryCase_EmptyValues, TestSize.Level0) +{ + const std::string jsonStr = R"( + { + "dynamicStartImeCfgList": [ + { "sysParam": "", "value": "" }, + { "sysParam": "", "value": "value2" } + ] + } + )"; + cJSON *node = cJSON_Parse(jsonStr.c_str()); + ASSERT_NE(node, nullptr) << "JSON parse failed."; + + DynamicStartImeCfg cfg; + bool ret = cfg.Unmarshal(node); + + EXPECT_TRUE(ret); + EXPECT_EQ(cfg.dynamicStartImeCfgList.size(), 2); + EXPECT_EQ(cfg.dynamicStartImeCfgList[0].sysParam, ""); + EXPECT_EQ(cfg.dynamicStartImeCfgList[0].value, ""); + EXPECT_EQ(cfg.dynamicStartImeCfgList[1].sysParam, ""); + EXPECT_EQ(cfg.dynamicStartImeCfgList[1].value, "value2"); - instance.systemConfig_.dynamicStartImeValue = ""; - instance.systemConfig_.dynamicStartImeSysParam = ""; + cJSON_Delete(node); } /** diff --git a/test/unittest/cpp_test/src/numkey_apps_manager_test.cpp b/test/unittest/cpp_test/src/numkey_apps_manager_test.cpp index cb2c3d28129bfab54499bc1769a5f9896c2d77ee..f8bef42b2a793c9f84fea3b33f0c21c446a11fbb 100644 --- a/test/unittest/cpp_test/src/numkey_apps_manager_test.cpp +++ b/test/unittest/cpp_test/src/numkey_apps_manager_test.cpp @@ -356,6 +356,7 @@ HWTEST_F(NumKeyAppsManagerTest, testRegisterUserBlockListData_002, TestSize.Leve NumkeyAppsManager::GetInstance().observers_[MAIN_USER_ID] = observer; auto ret = NumkeyAppsManager::GetInstance().RegisterUserBlockListData(MAIN_USER_ID); EXPECT_EQ(ret, ErrorCode::NO_ERROR); + NumkeyAppsManager::GetInstance().Release(); NumkeyAppsManager::GetInstance().observers_.clear(); }