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 <optional>
17
18 #include "gtest/gtest.h"
19
20 #define private public
21 #define protected public
22
23 #include "core/components_ng/manager/avoid_info/avoid_info_manager.h"
24 #include "test/mock/core/pipeline/mock_pipeline_context.h"
25 #include "test/mock/core/common/mock_container.h"
26 #include "test/mock/core/common/mock_theme_manager.h"
27 #include "test/mock/core/render/mock_render_context.h"
28
29 using namespace testing;
30 using namespace testing::ext;
31
32 namespace OHOS::Ace::NG {
operator ==(const ContainerModalAvoidInfo & a,const ContainerModalAvoidInfo & b)33 bool operator==(const ContainerModalAvoidInfo& a, const ContainerModalAvoidInfo& b)
34 {
35 return a.needAvoid == b.needAvoid &&
36 a.titleHeight == b.titleHeight &&
37 a.controlBottonsRect == b.controlBottonsRect;
38 }
39
operator !=(const ContainerModalAvoidInfo & a,const ContainerModalAvoidInfo & b)40 bool operator!=(const ContainerModalAvoidInfo& a, const ContainerModalAvoidInfo& b)
41 {
42 return !(a == b);
43 }
44
45 namespace {
46 class MockAvoidInfoListener : public IAvoidInfoListener {
47 DECLARE_ACE_TYPE(MockAvoidInfoListener, IAvoidInfoListener);
48 public:
49 MockAvoidInfoListener() = default;
50 ~MockAvoidInfoListener() = default;
51
52 MOCK_METHOD1(OnAvoidInfoChange, void(const ContainerModalAvoidInfo& info));
53 };
54
GetAvoidInfoManager()55 RefPtr<AvoidInfoManager> GetAvoidInfoManager()
56 {
57 auto pipeline = MockPipelineContext::GetCurrent();
58 return pipeline != nullptr ? pipeline->GetAvoidInfoManager() : nullptr;
59 }
60 } // namespace
61
62 class AvoidInfoManagerTestNg : public testing::Test {
63 public:
64 static void SetUpTestSuite();
65 static void TearDownTestSuite();
66 void SetUp();
TearDown()67 void TearDown() {}
68 };
69
SetUpTestSuite()70 void AvoidInfoManagerTestNg::SetUpTestSuite()
71 {
72 MockPipelineContext::SetUp();
73 MockContainer::SetUp();
74 }
75
TearDownTestSuite()76 void AvoidInfoManagerTestNg::TearDownTestSuite()
77 {
78 MockPipelineContext::TearDown();
79 MockContainer::TearDown();
80 }
81
SetUp()82 void AvoidInfoManagerTestNg::SetUp()
83 {
84 auto pipeline = MockPipelineContext::GetCurrent();
85 ASSERT_NE(pipeline, nullptr);
86 auto mgr = AceType::MakeRefPtr<AvoidInfoManager>();
87 ASSERT_NE(mgr, nullptr);
88 mgr->SetPipelineContext(WeakPtr(pipeline));
89 mgr->SetInstanceId(pipeline->GetInstanceId());
90 pipeline->avoidInfoMgr_ = mgr;
91 }
92
93 /**
94 * @tc.name: OnAvoidInfoChange001
95 * @tc.desc: Test basic logic of OnAvoidInfoChange
96 * @tc.type: FUNC
97 * @tc.author:
98 */
99 HWTEST_F(AvoidInfoManagerTestNg, OnAvoidInfoChange001, TestSize.Level1)
100 {
101 /**
102 * @tc.steps: step1. Get AvoidInfoManager.
103 */
104 auto manager = GetAvoidInfoManager();
105 ASSERT_NE(manager, nullptr);
106 ASSERT_TRUE(manager->listeners_.empty());
107
108 /**
109 * @tc.steps: step2. Create one listener, set expected input param and callTimes.
110 */
111 ContainerModalAvoidInfo info;
112 info.needAvoid = true;
113 info.titleHeight = 32;
114 auto listener = AceType::MakeRefPtr<MockAvoidInfoListener>();
115 ASSERT_NE(listener, nullptr);
116 EXPECT_CALL(*listener, OnAvoidInfoChange(info)).Times(1);
117
118 /**
119 * @tc.steps: step3. Add listener to AvoidInfoManager, and invoke OnAvoidInfoChange with specified Param.
120 * @tc.expected: Manager's input param equals to Listener input param.
121 */
122 manager->listeners_.emplace(listener);
123 ASSERT_EQ(manager->listeners_.size(), 1);
124 manager->OnAvoidInfoChange(info);
125 }
126
127 /**
128 * @tc.name: AddAvoidInfoListener001
129 * @tc.desc: Test basic logic of AddAvoidInfoListener&RemoveAvoidInfoListener
130 * @tc.type: FUNC
131 * @tc.author:
132 */
133 HWTEST_F(AvoidInfoManagerTestNg, AddAvoidInfoListener001, TestSize.Level1)
134 {
135 /**
136 * @tc.steps: step1. Get AvoidInfoManager.
137 */
138 auto manager = GetAvoidInfoManager();
139 ASSERT_NE(manager, nullptr);
140 ASSERT_TRUE(manager->listeners_.empty());
141
142 /**
143 * @tc.steps: step2. Create three listeners.
144 */
145 auto listener1 = AceType::MakeRefPtr<MockAvoidInfoListener>();
146 ASSERT_NE(listener1, nullptr);
147 auto listener2 = AceType::MakeRefPtr<MockAvoidInfoListener>();
148 ASSERT_NE(listener2, nullptr);
149 auto listener3 = AceType::MakeRefPtr<MockAvoidInfoListener>();
150 ASSERT_NE(listener3, nullptr);
151
152 /**
153 * @tc.steps: step2. Add listeners and check result.
154 */
155 manager->AddAvoidInfoListener(listener1);
156 ASSERT_EQ(manager->listeners_.size(), 1);
157 // add same listener again.
158 manager->AddAvoidInfoListener(listener1);
159 ASSERT_EQ(manager->listeners_.size(), 1);
160 manager->AddAvoidInfoListener(listener2);
161 manager->AddAvoidInfoListener(listener3);
162 ASSERT_EQ(manager->listeners_.size(), 3);
163
164 /**
165 * @tc.steps: step2. Remove listeners and check result.
166 */
167 manager->RemoveAvoidInfoListener(listener1);
168 manager->RemoveAvoidInfoListener(listener2);
169 ASSERT_EQ(manager->listeners_.size(), 1);
170 auto it = manager->listeners_.find(listener3);
171 ASSERT_TRUE(it != manager->listeners_.end());
172 }
173
174 /**
175 * @tc.name: GetContainerModalTitleHeight001
176 * @tc.desc: Test basic logic of GetContainerModalTitleHeight
177 * @tc.type: FUNC
178 * @tc.author:
179 */
180 HWTEST_F(AvoidInfoManagerTestNg, GetContainerModalTitleHeight001, TestSize.Level1)
181 {
182 /**
183 * @tc.steps: step1. Get AvoidInfoManager, Set AvoidInfo for normal scenario and UEC scenario.
184 */
185 auto container = MockContainer::Current();
186 ASSERT_NE(container, nullptr);
187 auto manager = GetAvoidInfoManager();
188 ASSERT_NE(manager, nullptr);
189 ContainerModalAvoidInfo info;
190 info.titleHeight = 32;
191 ContainerModalAvoidInfo uecInfo;
192 uecInfo.titleHeight = 64;
193 manager->SetAvoidInfo(info);
194 manager->SetAvoidInfoForUEC(uecInfo);
195
196 /**
197 * @tc.steps: step2. Set current Container is UEC Container.
198 * @tc.desc: Branch: if (container->IsUIExtensionWindow()) { => true
199 */
200 container->SetIsUIExtensionWindow(true);
201 int32_t height = manager->GetContainerModalTitleHeight();
202 ASSERT_EQ(height, 64);
203
204 /**
205 * @tc.steps: step2. Set current Container is regular Container.
206 * @tc.desc: Branch: if (container->IsUIExtensionWindow()) { => false
207 */
208 container->SetIsUIExtensionWindow(false);
209 height = manager->GetContainerModalTitleHeight();
210 ASSERT_EQ(height, 32);
211 }
212
213 /**
214 * @tc.name: GetContainerModalButtonsRect001
215 * @tc.desc: Test basic logic of GetContainerModalButtonsRect
216 * @tc.type: FUNC
217 * @tc.author:
218 */
219 HWTEST_F(AvoidInfoManagerTestNg, GetContainerModalButtonsRect001, TestSize.Level1)
220 {
221 /**
222 * @tc.steps: step1. Get AvoidInfoManager, Set AvoidInfo for normal scenario and UEC scenario.
223 */
224 auto container = MockContainer::Current();
225 ASSERT_NE(container, nullptr);
226 auto manager = GetAvoidInfoManager();
227 ASSERT_NE(manager, nullptr);
228 ContainerModalAvoidInfo info;
229 info.controlBottonsRect = RectF(0.0f, 0.0f, 300.0f, 400.f);
230 ContainerModalAvoidInfo uecInfo;
231 uecInfo.controlBottonsRect = RectF(50.0f, 60.0f, 300.0f, 400.f);
232 manager->SetAvoidInfo(info);
233 manager->SetAvoidInfoForUEC(uecInfo);
234
235 /**
236 * @tc.steps: step2. Set current Container is UEC Container.
237 * @tc.desc: Branch: if (container->IsUIExtensionWindow()) { => true
238 */
239 container->SetIsUIExtensionWindow(true);
240 RectF containerRect;
241 RectF buttonsRect;
242 ASSERT_TRUE(manager->GetContainerModalButtonsRect(containerRect, buttonsRect));
243 ASSERT_EQ(buttonsRect, uecInfo.controlBottonsRect);
244
245 /**
246 * @tc.steps: step2. Set current Container is regular Container.
247 * @tc.desc: Branch: if (container->IsUIExtensionWindow()) { => false
248 */
249 container->SetIsUIExtensionWindow(false);
250 ASSERT_TRUE(manager->GetContainerModalButtonsRect(containerRect, buttonsRect));
251 ASSERT_EQ(buttonsRect, info.controlBottonsRect);
252 }
253
254 /**
255 * @tc.name: NeedAvoidContainerModal001
256 * @tc.desc: Test basic logic of NeedAvoidContainerModal
257 * @tc.type: FUNC
258 * @tc.author:
259 */
260 HWTEST_F(AvoidInfoManagerTestNg, NeedAvoidContainerModal001, TestSize.Level1)
261 {
262 /**
263 * @tc.steps: step1. Get AvoidInfoManager, Set AvoidInfo for normal scenario and UEC scenario.
264 */
265 auto container = MockContainer::Current();
266 ASSERT_NE(container, nullptr);
267 auto manager = GetAvoidInfoManager();
268 ASSERT_NE(manager, nullptr);
269 ContainerModalAvoidInfo info;
270 info.needAvoid = true;
271 ContainerModalAvoidInfo uecInfo;
272 uecInfo.needAvoid = false;
273 manager->SetAvoidInfo(info);
274 manager->SetAvoidInfoForUEC(uecInfo);
275
276 /**
277 * @tc.steps: step2. Set current Container is UEC Container.
278 * @tc.desc: Branch: if (container->IsUIExtensionWindow()) { => true
279 */
280 container->SetIsUIExtensionWindow(true);
281 ASSERT_FALSE(manager->NeedAvoidContainerModal());
282
283 /**
284 * @tc.steps: step2. Set current Container is regular Container.
285 * @tc.desc: Branch: if (container->IsUIExtensionWindow()) { => false
286 */
287 container->SetIsUIExtensionWindow(false);
288 ASSERT_TRUE(manager->NeedAvoidContainerModal());
289 }
290
291 /**
292 * @tc.name: RegisterListenerIfNeeded001
293 * @tc.desc: Test basic logic of RegisterListenerIfNeeded
294 * @tc.type: FUNC
295 * @tc.author:
296 */
297 HWTEST_F(AvoidInfoManagerTestNg, RegisterListenerIfNeeded001, TestSize.Level1)
298 {
299 /**
300 * @tc.steps: step1. Get AvoidInfoManager.
301 */
302 auto container = MockContainer::Current();
303 ASSERT_NE(container, nullptr);
304 auto manager = GetAvoidInfoManager();
305 ASSERT_NE(manager, nullptr);
306 manager->hasRegisterListener_ = false;
307
308 /**
309 * @tc.steps: step2. Set current Container is regular Container.
310 * @tc.desc: Branch: if (!container->IsUIExtensionWindow()) { => true
311 */
312 container->SetIsUIExtensionWindow(false);
313 manager->RegisterListenerIfNeeded();
314 ASSERT_TRUE(manager->hasRegisterListener_);
315
316 /**
317 * @tc.steps: step2. Keep the callbacks of AvoidInfoManager in an unset state,
318 * Set current Container is UEC Container.
319 * @tc.desc: Branch: if (!registerUECConsumerCallback_ || !requestAvoidInfoCallback_) { => true
320 */
321 manager->hasRegisterListener_ = false;
322 container->SetIsUIExtensionWindow(true);
323 manager->RegisterListenerIfNeeded();
324 ASSERT_FALSE(manager->hasRegisterListener_);
325
326 /**
327 * @tc.steps: step2. Set callbacks to AvoidInfoManager, set current Container is UEC Container.
328 * @tc.desc: Branch: if (!registerUECConsumerCallback_ || !requestAvoidInfoCallback_) { => false
329 */
330 bool callRegisterFunc = false;
__anon14ccbd050202(UECAvoidInfoConsumer&& consumer) 331 auto registerCallback = [&callRegisterFunc](UECAvoidInfoConsumer&& consumer) {
332 callRegisterFunc = true;
333 };
334 bool callRequestFunc = false;
__anon14ccbd050302() 335 auto requestCallback = [&callRequestFunc]() {
336 callRequestFunc = true;
337 };
338 manager->SetRegisterUECAvoidInfoConsumerCallback(std::move(registerCallback));;
339 manager->SetRequestAvoidInfoCallback(std::move(requestCallback));
340 manager->RegisterListenerIfNeeded();
341 ASSERT_TRUE(manager->hasRegisterListener_);
342 ASSERT_TRUE(callRegisterFunc);
343 ASSERT_TRUE(callRequestFunc);
344 }
345
346 /**
347 * @tc.name: UnregisterListenerIfNeeded001
348 * @tc.desc: Test basic logic of UnregisterListenerIfNeeded
349 * @tc.type: FUNC
350 * @tc.author:
351 */
352 HWTEST_F(AvoidInfoManagerTestNg, UnregisterListenerIfNeeded001, TestSize.Level1)
353 {
354 /**
355 * @tc.steps: step1. Get AvoidInfoManager.
356 */
357 auto container = MockContainer::Current();
358 ASSERT_NE(container, nullptr);
359 auto manager = GetAvoidInfoManager();
360 ASSERT_NE(manager, nullptr);
361 manager->hasRegisterListener_ = true;
362
363 /**
364 * @tc.steps: step2. Set current Container is UEC Container.
365 * @tc.desc: Branch: if (container->IsUIExtensionWindow()) { => true
366 */
367 container->SetIsUIExtensionWindow(true);
368 manager->UnregisterListenerIfNeeded();
369 ASSERT_FALSE(manager->hasRegisterListener_);
370
371 /**
372 * @tc.steps: step2. Set current Container is regular Container.
373 * @tc.desc: Branch: if (container->IsUIExtensionWindow()) { => false
374 */
375 manager->hasRegisterListener_ = true;
376 container->SetIsUIExtensionWindow(false);
377 manager->UnregisterListenerIfNeeded();
378 ASSERT_FALSE(manager->hasRegisterListener_);
379 }
380
381 /**
382 * @tc.name: GetContainerModalAvoidInfoForUEC001
383 * @tc.desc: Branch: if (context->GetContainerCustomTitleVisible() ||
384 * !context->GetContainerControlButtonVisible()) { => false
385 * if (!context->GetContainerModalButtonsRect(containerModal, buttonsRect)) { => false
386 * if (height <= 0) { => false
387 * if (!uecRect.IsIntersectWith(buttonsRect)) { => true
388 * @tc.type: FUNC
389 * @tc.author:
390 */
391 HWTEST_F(AvoidInfoManagerTestNg, GetContainerModalAvoidInfoForUEC001, TestSize.Level1)
392 {
393 auto container = MockContainer::Current();
394 ASSERT_NE(container, nullptr);
395 auto pipeline = MockPipelineContext::GetCurrent();
396 ASSERT_NE(pipeline, nullptr);
397 auto manager = GetAvoidInfoManager();
398 ASSERT_NE(manager, nullptr);
399
400 bool preTitleVisible = pipeline->GetContainerCustomTitleVisible();
401 bool preBtnVisible = pipeline->GetContainerControlButtonVisible();
402 int32_t preHeight = pipeline->GetContainerModalTitleHeight();
403
404 pipeline->SetContainerCustomTitleVisible(false);
405 pipeline->SetContainerControlButtonVisible(true);
406 pipeline->SetContainerModalButtonsRect(true);
407 RectF btnRct{200.0f, 0.0f, 200.0f, 100.0f};
408 pipeline->SetContainerModalButtonsRect(btnRct);
409 pipeline->SetContainerModalTitleHeight(80);
410
411 auto uecNode = FrameNode::CreateFrameNode(V2::UI_EXTENSION_COMPONENT_ETS_TAG,
412 ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<Pattern>());
413 ASSERT_NE(uecNode, nullptr);
414 auto geometryNode = uecNode->GetGeometryNode();
415 ASSERT_NE(geometryNode, nullptr);
416 geometryNode->SetFrameOffset(OffsetF(100.0f, 0.0f));
417 geometryNode->SetFrameSize(SizeF(200.0f, 200.0f));
418
419 auto renderContext = AceType::MakeRefPtr<MockRenderContext>();
420 ASSERT_NE(geometryNode, nullptr);
421 renderContext->UpdatePaintRect(RectF(100.0f, 120.0f, 200.0f, 200.0f));
422 uecNode->renderContext_ = renderContext;
423
424 ContainerModalAvoidInfo info;
425 info.needAvoid = true;
426 manager->GetContainerModalAvoidInfoForUEC(uecNode, info);
427 EXPECT_FALSE(info.needAvoid);
428
429 pipeline->SetContainerCustomTitleVisible(preTitleVisible);
430 pipeline->SetContainerControlButtonVisible(preBtnVisible);
431 pipeline->SetContainerModalTitleHeight(preHeight);
432 }
433 } // namespace OHOS::Ace::NG
434