1 /* 2 * Copyright (c) 2025 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 #include <gmock/gmock-matchers.h> 16 #include <gtest/gtest.h> 17 18 #include <meta/api/animation.h> 19 #include <meta/interface/animation/intf_animation_controller.h> 20 #include <meta/interface/property/construct_property.h> 21 #include <meta/interface/property/property.h> 22 23 #include "TestRunner.h" 24 #include "helpers/animation_test_base.h" 25 #include "helpers/serialisation_utils.h" 26 #include "helpers/testing_objects.h" 27 28 using namespace testing; 29 using namespace testing::ext; 30 31 META_BEGIN_NAMESPACE() 32 33 class AnimationTest : public AnimationTestBase { 34 protected: SetUpTestSuite()35 static void SetUpTestSuite() 36 { 37 SetTest(); 38 } TearDownTestSuite()39 static void TearDownTestSuite() 40 { 41 TearDownTest(); 42 } CreateAnimation(const META_NS::ClassInfo & classId)43 IPropertyAnimation::Ptr CreateAnimation(const META_NS::ClassInfo& classId) 44 { 45 auto pani = GetObjectRegistry().Create<IPropertyAnimation>(classId); 46 if (auto ani = interface_cast<IAnimation>(pani)) { 47 ani->OnStarted()->AddHandler(MakeCallback<IOnChanged>([this]() { startedCalled_++; })); 48 ani->OnFinished()->AddHandler(MakeCallback<IOnChanged>([this]() { finishedCalled_++; })); 49 } 50 return pani; 51 } 52 GetStartedCalledCount() const53 auto GetStartedCalledCount() const 54 { 55 return startedCalled_; 56 } GetFinishedCalledCount() const57 auto GetFinishedCalledCount() const 58 { 59 return finishedCalled_; 60 } 61 62 private: 63 size_t startedCalled_ {}; 64 size_t finishedCalled_ {}; 65 }; 66 67 HWTEST_F(AnimationTest, KeyframeAnimation, TestSize.Level1) 68 { 69 auto p = ConstructProperty<int>("test"); 70 auto pani = CreateAnimation(ClassId::KeyframeAnimation); 71 ASSERT_TRUE(pani); 72 auto pp = pani->Property(); 73 ASSERT_TRUE(pp); 74 pp->SetValue(p); 75 76 auto ani = interface_pointer_cast<IKeyframeAnimation>(pani); 77 ASSERT_TRUE(ani); 78 ani->From()->SetValue(IAny::Ptr(new Any<int>(0))); 79 ani->To()->SetValue(IAny::Ptr(new Any<int>(10))); 80 ani->Duration()->SetValue(TimeSpan::Milliseconds(100)); 81 82 auto st = interface_pointer_cast<IStartableAnimation>(pani); 83 84 st->Start(); 85 86 EXPECT_EQ(GetStartedCalledCount(), 1); 87 EXPECT_EQ(GetFinishedCalledCount(), 0); 88 89 EXPECT_TRUE(ani->Running()->GetValue()); 90 __anon50d39ff20302(uint32_t frame) 91 this->RunFrames(11, [&](uint32_t frame) { 92 auto f = frame - 1; 93 EXPECT_EQ(f, p->GetValue()); 94 EXPECT_EQ(ani->Running()->GetValue(), f < 10); 95 EXPECT_FLOAT_EQ(ani->Progress()->GetValue(), f / 10.f); 96 }); 97 98 EXPECT_FALSE(ani->Running()->GetValue()); 99 100 EXPECT_EQ(GetStartedCalledCount(), 1); 101 EXPECT_EQ(GetFinishedCalledCount(), 1); 102 } 103 104 HWTEST_F(AnimationTest, KeyframeAnimationSerialization, TestSize.Level1) 105 { 106 TestSerialiser ser; 107 { 108 auto p = ConstructProperty<int>("test"); 109 auto pani = CreateAnimation(ClassId::KeyframeAnimation); 110 ASSERT_TRUE(pani); 111 auto pp = pani->Property(); 112 ASSERT_TRUE(pp); 113 pp->SetValue(p); 114 115 auto ani = interface_pointer_cast<IKeyframeAnimation>(pani); 116 ASSERT_TRUE(ani); 117 ani->From()->SetValue(IAny::Ptr(new Any<int>(0))); 118 ani->To()->SetValue(IAny::Ptr(new Any<int>(10))); 119 ani->Duration()->SetValue(TimeSpan::Milliseconds(100)); 120 121 Object obj(CreateInstance(ClassId::Object)); 122 Metadata(obj).AddProperty(p); 123 AttachmentContainer(obj).Attach(pani); 124 ASSERT_TRUE(ser.Export(obj)); 125 ser.Dump("app://test.json"); 126 } 127 128 auto obj = ser.Import<IMetadata>(); 129 ASSERT_TRUE(obj); 130 auto p = obj->GetProperty<int>("test"); 131 ASSERT_TRUE(p); 132 133 auto att = interface_cast<IAttach>(obj); 134 ASSERT_TRUE(att); 135 auto attvec = att->GetAttachments<IKeyframeAnimation>(); 136 ASSERT_EQ(attvec.size(), 1); 137 138 auto pani = interface_pointer_cast<IPropertyAnimation>(attvec.front()); 139 auto st = interface_pointer_cast<IStartableAnimation>(pani); 140 auto ani = interface_pointer_cast<IKeyframeAnimation>(pani); 141 ASSERT_TRUE(ani); 142 ASSERT_EQ(pani->Property()->GetValue().lock(), p.GetProperty()); 143 ASSERT_TRUE(ani->Valid()->GetValue()); 144 145 st->Start(); 146 147 EXPECT_TRUE(ani->Running()->GetValue()); 148 __anon50d39ff20402(uint32_t frame) 149 this->RunFrames(11, [&](uint32_t frame) { 150 auto f = frame - 1; 151 EXPECT_EQ(f, p->GetValue()); 152 EXPECT_EQ(ani->Running()->GetValue(), f < 10); 153 EXPECT_FLOAT_EQ(ani->Progress()->GetValue(), f / 10.f); 154 }); 155 156 EXPECT_FALSE(ani->Running()->GetValue()); 157 } 158 159 HWTEST_F(AnimationTest, ImplicitAnimation, TestSize.Level1) 160 { 161 auto p = ConstructProperty<int>("test"); 162 auto pani = CreateAnimation(ClassId::PropertyAnimation); 163 auto ani = interface_pointer_cast<ITimedAnimation>(pani); 164 ASSERT_TRUE(ani && pani); 165 166 EXPECT_TRUE(p->SetValue(10)); 167 EXPECT_EQ(p->GetValue(), 10); 168 169 EXPECT_TRUE(p->SetValue(0)); 170 EXPECT_EQ(p->GetValue(), 0); 171 172 EXPECT_TRUE(pani->Property()->SetValue(p)); 173 EXPECT_TRUE(ani->Duration()->SetValue(TimeSpan::Milliseconds(100))); 174 175 EXPECT_EQ(p->GetValue(), 0); 176 177 // Set the value, it should not immediately change but rather start animating as we 178 // run some frames 179 EXPECT_TRUE(p->SetValue(10)); 180 181 EXPECT_TRUE(ani->Running()->GetValue()); 182 EXPECT_EQ(p->GetValue(), 0); 183 EXPECT_EQ(GetStartedCalledCount(), 1); 184 EXPECT_EQ(GetFinishedCalledCount(), 0); 185 186 // Check that property value changes to target gradually __anon50d39ff20502(uint32_t frame) 187 this->RunFrames(11, [&](uint32_t frame) { 188 auto f = frame - 1; 189 EXPECT_EQ(f, p->GetValue()); 190 EXPECT_EQ(ani->Running()->GetValue(), f < 10); 191 EXPECT_FLOAT_EQ(ani->Progress()->GetValue(), f / 10.f); 192 }); 193 194 EXPECT_EQ(GetStartedCalledCount(), 1); 195 EXPECT_EQ(GetFinishedCalledCount(), 1); 196 197 EXPECT_FALSE(ani->Running()->GetValue()); 198 EXPECT_EQ(p->GetValue(), 10); 199 200 // Change the value again and verify that it still changes gradually 201 EXPECT_TRUE(p->SetValue(0)); 202 EXPECT_TRUE(ani->Running()->GetValue()); 203 EXPECT_EQ(p->GetValue(), 10); 204 205 EXPECT_EQ(GetStartedCalledCount(), 2); 206 EXPECT_EQ(GetFinishedCalledCount(), 1); 207 __anon50d39ff20602(uint32_t frame) 208 this->RunFrames(11, [&](uint32_t frame) { 209 auto f = frame - 1; 210 EXPECT_FLOAT_EQ(11 - frame, p->GetValue()) << "Frame: " << frame; 211 EXPECT_EQ(ani->Running()->GetValue(), f < 10) << "Frame: " << frame; 212 EXPECT_FLOAT_EQ(ani->Progress()->GetValue(), f / 10.f) << "Frame: " << frame; 213 }); 214 215 EXPECT_FALSE(ani->Running()->GetValue()); 216 EXPECT_EQ(p->GetValue(), 0); 217 218 EXPECT_EQ(GetStartedCalledCount(), 2); 219 EXPECT_EQ(GetFinishedCalledCount(), 2); 220 221 // Remove target property, now any changes to property value should be immediate 222 pani->Property()->SetValue({}); 223 224 EXPECT_TRUE(p->SetValue(10)); 225 EXPECT_FALSE(ani->Running()->GetValue()); 226 EXPECT_EQ(p->GetValue(), 10); 227 228 EXPECT_EQ(GetStartedCalledCount(), 2); 229 EXPECT_EQ(GetFinishedCalledCount(), 2); 230 } 231 232 HWTEST_F(AnimationTest, ImplicitAnimationNoEvaluate, TestSize.Level1) 233 { 234 auto p = ConstructProperty<int>("test"); 235 auto pani = CreateAnimation(ClassId::PropertyAnimation); 236 auto ani = interface_pointer_cast<ITimedAnimation>(pani); 237 ASSERT_TRUE(ani && pani); 238 239 EXPECT_TRUE(pani->Property()->SetValue(p)); 240 EXPECT_TRUE(ani->Duration()->SetValue(TimeSpan::Milliseconds(100))); 241 242 // Set the value, it should not immediately change but rather start animating as we 243 // run some frames 244 EXPECT_TRUE(p->SetValue(10)); 245 246 EXPECT_TRUE(ani->Running()->GetValue()); 247 __anon50d39ff20702(uint32_t frame) 248 this->RunFrames(11, [&](uint32_t frame) { 249 auto f = frame - 1; 250 EXPECT_EQ(ani->Running()->GetValue(), f < 10); 251 EXPECT_FLOAT_EQ(ani->Progress()->GetValue(), f / 10.f); 252 }); 253 254 EXPECT_TRUE(p->SetValue(0)); 255 EXPECT_EQ(p->GetValue(), 10); 256 } 257 258 HWTEST_F(AnimationTest, ImplicitAnimationSerialization, TestSize.Level1) 259 { 260 TestSerialiser ser; 261 { 262 auto p = ConstructProperty<int>("test"); 263 auto pani = CreateAnimation(ClassId::PropertyAnimation); 264 auto ani = interface_pointer_cast<ITimedAnimation>(pani); 265 ASSERT_TRUE(ani && pani); 266 267 EXPECT_TRUE(pani->Property()->SetValue(p)); 268 EXPECT_TRUE(ani->Duration()->SetValue(TimeSpan::Milliseconds(100))); 269 270 Object obj(CreateInstance(ClassId::Object)); 271 Metadata(obj).AddProperty(p); 272 ASSERT_TRUE(ser.Export(obj)); 273 ser.Dump("app://test.json"); 274 } 275 276 auto obj = ser.Import<IMetadata>(); 277 ASSERT_TRUE(obj); 278 auto p = obj->GetProperty<int>("test"); 279 ASSERT_TRUE(p); 280 281 auto vec = p->GetModifiers<ITimedAnimation>(); 282 ASSERT_EQ(vec.size(), 1); 283 auto ani = vec.front(); 284 ASSERT_TRUE(ani); 285 auto pani = interface_pointer_cast<IPropertyAnimation>(ani); 286 ASSERT_TRUE(pani); 287 288 EXPECT_EQ(ani->Duration()->GetValue(), TimeSpan::Milliseconds(100)); 289 EXPECT_EQ(pani->Property()->GetValue().lock(), p.GetProperty()); 290 291 // Set the value, it should not immediately change but rather start animating as we 292 // run some frames 293 EXPECT_TRUE(p->SetValue(10)); 294 295 EXPECT_TRUE(ani->Running()->GetValue()); 296 EXPECT_EQ(p->GetValue(), 0); 297 298 // Check that property value changes to target gradually __anon50d39ff20802(uint32_t frame) 299 this->RunFrames(11, [&](uint32_t frame) { 300 auto f = frame - 1; 301 EXPECT_EQ(f, p->GetValue()); 302 EXPECT_EQ(ani->Running()->GetValue(), f < 10); 303 EXPECT_FLOAT_EQ(ani->Progress()->GetValue(), f / 10.f); 304 }); 305 306 EXPECT_FALSE(ani->Running()->GetValue()); 307 EXPECT_EQ(p->GetValue(), 10); 308 } 309 310 HWTEST_F(AnimationTest, ImplicitAnimationSerializationWithAttachment, TestSize.Level1) 311 { 312 TestSerialiser ser; 313 { 314 auto p = ConstructProperty<int>("test"); 315 auto pani = CreateAnimation(ClassId::PropertyAnimation); 316 auto ani = interface_pointer_cast<ITimedAnimation>(pani); 317 ASSERT_TRUE(ani && pani); 318 319 EXPECT_TRUE(pani->Property()->SetValue(p)); 320 EXPECT_TRUE(ani->Duration()->SetValue(TimeSpan::Milliseconds(100))); 321 322 Object obj(CreateInstance(ClassId::Object)); 323 Metadata(obj).AddProperty(p); 324 AttachmentContainer(obj).Attach(interface_pointer_cast<IAttachment>(pani)); 325 ASSERT_TRUE(ser.Export(obj)); 326 ser.Dump("file://./test.json"); 327 } 328 329 auto obj = ser.Import<IMetadata>(); 330 ASSERT_TRUE(obj); 331 auto p = obj->GetProperty<int>("test"); 332 ASSERT_TRUE(p); 333 334 auto att = interface_cast<IAttach>(obj); 335 ASSERT_TRUE(att); 336 auto attvec = att->GetAttachments<IPropertyAnimation>(); 337 EXPECT_EQ(attvec.size(), 1); 338 339 auto vec = p->GetModifiers<ITimedAnimation>(); 340 ASSERT_EQ(vec.size(), 1); 341 auto ani = vec.front(); 342 ASSERT_TRUE(ani); 343 auto pani = interface_pointer_cast<IPropertyAnimation>(ani); 344 ASSERT_TRUE(pani); 345 346 EXPECT_EQ(ani->Duration()->GetValue(), TimeSpan::Milliseconds(100)); 347 EXPECT_EQ(pani->Property()->GetValue().lock(), p.GetProperty()); 348 349 // Set the value, it should not immediately change but rather start animating as we 350 // run some frames 351 EXPECT_TRUE(p->SetValue(10)); 352 353 EXPECT_TRUE(ani->Running()->GetValue()); 354 EXPECT_EQ(p->GetValue(), 0); 355 356 // Check that property value changes to target gradually __anon50d39ff20902(uint32_t frame) 357 this->RunFrames(11, [&](uint32_t frame) { 358 auto f = frame - 1; 359 EXPECT_EQ(f, p->GetValue()); 360 EXPECT_EQ(ani->Running()->GetValue(), f < 10); 361 EXPECT_FLOAT_EQ(ani->Progress()->GetValue(), f / 10.f); 362 }); 363 364 EXPECT_FALSE(ani->Running()->GetValue()); 365 EXPECT_EQ(p->GetValue(), 10); 366 } 367 368 /** 369 * @tc.name: ImplicitAnimationOnChanged 370 * @tc.desc: test ImplicitAnimationOnChanged 371 * @tc.type: FUNC 372 */ 373 HWTEST_F(AnimationTest, ImplicitAnimationOnChanged, TestSize.Level1) 374 { 375 auto p = ConstructProperty<int>("test"); 376 auto pani = CreateAnimation(ClassId::PropertyAnimation); 377 auto ani = interface_pointer_cast<ITimedAnimation>(pani); 378 ASSERT_TRUE(ani && pani); 379 380 int count = 0; __anon50d39ff20a02null381 p->OnChanged()->AddHandler(MakeCallback<IOnChanged>([&] { 382 ++count; 383 p->GetValue(); 384 })); 385 386 EXPECT_TRUE(pani->Property()->SetValue(p)); 387 EXPECT_TRUE(ani->Duration()->SetValue(TimeSpan::Milliseconds(100))); 388 389 // Set the value, it should not immediately change but rather start animating as we 390 // run some frames 391 EXPECT_TRUE(p->SetValue(10)); 392 393 EXPECT_TRUE(ani->Running()->GetValue()); 394 EXPECT_EQ(p->GetValue(), 0); 395 EXPECT_EQ(GetStartedCalledCount(), 1); 396 EXPECT_EQ(GetFinishedCalledCount(), 0); 397 398 // Check that property value changes to target gradually __anon50d39ff20b02(uint32_t frame) 399 this->RunFrames(11, [&](uint32_t frame) { 400 auto f = frame - 1; 401 EXPECT_EQ(f, p->GetValue()); 402 EXPECT_EQ(ani->Running()->GetValue(), f < 10); 403 EXPECT_FLOAT_EQ(ani->Progress()->GetValue(), f / 10.f); 404 }); 405 406 EXPECT_EQ(GetStartedCalledCount(), 1); 407 EXPECT_EQ(GetFinishedCalledCount(), 1); 408 409 EXPECT_FALSE(ani->Running()->GetValue()); 410 EXPECT_EQ(p->GetValue(), 10); 411 EXPECT_TRUE(count >= 10); 412 } 413 META_END_NAMESPACE() 414