* 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 <gtest/gtest.h>
#include "core/components_ng/pattern/text_field/text_field_pattern.h"
#include "test/unittest/capi/utils/custom_node_builder_test_helper.h"
#include "core/interfaces/native/implementation/paste_event_peer.h"
#include "core/interfaces/native/implementation/submit_event_peer.h"
#include "core/interfaces/native/utility/ace_engine_types.h"
#include "core/interfaces/native/utility/converter.h"
#include "core/interfaces/native/utility/reverse_converter.h"
#include "modifier_test_base.h"
#include "modifiers_test_utils.h"
using namespace testing;
using namespace testing::ext;
namespace OHOS::Ace::NG {
using namespace Converter;
namespace GeneratedModifier {
const GENERATED_ArkUITextInputControllerAccessor* GetTextInputControllerAccessor();
const GENERATED_ArkUISubmitEventAccessor* GetSubmitEventAccessor();
}
namespace Converter {
template<> PreviewText Convert(const Ark_PreviewText& src);
}
namespace {
Ark_EnterKeyType g_EventTestKey {};
const std::string TEST_CONTENT_ONE = "ContentTestOne";
const std::string TEST_CONTENT_TWO = "ContentTestTwo";
const std::string COLOR_TRANSPARENT = "#00000000";
const std::string COLOR_HALF_ALPHA_RED = "#7FFF0000";
const std::string COLOR_LOW_ALPHA_BLUE = "#330000FF";
const std::string COLOR_BLACK = "#FF000000";
const std::string COLOR_RED = "#FFFF0000";
const std::string COLOR_BLUE = "#FF0000FF";
const std::string COLOR_GREEN = "#FF008000";
const auto ATTRIBUTE_AUTOCAPITALIZATION_MODE_NAME = "autocapitalizationMode";
const auto ATTRIBUTE_AUTOCAPITALIZATION_MODE_DEFAULT_VALUE = "AutoCapitalizationMode.NONE";
std::vector<std::tuple<std::string, Opt_AutoCapitalizationMode, std::string>>
testFixtureEnumAutoCapitalizationModeTestPlan = {
{ "AutoCapitalizationMode.NONE", Converter::ArkValue<Opt_AutoCapitalizationMode>(AutoCapitalizationMode::NONE),
"AutoCapitalizationMode.NONE" },
{ "AutoCapitalizationMode.WORDS",
Converter::ArkValue<Opt_AutoCapitalizationMode>(AutoCapitalizationMode::WORDS),
"AutoCapitalizationMode.WORDS" },
{ "AutoCapitalizationMode.SENTENCES",
Converter::ArkValue<Opt_AutoCapitalizationMode>(AutoCapitalizationMode::SENTENCES),
"AutoCapitalizationMode.SENTENCES" },
{ "AutoCapitalizationMode.ALL_CHARACTERS",
Converter::ArkValue<Opt_AutoCapitalizationMode>(AutoCapitalizationMode::ALL_CHARACTERS),
"AutoCapitalizationMode.ALL_CHARACTERS" },
{ "AutoCapitalizationMode.INVALID",
Converter::ArkValue<Opt_AutoCapitalizationMode>(Converter::INVALID_ENUM_VAL<Ark_AutoCapitalizationMode>),
ATTRIBUTE_AUTOCAPITALIZATION_MODE_DEFAULT_VALUE },
};
}
class TextInputModifierTest2 : public ModifierTestBase<GENERATED_ArkUITextInputModifier,
&GENERATED_ArkUINodeModifiers::getTextInputModifier, GENERATED_ARKUI_TEXT_INPUT> {
public:
static void SetUpTestCase()
{
ModifierTestBase::SetUpTestCase();
SetupTheme<TextFieldTheme>();
}
std::vector<MenuItemParam> GetMenuItemParams()
{
std::vector<MenuItemParam> params;
MenuOptionsParam menuOptionItemOne;
menuOptionItemOne.content = TEST_CONTENT_ONE;
menuOptionItemOne.action = [](const std::string&) {};
MenuOptionsParam menuOptionItemTwo;
menuOptionItemTwo.content = TEST_CONTENT_TWO;
menuOptionItemTwo.action = [](const std::string&) {};
MenuItemParam param1;
param1.menuOptionsParam = menuOptionItemOne;
MenuItemParam param2;
param2.menuOptionsParam = menuOptionItemTwo;
params.push_back(param1);
params.push_back(param2);
return params;
}
};
* @tc.name: setAutoCapitalizationModeTest
* @tc.desc:
* @tc.type: FUNC
*/
HWTEST_F(TextInputModifierTest2, setAutoCapitalizationModeTest, TestSize.Level1)
{
ASSERT_TRUE(modifier_->setAutoCapitalizationMode);
auto jsonValue = GetJsonValue(node_);
auto resultStr = GetAttrValue<std::string>(jsonValue, ATTRIBUTE_AUTOCAPITALIZATION_MODE_NAME);
EXPECT_THAT(resultStr, Eq(ATTRIBUTE_AUTOCAPITALIZATION_MODE_DEFAULT_VALUE))
<< "Method: setAutoCapitalizationMode, attribute: keyboardAppearance";
auto checkValue = [this](const std::string& input, const std::string& expectedStr,
const Opt_AutoCapitalizationMode& value) {
modifier_->setAutoCapitalizationMode(node_, &value);
auto jsonValue = GetJsonValue(node_);
auto resultStr = GetAttrValue<std::string>(jsonValue, ATTRIBUTE_AUTOCAPITALIZATION_MODE_NAME);
EXPECT_THAT(resultStr, Eq(expectedStr)) << "Input value is: " << input
<< ", method: setAutoCapitalizationMode, attribute: keyboardAppearance";
};
for (auto& [input, value, expected] : testFixtureEnumAutoCapitalizationModeTestPlan) {
checkValue(input, expected, value);
}
}
* @tc.name: setOnChangeTest
* @tc.desc: Check the functionality of setOnChange.
* @tc.type: FUNC
*/
HWTEST_F(TextInputModifierTest2, setOnChangeTest, TestSize.Level1)
{
ASSERT_NE(modifier_->setOnChange, nullptr);
auto frameNode = reinterpret_cast<FrameNode*>(node_);
ASSERT_NE(frameNode, nullptr);
auto textFieldEventHub = frameNode->GetEventHub<TextFieldEventHub>();
ASSERT_NE(textFieldEventHub, nullptr);
std::u16string expectedText = u"test_text";
PreviewText expectedPreviewText = { .offset = 1234, .value = u"test_preview_text" };
static std::u16string resultText = u"";
static std::u16string resultPreviewText = u"";
static int32_t resultOffset = 0;
auto arkCallback = [](Ark_VMContext context, Ark_Int32 nodeId, const Ark_String value,
const Opt_PreviewText previewText, Opt_TextChangeOptions options) {
auto convPreviewText = Converter::OptConvert<PreviewText>(previewText).value_or(PreviewText{});
resultOffset = convPreviewText.offset;
resultPreviewText.append(convPreviewText.value);
resultText.append(Converter::OptConvert<std::u16string>(value).value_or(u""));
};
auto onChange = Converter::ArkCallback<Opt_EditableTextOnChangeCallback>(arkCallback);
modifier_->setOnChange(node_, &onChange);
textFieldEventHub->FireOnChange({expectedText, expectedPreviewText});
EXPECT_EQ(resultText, expectedText);
EXPECT_EQ(resultPreviewText, expectedPreviewText.value);
EXPECT_EQ(resultOffset, expectedPreviewText.offset);
}
* @tc.name: setOnPasteTest
* @tc.desc: Check the functionality of setOnPaste.
* @tc.type: FUNC
*/
HWTEST_F(TextInputModifierTest2, setOnPasteTest, TestSize.Level1)
{
ASSERT_NE(modifier_->setOnPaste, nullptr);
auto frameNode = reinterpret_cast<FrameNode*>(node_);
ASSERT_NE(frameNode, nullptr);
auto textFieldEventHub = frameNode->GetEventHub<TextFieldEventHub>();
ASSERT_NE(textFieldEventHub, nullptr);
std::u16string expectedText = u"test_text";
static std::u16string resultText = u"";
auto arkCallback = [](Ark_VMContext context, const Ark_Int32 resourceId, const Ark_String content,
const Ark_PasteEvent event) {
resultText = Converter::OptConvert<std::u16string>(content).value_or(u"");
if (event) {
event->HandlePreventDefault();
}
};
auto onPaste = Converter::ArkCallback<Opt_OnPasteCallback>(arkCallback);
modifier_->setOnPaste(node_, &onPaste);
TextCommonEvent event;
EXPECT_FALSE(event.IsPreventDefault());
textFieldEventHub->FireOnPasteWithEvent(expectedText, event);
EXPECT_EQ(resultText, expectedText);
EXPECT_TRUE(event.IsPreventDefault());
}
* @tc.name: setCustomKeyboardTestCustomNodeBuilder
* @tc.desc:
* @tc.type: FUNC
*/
HWTEST_F(TextInputModifierTest2, setCustomKeyboardTestCustomNodeBuilder, TestSize.Level1)
{
ASSERT_NE(modifier_->setCustomKeyboard, nullptr);
auto frameNode = reinterpret_cast<FrameNode*>(node_);
ASSERT_NE(frameNode, nullptr);
int callsCount = 0;
CustomNodeBuilderTestHelper<TextInputModifierTest2> builderHelper(this, frameNode);
const auto customNodeBuilder = Converter::ArkUnion<Opt_Union_CustomBuilder_ComponentContentBase,
CustomNodeBuilder>(Converter::ArkValue<Opt_CustomNodeBuilder>(builderHelper.GetBuilder()).value);
modifier_->setCustomKeyboard(node_, &customNodeBuilder, nullptr);
auto textFieldPattern = frameNode->GetPattern<TextFieldPattern>();
EXPECT_TRUE(textFieldPattern->HasCustomKeyboard());
EXPECT_TRUE(textFieldPattern->RequestCustomKeyboard());
EXPECT_EQ(builderHelper.GetCallsCountAsync(), ++callsCount);
}
* @tc.name: setCustomKeyboardTestCustomNodeBuilderKeyboardOptions
* @tc.desc:
* @tc.type: FUNC
*/
HWTEST_F(TextInputModifierTest2, setCustomKeyboardTestCustomNodeBuilderKeyboardOptions, TestSize.Level1)
{
ASSERT_NE(modifier_->setCustomKeyboard, nullptr);
auto frameNode = reinterpret_cast<FrameNode*>(node_);
ASSERT_NE(frameNode, nullptr);
KeyboardOptions keyboardOptions = {.supportAvoidance = true};
auto optKeyboardOptions = Converter::ArkValue<Opt_KeyboardOptions>(keyboardOptions);
int callsCount = 0;
CustomNodeBuilderTestHelper<TextInputModifierTest2> builderHelper(this, frameNode);
const auto customNodeBuilder = Converter::ArkUnion<Opt_Union_CustomBuilder_ComponentContentBase,
CustomNodeBuilder>(Converter::ArkValue<Opt_CustomNodeBuilder>(builderHelper.GetBuilder()).value);
modifier_->setCustomKeyboard(node_, &customNodeBuilder, &optKeyboardOptions);
auto textFieldPattern = frameNode->GetPattern<TextFieldPattern>();
EXPECT_TRUE(textFieldPattern->HasCustomKeyboard());
EXPECT_TRUE(textFieldPattern->RequestCustomKeyboard());
EXPECT_EQ(builderHelper.GetCallsCountAsync(), ++callsCount);
}
* @tc.name: setOnSubmitTestOnSubmit
* @tc.desc: setOnSubmit test
* @tc.type: FUNC
*/
HWTEST_F(TextInputModifierTest2, setOnSubmitTestOnSubmit, TestSize.Level1)
{
static const int expectedResId = 123;
static const std::u16string testValue = u"string text";
auto frameNode = reinterpret_cast<FrameNode*>(node_);
auto eventHub = frameNode->GetEventHub<NG::TextFieldEventHub>();
ASSERT_NE(eventHub, nullptr);
auto onSubmitFunc = [](
Ark_VMContext, Ark_Int32 resourceId, Ark_EnterKeyType enterKeyType, const Ark_SubmitEvent event
) {
auto peer = event;
ASSERT_NE(peer, nullptr);
auto submitEventInfo = peer->GetEventInfo();
ASSERT_NE(submitEventInfo, nullptr);
EXPECT_EQ(submitEventInfo->GetText(), testValue);
GeneratedModifier::GetSubmitEventAccessor()->destroyPeer(peer);
EXPECT_EQ(resourceId, expectedResId);
g_EventTestKey = enterKeyType;
};
auto func = Converter::ArkCallback<Opt_OnSubmitCallback>(onSubmitFunc, expectedResId);
modifier_->setOnSubmit(node_, &func);
TextFieldCommonEvent event;
event.SetText(testValue);
eventHub->FireOnSubmit(111, event);
EXPECT_EQ(g_EventTestKey, -1);
eventHub->FireOnSubmit(ARK_ENTER_KEY_TYPE_NEXT, event);
EXPECT_EQ(g_EventTestKey, 5);
eventHub->FireOnSubmit(ARK_ENTER_KEY_TYPE_GO, event);
EXPECT_EQ(g_EventTestKey, 2);
eventHub->FireOnSubmit(ARK_ENTER_KEY_TYPE_SEARCH, event);
EXPECT_EQ(g_EventTestKey, 3);
eventHub->FireOnSubmit(ARK_ENTER_KEY_TYPE_SEND, event);
EXPECT_EQ(g_EventTestKey, 4);
eventHub->FireOnSubmit(ARK_ENTER_KEY_TYPE_NEXT, event);
EXPECT_EQ(g_EventTestKey, 5);
eventHub->FireOnSubmit(ARK_ENTER_KEY_TYPE_DONE, event);
EXPECT_EQ(g_EventTestKey, 6);
eventHub->FireOnSubmit(ARK_ENTER_KEY_TYPE_PREVIOUS, event);
EXPECT_EQ(g_EventTestKey, 7);
eventHub->FireOnSubmit(ARK_ENTER_KEY_TYPE_NEW_LINE, event);
EXPECT_EQ(g_EventTestKey, 8);
}
#ifdef WRONG_GEN
* @tc.name: setEditMenuOptionsTest
* @tc.desc: setEditMenuOptions test
* @tc.type: FUNC
*/
HWTEST_F(TextInputModifierTest2, DISABLED_setEditMenuOptionsTest, TestSize.Level1)
{
#ifdef WRONG_PRIVATE
ASSERT_NE(modifier_->setEditMenuOptions, nullptr);
auto frameNode = reinterpret_cast<FrameNode*>(node_);
auto pattern = frameNode->GetPattern<TextFieldPattern>();
ASSERT_NE(pattern, nullptr);
int32_t testID = 323;
struct CheckEvent {
int32_t resourceId;
};
static std::optional<CheckEvent> checkEvent = std::nullopt;
auto testOnCreateMenuCallback = [](Ark_VMContext context, const Ark_Int32 resourceId,
const Array_TextMenuItem menuItems, const Callback_Array_TextMenuItem_Void continuation) {
checkEvent = CheckEvent{
.resourceId = Converter::Convert<int32_t>(resourceId),
};
CallbackHelper(continuation).Invoke(menuItems);
};
auto arkCreateCallback = Converter::ArkCallback<Opt_OnCreateMenuCallback>(testOnCreateMenuCallback);
auto testOnMenuItemClickCallback = [](Ark_VMContext context, const Ark_Int32 resourceId,
const Ark_TextMenuItem menuItem, const Ark_TextRange range, const Callback_Boolean_Void continuation) {
auto item = Converter::OptConvert<MenuOptionsParam>(menuItem);
ASSERT_TRUE(item.has_value());
ASSERT_TRUE(item->content.has_value());
CallbackHelper(continuation).Invoke(Converter::ArkValue<Ark_Boolean>(*item->content == TEST_CONTENT_ONE));
};
auto arkClickCallback = Converter::ArkCallback<Opt_OnMenuItemClickCallback>(testOnMenuItemClickCallback);
Ark_EditMenuOptions options {
.onCreateMenu = arkCreateCallback,
.onMenuItemClick = arkClickCallback
};
auto optOptions = Converter::ArkValue<Opt_EditMenuOptions>(options);
SelectOverlayInfo selectOverlayInfo;
auto params = GetMenuItemParams();
FriendClassAccessor::OnUpdateOnCreateMenuCallback(selectOverlayInfo, pattern);
EXPECT_TRUE(selectOverlayInfo.onCreateCallback.onCreateMenuCallback == nullptr);
modifier_->setEditMenuOptions(node_, &optOptions);
FriendClassAccessor::OnUpdateOnCreateMenuCallback(selectOverlayInfo, pattern);
ASSERT_NE(selectOverlayInfo.onCreateCallback.onCreateMenuCallback, nullptr);
selectOverlayInfo.onCreateCallback.onCreateMenuCallback(params);
ASSERT_TRUE(checkEvent.has_value());
EXPECT_EQ(checkEvent->resourceId, testID);
ASSERT_NE(selectOverlayInfo.onCreateCallback.onMenuItemClick, nullptr);
EXPECT_TRUE(selectOverlayInfo.onCreateCallback.onMenuItemClick(params[0]));
EXPECT_FALSE(selectOverlayInfo.onCreateCallback.onMenuItemClick(params[1]));
#endif
}
#endif
* @tc.name: setFontColorTestNullNode
* @tc.desc: Check the functionality of GENERATED_ArkUITextInputModifier.setFontColor with null node
* @tc.type: FUNC
*/
HWTEST_F(TextInputModifierTest2, setFontColorTestNullNode, TestSize.Level1)
{
static const std::string propName("fontColor");
ASSERT_NE(modifier_->setFontColor, nullptr);
auto checkVal = GetAttrValue<std::string>(node_, propName);
EXPECT_THAT(checkVal, Eq(COLOR_BLACK));
auto redColor = Converter::ArkValue<Opt_ResourceColor>(
Converter::ArkUnion<Ark_ResourceColor, Ark_Color>(ARK_COLOR_RED));
modifier_->setFontColor(node_, &redColor);
checkVal = GetAttrValue<std::string>(node_, propName);
EXPECT_THAT(checkVal, Eq(COLOR_RED));
modifier_->setFontColor(nullptr, &redColor);
checkVal = GetAttrValue<std::string>(node_, propName);
EXPECT_THAT(checkVal, Eq(COLOR_RED));
}
* @tc.name: setFontColorTestTransparent
* @tc.desc: Check the functionality of GENERATED_ArkUITextInputModifier.setFontColor with transparent colors
* @tc.type: FUNC
*/
HWTEST_F(TextInputModifierTest2, setFontColorTestTransparent, TestSize.Level1)
{
static const std::string propName("fontColor");
ASSERT_NE(modifier_->setFontColor, nullptr);
auto transparentColor = Converter::ArkValue<Opt_ResourceColor>(
Converter::ArkUnion<Ark_ResourceColor, Ark_String>("#00000000"));
modifier_->setFontColor(node_, &transparentColor);
auto result = GetAttrValue<std::string>(node_, propName);
EXPECT_THAT(result, Eq(COLOR_TRANSPARENT));
auto halfAlphaRed = Converter::ArkValue<Opt_ResourceColor>(
Converter::ArkUnion<Ark_ResourceColor, Ark_String>("#7FFF0000"));
modifier_->setFontColor(node_, &halfAlphaRed);
result = GetAttrValue<std::string>(node_, propName);
EXPECT_THAT(result, Eq(COLOR_HALF_ALPHA_RED));
auto lowAlphaBlue = Converter::ArkValue<Opt_ResourceColor>(
Converter::ArkUnion<Ark_ResourceColor, Ark_String>("#330000FF"));
modifier_->setFontColor(node_, &lowAlphaBlue);
result = GetAttrValue<std::string>(node_, propName);
EXPECT_THAT(result, Eq(COLOR_LOW_ALPHA_BLUE));
}
* @tc.name: setFontColorTestEmptyOptional
* @tc.desc: Check the functionality of GENERATED_ArkUITextInputModifier.setFontColor with empty optional
* @tc.type: FUNC
*/
HWTEST_F(TextInputModifierTest2, setFontColorTestEmptyOptional, TestSize.Level1)
{
static const std::string propName("fontColor");
ASSERT_NE(modifier_->setFontColor, nullptr);
auto redColor = Converter::ArkValue<Opt_ResourceColor>(
Converter::ArkUnion<Ark_ResourceColor, Ark_Color>(ARK_COLOR_RED));
modifier_->setFontColor(node_, &redColor);
auto result = GetAttrValue<std::string>(node_, propName);
EXPECT_THAT(result, Eq(COLOR_RED));
auto emptyOptional = Converter::ArkValue<Opt_ResourceColor>();
modifier_->setFontColor(node_, &emptyOptional);
result = GetAttrValue<std::string>(node_, propName);
EXPECT_THAT(result, Eq(COLOR_BLACK));
}
* @tc.name: setFontColorTestInvalidUnion
* @tc.desc: Check the functionality of GENERATED_ArkUITextInputModifier.setFontColor with invalid union
* @tc.type: FUNC
*/
HWTEST_F(TextInputModifierTest2, setFontColorTestInvalidUnion, TestSize.Level1)
{
static const std::string propName("fontColor");
ASSERT_NE(modifier_->setFontColor, nullptr);
auto redColor = Converter::ArkValue<Opt_ResourceColor>(
Converter::ArkUnion<Ark_ResourceColor, Ark_Color>(ARK_COLOR_RED));
modifier_->setFontColor(node_, &redColor);
auto result = GetAttrValue<std::string>(node_, propName);
EXPECT_THAT(result, Eq(COLOR_RED));
auto invalidUnion = Converter::ArkValue<Opt_ResourceColor>(
Converter::ArkUnion<Ark_ResourceColor, Ark_Empty>(nullptr));
modifier_->setFontColor(node_, &invalidUnion);
result = GetAttrValue<std::string>(node_, propName);
EXPECT_THAT(result, Eq(COLOR_BLACK));
}
* @tc.name: setFontColorTestColorSequence
* @tc.desc: Check the functionality of GENERATED_ArkUITextInputModifier.setFontColor with color sequence
* @tc.type: FUNC
*/
HWTEST_F(TextInputModifierTest2, setFontColorTestColorSequence, TestSize.Level1)
{
static const std::string propName("fontColor");
ASSERT_NE(modifier_->setFontColor, nullptr);
auto redColor = Converter::ArkValue<Opt_ResourceColor>(
Converter::ArkUnion<Ark_ResourceColor, Ark_Color>(ARK_COLOR_RED));
auto blueColor = Converter::ArkValue<Opt_ResourceColor>(
Converter::ArkUnion<Ark_ResourceColor, Ark_Color>(ARK_COLOR_BLUE));
auto greenColor = Converter::ArkValue<Opt_ResourceColor>(
Converter::ArkUnion<Ark_ResourceColor, Ark_Color>(ARK_COLOR_GREEN));
modifier_->setFontColor(node_, &redColor);
auto result = GetAttrValue<std::string>(node_, propName);
EXPECT_THAT(result, Eq(COLOR_RED));
modifier_->setFontColor(node_, &blueColor);
result = GetAttrValue<std::string>(node_, propName);
EXPECT_THAT(result, Eq(COLOR_BLUE));
modifier_->setFontColor(node_, &greenColor);
result = GetAttrValue<std::string>(node_, propName);
EXPECT_THAT(result, Eq(COLOR_GREEN));
}
}