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