1 /*
2 * Copyright (c) 2024 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 "list_test_ng.h"
17 #include "test/mock/core/pipeline/mock_pipeline_context.h"
18 #include "test/mock/core/rosen/mock_canvas.h"
19
20 #include "core/components_ng/pattern/list/list_item_group_paint_method.h"
21 #include "core/components_ng/syntax/repeat_virtual_scroll_node.h"
22
23 namespace OHOS::Ace::NG {
24
25 namespace {} // namespace
26
27 class ListLayoutTestNg : public ListTestNg {
28 public:
29 void UpdateContentModifier();
30 RefPtr<ListPaintMethod> UpdateOverlayModifier(RefPtr<PaintWrapper> paintWrapper);
31 void UpdateDividerMap();
32 void PaintDivider(RefPtr<PaintWrapper> paintWrapper, int32_t expectLineNumber, bool isClip = false);
33 void GroupPaintDivider(RefPtr<PaintWrapper> paintWrapper, int32_t expectLineNumber);
34 };
35
UpdateContentModifier()36 void ListLayoutTestNg::UpdateContentModifier()
37 {
38 RefPtr<NodePaintMethod> paint = pattern_->CreateNodePaintMethod();
39 RefPtr<ListPaintMethod> listPaint = AceType::DynamicCast<ListPaintMethod>(paint);
40 auto paintWrapper = frameNode_->CreatePaintWrapper();
41 listPaint->UpdateContentModifier(AceType::RawPtr(paintWrapper));
42 }
43
UpdateOverlayModifier(RefPtr<PaintWrapper> paintWrapper)44 RefPtr<ListPaintMethod> ListLayoutTestNg::UpdateOverlayModifier(RefPtr<PaintWrapper> paintWrapper)
45 {
46 auto paintMethod = AceType::DynamicCast<ListPaintMethod>(paintWrapper->nodePaintImpl_);
47 paintMethod->UpdateOverlayModifier(AceType::RawPtr(paintWrapper));
48 return paintMethod;
49 }
50
UpdateDividerMap()51 void ListLayoutTestNg::UpdateDividerMap()
52 {
53 int cur = 0;
54 for (auto& child : pattern_->itemPosition_) {
55 child.second.id += cur;
56 cur++;
57 }
58 UpdateContentModifier();
59 }
60
PaintDivider(RefPtr<PaintWrapper> paintWrapper,int32_t expectLineNumber,bool isClip)61 void ListLayoutTestNg::PaintDivider(RefPtr<PaintWrapper> paintWrapper, int32_t expectLineNumber, bool isClip)
62 {
63 auto paintMethod = AceType::DynamicCast<ListPaintMethod>(paintWrapper->nodePaintImpl_);
64 auto modifier = paintMethod->GetContentModifier(nullptr);
65 auto listContentModifier = AceType::DynamicCast<ListContentModifier>(modifier);
66 Testing::MockCanvas canvas;
67 EXPECT_CALL(canvas, ClipRect(_, _, _)).Times(isClip ? 1 : 0);
68 EXPECT_CALL(canvas, AttachBrush(_)).WillRepeatedly(ReturnRef(canvas));
69 EXPECT_CALL(canvas, AttachPen(_)).WillRepeatedly(ReturnRef(canvas));
70 EXPECT_CALL(canvas, DetachBrush()).WillRepeatedly(ReturnRef(canvas));
71 EXPECT_CALL(canvas, DetachPen()).WillRepeatedly(ReturnRef(canvas));
72 EXPECT_CALL(canvas, DrawLine(_, _)).Times(expectLineNumber); // DrawLine
73 DrawingContext drawingContext = { canvas, LIST_WIDTH, LIST_HEIGHT };
74 paintMethod->UpdateContentModifier(AceType::RawPtr(paintWrapper));
75 listContentModifier->onDraw(drawingContext);
76 }
77
GroupPaintDivider(RefPtr<PaintWrapper> paintWrapper,int32_t expectLineNumber)78 void ListLayoutTestNg::GroupPaintDivider(RefPtr<PaintWrapper> paintWrapper, int32_t expectLineNumber)
79 {
80 auto paintMethod = AceType::DynamicCast<ListItemGroupPaintMethod>(paintWrapper->nodePaintImpl_);
81 Testing::MockCanvas canvas;
82 EXPECT_CALL(canvas, AttachBrush(_)).WillRepeatedly(ReturnRef(canvas));
83 EXPECT_CALL(canvas, AttachPen(_)).WillRepeatedly(ReturnRef(canvas));
84 EXPECT_CALL(canvas, DetachBrush()).WillRepeatedly(ReturnRef(canvas));
85 EXPECT_CALL(canvas, DetachPen()).WillRepeatedly(ReturnRef(canvas));
86 EXPECT_CALL(canvas, DrawLine(_, _)).Times(expectLineNumber); // DrawLine
87 paintMethod->PaintDivider(AceType::RawPtr(paintWrapper), canvas);
88 }
89
90 /**
91 * @tc.name: GetOverScrollOffset001
92 * @tc.desc: Test GetOverScrollOffset
93 * @tc.type: FUNC
94 */
95 HWTEST_F(ListLayoutTestNg, GetOverScrollOffset001, TestSize.Level1)
96 {
97 /**
98 * @tc.steps: step1. !IsScrollSnapAlignCenter
99 */
100 CreateList();
101 CreateListItemGroups(2);
102 CreateDone(frameNode_);
103 OverScrollOffset offset = pattern_->GetOverScrollOffset(ITEM_HEIGHT);
104 OverScrollOffset expectOffset = { ITEM_HEIGHT, 0 };
105 EXPECT_TRUE(IsEqual(offset, expectOffset));
106 offset = pattern_->GetOverScrollOffset(-ITEM_HEIGHT);
107 expectOffset = { 0, -ITEM_HEIGHT };
108 EXPECT_TRUE(IsEqual(offset, expectOffset));
109
110 ScrollTo(ITEM_HEIGHT);
111 offset = pattern_->GetOverScrollOffset(ITEM_HEIGHT);
112 expectOffset = { ITEM_HEIGHT, 0 };
113 EXPECT_TRUE(IsEqual(offset, expectOffset));
114 offset = pattern_->GetOverScrollOffset(-ITEM_HEIGHT);
115 expectOffset = { 0, -ITEM_HEIGHT };
116 EXPECT_TRUE(IsEqual(offset, expectOffset));
117
118 /**
119 * @tc.steps: step2. !IsScrollSnapAlignCenter
120 */
121 ClearOldNodes();
122 CreateList();
123 CreateListItemGroups(1);
124 CreateDone(frameNode_);
125 offset = pattern_->GetOverScrollOffset(ITEM_HEIGHT * 5);
126 expectOffset = { 500, 0 };
127 EXPECT_TRUE(IsEqual(offset, expectOffset));
128 offset = pattern_->GetOverScrollOffset(-ITEM_HEIGHT);
129 expectOffset = { 0, -ITEM_HEIGHT };
130 EXPECT_TRUE(IsEqual(offset, expectOffset));
131
132 ScrollTo(ITEM_HEIGHT);
133 offset = pattern_->GetOverScrollOffset(ITEM_HEIGHT);
134 expectOffset = { ITEM_HEIGHT, 0 };
135 EXPECT_TRUE(IsEqual(offset, expectOffset));
136 offset = pattern_->GetOverScrollOffset(-ITEM_HEIGHT);
137 expectOffset = { 0, -ITEM_HEIGHT };
138 EXPECT_TRUE(IsEqual(offset, expectOffset));
139
140 /**
141 * @tc.steps: step3. IsScrollSnapAlignCenter
142 */
143 ClearOldNodes();
144 ListModelNG model = CreateList();
145 model.SetScrollSnapAlign(V2::ScrollSnapAlign::CENTER);
146 CreateListItemGroups(2);
147 CreateDone(frameNode_);
148 offset = pattern_->GetOverScrollOffset(ITEM_HEIGHT);
149 expectOffset = { ITEM_HEIGHT, 0 };
150 EXPECT_TRUE(IsEqual(offset, expectOffset));
151 offset = pattern_->GetOverScrollOffset(-ITEM_HEIGHT);
152 expectOffset = { 0, 0 };
153 EXPECT_TRUE(IsEqual(offset, expectOffset));
154
155 UpdateCurrentOffset(-ITEM_HEIGHT);
156 offset = pattern_->GetOverScrollOffset(ITEM_HEIGHT);
157 expectOffset = { 0, 0 };
158 EXPECT_TRUE(IsEqual(offset, expectOffset));
159 offset = pattern_->GetOverScrollOffset(-ITEM_HEIGHT * 4);
160 expectOffset = { 0, -ITEM_HEIGHT * 3 };
161 EXPECT_TRUE(IsEqual(offset, expectOffset));
162
163 /**
164 * @tc.steps: step4. has no group, groupAtStart and groupAtEnd are false
165 */
166 ClearOldNodes();
167 CreateList();
168 CreateListItems(TOTAL_ITEM_NUMBER);
169 CreateDone(frameNode_);
170 offset = pattern_->GetOverScrollOffset(ITEM_HEIGHT);
171 expectOffset = { ITEM_HEIGHT, 0 };
172 EXPECT_TRUE(IsEqual(offset, expectOffset));
173 }
174
175 /**
176 * @tc.name: ContentEndOffset001
177 * @tc.desc: Test ContentEndOffset should change behavior of IsAtBottom
178 * @tc.type: FUNC
179 */
180 HWTEST_F(ListLayoutTestNg, ContentEndOffset001, TestSize.Level1)
181 {
182 /**
183 * @tc.steps: step1. create List
184 */
185 ListModelNG model = CreateList();
186 model.SetScrollBar(DisplayMode::ON);
187 model.SetEdgeEffect(EdgeEffect::FADE, false);
188 model.SetContentEndOffset(100);
189 // total height = 1600
190 CreateListItems(16);
191 CreateDone(frameNode_);
192 std::vector<int32_t> scrollFromVector = { SCROLL_FROM_NONE, SCROLL_FROM_UPDATE, SCROLL_FROM_ANIMATION,
193 SCROLL_FROM_JUMP, SCROLL_FROM_ANIMATION_SPRING, SCROLL_FROM_BAR, SCROLL_FROM_ANIMATION_CONTROLLER,
194 SCROLL_FROM_BAR_FLING };
195
196 // ~ -1200 to reach bottom if no contentEndOffset
197 EXPECT_TRUE(pattern_->UpdateCurrentOffset(-1195, SCROLL_FROM_UPDATE));
198 FlushLayoutTask(frameNode_);
199 EXPECT_FALSE(pattern_->IsAtBottom());
200
201 // contentEndOffset_ takes 100 extra offset to reach bottom
202 EXPECT_TRUE(pattern_->UpdateCurrentOffset(-50, SCROLL_FROM_UPDATE));
203 FlushLayoutTask(frameNode_);
204 EXPECT_FALSE(pattern_->IsAtBottom());
205
206 EXPECT_TRUE(pattern_->UpdateCurrentOffset(-100, SCROLL_FROM_UPDATE));
207 FlushLayoutTask(frameNode_);
208 EXPECT_TRUE(pattern_->IsAtBottom());
209 }
210
211 /**
212 * @tc.name: ContentOffset001
213 * @tc.desc: Test top content offset and bottom end offset
214 * @tc.type: FUNC
215 */
216 HWTEST_F(ListLayoutTestNg, ContentOffset001, TestSize.Level1)
217 {
218 /**
219 * @tc.steps: step1. create List
220 * @tc.expected: Total Offset is negative contentStartOffset.
221 */
222 const int32_t itemNumber = 10;
223 const float contentStartOffset = 100;
224 const float contentEndOffset = 50;
225 ListModelNG model = CreateList();
226 model.SetContentStartOffset(contentStartOffset);
227 model.SetContentEndOffset(contentEndOffset);
228 CreateListItems(itemNumber);
229 CreateDone(frameNode_);
230 for (int32_t index = 0; index < 3; index++) {
231 EXPECT_EQ(GetChildRect(frameNode_, index).GetY(), contentStartOffset + index * ITEM_HEIGHT);
232 }
233
234 float offset = pattern_->GetTotalOffset();
235 EXPECT_FLOAT_EQ(offset, -contentStartOffset);
236
237 /**
238 * @tc.steps: step2. scroll to bottom
239 * @tc.expected: Bottom content offset equal to contentEndOffset.
240 */
241 ScrollToEdge(ScrollEdgeType::SCROLL_BOTTOM);
242 offset = pattern_->GetTotalOffset();
243 EXPECT_FLOAT_EQ(offset, itemNumber * ITEM_HEIGHT - LIST_HEIGHT + contentEndOffset);
244
245 /**
246 * @tc.steps: step3. scroll to top
247 * @tc.expected: Bottom content offset equal to contentEndOffset.
248 */
249 ScrollToEdge(ScrollEdgeType::SCROLL_TOP);
250 offset = pattern_->GetTotalOffset();
251 EXPECT_FLOAT_EQ(offset, -contentStartOffset);
252 }
253
254 /**
255 * @tc.name: ContentOffset002
256 * @tc.desc: Test scroll to Index with content offset
257 * @tc.type: FUNC
258 */
259 HWTEST_F(ListLayoutTestNg, ContentOffset002, TestSize.Level1)
260 {
261 /**
262 * @tc.steps: step1. create List
263 */
264 const int32_t itemNumber = 20;
265 const float contentStartOffset = 100;
266 const float contentEndOffset = 50;
267 ListModelNG model = CreateList();
268 model.SetContentStartOffset(contentStartOffset);
269 model.SetContentEndOffset(contentEndOffset);
270 CreateListItems(itemNumber);
271 CreateDone(frameNode_);
272
273 /**
274 * @tc.steps: step2. scroll to target item align start.
275 * @tc.expected: check whether the offset is correct.
276 */
277 EXPECT_TRUE(ScrollToIndex(0, false, ScrollAlign::START, -contentStartOffset));
278 EXPECT_TRUE(ScrollToIndex(1, false, ScrollAlign::START, ITEM_HEIGHT - contentStartOffset));
279 EXPECT_TRUE(ScrollToIndex(2, false, ScrollAlign::START, ITEM_HEIGHT * 2 - contentStartOffset));
280 ScrollToIndex(0, true, ScrollAlign::START);
281 EXPECT_EQ(pattern_->GetTotalOffset(), -contentStartOffset);
282 ScrollToIndex(1, true, ScrollAlign::START);
283 EXPECT_EQ(pattern_->GetTotalOffset(), ITEM_HEIGHT - contentStartOffset);
284 ScrollToIndex(2, true, ScrollAlign::START);
285 EXPECT_EQ(pattern_->GetTotalOffset(), ITEM_HEIGHT * 2 - contentStartOffset);
286
287 /**
288 * @tc.steps: step3. scroll to target item align end.
289 * @tc.expected: check whether the offset is correct.
290 */
291 const float MAX_OFFSET = itemNumber * ITEM_HEIGHT - LIST_HEIGHT + contentEndOffset;
292 EXPECT_TRUE(ScrollToIndex(itemNumber - 1, false, ScrollAlign::END, MAX_OFFSET));
293 EXPECT_TRUE(ScrollToIndex(itemNumber - 2, false, ScrollAlign::END, MAX_OFFSET - ITEM_HEIGHT));
294 EXPECT_TRUE(ScrollToIndex(itemNumber - 3, false, ScrollAlign::END, MAX_OFFSET - ITEM_HEIGHT * 2));
295 ScrollToIndex(itemNumber - 1, true, ScrollAlign::END);
296 EXPECT_EQ(pattern_->GetTotalOffset(), MAX_OFFSET);
297 ScrollToIndex(itemNumber - 2, true, ScrollAlign::END);
298 EXPECT_EQ(pattern_->GetTotalOffset(), MAX_OFFSET - ITEM_HEIGHT);
299 ScrollToIndex(itemNumber - 3, true, ScrollAlign::END);
300 EXPECT_EQ(pattern_->GetTotalOffset(), MAX_OFFSET - ITEM_HEIGHT * 2);
301 }
302
303 /**
304 * @tc.name: ContentOffset003
305 * @tc.desc: Test scroll to ListItemGroup with content offset
306 * @tc.type: FUNC
307 */
308 HWTEST_F(ListLayoutTestNg, ContentOffset003, TestSize.Level1)
309 {
310 /**
311 * @tc.steps: step1. create List
312 */
313 const int32_t GroupNumber = 5;
314 const float contentStartOffset = 100;
315 const float contentEndOffset = 50;
316 ListModelNG model = CreateList();
317 model.SetContentStartOffset(contentStartOffset);
318 model.SetContentEndOffset(contentEndOffset);
319 CreateListItemGroups(GroupNumber);
320 CreateDone(frameNode_);
321
322 /**
323 * @tc.steps: step2. scroll to target group align start.
324 * @tc.expected: check whether the offset is correct.
325 */
326 for (int32_t i = 0; i < 3; i++) {
327 ScrollToIndex(i, false, ScrollAlign::START);
328 EXPECT_EQ(GetChildRect(frameNode_, i).GetY(), contentStartOffset);
329 }
330 for (int32_t i = 0; i < 3; i++) {
331 ScrollToIndex(i, true, ScrollAlign::START);
332 EXPECT_EQ(GetChildRect(frameNode_, i).GetY(), contentStartOffset);
333 }
334
335 /**
336 * @tc.steps: step3. scroll to target group align end.
337 * @tc.expected: check whether the offset is correct.
338 */
339 for (int32_t i = 0; i < 3; i++) {
340 int32_t index = GroupNumber - i - 1;
341 ScrollToIndex(index, false, ScrollAlign::END);
342 auto rect = GetChildRect(frameNode_, index);
343 EXPECT_EQ(rect.Bottom(), LIST_HEIGHT - contentEndOffset);
344 }
345 for (int32_t i = 0; i < 3; i++) {
346 int32_t index = GroupNumber - i - 1;
347 ScrollToIndex(index, true, ScrollAlign::END);
348 auto rect = GetChildRect(frameNode_, index);
349 EXPECT_EQ(rect.Bottom(), LIST_HEIGHT - contentEndOffset);
350 }
351 }
352
353 /**
354 * @tc.name: ContentOffset004
355 * @tc.desc: Test ListItemGroup Sticky postion
356 * @tc.type: FUNC
357 */
358 HWTEST_F(ListLayoutTestNg, ContentOffset004, TestSize.Level1)
359 {
360 /**
361 * @tc.steps: step1. create List
362 */
363 const int32_t groupNumber = 5;
364 const float contentStartOffset = 100;
365 const float contentEndOffset = 50;
366 ListModelNG model = CreateList();
367 model.SetContentStartOffset(contentStartOffset);
368 model.SetContentEndOffset(contentEndOffset);
369 CreateGroupWithSetting(groupNumber, V2::ListItemGroupStyle::NONE);
370 CreateDone(frameNode_);
371
372 /**
373 * @tc.steps: step2. Scroll To ListItem in group.
374 * @tc.expected: ListItem position is correct.
375 */
376 ScrollToItemInGroup(1, 0, false, ScrollAlign::START);
377 auto group1 = GetChildFrameNode(frameNode_, 1);
378 auto groupRect = group1->GetGeometryNode()->GetFrameRect();
379 float groupPos = groupRect.Top();
380 auto item1Rect = GetChildRect(group1, 2);
381 EXPECT_EQ(item1Rect.Top(), contentStartOffset - groupPos);
382
383 ScrollToItemInGroup(2, 1, false, ScrollAlign::END);
384 auto group2 = GetChildFrameNode(frameNode_, 2);
385 groupPos = group2->GetGeometryNode()->GetFrameRect().Top();
386 auto item2Rect = GetChildRect(group1, 3);
387 EXPECT_EQ(item2Rect.Bottom(), LIST_HEIGHT - contentEndOffset - groupPos);
388
389 ScrollToItemInGroup(1, 0, true, ScrollAlign::START);
390 group1 = GetChildFrameNode(frameNode_, 1);
391 groupRect = group1->GetGeometryNode()->GetFrameRect();
392 groupPos = groupRect.Top();
393 item1Rect = GetChildRect(group1, 2);
394 EXPECT_EQ(item1Rect.Top(), contentStartOffset - groupPos);
395
396 ScrollToItemInGroup(2, 1, true, ScrollAlign::END);
397 group2 = GetChildFrameNode(frameNode_, 2);
398 groupPos = group2->GetGeometryNode()->GetFrameRect().Top();
399 item2Rect = GetChildRect(group1, 3);
400 EXPECT_EQ(item2Rect.Bottom(), LIST_HEIGHT - contentEndOffset - groupPos);
401 }
402
403 /**
404 * @tc.name: ContentOffset005
405 * @tc.desc: Test ListItemGroup Sticky postion
406 * @tc.type: FUNC
407 */
408 HWTEST_F(ListLayoutTestNg, ContentOffset005, TestSize.Level1)
409 {
410 /**
411 * @tc.steps: step1. create List
412 */
413 const int32_t groupNumber = 5;
414 const float contentStartOffset = 100;
415 const float contentEndOffset = 50;
416 ListModelNG model = CreateList();
417 model.SetContentStartOffset(contentStartOffset);
418 model.SetContentEndOffset(contentEndOffset);
419 model.SetSticky(V2::StickyStyle::BOTH);
420 CreateGroupWithSetting(groupNumber, V2::ListItemGroupStyle::NONE);
421 CreateDone(frameNode_);
422
423 /**
424 * @tc.steps: step2. scroll by 100.
425 * @tc.expected: header stick postion and footer sticky postion is correct.
426 */
427 pattern_->UpdateCurrentOffset(-100, SCROLL_FROM_UPDATE);
428 FlushLayoutTask(frameNode_);
429 auto group0 = GetChildFrameNode(frameNode_, 0);
430 auto groupPos = group0->GetGeometryNode()->GetFrameRect().Top();
431 auto header0Rect = GetChildRect(group0, 0);
432 EXPECT_EQ(header0Rect.Top(), contentStartOffset - groupPos);
433
434 auto group1 = GetChildFrameNode(frameNode_, 1);
435 groupPos = group1->GetGeometryNode()->GetFrameRect().Top();
436 auto footer1Rect = GetChildRect(group1, 1);
437 EXPECT_EQ(footer1Rect.Bottom(), 100.f);
438
439 /**
440 * @tc.steps: step3. Scroll To ListItem in group.
441 * @tc.expected: ListItem position is correct.
442 */
443 ScrollToItemInGroup(1, 0, false, ScrollAlign::START);
444 group1 = GetChildFrameNode(frameNode_, 1);
445 groupPos = group1->GetGeometryNode()->GetFrameRect().Top();
446 auto item1Rect = GetChildRect(group1, 2);
447 EXPECT_EQ(item1Rect.Top(), contentStartOffset + GROUP_HEADER_LEN - groupPos);
448
449 ScrollToItemInGroup(2, 1, false, ScrollAlign::END);
450 auto group2 = GetChildFrameNode(frameNode_, 2);
451 groupPos = group2->GetGeometryNode()->GetFrameRect().Top();
452 auto item2Rect = GetChildRect(group2, 3);
453 EXPECT_EQ(item2Rect.Bottom(), LIST_HEIGHT - contentEndOffset - GROUP_HEADER_LEN - groupPos);
454
455 ScrollToItemInGroup(1, 0, true, ScrollAlign::START);
456 group1 = GetChildFrameNode(frameNode_, 1);
457 groupPos = group1->GetGeometryNode()->GetFrameRect().Top();
458 item1Rect = GetChildRect(group1, 2);
459 EXPECT_EQ(item1Rect.Top(), contentStartOffset + GROUP_HEADER_LEN - groupPos);
460
461 ScrollToItemInGroup(2, 1, true, ScrollAlign::END);
462 group2 = GetChildFrameNode(frameNode_, 2);
463 groupPos = group2->GetGeometryNode()->GetFrameRect().Top();
464 item2Rect = GetChildRect(group2, 3);
465 EXPECT_EQ(item2Rect.Bottom(), LIST_HEIGHT - contentEndOffset - GROUP_HEADER_LEN - groupPos);
466 }
467
468 /**
469 * @tc.name: ContentOffset006
470 * @tc.desc: Test top content offset and bottom end offset
471 * @tc.type: FUNC
472 */
473 HWTEST_F(ListLayoutTestNg, ContentOffset006, TestSize.Level1)
474 {
475 /**
476 * @tc.steps: step1. create List with ScrollSnapAlign START
477 * @tc.expected:
478 */
479 const int32_t itemNumber = 20;
480 const float contentStartOffset = 100;
481 const float contentEndOffset = 50;
482 ListModelNG model = CreateList();
483 model.SetContentStartOffset(contentStartOffset);
484 model.SetContentEndOffset(contentEndOffset);
485 model.SetScrollSnapAlign(V2::ScrollSnapAlign::START);
486 CreateListItems(itemNumber);
487 CreateDone(frameNode_);
488
489 /**
490 * @tc.steps: step2. scroll snap
491 * @tc.expected: item top snap to contentEndOffset.
492 */
493 ScrollSnap(-120, 0);
494 EXPECT_FLOAT_EQ(pattern_->GetTotalOffset(), ITEM_HEIGHT - contentStartOffset);
495 ScrollSnap(-80, 0);
496 EXPECT_FLOAT_EQ(pattern_->GetTotalOffset(), ITEM_HEIGHT * 2 - contentStartOffset);
497
498 /**
499 * @tc.steps: step3. change scroll snap to END
500 * @tc.expected: item bottom snap to contentEndOffset.
501 */
502 ClearOldNodes();
503 model = CreateList();
504 model.SetContentStartOffset(contentStartOffset);
505 model.SetContentEndOffset(contentEndOffset);
506 model.SetScrollSnapAlign(V2::ScrollSnapAlign::END);
507 CreateListItems(itemNumber);
508 CreateDone(frameNode_);
509 ScrollSnap(-40, 0);
510 EXPECT_FLOAT_EQ(pattern_->GetTotalOffset(), -100);
511 ScrollSnap(-110, 0);
512 EXPECT_FLOAT_EQ(pattern_->GetTotalOffset(), 50);
513 }
514
515 /**
516 * @tc.name: ContentOffset007
517 * @tc.desc: Test List edge check
518 * @tc.type: FUNC
519 */
520 HWTEST_F(ListLayoutTestNg, ContentOffset007, TestSize.Level1)
521 {
522 /**
523 * @tc.steps: step1. create List with ScrollSnapAlign START
524 * @tc.expected: not OutOfBoundary
525 */
526 const float contentStartOffset = 50;
527 const float contentEndOffset = 50;
528 ListModelNG model = CreateList();
529 model.SetContentStartOffset(contentStartOffset);
530 model.SetContentEndOffset(contentEndOffset);
531 model.SetScrollSnapAlign(V2::ScrollSnapAlign::START);
532 CreateDone(frameNode_);
533
534 EXPECT_FALSE(pattern_->IsOutOfBoundary());
535 }
536
537 /**
538 * @tc.name: PaintMethod001
539 * @tc.desc: Test paint method when has no ListItem in List and in ListItemGroup
540 * @tc.type: FUNC
541 */
542 HWTEST_F(ListLayoutTestNg, PaintMethod001, TestSize.Level1)
543 {
544 /**
545 * @tc.steps: step1. Has no ListItem
546 * @tc.expected: UnScrollable, not need paint scrollBar, not DrawLine
547 */
548 ListModelNG model = CreateList();
549 model.SetScrollBar(DisplayMode::ON);
550 CreateListItemGroup(V2::ListItemGroupStyle::NONE); // no ListItem in ListItemGroup
551 auto paintWrapper = CreateDone(frameNode_);
552
553 /**
554 * @tc.steps: step2. UnScrollable List
555 * @tc.expected: Not need paint scrollBar
556 */
557 auto paintMethod = UpdateOverlayModifier(paintWrapper);
558 auto scrollBarOverlayModifier = paintMethod->scrollBarOverlayModifier_.Upgrade();
559 auto scrollBar = paintMethod->scrollBar_.Upgrade();
560 EXPECT_NE(scrollBar, nullptr);
561 EXPECT_FALSE(scrollBar->NeedPaint());
562 PaintDivider(paintWrapper, 0);
563
564 /**
565 * @tc.steps: step3. No ListItem in ListItemGroup
566 * @tc.expected: Not DrawLine
567 */
568 auto groupFrameNode = GetChildFrameNode(frameNode_, 0);
569 auto groupPaintWrapper = FlushLayoutTask(groupFrameNode);
570 GroupPaintDivider(groupPaintWrapper, 0);
571 }
572
573 /**
574 * @tc.name: PaintMethod002
575 * @tc.desc: Test List paint method about UpdateOverlayModifier(scroll bar)
576 * @tc.type: FUNC
577 */
578 HWTEST_F(ListLayoutTestNg, PaintMethod002, TestSize.Level1)
579 {
580 /**
581 * @tc.steps: step1. Set DisplayMode ON
582 * @tc.expected: Has scrollbar and on the right
583 */
584 ListModelNG model = CreateList();
585 model.SetScrollBar(DisplayMode::ON);
586 CreateListItems(TOTAL_ITEM_NUMBER);
587 auto paintWrapper = CreateDone(frameNode_);
588 RefPtr<ListPaintMethod> paintMethod = UpdateOverlayModifier(paintWrapper);
589 auto scrollBarOverlayModifier = paintMethod->scrollBarOverlayModifier_.Upgrade();
590 auto scrollBar = paintMethod->scrollBar_.Upgrade();
591 EXPECT_EQ(scrollBarOverlayModifier->positionMode_, PositionMode::RIGHT);
592 EXPECT_TRUE(scrollBar->NeedPaint());
593
594 /**
595 * @tc.steps: step2. Change axis to HORIZONTAL
596 * @tc.expected: The scrollbar and on the bottom
597 */
598 model = CreateList();
599 model.SetScrollBar(DisplayMode::ON);
600 model.SetListDirection(Axis::HORIZONTAL);
601 CreateListItems(TOTAL_ITEM_NUMBER);
602 paintWrapper = CreateDone(frameNode_);
603 paintMethod = UpdateOverlayModifier(paintWrapper);
604 scrollBarOverlayModifier = paintMethod->scrollBarOverlayModifier_.Upgrade();
605 scrollBar = paintMethod->scrollBar_.Upgrade();
606 EXPECT_TRUE(scrollBar->NeedPaint());
607 EXPECT_EQ(scrollBarOverlayModifier->positionMode_, PositionMode::BOTTOM);
608
609 /**
610 * @tc.steps: step3. Set DisplayMode::OFF
611 * @tc.expected: Has no scrollbar
612 */
613 model = CreateList();
614 model.SetScrollBar(DisplayMode::OFF);
615 CreateListItems(TOTAL_ITEM_NUMBER);
616 paintWrapper = CreateDone(frameNode_);
617 paintMethod = UpdateOverlayModifier(paintWrapper);
618 scrollBar = paintMethod->scrollBar_.Upgrade();
619 EXPECT_EQ(scrollBar, nullptr);
620 }
621
622 /**
623 * @tc.name: PaintMethod003
624 * @tc.desc: Test List paint method about PaintDivider in diff Layout
625 * @tc.type: FUNC
626 */
627 HWTEST_F(ListLayoutTestNg, PaintMethod003, TestSize.Level1)
628 {
629 /**
630 * @tc.steps: step1. Not set divider
631 * @tc.expected: Not DrawLine
632 */
633 ListModelNG model = CreateList();
634 // Group
635 ListItemGroupModelNG groupModel = CreateListItemGroup(V2::ListItemGroupStyle::NONE);
636 CreateListItems(2);
637 ViewStackProcessor::GetInstance()->Pop();
638 ViewStackProcessor::GetInstance()->StopGetAccessRecording();
639 // ListItems
640 CreateListItems(2);
641 auto paintWrapper = CreateDone(frameNode_);
642 auto groupFrameNode = GetChildFrameNode(frameNode_, 0);
643 auto groupPaintWrapper = FlushLayoutTask(groupFrameNode);
644 PaintDivider(paintWrapper, 0);
645 GroupPaintDivider(groupPaintWrapper, 0);
646
647 /**
648 * @tc.steps: step2. Set divider
649 * @tc.expected: DrawLine, call times depends on the divider number in view
650 */
651 model.SetDivider(AceType::RawPtr(frameNode_), ITEM_DIVIDER);
652 groupModel.SetDivider(AceType::RawPtr(groupFrameNode), ITEM_DIVIDER);
653 paintWrapper = FlushLayoutTask(frameNode_);
654 groupPaintWrapper = FlushLayoutTask(groupFrameNode);
655 PaintDivider(paintWrapper, 2);
656 GroupPaintDivider(groupPaintWrapper, 1);
657
658 /**
659 * @tc.steps: step3. Set lanes>1
660 * @tc.expected: DrawLine, call times depends on the divider number in view
661 */
662 model.SetLanes(AceType::RawPtr(frameNode_), 2);
663 paintWrapper = FlushLayoutTask(frameNode_);
664 groupPaintWrapper = FlushLayoutTask(groupFrameNode);
665 PaintDivider(paintWrapper, 2);
666 GroupPaintDivider(groupPaintWrapper, 0);
667
668 /**
669 * @tc.steps: step4. Set padding
670 * @tc.expected: Trigger ClipRect
671 */
672 ViewAbstract::SetPadding(AceType::RawPtr(frameNode_), CalcLength(10.f));
673 paintWrapper = FlushLayoutTask(frameNode_);
674 groupPaintWrapper = FlushLayoutTask(groupFrameNode);
675 PaintDivider(paintWrapper, 2, true);
676 GroupPaintDivider(groupPaintWrapper, 0);
677 }
678
679 /**
680 * @tc.name: PaintMethod004
681 * @tc.desc: Test ListItemGroup paint method about PaintDivider with diff args
682 * @tc.type: FUNC
683 */
684 HWTEST_F(ListLayoutTestNg, PaintMethod004, TestSize.Level1)
685 {
686 auto itemDivider = ITEM_DIVIDER;
687 ListModelNG model = CreateList();
688 model.SetDivider(itemDivider);
689 // Group
690 ListItemGroupModelNG groupModel = CreateListItemGroup(V2::ListItemGroupStyle::NONE);
691 groupModel.SetDivider(itemDivider);
692 CreateListItems(2);
693 ViewStackProcessor::GetInstance()->Pop();
694 ViewStackProcessor::GetInstance()->StopGetAccessRecording();
695 // ListItems
696 CreateListItems(2);
697 auto paintWrapper = CreateDone(frameNode_);
698 auto groupFrameNode = GetChildFrameNode(frameNode_, 0);
699 auto groupPaintWrapper = FlushLayoutTask(groupFrameNode);
700 auto groupPaint = AceType::DynamicCast<ListItemGroupPaintMethod>(groupPaintWrapper->nodePaintImpl_);
701
702 /**
703 * @tc.steps: step1. strokeWidth > 0
704 * @tc.expected: DrawLine, call times depends on the divider number in view
705 */
706 PaintDivider(paintWrapper, 2);
707 GroupPaintDivider(groupPaintWrapper, 1);
708
709 /**
710 * @tc.steps: step2. strokeWidth > 0, but PERCENT
711 * @tc.expected: Not DrawLine
712 */
713 itemDivider.strokeWidth = Dimension(STROKE_WIDTH, DimensionUnit::PERCENT);
714 model.SetDivider(AceType::RawPtr(frameNode_), itemDivider);
715 groupModel.SetDivider(AceType::RawPtr(groupFrameNode), itemDivider);
716 paintWrapper = FlushLayoutTask(frameNode_);
717 groupPaintWrapper = FlushLayoutTask(groupFrameNode);
718 PaintDivider(paintWrapper, 0);
719 GroupPaintDivider(groupPaintWrapper, 0);
720
721 /**
722 * @tc.steps: step3. strokeWidth < 0
723 * @tc.expected: Not DrawLine
724 */
725 itemDivider.strokeWidth = Dimension(-1);
726 model.SetDivider(AceType::RawPtr(frameNode_), itemDivider);
727 groupModel.SetDivider(AceType::RawPtr(groupFrameNode), itemDivider);
728 paintWrapper = FlushLayoutTask(frameNode_);
729 groupPaintWrapper = FlushLayoutTask(groupFrameNode);
730 PaintDivider(paintWrapper, 0);
731 GroupPaintDivider(groupPaintWrapper, 0);
732
733 /**
734 * @tc.steps: step4. startMargin + endMargin == LIST_WIDTH
735 * @tc.expected: Not DrawLine
736 */
737 itemDivider = ITEM_DIVIDER;
738 itemDivider.startMargin = Dimension(LIST_WIDTH / 2);
739 itemDivider.endMargin = Dimension(LIST_WIDTH / 2);
740 model.SetDivider(AceType::RawPtr(frameNode_), itemDivider);
741 groupModel.SetDivider(AceType::RawPtr(groupFrameNode), itemDivider);
742 paintWrapper = FlushLayoutTask(frameNode_);
743 groupPaintWrapper = FlushLayoutTask(groupFrameNode);
744 PaintDivider(paintWrapper, 0);
745 GroupPaintDivider(groupPaintWrapper, 0);
746
747 /**
748 * @tc.steps: step5. startMargin + endMargin > LIST_WIDTH
749 * @tc.expected: Rest margin and DrawLine
750 */
751 itemDivider = ITEM_DIVIDER;
752 itemDivider.startMargin = Dimension(LIST_WIDTH / 2);
753 itemDivider.endMargin = Dimension(LIST_WIDTH / 2 + 1);
754 model.SetDivider(AceType::RawPtr(frameNode_), itemDivider);
755 groupModel.SetDivider(AceType::RawPtr(groupFrameNode), itemDivider);
756 paintWrapper = FlushLayoutTask(frameNode_);
757 groupPaintWrapper = FlushLayoutTask(groupFrameNode);
758 PaintDivider(paintWrapper, 2);
759 GroupPaintDivider(groupPaintWrapper, 1);
760 }
761
762 /**
763 * @tc.name: PaintMethod005
764 * @tc.desc: Test List paint method about UpdateContentModifier
765 * @tc.type: FUNC
766 */
767 HWTEST_F(ListLayoutTestNg, PaintMethod005, TestSize.Level1)
768 {
769 /**
770 * @tc.steps: step1. Set divider startMargin and endMargin normal value
771 * @tc.expected: offset.GetX() == startMargin and length = LIST_WIDTH - startMargin - endMargin
772 */
773 auto itemDivider = ITEM_DIVIDER;
774 ListModelNG model = CreateList();
775 model.SetDivider(itemDivider);
776 CreateListItems(TOTAL_ITEM_NUMBER);
777 CreateDone(frameNode_);
778 auto renderContext = frameNode_->GetRenderContext();
779 renderContext->UpdatePaintRect(frameNode_->GetGeometryNode()->GetFrameRect());
780 UpdateDividerMap();
781 auto dividerList = pattern_->listContentModifier_->dividerList_->Get();
782 auto dividerMap = AceType::DynamicCast<ListDividerArithmetic>(dividerList)->GetDividerMap();
783 EXPECT_EQ(dividerMap.size(), 4);
784 auto length = LIST_WIDTH - (ITEM_DIVIDER.startMargin + ITEM_DIVIDER.endMargin).ConvertToPx();
785 EXPECT_EQ(pattern_->listContentModifier_->width_, ITEM_DIVIDER.strokeWidth.ConvertToPx());
786 for (auto child : dividerMap) {
787 EXPECT_EQ(child.second.offset.GetX(), ITEM_DIVIDER.startMargin.ConvertToPx());
788 EXPECT_EQ(child.second.length, length);
789 }
790
791 /**
792 * @tc.steps: step2. Set divider startMargin and endMargin abnormal value
793 * @tc.expected: startMargin == 0 and endMargin == 0
794 */
795 std::vector<V2::ItemDivider> dividerArray = { { Dimension(10), Dimension(-10), Dimension(-10) },
796 { Dimension(10), Dimension(LIST_WIDTH), Dimension(LIST_WIDTH) },
797 { Dimension(10), Dimension(10, DimensionUnit::PERCENT), Dimension(10, DimensionUnit::PERCENT) } };
798 for (auto itemDivider : dividerArray) {
799 layoutProperty_->UpdateDivider(itemDivider);
800 FlushLayoutTask(frameNode_);
801 auto renderContext = frameNode_->GetRenderContext();
802 renderContext->UpdatePaintRect(frameNode_->GetGeometryNode()->GetFrameRect());
803 UpdateDividerMap();
804 dividerList = pattern_->listContentModifier_->dividerList_->Get();
805 dividerMap = AceType::DynamicCast<ListDividerArithmetic>(dividerList)->GetDividerMap();
806 EXPECT_EQ(dividerMap.size(), 4);
807 EXPECT_EQ(pattern_->listContentModifier_->width_, itemDivider.strokeWidth.ConvertToPx());
808 for (auto child : dividerMap) {
809 EXPECT_EQ(child.second.offset.GetX(), 0.f);
810 EXPECT_EQ(child.second.length, LIST_WIDTH);
811 }
812 }
813 }
814
815 /**
816 * @tc.name: OnModifyDone001
817 * @tc.desc: Test list_pattern OnModifyDone
818 * @tc.type: FUNC
819 */
820 HWTEST_F(ListLayoutTestNg, OnModifyDone001, TestSize.Level1)
821 {
822 /**
823 * @tc.steps: step1. Set multiSelectable_ to true
824 * @tc.expected: InitMouseEvent() triggered by OnModifyDone()
825 */
826 ListModelNG model = CreateList();
827 model.SetScrollBar(DisplayMode::ON);
828 model.SetMultiSelectable(true);
829 CreateListItems(TOTAL_ITEM_NUMBER);
830 ViewStackProcessor::GetInstance()->Finish();
831 ViewStackProcessor::GetInstance()->StopGetAccessRecording();
832 EXPECT_NE(pattern_->GetScrollableEvent(), nullptr);
833 ASSERT_NE(pattern_->GetScrollBar(), nullptr);
834 EXPECT_EQ(pattern_->GetScrollBar()->GetDisplayMode(), DisplayMode::ON);
835 EXPECT_TRUE(pattern_->isMouseEventInit_);
836
837 /**
838 * @tc.steps: step2. Call OnDirtyLayoutWrapperSwap()
839 * @tc.expected: isInitialized_ would be true
840 */
841 EXPECT_FALSE(pattern_->isInitialized_);
842 FlushLayoutTask(frameNode_);
843 EXPECT_TRUE(pattern_->isInitialized_);
844
845 /**
846 * @tc.steps: step3. When isMouseEventInit_ is true, Call OnModifyDone()
847 * @tc.expected: UninitMouseEvent() would not be triggered, isMouseEventInit_ is still be true
848 */
849 pattern_->OnModifyDone();
850 EXPECT_TRUE(pattern_->isMouseEventInit_);
851
852 /**
853 * @tc.steps: step4. Change multiSelectable_ to false, call OnModifyDone()
854 * @tc.expected: UninitMouseEvent() triggered
855 */
856 pattern_->SetMultiSelectable(false);
857 EXPECT_FALSE(pattern_->multiSelectable_);
858 pattern_->OnModifyDone();
859 EXPECT_FALSE(pattern_->isMouseEventInit_);
860 }
861
862 /**
863 * @tc.name: Pattern003
864 * @tc.desc: Test OutBoundaryCallback
865 * @tc.type: FUNC
866 */
867 HWTEST_F(ListLayoutTestNg, Pattern003, TestSize.Level1)
868 {
869 CreateList();
870 CreateListItems(TOTAL_ITEM_NUMBER);
871 CreateDone(frameNode_);
872 EXPECT_NE(pattern_->scrollableEvent_, nullptr);
873 auto scrollable = pattern_->scrollableEvent_->GetScrollable();
874 EXPECT_NE(scrollable, nullptr);
875 scrollable->isTouching_ = true;
876 EXPECT_FALSE(pattern_->OutBoundaryCallback());
877 UpdateCurrentOffset(ITEM_HEIGHT);
878 EXPECT_TRUE(pattern_->OutBoundaryCallback());
879 ScrollTo(ITEM_HEIGHT * 2);
880 EXPECT_FALSE(pattern_->OutBoundaryCallback());
881 UpdateCurrentOffset(-ITEM_HEIGHT * 2);
882 EXPECT_TRUE(pattern_->OutBoundaryCallback());
883
884 ClearOldNodes();
885 ListModelNG model = CreateList();
886 model.SetChainAnimation(true);
887 model.SetChainAnimationOptions({ Dimension(0), Dimension(10), 0, 0, 0, DEFAULT_STIFFNESS, DEFAULT_DAMPING });
888 CreateListItems(TOTAL_ITEM_NUMBER);
889 CreateDone(frameNode_);
890 EXPECT_NE(pattern_->scrollableEvent_, nullptr);
891 scrollable = pattern_->scrollableEvent_->GetScrollable();
892 EXPECT_NE(scrollable, nullptr);
893 scrollable->isTouching_ = true;
894 EXPECT_NE(pattern_->springProperty_, nullptr);
895 EXPECT_NE(pattern_->chainAnimation_, nullptr);
896 UpdateCurrentOffset(ITEM_HEIGHT);
897 EXPECT_TRUE(pattern_->OutBoundaryCallback());
898 }
899
900 /**
901 * @tc.name: Pattern006
902 * @tc.desc: Test GetItemIndexByPosition
903 * @tc.type: FUNC
904 */
905 HWTEST_F(ListLayoutTestNg, Pattern006, TestSize.Level1)
906 {
907 int32_t lanes = 2;
908 ListModelNG model = CreateList();
909 model.SetLanes(lanes);
910 CreateListItems(VIEW_ITEM_NUMBER * lanes);
911 CreateDone(frameNode_);
912
913 /**
914 * @tc.steps: step1. When lanes > 1, call GetItemIndexByPosition
915 * @tc.expected: Would return correct itemIndex
916 */
917 const Point point = Point(150.f, 250.f);
918 int32_t itemIndex = pattern_->GetItemIndexByPosition(point.GetX(), point.GetY());
919 EXPECT_EQ(itemIndex, 5);
920 }
921
922 /**
923 * @tc.name: Pattern007
924 * @tc.desc: Test GetItemIndexByPosition
925 * @tc.type: FUNC
926 */
927 HWTEST_F(ListLayoutTestNg, Pattern007, TestSize.Level1)
928 {
929 /**
930 * @tc.steps: step1. When has ListItem, position not at any ListItem
931 * @tc.expected: Would return the last itemIndex
932 */
933 CreateList();
934 CreateListItems(VIEW_ITEM_NUMBER);
935 CreateDone(frameNode_);
936 const Point point = Point(0, 1000.f);
937 int32_t itemIndex = pattern_->GetItemIndexByPosition(point.GetX(), point.GetY());
938 EXPECT_EQ(itemIndex, VIEW_ITEM_NUMBER);
939 }
940
941 /**
942 * @tc.name: Pattern008
943 * @tc.desc: Test GetItemIndexByPosition
944 * @tc.type: FUNC
945 */
946 HWTEST_F(ListLayoutTestNg, Pattern008, TestSize.Level1)
947 {
948 /**
949 * @tc.steps: step1. When has no ListItem, call GetItemIndexByPosition
950 * @tc.expected: Would return 0
951 */
952 CreateList();
953 CreateDone(frameNode_);
954 const Point point = Point(0, 1000.f);
955 int32_t itemIndex = pattern_->GetItemIndexByPosition(point.GetX(), point.GetY());
956 EXPECT_EQ(itemIndex, 0);
957 }
958
959 /**
960 * @tc.name: ListSize001
961 * @tc.desc: Test List size in diff condition
962 * @tc.type: FUNC
963 */
964 HWTEST_F(ListLayoutTestNg, ListSize001, TestSize.Level1)
965 {
966 /**
967 * @tc.steps: step1. Not set size to List, but no ListItems
968 * @tc.expected: List with is rootWidth
969 */
970 const float rootWidth = MockPipelineContext::GetCurrent()->rootWidth_;
971 ListModelNG model;
972 model.Create();
973 GetList();
974 CreateDone(frameNode_);
975 EXPECT_EQ(frameNode_->GetGeometryNode()->GetFrameSize().Width(), rootWidth);
976
977 /**
978 * @tc.steps: step2. Not set size to List and has ListItems
979 * @tc.expected: List with is rootWidth
980 */
981 model.Create();
982 CreateListItems(TOTAL_ITEM_NUMBER);
983 GetList();
984 CreateDone(frameNode_);
985 EXPECT_EQ(frameNode_->GetGeometryNode()->GetFrameSize().Width(), rootWidth);
986
987 /**
988 * @tc.steps: step3. Set List width to Infinity
989 * @tc.expected: List with is Infinity
990 */
991 CreateList();
992 ViewAbstract::SetWidth(CalcLength(Infinity<float>()));
993 CreateListItems(TOTAL_ITEM_NUMBER);
994 CreateDone(frameNode_);
995 EXPECT_EQ(frameNode_->GetGeometryNode()->GetFrameSize().Width(), Infinity<float>());
996
997 /**
998 * @tc.steps: step4. Set List width to Infinity, but no ListItems
999 * @tc.expected: List with is 0
1000 */
1001 ClearOldNodes();
1002 CreateList();
1003 ViewAbstract::SetWidth(CalcLength(Infinity<float>()));
1004 CreateDone(frameNode_);
1005 EXPECT_EQ(frameNode_->GetGeometryNode()->GetFrameSize().Width(), 0.f);
1006 }
1007
1008 /**
1009 * @tc.name: Pattern011
1010 * @tc.desc: Test ContentStartOffset and ContentEndOffset
1011 * @tc.type: FUNC
1012 */
1013 HWTEST_F(ListLayoutTestNg, Pattern011, TestSize.Level1)
1014 {
1015 /**
1016 * @tc.cases: contentStartOffset_ + contentEndOffset_ < contentMainSize
1017 * @tc.expected: contentStartOffset_ = 10.f and contentEndOffset_ = 10.f
1018 */
1019 ListModelNG model = CreateList();
1020 model.SetContentStartOffset(10.f);
1021 model.SetContentEndOffset(10.f);
1022 CreateListItems(20);
1023 CreateDone(frameNode_);
1024 EXPECT_EQ(layoutProperty_->GetContentStartOffsetValue(), 10.f);
1025 EXPECT_EQ(layoutProperty_->GetContentEndOffsetValue(), 10.f);
1026 EXPECT_EQ(pattern_->contentStartOffset_, 10.f);
1027 EXPECT_EQ(pattern_->contentEndOffset_, 10.f);
1028 EXPECT_EQ(pattern_->GetOffsetWithLimit(5.f), 0.f);
1029 EXPECT_EQ(pattern_->GetOffsetWithLimit(0.f), 0.f);
1030 EXPECT_EQ(pattern_->GetOffsetWithLimit(-5.f), -5.f);
1031
1032 /**
1033 * @tc.cases: contentStartOffset_ + contentEndOffset_ >= contentMainSize
1034 * @tc.expected: contentStartOffset_ = 0.f and contentEndOffset_ = 0.f
1035 */
1036 model = CreateList();
1037 model.SetContentStartOffset(0.5f * LIST_HEIGHT);
1038 model.SetContentEndOffset(0.5f * LIST_HEIGHT);
1039 CreateListItems(20);
1040 CreateDone(frameNode_);
1041 EXPECT_EQ(layoutProperty_->GetContentStartOffsetValue(), 0.5f * LIST_HEIGHT);
1042 EXPECT_EQ(layoutProperty_->GetContentEndOffsetValue(), 0.5f * LIST_HEIGHT);
1043 EXPECT_EQ(pattern_->contentStartOffset_, 0.f);
1044 EXPECT_EQ(pattern_->contentEndOffset_, 0.f);
1045 }
1046
1047 /**
1048 * @tc.name: ListItemGroupCreateForCardModeTest001
1049 * @tc.desc: Test the initialization of listItem in card mode.
1050 * @tc.type: FUNC
1051 */
1052 HWTEST_F(ListLayoutTestNg, ListItemGroupCreateForCardModeTest001, TestSize.Level1)
1053 {
1054 /**
1055 * @tc.steps: step2. create ListItemGroup.
1056 * @tc.expected: step2. create a card style ListItemGroup success.
1057 */
1058 ListItemGroupModelNG groupModel;
1059 groupModel.Create(V2::ListItemGroupStyle::CARD);
1060 auto frameNode = AceType::DynamicCast<FrameNode>(ViewStackProcessor::GetInstance()->Finish());
1061 auto pattern = frameNode->GetPattern<ListItemGroupPattern>();
1062 RefPtr<LayoutProperty> layoutProperty = frameNode->GetLayoutProperty();
1063 EXPECT_EQ(pattern->GetListItemGroupStyle(), V2::ListItemGroupStyle::CARD);
1064
1065 /**
1066 * @tc.steps: step3. compare the obtained value with the set value.
1067 * @tc.expected: step3. the obtained value is equal to the set value.
1068 */
1069 auto renderContext = frameNode->GetRenderContext();
1070 EXPECT_EQ(renderContext->GetBackgroundColorValue(), Color::WHITE);
1071 EXPECT_EQ(layoutProperty->GetMarginProperty()->left.value(), CalcLength(GROUP_MARGIN));
1072 EXPECT_EQ(layoutProperty->GetMarginProperty()->right.value(), CalcLength(GROUP_MARGIN));
1073 }
1074
1075 /**
1076 * @tc.name: ListItemCreateForCardModeTest001
1077 * @tc.desc: Test the initialization of listItem in card mode.
1078 * @tc.type: FUNC
1079 */
1080 HWTEST_F(ListLayoutTestNg, ListItemCreateForCardModeTest001, TestSize.Level1)
1081 {
1082 /**
1083 * @tc.steps: step2. create ListItem in card mode.
1084 * @tc.expected: step2. create a card style ListItem success.
1085 */
1086 ListItemModelNG itemModel;
__anonc56bfe6a0202(int32_t) 1087 itemModel.Create([](int32_t) {}, V2::ListItemStyle::CARD);
1088 auto frameNode = AceType::DynamicCast<FrameNode>(ViewStackProcessor::GetInstance()->Finish());
1089 auto pattern = frameNode->GetPattern<ListItemPattern>();
1090 RefPtr<LayoutProperty> layoutProperty = frameNode->GetLayoutProperty();
1091 EXPECT_EQ(pattern->GetListItemStyle(), V2::ListItemStyle::CARD);
1092
1093 /**
1094 * @tc.steps: step3. compare the obtained value with the set value.
1095 * @tc.expected: step3. the obtained value is equal to the set value.
1096 */
1097 auto renderContext = frameNode->GetRenderContext();
1098 EXPECT_EQ(renderContext->GetBackgroundColorValue(), Color::WHITE);
1099 }
1100
1101 /**
1102 * @tc.name: ListItemHoverEventForCardModeTest001
1103 * @tc.desc: Test the hover event when the hover status of card mode listItem is true.
1104 * @tc.type: FUNC
1105 */
1106 HWTEST_F(ListLayoutTestNg, ListItemHoverEventForCardModeTest001, TestSize.Level1)
1107 {
1108 /**
1109 * @tc.steps: step2. create ListItem in card mode.
1110 * @tc.expected: step2. create a card style ListItem success.
1111 */
1112 ListItemModelNG itemModel;
__anonc56bfe6a0302(int32_t) 1113 itemModel.Create([](int32_t) {}, V2::ListItemStyle::CARD);
1114 auto frameNode = AceType::DynamicCast<FrameNode>(ViewStackProcessor::GetInstance()->Finish());
1115 ASSERT_NE(frameNode, nullptr);
1116 auto pattern = frameNode->GetPattern<ListItemPattern>();
1117 ASSERT_NE(pattern, nullptr);
1118
1119 /**
1120 * @tc.steps: step3. call function HandleHoverEvent and Set hover status to true.
1121 * @tc.expected: step3. the hover status is true.
1122 */
1123 pattern->HandleHoverEvent(true, frameNode);
1124 EXPECT_TRUE(pattern->isHover_);
1125
1126 /**
1127 * @tc.steps: step3. call function HandleHoverEvent and Set hover status to false.
1128 * @tc.expected: step3. the hover status is false.
1129 */
1130 pattern->HandleHoverEvent(false, frameNode);
1131 EXPECT_FALSE(pattern->isHover_);
1132 }
1133
1134 /**
1135 * @tc.name: ListItemPressEventForCardModeTest001
1136 * @tc.desc: Test the press event when the TouchType is DOWN.
1137 * @tc.type: FUNC
1138 */
1139 HWTEST_F(ListLayoutTestNg, ListItemPressEventForCardModeTest001, TestSize.Level1)
1140 {
1141 CreateList();
1142 CreateListItem(V2::ListItemStyle::CARD);
1143 CreateDone(frameNode_);
1144 auto itemPattern = GetChildPattern<ListItemPattern>(frameNode_, 0);
1145 auto handleHoverEvent = itemPattern->hoverEvent_->GetOnHoverEventFunc();
1146 auto itemNode = GetChildFrameNode(frameNode_, 0);
1147 auto gesture = itemNode->GetOrCreateGestureEventHub();
1148 auto handlePressEvent = gesture->touchEventActuator_->touchEvents_.back()->GetTouchEventCallback();
1149
1150 /**
1151 * @tc.steps: step1. Hover and Touch Down/Move/Up
1152 */
1153 handleHoverEvent(true);
1154 EXPECT_TRUE(itemPattern->isHover_);
1155 EXPECT_EQ(itemPattern->GetBlendGgColor(), HOVER_COLOR);
1156
1157 TouchEventInfo info = CreateTouchEventInfo(TouchType::DOWN, Offset());
1158 handlePressEvent(info);
1159 EXPECT_TRUE(itemPattern->isPressed_);
1160 EXPECT_EQ(itemPattern->GetBlendGgColor(), PRESS_COLOR);
1161
1162 info = CreateTouchEventInfo(TouchType::MOVE, Offset());
1163 handlePressEvent(info);
1164 EXPECT_TRUE(itemPattern->isPressed_);
1165 EXPECT_EQ(itemPattern->GetBlendGgColor(), PRESS_COLOR);
1166
1167 info = CreateTouchEventInfo(TouchType::UP, Offset());
1168 handlePressEvent(info);
1169 EXPECT_FALSE(itemPattern->isPressed_);
1170 EXPECT_EQ(itemPattern->GetBlendGgColor(), HOVER_COLOR);
1171
1172 handleHoverEvent(false);
1173 EXPECT_FALSE(itemPattern->isHover_);
1174 EXPECT_EQ(itemPattern->GetBlendGgColor(), Color::TRANSPARENT);
1175
1176 /**
1177 * @tc.steps: step2. Touch Down/Cancel
1178 */
1179 info = CreateTouchEventInfo(TouchType::DOWN, Offset());
1180 handlePressEvent(info);
1181 EXPECT_TRUE(itemPattern->isPressed_);
1182
1183 info = CreateTouchEventInfo(TouchType::CANCEL, Offset());
1184 handlePressEvent(info);
1185 EXPECT_FALSE(itemPattern->isPressed_);
1186 }
1187
1188 /**
1189 * @tc.name: ListItemDisableEventForCardModeTest001
1190 * @tc.desc: Test InitDisableEvent
1191 * @tc.type: FUNC
1192 */
1193 HWTEST_F(ListLayoutTestNg, ListItemDisableEventForCardModeTest001, TestSize.Level1)
1194 {
1195 /**
1196 * @tc.steps: step1. create ListItem in card mode.
1197 * @tc.expected: create a card style ListItem success and set enable status to false.
1198 */
1199 CreateList();
1200 CreateListItem(V2::ListItemStyle::CARD);
1201 CreateDone(frameNode_);
1202 auto itemNode = GetChildFrameNode(frameNode_, 0);
1203 auto itemPattern = GetChildPattern<ListItemPattern>(frameNode_, 0);
1204 auto itemEventHub = GetChildEventHub<ListItemEventHub>(frameNode_, 0);
1205 auto itemRenderContext = itemNode->GetRenderContext();
1206 EXPECT_TRUE(itemEventHub->IsEnabled());
1207 EXPECT_TRUE(itemEventHub->IsDeveloperEnabled());
1208 EXPECT_EQ(itemRenderContext->GetOpacity(), 1.0);
1209
1210 itemEventHub->SetEnabled(false);
1211 itemPattern->OnModifyDone(); // Test InitDisableEvent
1212 EXPECT_FALSE(itemPattern->Selectable());
1213 EXPECT_FALSE(itemEventHub->IsEnabled());
1214 EXPECT_FALSE(itemEventHub->IsDeveloperEnabled());
1215 EXPECT_EQ(itemRenderContext->GetOpacity(), 0.4);
1216
1217 itemPattern->OnModifyDone();
1218 EXPECT_FALSE(itemPattern->Selectable());
1219
1220 itemEventHub->SetEnabled(true);
1221 itemPattern->OnModifyDone();
1222 EXPECT_FALSE(itemPattern->Selectable());
1223 EXPECT_EQ(itemRenderContext->GetOpacity(), 0.4);
1224 }
1225
1226 /**
1227 * @tc.name: ListPattern_GetItemRect001
1228 * @tc.desc: Test the GetItemRect function of List.
1229 * @tc.type: FUNC
1230 */
1231 HWTEST_F(ListLayoutTestNg, ListPattern_GetItemRect001, TestSize.Level1)
1232 {
1233 /**
1234 * @tc.steps: step1. Init List then slide List by Scroller.
1235 */
1236 ListModelNG model = CreateList();
1237 model.SetInitialIndex(1);
1238 CreateListItems(TOTAL_ITEM_NUMBER * 2);
1239 CreateDone(frameNode_);
1240 pattern_->ScrollBy(ITEM_HEIGHT / 2.0f);
1241 FlushLayoutTask(frameNode_);
1242
1243 /**
1244 * @tc.steps: step2. Get invalid ListItem Rect.
1245 * @tc.expected: Return 0 when input invalid index.
1246 */
1247 EXPECT_TRUE(IsEqual(pattern_->GetItemRect(-1), Rect()));
1248 EXPECT_TRUE(IsEqual(pattern_->GetItemRect(0), Rect()));
1249 EXPECT_TRUE(IsEqual(pattern_->GetItemRect(TOTAL_ITEM_NUMBER * 2 - 1), Rect()));
1250 EXPECT_TRUE(IsEqual(pattern_->GetItemRect(TOTAL_ITEM_NUMBER * 2), Rect()));
1251
1252 /**
1253 * @tc.steps: step3. Get ListItem Rect by GetItemRectInGroup.
1254 * @tc.expected: Return 0 when get ListItem Rect by GetItemRectInGroup.
1255 */
1256 EXPECT_TRUE(IsEqual(pattern_->GetItemRectInGroup(1, 0), Rect()));
1257
1258 /**
1259 * @tc.steps: step4. Get valid ListItem Rect.
1260 * @tc.expected: Return actual Rect when input valid index.
1261 */
1262 EXPECT_TRUE(
1263 IsEqual(pattern_->GetItemRect(1), Rect(0, -ITEM_HEIGHT / 2.0f, FILL_LENGTH.Value() * LIST_WIDTH, ITEM_HEIGHT)));
1264 EXPECT_TRUE(IsEqual(pattern_->GetItemRect(3),
1265 Rect(0, -ITEM_HEIGHT / 2.0f + ITEM_HEIGHT * 2, FILL_LENGTH.Value() * LIST_WIDTH, ITEM_HEIGHT)));
1266
1267 /**
1268 * @tc.steps: step5. Slide List by Scroller.
1269 */
1270 pattern_->ScrollToIndex(8);
1271 FlushLayoutTask(frameNode_);
1272 /**
1273 * @tc.steps: step6. Get invalid ListItem Rect.
1274 * @tc.expected: Return 0 when input invalid index.
1275 */
1276 EXPECT_TRUE(IsEqual(pattern_->GetItemRect(7), Rect()));
1277
1278 /**
1279 * @tc.steps: step7. Get valid ListItem Rect.
1280 * @tc.expected: Return actual Rect when input valid index.
1281 */
1282 EXPECT_TRUE(IsEqual(pattern_->GetItemRect(pattern_->GetEndIndex()),
1283 Rect(0, LIST_HEIGHT - ITEM_HEIGHT, FILL_LENGTH.Value() * LIST_WIDTH, ITEM_HEIGHT)));
1284 }
1285
1286 /**
1287 * @tc.name: ListPattern_GetItemRectInGroup001
1288 * @tc.desc: Test the GetItemRectInGroup function of List.
1289 * @tc.type: FUNC
1290 */
1291 HWTEST_F(ListLayoutTestNg, ListPattern_GetItemRectInGroup001, TestSize.Level1)
1292 {
1293 /**
1294 * @tc.steps: step1. Init List then slide List by Scroller.
1295 */
1296 ListModelNG model = CreateList();
1297 CreateListItemGroup(V2::ListItemGroupStyle::NONE);
1298 CreateListItems(TOTAL_ITEM_NUMBER);
1299 CreateDone(frameNode_);
1300 pattern_->ScrollTo(ITEM_HEIGHT * 2);
1301 FlushLayoutTask(frameNode_);
1302
1303 /**
1304 * @tc.steps: step2. Get invalid group item Rect.
1305 * @tc.expected: Return 0 when input invalid group index.
1306 */
1307 EXPECT_TRUE(IsEqual(pattern_->GetItemRectInGroup(-1, 0), Rect()));
1308 EXPECT_TRUE(IsEqual(pattern_->GetItemRectInGroup(2, -1), Rect()));
1309 EXPECT_TRUE(IsEqual(pattern_->GetItemRectInGroup(0, 0), Rect()));
1310 EXPECT_TRUE(IsEqual(pattern_->GetItemRectInGroup(1, 0), Rect()));
1311 EXPECT_TRUE(IsEqual(pattern_->GetItemRectInGroup(0, TOTAL_ITEM_NUMBER), Rect()));
1312
1313 /**
1314 * @tc.steps: step3. Get valid group item Rect.
1315 * @tc.expected: Return actual Rect when input valid group index.
1316 */
1317 EXPECT_TRUE(IsEqual(
1318 pattern_->GetItemRectInGroup(0, 2), Rect(0, 0, FILL_LENGTH.Value() * LIST_WIDTH, ITEM_HEIGHT)));
1319
1320 /**
1321 * @tc.steps: step4. Get valid ListItemGroup Rect.
1322 * @tc.expected: Return actual Rect when input valid index.
1323 */
1324 EXPECT_TRUE(IsEqual(pattern_->GetItemRect(0),
1325 Rect(0, -ITEM_HEIGHT * 2, LIST_WIDTH, ITEM_HEIGHT * TOTAL_ITEM_NUMBER)));
1326 }
1327
1328 /**
1329 * @tc.name: ListLayout_SafeArea001
1330 * @tc.desc: Test list layout with expandSafeArea.
1331 * @tc.type: FUNC
1332 */
1333 HWTEST_F(ListLayoutTestNg, ListLayout_SafeArea001, TestSize.Level1)
1334 {
1335 /**
1336 * @tc.steps: step1. Init List.
1337 */
1338 ListModelNG model = CreateList();
1339 model.SetInitialIndex(1);
1340 CreateListItems(TOTAL_ITEM_NUMBER * 2);
1341 CreateDone(frameNode_);
1342 EXPECT_CALL(*MockPipelineContext::pipeline_, GetSafeArea)
1343 .Times(1)
1344 .WillOnce(Return(SafeAreaInsets { {}, {}, {}, { .start = 0, .end = 100 } }));
1345 layoutProperty_->UpdateSafeAreaExpandOpts({ .type = SAFE_AREA_TYPE_SYSTEM, .edges = SAFE_AREA_EDGE_ALL });
1346 FlushLayoutTask(frameNode_);
1347 EXPECT_EQ(pattern_->contentEndOffset_, 100);
1348 EXPECT_TRUE(IsEqual(frameNode_->geometryNode_->GetFrameSize(), SizeF(LIST_WIDTH, LIST_HEIGHT)));
1349 }
1350
1351 /**
1352 * @tc.name: ListLayout_SafeArea002
1353 * @tc.desc: Test list layout with expandSafeArea.
1354 * @tc.type: FUNC
1355 */
1356 HWTEST_F(ListLayoutTestNg, ListLayout_SafeArea002, TestSize.Level1)
1357 {
1358 /**
1359 * @tc.steps: step1. Init List.
1360 */
1361 ListModelNG model = CreateList();
1362 model.SetInitialIndex(1);
1363 CreateListItems(TOTAL_ITEM_NUMBER * 2);
1364 CreateDone(frameNode_);
1365 EXPECT_CALL(*MockPipelineContext::pipeline_, GetSafeArea).Times(0);
1366 layoutProperty_->UpdateSafeAreaExpandOpts({ .type = SAFE_AREA_TYPE_SYSTEM, .edges = SAFE_AREA_EDGE_TOP });
1367 FlushLayoutTask(frameNode_);
1368 EXPECT_EQ(pattern_->contentEndOffset_, 0);
1369 EXPECT_TRUE(IsEqual(frameNode_->geometryNode_->GetFrameSize(), SizeF(LIST_WIDTH, LIST_HEIGHT)));
1370 }
1371
1372 /**
1373 * @tc.name: PostListItemPressStyleTask001
1374 * @tc.desc: Test list layout with PostListItemPressStyleTask.
1375 * @tc.type: FUNC
1376 */
1377 HWTEST_F(ListLayoutTestNg, PostListItemPressStyleTask001, TestSize.Level1)
1378 {
1379 /**
1380 * @tc.steps: step1. Init List.
1381 */
1382 ListModelNG model = CreateList();
1383 model.SetDivider(ITEM_DIVIDER);
1384 CreateListItems(TOTAL_ITEM_NUMBER);
1385 CreateDone(frameNode_);
1386 int cur = 0;
1387 for (auto& child : pattern_->itemPosition_) {
1388 child.second.id += cur;
1389 cur++;
1390 }
1391 auto renderContext = frameNode_->GetRenderContext();
1392 renderContext->UpdatePaintRect(frameNode_->GetGeometryNode()->GetFrameRect());
1393 UpdateContentModifier();
1394 auto dividerList_ = pattern_->listContentModifier_->dividerList_->Get();
1395 auto lda = AceType::DynamicCast<ListDividerArithmetic>(dividerList_);
1396 auto dividerMap = lda->GetDividerMap();
1397 EXPECT_EQ(dividerMap.size(), 4);
1398
1399 auto listItemNode = GetChildFrameNode(frameNode_, 0);
1400 auto listItemNodeId = listItemNode->GetId();
1401 auto stateStyleMgr = AceType::MakeRefPtr<StateStyleManager>(listItemNode);
1402 stateStyleMgr->PostListItemPressStyleTask(UI_STATE_PRESSED);
1403 RefPtr<NodePaintMethod> paint = pattern_->CreateNodePaintMethod();
1404 RefPtr<ListPaintMethod> listPaint = AceType::DynamicCast<ListPaintMethod>(paint);
1405 for (auto child : listPaint->itemPosition_) {
1406 if (child.second.id == listItemNodeId) {
1407 EXPECT_TRUE(child.second.isPressed);
1408 }
1409 }
1410
1411 UpdateContentModifier();
1412 dividerList_ = pattern_->listContentModifier_->dividerList_->Get();
1413 lda = AceType::DynamicCast<ListDividerArithmetic>(dividerList_);
1414 dividerMap = lda->GetDividerMap();
1415 EXPECT_EQ(dividerMap.size(), 3);
1416 }
1417
1418 /**
1419 * @tc.name: PostListItemPressStyleTask002
1420 * @tc.desc: Test listItemGroup layout with PostListItemPressStyleTask.
1421 * @tc.type: FUNC
1422 */
1423 HWTEST_F(ListLayoutTestNg, PostListItemPressStyleTask002, TestSize.Level1)
1424 {
1425 /**
1426 * @tc.steps: step1. Init List.
1427 */
1428 ListModelNG model = CreateList();
1429 model.SetDivider(ITEM_DIVIDER);
1430 CreateListItemGroups(TOTAL_ITEM_NUMBER);
1431 CreateDone(frameNode_);
1432 auto groupFrameNode = GetChildFrameNode(frameNode_, 0);
1433 auto groupPattern = groupFrameNode->GetPattern<ListItemGroupPattern>();
1434 int cur = 0;
1435 for (auto& child : groupPattern->itemPosition_) {
1436 child.second.id += cur;
1437 cur++;
1438 }
1439
1440 auto listItemNode = GetChildFrameNode(groupFrameNode, 0);
1441 auto listItemNodeId = listItemNode->GetId();
1442 auto stateStyleMgr = AceType::MakeRefPtr<StateStyleManager>(listItemNode);
1443 stateStyleMgr->PostListItemPressStyleTask(UI_STATE_PRESSED);
1444 RefPtr<NodePaintMethod> paint = groupPattern->CreateNodePaintMethod();
1445 RefPtr<ListItemGroupPaintMethod> groupPaint = AceType::DynamicCast<ListItemGroupPaintMethod>(paint);
1446 for (auto child : groupPaint->itemPosition_) {
1447 if (child.second.id == listItemNodeId) {
1448 EXPECT_TRUE(child.second.isPressed);
1449 }
1450 }
1451 }
1452
1453 /**
1454 * @tc.name: ChildrenMainSize005
1455 * @tc.desc: Test childrenMainSize layout
1456 * @tc.type: FUNC
1457 */
1458 HWTEST_F(ListLayoutTestNg, ChildrenMainSize005, TestSize.Level1)
1459 {
1460 /**
1461 * @tc.steps: step1. Create list
1462 * @tc.expected: Default Size is 0
1463 */
1464 ListModelNG model = CreateList();
1465 auto childrenSize = model.GetOrCreateListChildrenMainSize();
1466 childrenSize->UpdateDefaultSize(0);
1467 childrenSize->ChangeData(0, 2, { 100.f, 100.f });
1468 childrenSize->ChangeData(4, 1, { 200.f });
1469 childrenSize->ChangeData(5, 8, { 100.f, 100.f, 100.f, 100.f, 100.f, 100.f, 100.f, 100.f });
1470 CreateListItems(2);
1471 CreateItemWithSize(2, SizeT<Dimension>(FILL_LENGTH, Dimension(0.f)));
1472 CreateItemWithSize(1, SizeT<Dimension>(FILL_LENGTH, Dimension(200.f)));
1473 CreateListItems(8);
1474 CreateDone(frameNode_);
1475 EXPECT_TRUE(ScrollToIndex(1, false, ScrollAlign::START, 100.f));
1476 EXPECT_TRUE(ScrollToIndex(2, false, ScrollAlign::START, 200.f));
1477 EXPECT_TRUE(ScrollToIndex(3, false, ScrollAlign::START, 200.f));
1478 EXPECT_TRUE(ScrollToIndex(4, false, ScrollAlign::START, 200.f));
1479 }
1480
1481 /**
1482 * @tc.name: ChildrenMainSize006
1483 * @tc.desc: Test childrenMainSize layout
1484 * @tc.type: FUNC
1485 */
1486 HWTEST_F(ListLayoutTestNg, ChildrenMainSize006, TestSize.Level1)
1487 {
1488 /**
1489 * @tc.steps: step1. Create list
1490 * @tc.expected: Default Size is 100
1491 */
1492 ListModelNG model = CreateList();
1493 auto childrenSize = model.GetOrCreateListChildrenMainSize();
1494 childrenSize->UpdateDefaultSize(ITEM_HEIGHT);
1495 childrenSize->ChangeData(2, 2, { -100.f, 200.f });
1496 CreateListItems(2);
1497 CreateItemWithSize(1, SizeT<Dimension>(FILL_LENGTH, Dimension(-100.f)));
1498 CreateItemWithSize(1, SizeT<Dimension>(FILL_LENGTH, Dimension(200.f)));
1499 CreateListItems(8);
1500 CreateDone(frameNode_);
1501 EXPECT_TRUE(ScrollToIndex(3, false, ScrollAlign::START, ITEM_HEIGHT));
1502 EXPECT_TRUE(ScrollToIndex(4, false, ScrollAlign::START, 300.f));
1503
1504 /**
1505 * @tc.steps: step2. insert data
1506 * @tc.expected: childrenSize_.size() == 10
1507 */
1508 ClearOldNodes();
1509 model = CreateList();
1510 childrenSize = model.GetOrCreateListChildrenMainSize();
1511 childrenSize->UpdateDefaultSize(ITEM_HEIGHT);
1512 childrenSize->ChangeData(8, 0, { 50.f, 200.f });
1513 CreateListItems(8);
1514 CreateItemWithSize(1, SizeT<Dimension>(FILL_LENGTH, Dimension(50.f)));
1515 CreateItemWithSize(1, SizeT<Dimension>(FILL_LENGTH, Dimension(200.f)));
1516 CreateDone(frameNode_);
1517 EXPECT_EQ(pattern_->childrenSize_->childrenSize_.size(), 10);
1518 EXPECT_TRUE(ScrollToIndex(8, false, ScrollAlign::END, 450.f));
1519 EXPECT_TRUE(ScrollToIndex(9, false, ScrollAlign::END, 650.f));
1520 }
1521
1522 /**
1523 * @tc.name: ListRepeatCacheCount001
1524 * @tc.desc: List cacheCount
1525 * @tc.type: FUNC
1526 */
1527 HWTEST_F(ListLayoutTestNg, ListRepeatCacheCount001, TestSize.Level1)
1528 {
1529 ListModelNG model = CreateList();
1530 ViewStackProcessor::GetInstance()->StartGetAccessRecordingFor(GetElmtId());
__anonc56bfe6a0402(int32_t idx) 1531 CreateRepeatVirtualScrollNode(10, [this](int32_t idx) {
1532 CreateListItem();
1533 ViewStackProcessor::GetInstance()->Pop();
1534 ViewStackProcessor::GetInstance()->StopGetAccessRecording();
1535 });
1536 CreateDone(frameNode_);
1537
1538 /**
1539 * @tc.steps: step1. Check Repeat frameCount
1540 */
1541 auto repeat = AceType::DynamicCast<RepeatVirtualScrollNode>(frameNode_->GetChildAtIndex(0));
1542 EXPECT_NE(repeat, nullptr);
1543 int32_t frameCount = repeat->FrameCount();
1544 EXPECT_EQ(frameCount, 10);
1545
1546 /**
1547 * @tc.steps: step2. Flush Idle Task
1548 * @tc.expected: ListItem 4 is cached
1549 */
1550 auto listPattern = frameNode_->GetPattern<ListPattern>();
1551 FlushIdleTask(listPattern);
1552 int32_t childrenCount = repeat->GetChildren().size();
1553 EXPECT_EQ(childrenCount, 5);
1554 auto cachedItem = frameNode_->GetChildByIndex(4)->GetHostNode();
1555 EXPECT_EQ(cachedItem->IsActive(), false);
1556 EXPECT_EQ(GetChildY(frameNode_, 4), LIST_HEIGHT);
1557
1558 /**
1559 * @tc.steps: step2. Flush Idle Task
1560 * @tc.expected: ListItem 1 and 7 is cached, ListItem 2,3,4,5,6 is active.
1561 */
1562 UpdateCurrentOffset(-250);
1563 FlushIdleTask(listPattern);
1564 childrenCount = repeat->GetChildren().size();
1565 EXPECT_EQ(childrenCount, 7);
1566 cachedItem = frameNode_->GetChildByIndex(1)->GetHostNode();
1567 EXPECT_EQ(cachedItem->IsActive(), false);
1568 cachedItem = frameNode_->GetChildByIndex(7)->GetHostNode();
1569 EXPECT_EQ(cachedItem->IsActive(), false);
1570 EXPECT_EQ(GetChildY(frameNode_, 1), -150.0f);
1571 EXPECT_EQ(GetChildY(frameNode_, 7), 450.0f);
1572 }
1573
1574 /**
1575 * @tc.name: ListRepeatCacheCount002
1576 * @tc.desc: List lanes cacheCount
1577 * @tc.type: FUNC
1578 */
1579 HWTEST_F(ListLayoutTestNg, ListRepeatCacheCount002, TestSize.Level1)
1580 {
1581 ListModelNG model = CreateList();
1582 model.SetLanes(2);
1583 ViewStackProcessor::GetInstance()->StartGetAccessRecordingFor(GetElmtId());
__anonc56bfe6a0502(int32_t idx) 1584 CreateRepeatVirtualScrollNode(20, [this](int32_t idx) {
1585 CreateListItem();
1586 ViewStackProcessor::GetInstance()->Pop();
1587 ViewStackProcessor::GetInstance()->StopGetAccessRecording();
1588 });
1589 CreateDone(frameNode_);
1590
1591 /**
1592 * @tc.steps: step1. Check Repeat frameCount
1593 */
1594 auto repeat = AceType::DynamicCast<RepeatVirtualScrollNode>(frameNode_->GetChildAtIndex(0));
1595 EXPECT_NE(repeat, nullptr);
1596 int32_t frameCount = repeat->FrameCount();
1597 EXPECT_EQ(frameCount, 20);
1598
1599 /**
1600 * @tc.steps: step2. Flush Idle Task
1601 * @tc.expected: ListItem 8,9 is cached
1602 */
1603 auto listPattern = frameNode_->GetPattern<ListPattern>();
1604 FlushIdleTask(listPattern);
1605 int32_t childrenCount = repeat->GetChildren().size();
1606 EXPECT_EQ(childrenCount, 10);
1607 auto item8 = frameNode_->GetChildByIndex(8)->GetHostNode();
1608 EXPECT_EQ(item8->IsActive(), false);
1609 EXPECT_EQ(GetChildX(frameNode_, 8), 0.0f);
1610 EXPECT_EQ(GetChildY(frameNode_, 8), LIST_HEIGHT);
1611 auto item9 = frameNode_->GetChildByIndex(9)->GetHostNode();
1612 EXPECT_EQ(item9->IsActive(), false);
1613 EXPECT_EQ(GetChildX(frameNode_, 9), LIST_WIDTH / 2);
1614 EXPECT_EQ(GetChildY(frameNode_, 9), LIST_HEIGHT);
1615
1616 /**
1617 * @tc.steps: step2. Flush Idle Task
1618 * @tc.expected: ListItem 2,3,14,15 is cached, ListItem 4-13 active.
1619 */
1620 UpdateCurrentOffset(-250);
1621 FlushIdleTask(listPattern);
1622 childrenCount = repeat->GetChildren().size();
1623 EXPECT_EQ(childrenCount, 14);
1624 auto item2 = frameNode_->GetChildByIndex(2)->GetHostNode();
1625 EXPECT_EQ(item2->IsActive(), false);
1626 EXPECT_EQ(GetChildX(frameNode_, 2), 0.0f);
1627 EXPECT_EQ(GetChildY(frameNode_, 2), -150.0f);
1628 auto item3 = frameNode_->GetChildByIndex(3)->GetHostNode();
1629 EXPECT_EQ(item3->IsActive(), false);
1630 EXPECT_EQ(GetChildX(frameNode_, 3), LIST_WIDTH / 2);
1631 EXPECT_EQ(GetChildY(frameNode_, 3), -150.0f);
1632 auto item14 = frameNode_->GetChildByIndex(14)->GetHostNode();
1633 EXPECT_EQ(item14->IsActive(), false);
1634 EXPECT_EQ(GetChildX(frameNode_, 14), 0.0f);
1635 EXPECT_EQ(GetChildY(frameNode_, 14), 450.0f);
1636 auto item15 = frameNode_->GetChildByIndex(15)->GetHostNode();
1637 EXPECT_EQ(item15->IsActive(), false);
1638 EXPECT_EQ(GetChildX(frameNode_, 15), LIST_WIDTH / 2);
1639 EXPECT_EQ(GetChildY(frameNode_, 15), 450.0f);
1640 }
1641
1642 /**
1643 * @tc.name: SetHeaderFooterComponent01
1644 * @tc.desc: Test HeaderComponent/FooterComponent of ListItemGroup
1645 * @tc.type: FUNC
1646 */
1647 HWTEST_F(ListLayoutTestNg, SetHeaderFooterComponent01, TestSize.Level1)
1648 {
1649 /**
1650 * @tc.steps: step1. create List group with ComponentContent
1651 */
1652 const int32_t groupNumber = 5;
1653 const float contentStartOffset = 100;
1654 const float contentEndOffset = 50;
1655 ListModelNG model = CreateList();
1656 model.SetContentStartOffset(contentStartOffset);
1657 model.SetContentEndOffset(contentEndOffset);
1658 model.SetSticky(V2::StickyStyle::BOTH);
1659 CreateGroupWithSettingWithComponentContent(groupNumber, V2::ListItemGroupStyle::NONE);
1660 CreateDone(frameNode_);
1661
1662 /**
1663 * @tc.steps: step2. Get the count of group
1664 * @tc.expected: header and footer can be added successfully.
1665 */
1666 auto group0 = GetChildFrameNode(frameNode_, 0);
1667 auto group1 = GetChildFrameNode(frameNode_, 1);
1668 auto group0Children = group0->GetChildren();
1669 auto group1Children = group1->GetChildren();
1670 auto group0Pattern = group0->GetPattern<ListItemGroupPattern>();
1671 EXPECT_EQ(group0Children.size(), 4);
1672 EXPECT_EQ(group1Children.size(), 4);
1673
1674 /**
1675 * @tc.steps: step3. Update header and footer
1676 * @tc.expected: new header and footer can be set.
1677 */
1678 bool headerResult = false;
1679 bool footerResult = false;
1680 group0Pattern->AddHeader(CreateCustomNode("NewHeader"));
1681 group0Pattern->AddFooter(CreateCustomNode("NewFooter"));
1682 const char newFooter[] = "NewFooter";
1683 const char newHeader[] = "NewHeader";
1684 auto children = group0->GetChildren();
1685 for (auto child : children) {
1686 auto childFrameNode = AceType::DynamicCast<FrameNode>(child);
1687 if (childFrameNode->GetTag() == newHeader) {
1688 headerResult = true;
1689 }
1690 if (childFrameNode->GetTag() == newFooter) {
1691 footerResult = true;
1692 }
1693 }
1694 EXPECT_TRUE(headerResult);
1695 EXPECT_TRUE(footerResult);
1696
1697 /**
1698 * @tc.steps: step4. Remove group0 header and footer
1699 * @tc.expected: header and footer can be removed successfully.
1700 */
1701 group0Pattern->RemoveHeader();
1702 group0Pattern->RemoveFooter();
1703 group0Children = group0->GetChildren();
1704 EXPECT_EQ(group0Children.size(), 2);
1705 }
1706 } // namespace OHOS::Ace::NG
1707