1 /*
2 * Copyright (c) 2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "gtest/gtest.h"
17 #define private public
18 #define protected public
19 #include "test/mock/core/common/mock_container.h"
20 #include "test/mock/core/common/mock_theme_manager.h"
21 #include "test/mock/core/pipeline/mock_pipeline_context.h"
22
23 #include "base/memory/referenced.h"
24 #include "core/components/common/properties/color.h"
25 #include "core/components/theme/app_theme.h"
26 #include "core/components_ng/base/frame_node.h"
27 #include "core/components_ng/event/event_hub.h"
28 #include "core/components_ng/event/focus_event_handler.h"
29 #include "core/components_ng/event/focus_hub.h"
30 #include "core/components_ng/pattern/button/button_pattern.h"
31 #include "core/components_ng/pattern/linear_layout/linear_layout_pattern.h"
32 #include "core/components_ng/pattern/stage/page_pattern.h"
33 namespace OHOS::Ace::NG {
34 namespace {
35 const int32_t VERSION_TWELVE = 12;
36 const int32_t VERSION_EIGHTEEN = 18;
37 } // namespace
38
39 class FocusEventHandlerTestNg : public testing::Test {
40 public:
41 static void SetUpTestSuite();
42 static void TearDownTestSuite();
43 void SetUp() override;
44 void TearDown() override;
45 };
46 } // namespace OHOS::Ace::NG
47
48 using namespace testing;
49 using namespace testing::ext;
50
51 namespace OHOS::Ace::NG {
SetUpTestSuite()52 void FocusEventHandlerTestNg::SetUpTestSuite()
53 {
54 MockPipelineContext::SetUp();
55 MockContainer::SetUp(MockPipelineContext::GetCurrent());
56 }
57
TearDownTestSuite()58 void FocusEventHandlerTestNg::TearDownTestSuite()
59 {
60 MockPipelineContext::TearDown();
61 MockContainer::TearDown();
62 }
63
SetUp()64 void FocusEventHandlerTestNg::SetUp() {}
65
TearDown()66 void FocusEventHandlerTestNg::TearDown()
67 {
68 auto context = MockPipelineContext::GetCurrent();
69 ASSERT_NE(context, nullptr);
70 ASSERT_NE(context->rootNode_, nullptr);
71 context->rootNode_->children_.clear();
72 }
73
74 struct KeyEventClickTestCase {
75 bool focusActive;
76 bool needFocusHandleClick;
77 FocusIntension intension;
78 bool isTabStop;
79 bool expect;
80 };
81
82 const vector<KeyEventClickTestCase> HandleKeyEventClickOnVersion12TestCase {
83 { false, false, FocusIntension::SELECT, false, false },
84 { true, false, FocusIntension::SELECT, false, false },
85 { false, true, FocusIntension::SELECT, false, true },
86 { true, true, FocusIntension::SELECT, false, true },
87 { false, false, FocusIntension::SPACE, false, false },
88 { true, false, FocusIntension::SPACE, false, false },
89 { false, true, FocusIntension::SPACE, false, true },
90 { true, true, FocusIntension::SPACE, false, true },
91 { false, false, FocusIntension::SELECT, true, false },
92 { true, false, FocusIntension::SELECT, true, false },
93 { false, true, FocusIntension::SELECT, true, false },
94 { true, true, FocusIntension::SELECT, true, false },
95 { false, false, FocusIntension::SPACE, true, false },
96 { true, false, FocusIntension::SPACE, true, false },
97 { false, true, FocusIntension::SPACE, true, true },
98 { true, true, FocusIntension::SPACE, true, true },
99 };
100
101 const vector<KeyEventClickTestCase> HandleKeyEventClickOnVersion18TestCase {
102 { false, false, FocusIntension::SELECT, false, false },
103 { true, false, FocusIntension::SELECT, false, false },
104 { false, true, FocusIntension::SELECT, false, false },
105 { true, true, FocusIntension::SELECT, false, true },
106 { false, false, FocusIntension::SPACE, false, false },
107 { true, false, FocusIntension::SPACE, false, false },
108 { false, true, FocusIntension::SPACE, false, false },
109 { true, true, FocusIntension::SPACE, false, true },
110 { false, false, FocusIntension::SELECT, true, false },
111 { true, false, FocusIntension::SELECT, true, false },
112 { false, true, FocusIntension::SELECT, true, false },
113 { true, true, FocusIntension::SELECT, true, false },
114 { false, false, FocusIntension::SPACE, true, false },
115 { true, false, FocusIntension::SPACE, true, false },
116 { false, true, FocusIntension::SPACE, true, false },
117 { true, true, FocusIntension::SPACE, true, true },
118 };
119
CreateTestTreeWithDefaultFocus()120 RefPtr<FrameNode> CreateTestTreeWithDefaultFocus()
121 {
122 auto context = MockPipelineContext::GetCurrent();
123 auto focusManager = context->GetOrCreateFocusManager();
124 auto pagePattern = AceType::MakeRefPtr<PagePattern>(AceType::MakeRefPtr<PageInfo>());
125 auto pageNode = FrameNode::CreateFrameNode(V2::PAGE_ETS_TAG, 1, pagePattern);
126 pageNode->onMainTree_ = true;
127 auto pageFocusHub = pageNode->GetOrCreateFocusHub();
128 context->rootNode_->AddChild(pageNode);
129 auto columnPattern = AceType::MakeRefPtr<LinearLayoutPattern>(true);
130 auto columnNode = FrameNode::CreateFrameNode(V2::COLUMN_ETS_TAG, 2, columnPattern);
131 columnNode->onMainTree_ = true;
132 auto columnFocusHub = columnNode->GetOrCreateFocusHub();
133 auto buttonPattern = AceType::MakeRefPtr<ButtonPattern>();
134 auto buttonNode = FrameNode::CreateFrameNode(V2::BUTTON_ETS_TAG, 3, buttonPattern);
135 buttonNode->onMainTree_ = true;
136 auto buttonFocusHub = buttonNode->GetOrCreateFocusHub();
137 pageNode->AddChild(columnNode);
138 columnNode->AddChild(buttonNode);
139 pagePattern->FocusViewShow();
140 context->FlushFocusView();
141 pagePattern->TriggerFocusMove();
142 EXPECT_EQ(buttonFocusHub->IsCurrentFocus(), true);
143 return buttonNode;
144 }
145
ClearRootChild()146 void ClearRootChild()
147 {
148 auto context = MockPipelineContext::GetCurrent();
149 ASSERT_NE(context, nullptr);
150 ASSERT_NE(context->rootNode_, nullptr);
151 context->rootNode_->children_.clear();
152 }
153
154 /**
155 * @tc.name: GetFocusIntension001
156 * @tc.desc: Create SetStyle.
157 * @tc.type: FUNC
158 */
159 HWTEST_F(FocusEventHandlerTestNg, GetFocusIntensionTest001, TestSize.Level1)
160 {
161 KeyEvent event;
162 event.action = KeyAction::DOWN;
163 event.isPreIme = false;
164 event.code = KeyCode::KEY_NUMPAD_ENTER;
165 event.pressedCodes = { KeyCode::KEY_NUMPAD_ENTER };
166 auto expectIntension = FocusEvent::GetFocusIntension(event);
167 EXPECT_EQ(expectIntension, FocusIntension::SELECT);
168 event.code = KeyCode::KEY_SPACE;
169 event.pressedCodes = { KeyCode::KEY_SPACE };
170 expectIntension = FocusEvent::GetFocusIntension(event);
171 EXPECT_EQ(expectIntension, FocusIntension::SPACE);
172 }
173
174 /**
175 * @tc.name: GetFocusIntensionFromKey001
176 * @tc.desc: Create SetStyle.
177 * @tc.type: FUNC
178 */
179 HWTEST_F(FocusEventHandlerTestNg, GetFocusIntensionFromKeyTest001, TestSize.Level1)
180 {
181 KeyIntention keyIntention;
182 keyIntention = KeyIntention::INTENTION_SELECT;
183 auto expectIntension = FocusEvent::GetFocusIntensionFromKey(keyIntention);
184 EXPECT_EQ(expectIntension, FocusIntension::SELECT);
185 keyIntention = KeyIntention::INTENTION_ESCAPE;
186 expectIntension = FocusEvent::GetFocusIntensionFromKey(keyIntention);
187 EXPECT_EQ(expectIntension, FocusIntension::ESC);
188 keyIntention = KeyIntention::INTENTION_HOME;
189 expectIntension = FocusEvent::GetFocusIntensionFromKey(keyIntention);
190 EXPECT_EQ(expectIntension, FocusIntension::HOME);
191 keyIntention = KeyIntention::INTENTION_UNKNOWN;
192 expectIntension = FocusEvent::GetFocusIntensionFromKey(keyIntention);
193 EXPECT_EQ(expectIntension, FocusIntension::NONE);
194 }
195
196 /**
197 * @tc.name: HandleKeyEventRedispatchTest001
198 * @tc.desc: Create SetStyle.
199 * @tc.type: FUNC
200 */
201 HWTEST_F(FocusEventHandlerTestNg, HandleKeyEventRedispatchTest001, TestSize.Level1)
202 {
203 /**
204 * @tc.steps: step1. Test HandleKeyEvent Redispatch false
205 * expected: return false
206 */
207 auto context = MockPipelineContext::GetCurrent();
208 ASSERT_NE(context, nullptr);
209 auto buttonNode = CreateTestTreeWithDefaultFocus();
210 EXPECT_NE(buttonNode, nullptr);
211 auto buttonFocusHub = buttonNode->GetOrCreateFocusHub();
212 EXPECT_NE(buttonFocusHub, nullptr);
213 KeyEvent event;
214 event.isRedispatch = true;
215 FocusIntension intension = FocusIntension::NONE;
216 auto result = buttonFocusHub->HandleKeyEvent(event, intension);
217 EXPECT_EQ(result, false);
218 }
219
220 /**
221 * @tc.name: HandleKeyEventMetaKeyTest001
222 * @tc.desc: Create SetStyle.
223 * @tc.type: FUNC
224 */
225 HWTEST_F(FocusEventHandlerTestNg, HandleKeyEventMetaKeyTest001, TestSize.Level1)
226 {
227 /**
228 * @tc.steps: step1. Test HandleKeyEventMetaKey with KeyCode::KEY_0
229 * expected: PreIme consume and metaKey is 0;
230 */
231 auto context = MockPipelineContext::GetCurrent();
232 auto focusManager = context->GetOrCreateFocusManager();
233 ASSERT_NE(context, nullptr);
234 KeyEvent event;
235 event.isRedispatch = false;
236 event.isPreIme = true;
237 event.code = KeyCode::KEY_0;
238 event.pressedCodes = { KeyCode::KEY_0 };
239 FocusIntension intension = FocusIntension::NONE;
240 auto metaKey = 0;
__anon546ba6f20202(KeyEventInfo& event) 241 auto onKeyEventCallback = [&metaKey](KeyEventInfo& event) {
242 if (event.GetMetaKey() == 1) {
243 metaKey = 1;
244 }
245 event.SetStopPropagation(true);
246 return true;
247 };
248 auto buttonNode = CreateTestTreeWithDefaultFocus();
249 EXPECT_NE(buttonNode, nullptr);
250 auto buttonFocusHub = buttonNode->GetOrCreateFocusHub();
251 EXPECT_NE(buttonFocusHub, nullptr);
252 buttonFocusHub->SetOnKeyPreIme(std::move(onKeyEventCallback));
253 auto result = buttonFocusHub->HandleKeyEvent(event, intension);
254 EXPECT_EQ(result, true);
255 EXPECT_EQ(metaKey, 0);
256
257 /**
258 * @tc.steps: step2. Test HandleKeyEventMetaKey with KeyCode::KEY_META_LEFT
259 * expected: PreIme consume and metaKey is 1;
260 */
261 event.code = KeyCode::KEY_META_LEFT;
262 event.pressedCodes = { KeyCode::KEY_META_LEFT };
263 auto result2 = buttonFocusHub->HandleKeyEvent(event, intension);
264 EXPECT_EQ(result2, true);
265 EXPECT_EQ(metaKey, 1);
266
267 /**
268 * @tc.steps: step3. Test HandleKeyEventMetaKey with KeyCode::KEY_META_RIGHT
269 * expected: PreIme consume and metaKey is 1;
270 */
271 metaKey = 0;
272 event.code = KeyCode::KEY_META_RIGHT;
273 event.pressedCodes = { KeyCode::KEY_META_RIGHT };
274 auto result3 = buttonFocusHub->HandleKeyEvent(event, intension);
275 EXPECT_EQ(result3, true);
276 EXPECT_EQ(metaKey, 1);
277 }
278
279 /**
280 * @tc.name: HandleKeyEventOnClickTest001
281 * @tc.desc: Create SetStyle.
282 * @tc.type: FUNC
283 */
284 HWTEST_F(FocusEventHandlerTestNg, HandleKeyEventOnClickTest001, TestSize.Level1)
285 {
286 /**
287 * @tc.steps: step1. Set APITargetVersion 12
288 * expected: ret is equal to expect;
289 */
290 KeyEvent event;
291 event.isRedispatch = false;
292 event.isPreIme = false;
293 for (auto& testcase : HandleKeyEventClickOnVersion12TestCase) {
294 auto context = MockPipelineContext::GetCurrent();
295 ASSERT_NE(context, nullptr);
296 auto buttonNode = CreateTestTreeWithDefaultFocus();
297 EXPECT_NE(buttonNode, nullptr);
298 auto buttonFocusHub = buttonNode->GetOrCreateFocusHub();
299 EXPECT_NE(buttonFocusHub, nullptr);
300 MockContainer::Current()->SetApiTargetVersion(VERSION_TWELVE);
301 FocusIntension intension = testcase.intension;
302 buttonFocusHub->ClearOnClickCallback();
303 if (testcase.needFocusHandleClick) {
__anon546ba6f20302(GestureEvent& info) 304 auto onClickEventCallback = [](GestureEvent& info) { return true; };
305 buttonFocusHub->SetOnClickCallback(std::move(onClickEventCallback));
306 }
307 auto focusManager = context->GetOrCreateFocusManager();
308 focusManager->isFocusActive_ = testcase.focusActive;
309 auto themeManager = AceType::MakeRefPtr<MockThemeManager>();
310 context->SetThemeManager(themeManager);
311 EXPECT_CALL(*themeManager, GetTheme(_)).WillRepeatedly(Return(AceType::MakeRefPtr<AppTheme>()));
312 auto appTheme = context->GetTheme<AppTheme>();
313 appTheme->focusActiveByTab_ = testcase.needFocusHandleClick;
314 buttonFocusHub->tabStop_ = testcase.isTabStop;
315 auto result = buttonFocusHub->HandleKeyEvent(event, intension);
316 EXPECT_EQ(result, testcase.expect);
317 }
318 }
319
320 /**
321 * @tc.name: HandleKeyEventOnClickTest002
322 * @tc.desc: Create SetStyle.
323 * @tc.type: FUNC
324 */
325 HWTEST_F(FocusEventHandlerTestNg, HandleKeyEventOnClickTest002, TestSize.Level1)
326 {
327 /**
328 * @tc.steps: step1. Set APITargetVersion 18
329 * expected: ret is equal to expect;
330 */
331 KeyEvent event;
332 event.isRedispatch = false;
333 event.isPreIme = false;
334 for (auto& testcase : HandleKeyEventClickOnVersion18TestCase) {
335 auto context = MockPipelineContext::GetCurrent();
336 ASSERT_NE(context, nullptr);
337 auto buttonNode = CreateTestTreeWithDefaultFocus();
338 EXPECT_NE(buttonNode, nullptr);
339 auto buttonFocusHub = buttonNode->GetOrCreateFocusHub();
340 EXPECT_NE(buttonFocusHub, nullptr);
341 MockContainer::Current()->SetApiTargetVersion(VERSION_EIGHTEEN);
342 FocusIntension intension = testcase.intension;
343 buttonFocusHub->ClearOnClickCallback();
344 if (testcase.needFocusHandleClick) {
__anon546ba6f20402(GestureEvent& info) 345 auto onClickEventCallback = [](GestureEvent& info) { return true; };
346 buttonFocusHub->SetOnClickCallback(std::move(onClickEventCallback));
347 }
348 auto focusManager = context->GetOrCreateFocusManager();
349 focusManager->isFocusActive_ = testcase.focusActive;
350 auto themeManager = AceType::MakeRefPtr<MockThemeManager>();
351 context->SetThemeManager(themeManager);
352 EXPECT_CALL(*themeManager, GetTheme(_)).WillRepeatedly(Return(AceType::MakeRefPtr<AppTheme>()));
353 auto appTheme = context->GetTheme<AppTheme>();
354 appTheme->focusActiveByTab_ = testcase.needFocusHandleClick;
355 buttonFocusHub->tabStop_ = testcase.isTabStop;
356 auto result = buttonFocusHub->HandleKeyEvent(event, intension);
357 EXPECT_EQ(result, testcase.expect);
358 }
359 }
360
361 /**
362 * @tc.name: HandleCrownEventTest001
363 * @tc.desc: Create SetStyle.
364 * @tc.type: FUNC
365 */
366 HWTEST_F(FocusEventHandlerTestNg, HandleCrownEventTest001, TestSize.Level1)
367 {
368 /**
369 * @tc.steps: step1. Set CrownEventInternal
370 * expected: ret is equal to expect;
371 */
372 CrownEvent event;
373 FocusEvent focusEvent(static_cast<const NonPointerEvent&>(event));
374 auto consume = false;
__anon546ba6f20502(const CrownEvent&) 375 auto onCrownEventCallbackInternal = [&consume](const CrownEvent&) {
376 consume = true;
377 return true;
378 };
379 auto buttonNode = CreateTestTreeWithDefaultFocus();
380 EXPECT_NE(buttonNode, nullptr);
381 auto buttonFocusHub = buttonNode->GetOrCreateFocusHub();
382 EXPECT_NE(buttonFocusHub, nullptr);
383 buttonFocusHub->SetOnCrownEventInternal(std::move(onCrownEventCallbackInternal));
384 auto result = buttonFocusHub->OnFocusEventNode(focusEvent);
385 EXPECT_EQ(consume, result);
386
387 /**
388 * @tc.steps: step2. Set CrownEventUser
389 * expected: ret is equal to expect;
390 */
391 consume = false;
392 auto consume2 = false;
__anon546ba6f20602(CrownEventInfo& crownInfo) 393 auto onCrownEventCallbackUser = [&consume2](CrownEventInfo& crownInfo) {
394 crownInfo.SetStopPropagation(true);
395 consume2 = true;
396 return true;
397 };
398 buttonFocusHub->SetOnCrownCallback(std::move(onCrownEventCallbackUser));
399 result = buttonFocusHub->OnFocusEventNode(focusEvent);
400 EXPECT_EQ(consume, false);
401 EXPECT_EQ(consume2, result);
402 }
403
404 /**
405 * @tc.name: OnKeyPreIme001
406 * @tc.desc: Test the function OnKeyPreIme.
407 * @tc.type: FUNC
408 */
409 HWTEST_F(FocusEventHandlerTestNg, OnKeyPreIme001, TestSize.Level1)
410 {
411 /**
412 * @tc.steps1: create frameNode.
413 */
414 auto frameNode = FrameNode::CreateFrameNode(V2::DYNAMIC_COMPONENT_ETS_TAG, -1, AceType::MakeRefPtr<Pattern>());
415
416 /**
417 * @tc.steps2: create eventHub and focusHub.
418 */
419 RefPtr<EventHub> eventHub = AceType::MakeRefPtr<EventHub>();
420 eventHub->AttachHost(frameNode);
421 auto focusHub = AceType::MakeRefPtr<FocusHub>(AceType::WeakClaim(AceType::RawPtr(eventHub)));
422 KeyEvent keyEvent;
423 keyEvent.action = KeyAction::UP;
424 keyEvent.code = KeyCode::KEY_SPACE;
425
426 /**
427 * @tc.steps3: call the function OnKeyEvent with FocusType::NODE.
428 * @tc.expected: The return value of OnKeyEvent is true.
429 */
430 focusHub->SetFocusType(FocusType::NODE);
431 focusHub->currentFocus_ = true;
432 focusHub->SetIsNodeNeedKey(true);
433
434 bool isExecute = false;
__anon546ba6f20702(const KeyEvent& event) 435 auto onKeyEvent = [&isExecute](const KeyEvent& event) mutable -> bool {
436 isExecute = true;
437 return true;
438 };
439 focusHub->SetOnKeyEventInternal(std::move(onKeyEvent));
440 KeyEventInfo info(keyEvent);
441 focusHub->OnKeyPreIme(info, keyEvent);
442 EXPECT_TRUE(isExecute);
443 }
444
445
446 /**
447 * @tc.name: HandleCrownEventTest001
448 * @tc.desc: test OnClick function.
449 * @tc.type: FUNC
450 */
451 HWTEST_F(FocusEventHandlerTestNg, FocusEventHubOnClickTest001, TestSize.Level1)
452 {
453 /**
454 * @tc.steps: step1. Set onClickCallback
455 * expected: ret is equal to expect;
456 */
457 KeyEvent event;
458 auto consume = false;
__anon546ba6f20802(const GestureEvent&) 459 auto onClickCallback = [&consume](const GestureEvent&) {
460 consume = true;
461 };
462 auto buttonNode = CreateTestTreeWithDefaultFocus();
463 EXPECT_NE(buttonNode, nullptr);
464 auto buttonFocusHub = buttonNode->GetOrCreateFocusHub();
465 EXPECT_NE(buttonFocusHub, nullptr);
466 buttonFocusHub->SetOnClickCallback(std::move(onClickCallback));
467 buttonFocusHub->OnClick(event);
468 EXPECT_EQ(consume, true);
469 }
470 } // namespace OHOS::Ace::NG
471