1 /*
2  * Copyright (c) 2022-2023 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 
20 #include "base/geometry/ng/size_t.h"
21 #include "core/components/common/properties/color.h"
22 #include "core/components_ng/base/view_stack_processor.h"
23 #include "core/components_ng/pattern/divider/divider_layout_algorithm.h"
24 #include "core/components_ng/pattern/divider/divider_layout_property.h"
25 #include "core/components_ng/pattern/divider/divider_model_ng.h"
26 #include "core/components_ng/pattern/divider/divider_pattern.h"
27 #include "core/components_ng/pattern/divider/divider_render_property.h"
28 #include "test/mock/core/rosen/mock_canvas.h"
29 #include "test/mock/core/common/mock_theme_manager.h"
30 #include "test/mock/core/pipeline/mock_pipeline_context.h"
31 
32 using namespace testing;
33 using namespace testing::ext;
34 
35 namespace OHOS::Ace::NG {
36 struct TestProperty {
37     std::optional<bool> vertical = std::nullopt;
38     std::optional<Color> dividerColor = std::nullopt;
39     std::optional<Dimension> strokeWidth = std::nullopt;
40     std::optional<Ace::LineCap> lineCap = std::nullopt;
41 };
42 namespace {
43 const bool VERTICAL_TRUE = true;
44 const bool VERTICAL_FALSE = false;
45 const Color DIVIDER_COLOR = Color(0xff000000);
46 const Dimension STROKE_WIDTH = Dimension(1.0);
47 const Ace::LineCap LINE_CAP = Ace::LineCap::BUTT;
48 const OptionalSize<float> SELF_IDEAL_SIZE = OptionalSize<float>(100.0f, 100.0f);
49 const SizeT<float> MAX_SIZE = SizeT<float>(1000.0f, 1000.0f);
50 TestProperty testProperty;
51 DirtySwapConfig config;
52 } // namespace
53 
54 class DividerTestNg : public testing::Test {
55 public:
56     static void SetUpTestCase();
57     static void TearDownTestCase();
58 
59 protected:
60     static RefPtr<FrameNode> CreateDividerNode(TestProperty& testProperty);
61 };
62 
SetUpTestCase()63 void DividerTestNg::SetUpTestCase()
64 {
65     MockPipelineContext::SetUp();
66     testProperty.vertical = VERTICAL_TRUE;
67     testProperty.dividerColor = DIVIDER_COLOR;
68     testProperty.strokeWidth = STROKE_WIDTH;
69     testProperty.lineCap = LINE_CAP;
70 }
71 
TearDownTestCase()72 void DividerTestNg::TearDownTestCase()
73 {
74     MockPipelineContext::TearDown();
75 }
76 
CreateDividerNode(TestProperty & testProperty)77 RefPtr<FrameNode> DividerTestNg::CreateDividerNode(TestProperty& testProperty)
78 {
79     DividerModelNG().Create();
80     if (testProperty.vertical.has_value()) {
81         DividerModelNG().Vertical(testProperty.vertical.value());
82     }
83     if (testProperty.dividerColor.has_value()) {
84         DividerModelNG().DividerColor(testProperty.dividerColor.value());
85     }
86     if (testProperty.strokeWidth.has_value()) {
87         DividerModelNG().StrokeWidth(testProperty.strokeWidth.value());
88     }
89     if (testProperty.lineCap.has_value()) {
90         DividerModelNG().LineCap(testProperty.lineCap.value());
91     }
92 
93     RefPtr<UINode> element = ViewStackProcessor::GetInstance()->Finish(); // TextView pop
94     return AceType::DynamicCast<FrameNode>(element);
95 }
96 
97 /**
98  * @tc.name: DividerFrameNodeCreator001
99  * @tc.desc: Test all the property of divider.
100  * @tc.type: FUNC
101  */
102 HWTEST_F(DividerTestNg, DividerPatternTest001, TestSize.Level1)
103 {
104     /**
105      * @tc.steps: step1. create frameNode
106      * @tc.expected: step1. create frameNode success
107      */
108     RefPtr<FrameNode> frameNode = CreateDividerNode(testProperty);
109     EXPECT_NE(frameNode, nullptr);
110 
111     /**
112      * @tc.steps: step2. create divider layout and paint property
113      * @tc.expected: step2. create property success
114      */
115     RefPtr<DividerLayoutProperty> layoutProperty = frameNode->GetLayoutProperty<DividerLayoutProperty>();
116     EXPECT_NE(layoutProperty, nullptr);
117     EXPECT_EQ(layoutProperty->GetVerticalValue(), VERTICAL_TRUE);
118     EXPECT_EQ(layoutProperty->GetStrokeWidthValue(), STROKE_WIDTH);
119     RefPtr<DividerRenderProperty> paintProperty = frameNode->GetPaintProperty<DividerRenderProperty>();
120     EXPECT_EQ(paintProperty->GetDividerColorValue(), DIVIDER_COLOR);
121     EXPECT_EQ(paintProperty->GetLineCapValue(), LINE_CAP);
122 }
123 
124 /**
125  * @tc.name: DividerFrameNodeCreator002
126  * @tc.desc: Test all the layoutAlgorithm of divider
127  * @tc.type: FUNC
128  */
129 HWTEST_F(DividerTestNg, DividerPatternTest002, TestSize.Level1)
130 {
131     bool vertical[2] = { VERTICAL_TRUE, VERTICAL_FALSE };
132     testProperty.strokeWidth = STROKE_WIDTH;
133     LayoutConstraintF layoutConstraintF;
134     layoutConstraintF.selfIdealSize = SELF_IDEAL_SIZE;
135     layoutConstraintF.maxSize = MAX_SIZE;
136     RefPtr<DividerLayoutAlgorithm> dividerLayoutAlgorithm = AceType::MakeRefPtr<DividerLayoutAlgorithm>();
137     /**
138      * @tc.steps: step1. layout algorithm measureContent method about vertical
139      * @tc.expected: step1. vertical is false or true, the constrainSize is (1.0, 100.0)
140      */
141     for (int32_t i = 0; i < 2; ++i) {
142         testProperty.vertical = vertical[i];
143         RefPtr<FrameNode> frameNode = CreateDividerNode(testProperty);
144         EXPECT_NE(frameNode, nullptr);
145         RefPtr<GeometryNode> geometryNode = AceType::MakeRefPtr<GeometryNode>();
146         EXPECT_NE(geometryNode, nullptr);
147         RefPtr<DividerLayoutProperty> layoutProperty = frameNode->GetLayoutProperty<DividerLayoutProperty>();
148         EXPECT_NE(layoutProperty, nullptr);
149         LayoutWrapperNode layoutWrapper = LayoutWrapperNode(frameNode, geometryNode, layoutProperty);
150         dividerLayoutAlgorithm->MeasureContent(layoutConstraintF, &layoutWrapper);
151     }
152     /**
153      * @tc.steps: step2. layout algorithm test
154      * @tc.expected: step2. constrainStrokeWidth is 1.0f, dividerLength is 100.0f, and vertical is false
155      */
156     EXPECT_EQ(dividerLayoutAlgorithm->GetVertical(), VERTICAL_FALSE);
157 }
158 
159 /**
160  * @tc.name: DividerFrameNodeCreator002
161  * @tc.desc: Test all the pattern of divider
162  * @tc.type: FUNC
163  */
164 HWTEST_F(DividerTestNg, DividerPatternTest003, TestSize.Level1)
165 {
166     RefPtr<DividerLayoutAlgorithm> dividerLayoutAlgorithm = AceType::MakeRefPtr<DividerLayoutAlgorithm>();
167     RefPtr<FrameNode> frameNode = CreateDividerNode(testProperty);
168     EXPECT_NE(frameNode, nullptr);
169     RefPtr<GeometryNode> geometryNode = AceType::MakeRefPtr<GeometryNode>();
170     EXPECT_NE(geometryNode, nullptr);
171     RefPtr<DividerLayoutProperty> layoutProperty = frameNode->GetLayoutProperty<DividerLayoutProperty>();
172     EXPECT_NE(layoutProperty, nullptr);
173     auto layoutWrapper = AceType::MakeRefPtr<LayoutWrapperNode>(frameNode, geometryNode, layoutProperty);
174     EXPECT_NE(layoutWrapper, nullptr);
175     bool skipMeasures[2] = { false, true };
176     bool isSwaps[4] = { true, false, false, false };
177     /**
178      * @tc.steps: step1. OnDirtyLayoutWrapperSwap test
179      * @tc.expected: step1. adjust skipMeasure and config, OnDirtyLayoutWrapperSwap return true, false
180      */
181     int k = 0;
182     for (int i = 0; i < 2; ++i) {
183         config.skipMeasure = skipMeasures[i];
184         for (int j = 0; j < 2; ++j) {
185             auto layoutAlgorithmWrapper =
186                 AceType::MakeRefPtr<LayoutAlgorithmWrapper>(dividerLayoutAlgorithm, skipMeasures[j]);
187             layoutWrapper->SetLayoutAlgorithm(layoutAlgorithmWrapper);
188             layoutWrapper->skipMeasureContent_ = skipMeasures[j];
189             auto pattern = frameNode->GetPattern<DividerPattern>();
190             EXPECT_NE(pattern, nullptr);
191             auto isSwap = pattern->OnDirtyLayoutWrapperSwap(layoutWrapper, config);
192             EXPECT_EQ(isSwap, isSwaps[k]);
193             k++;
194         }
195     }
196 }
197 
198 /**
199  * @tc.name: DividerModifier
200  * @tc.desc: Test the dynamic effect of the Divider
201  * @tc.type: FUNC
202  */
203 HWTEST_F(DividerTestNg, DividerModifierTest001, TestSize.Level1)
204 {
205     DividerModifier dividerModifier;
206     Testing::MockCanvas rsCanvas;
207     EXPECT_CALL(rsCanvas, AttachPen(_)).WillOnce(ReturnRef(rsCanvas));
208     EXPECT_CALL(rsCanvas, DetachPen()).WillRepeatedly(ReturnRef(rsCanvas));
209     DrawingContext context = { rsCanvas, 10.0f, 10.0f };
210     dividerModifier.onDraw(context);
211 }
212 
213 /**
214  * @tc.name: DivideAlgorithmTest001
215  * @tc.desc: Test layoutAlgorithm of divider with testProperty.vertical = VERTICAL_TRUE
216  * @tc.type: FUNC
217  */
218 HWTEST_F(DividerTestNg, DivideAlgorithmTest001, TestSize.Level1)
219 {
220     testProperty.strokeWidth = STROKE_WIDTH;
221     testProperty.vertical = VERTICAL_TRUE;
222     LayoutConstraintF layoutConstraintF;
223     layoutConstraintF.selfIdealSize = SELF_IDEAL_SIZE;
224     layoutConstraintF.maxSize = MAX_SIZE;
225     RefPtr<DividerLayoutAlgorithm> dividerLayoutAlgorithm = AceType::MakeRefPtr<DividerLayoutAlgorithm>();
226     auto themeManager = AceType::MakeRefPtr<MockThemeManager>();
227     MockPipelineContext::GetCurrent()->SetThemeManager(themeManager);
228     EXPECT_CALL(*themeManager, GetTheme(_)).WillOnce(Return(AceType::MakeRefPtr<DividerTheme>()));
229 
230     RefPtr<FrameNode> frameNode = CreateDividerNode(testProperty);
231     EXPECT_NE(frameNode, nullptr);
232     RefPtr<GeometryNode> geometryNode = AceType::MakeRefPtr<GeometryNode>();
233     EXPECT_NE(geometryNode, nullptr);
234     RefPtr<DividerLayoutProperty> layoutProperty = frameNode->GetLayoutProperty<DividerLayoutProperty>();
235     EXPECT_NE(layoutProperty, nullptr);
236     LayoutWrapperNode layoutWrapper = LayoutWrapperNode(frameNode, geometryNode, layoutProperty);
237     dividerLayoutAlgorithm->MeasureContent(layoutConstraintF, &layoutWrapper);
238     EXPECT_EQ(dividerLayoutAlgorithm->GetVertical(), testProperty.vertical);
239     EXPECT_EQ(dividerLayoutAlgorithm->GetConstrainStrokeWidth(), 1.0);
240     EXPECT_EQ(dividerLayoutAlgorithm->GetDividerLength(), 100.0f);
241 }
242 
243 /**
244  * @tc.name: DivideAlgorithmTest002
245  * @tc.desc: Test layoutAlgorithm of divider with testProperty.vertical = VERTICAL_FALSE
246  * @tc.type: FUNC
247  */
248 HWTEST_F(DividerTestNg, DivideAlgorithmTest002, TestSize.Level1)
249 {
250     testProperty.strokeWidth = STROKE_WIDTH;
251     testProperty.vertical = VERTICAL_FALSE;
252     LayoutConstraintF layoutConstraintF;
253     layoutConstraintF.selfIdealSize = SELF_IDEAL_SIZE;
254     layoutConstraintF.maxSize = MAX_SIZE;
255     RefPtr<DividerLayoutAlgorithm> dividerLayoutAlgorithm = AceType::MakeRefPtr<DividerLayoutAlgorithm>();
256     auto themeManager = AceType::MakeRefPtr<MockThemeManager>();
257     MockPipelineContext::GetCurrent()->SetThemeManager(themeManager);
258     EXPECT_CALL(*themeManager, GetTheme(_)).WillOnce(Return(AceType::MakeRefPtr<DividerTheme>()));
259 
260     RefPtr<FrameNode> frameNode = CreateDividerNode(testProperty);
261     EXPECT_NE(frameNode, nullptr);
262     RefPtr<GeometryNode> geometryNode = AceType::MakeRefPtr<GeometryNode>();
263     EXPECT_NE(geometryNode, nullptr);
264     RefPtr<DividerLayoutProperty> layoutProperty = frameNode->GetLayoutProperty<DividerLayoutProperty>();
265     EXPECT_NE(layoutProperty, nullptr);
266     LayoutWrapperNode layoutWrapper = LayoutWrapperNode(frameNode, geometryNode, layoutProperty);
267     dividerLayoutAlgorithm->MeasureContent(layoutConstraintF, &layoutWrapper);
268     EXPECT_EQ(dividerLayoutAlgorithm->GetVertical(), testProperty.vertical);
269 }
270 
271 /**
272  * @tc.name: DivideAlgorithmTest003
273  * @tc.desc: Test layoutAlgorithm of divider with testProperty.vertical = VERTICAL_FALSE and no selfIdealSize
274  * @tc.type: FUNC
275  */
276 HWTEST_F(DividerTestNg, DivideAlgorithmTest003, TestSize.Level1)
277 {
278     testProperty.strokeWidth = STROKE_WIDTH;
279     testProperty.vertical = VERTICAL_FALSE;
280     LayoutConstraintF layoutConstraintF;
281     layoutConstraintF.maxSize = MAX_SIZE;
282     RefPtr<DividerLayoutAlgorithm> dividerLayoutAlgorithm = AceType::MakeRefPtr<DividerLayoutAlgorithm>();
283     auto themeManager = AceType::MakeRefPtr<MockThemeManager>();
284     MockPipelineContext::GetCurrent()->SetThemeManager(themeManager);
285     EXPECT_CALL(*themeManager, GetTheme(_)).WillOnce(Return(AceType::MakeRefPtr<DividerTheme>()));
286 
287     RefPtr<FrameNode> frameNode = CreateDividerNode(testProperty);
288     EXPECT_NE(frameNode, nullptr);
289     RefPtr<GeometryNode> geometryNode = AceType::MakeRefPtr<GeometryNode>();
290     EXPECT_NE(geometryNode, nullptr);
291     RefPtr<DividerLayoutProperty> layoutProperty = frameNode->GetLayoutProperty<DividerLayoutProperty>();
292     EXPECT_NE(layoutProperty, nullptr);
293     LayoutWrapperNode layoutWrapper = LayoutWrapperNode(frameNode, geometryNode, layoutProperty);
294     dividerLayoutAlgorithm->MeasureContent(layoutConstraintF, &layoutWrapper);
295     EXPECT_EQ(dividerLayoutAlgorithm->GetVertical(), testProperty.vertical);
296 }
297 
298 /**
299  * @tc.name: DivideAlgorithmTest004
300  * @tc.desc: Test layoutAlgorithm of divider with testProperty.vertical = VERTICAL_TRUE and no selfIdealSize
301  * @tc.type: FUNC
302  */
303 HWTEST_F(DividerTestNg, DivideAlgorithmTest004, TestSize.Level1)
304 {
305     testProperty.strokeWidth = STROKE_WIDTH;
306     testProperty.vertical = VERTICAL_TRUE;
307     LayoutConstraintF layoutConstraintF;
308     layoutConstraintF.maxSize = MAX_SIZE;
309     RefPtr<DividerLayoutAlgorithm> dividerLayoutAlgorithm = AceType::MakeRefPtr<DividerLayoutAlgorithm>();
310     auto themeManager = AceType::MakeRefPtr<MockThemeManager>();
311     MockPipelineContext::GetCurrent()->SetThemeManager(themeManager);
312     EXPECT_CALL(*themeManager, GetTheme(_)).WillOnce(Return(AceType::MakeRefPtr<DividerTheme>()));
313 
314     RefPtr<FrameNode> frameNode = CreateDividerNode(testProperty);
315     EXPECT_NE(frameNode, nullptr);
316     RefPtr<GeometryNode> geometryNode = AceType::MakeRefPtr<GeometryNode>();
317     EXPECT_NE(geometryNode, nullptr);
318     RefPtr<DividerLayoutProperty> layoutProperty = frameNode->GetLayoutProperty<DividerLayoutProperty>();
319     EXPECT_NE(layoutProperty, nullptr);
320     LayoutWrapperNode layoutWrapper = LayoutWrapperNode(frameNode, geometryNode, layoutProperty);
321     dividerLayoutAlgorithm->MeasureContent(layoutConstraintF, &layoutWrapper);
322     EXPECT_EQ(dividerLayoutAlgorithm->GetVertical(), testProperty.vertical);
323 }
324 } // namespace OHOS::Ace::NG
325