• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/property/construct_property.h>
20 #include <meta/interface/property/property.h>
21 
22 #include "TestRunner.h"
23 #include "helpers/animation_test_base.h"
24 #include "helpers/serialisation_utils.h"
25 #include "helpers/test_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 AnimationModifierTestBase;
34 
35 namespace {
36 struct TestDefinition {
37     std::string name;
38     std::function<IAnimation::Ptr(AnimationModifierTestBase&)> constructor;
__anonab38eef20202__anonab38eef20111::TestDefinition39     std::function<IAnimation::Ptr(AnimationModifierTestBase& test, IAnimation::Ptr)> transform = [](auto&, auto p) {
40         return p;
41     };
42 };
43 
44 } // namespace
45 
46 class AnimationModifierTestBase : public AnimationTestBase,
47                                       public ::testing::WithParamInterface<std::tuple<TestDefinition, int>> {
48 public:
SetUpTestSuite()49     static void SetUpTestSuite()
50     {
51         SetTest();
52     }
TearDownTestSuite()53     static void TearDownTestSuite()
54     {
55         TearDownTest();
56     }
SetUp()57     void SetUp() override
58     {
59         AnimationTestBase::SetUp();
60     }
61 
TearDown()62     void TearDown() override
63     {
64         keepAliveProperties.clear();
65         AnimationTestBase::TearDown();
66     }
67 
GetAnimation()68     IAnimation::Ptr GetAnimation()
69     {
70         return std::get<0>(GetParam()).constructor(*this);
71     }
72 
Transform(IAnimation::Ptr p)73     IAnimation::Ptr Transform(IAnimation::Ptr p)
74     {
75         return std::get<0>(GetParam()).transform(*this, p);
76     }
77 
78     BASE_NS::vector<META_NS::IProperty::Ptr> keepAliveProperties;
79 };
80 
81 /**
82  * @tc.name: ReverseImplicitAnimation
83  * @tc.desc: test ReverseImplicitAnimation
84  * @tc.type: FUNC
85  */
86 HWTEST_F(AnimationModifierTestBase, ReverseImplicitAnimation, TestSize.Level1)
87 {
88     auto animation = META_NS::PropertyAnimation(CreateInstance(ClassId::PropertyAnimation));
89     constexpr auto start = 10.0f;
90     constexpr auto to = 20.0f;
91 
92     auto property = META_NS::ConstructProperty<float>("test", start);
93 
94     animation.SetProperty(property);
95     animation.SetDuration(META_NS::TimeSpan::Milliseconds(100));
96     animation.AddModifier(META_NS::AnimationModifiers::Reverse(CreateInstance(ClassId::ReverseAnimationModifier)));
97 
98     property->SetValue(to);
99 
100     EXPECT_TRUE(animation.GetRunning());
101     animation.Step(GetTestClock());
102 
103     bool finished = false;
__anonab38eef20302null104     animation.OnFinished()->AddHandler(MakeCallback<IOnChanged>([&] { finished = true; }));
105 
__anonab38eef20402(uint32_t frame) 106     StepAnimations({ animation }, 10, [&](uint32_t frame) {
107         auto progress = animation.GetProgress();
108         EXPECT_EQ(progress, frame / 10.f) << "Frame: " << frame;
109 
110         auto value = GetValue(property);
111         EXPECT_EQ(value, start + (1.f - progress) * (to - start)) << "Frame: " << frame;
112     });
113 
114     EXPECT_FALSE(animation.GetRunning());
115     EXPECT_EQ(animation.GetProgress(), 1.f);
116     EXPECT_TRUE(finished);
117 }
118 
119 class LoopAnimationModifierTest : public AnimationModifierTestBase {
120 public:
SetUpTestSuite()121     static void SetUpTestSuite()
122     {
123         SetTest();
124     }
TearDownTestSuite()125     static void TearDownTestSuite()
126     {
127         TearDownTest();
128     }
GetLoopCount()129     int GetLoopCount()
130     {
131         return std::get<1>(GetParam());
132     }
133 };
134 
135 class SpeedAnimationModifierTest : public AnimationModifierTestBase {
136 public:
SetUpTestSuite()137     static void SetUpTestSuite()
138     {
139         SetTest();
140     }
TearDownTestSuite()141     static void TearDownTestSuite()
142     {
143         TearDownTest();
144     }
GetSpeedFactor()145     float GetSpeedFactor()
146     {
147         return std::get<1>(GetParam()) / 10.f;
148     }
149 };
150 
StartOrSetPropertyValue(IAnimation::Ptr anim)151 static void StartOrSetPropertyValue(IAnimation::Ptr anim)
152 {
153     if (auto startable = interface_cast<IStartableAnimation>(anim)) {
154         startable->Start();
155     } else if (auto p = interface_cast<IPropertyAnimation>(anim)) {
156         Property<float> prop(p->Property()->GetValue().lock());
157         if (prop) {
158             prop->SetValue(20.0f);
159         }
160     }
161 }
162 
163 class ReverseAnimationModifierTest : public AnimationModifierTestBase {
164 public:
SetUpTestSuite()165     static void SetUpTestSuite()
166     {
167         SetTest();
168     }
TearDownTestSuite()169     static void TearDownTestSuite()
170     {
171         TearDownTest();
172     }
GetFrameCount() const173     int GetFrameCount() const
174     {
175         return std::get<1>(GetParam());
176     }
177 
CollectFrames(const META_NS::IAnimation::Ptr & anim)178     BASE_NS::vector<BASE_NS::vector<float>> CollectFrames(const META_NS::IAnimation::Ptr& anim)
179     {
180         const auto frames = GetFrameCount();
181         const auto millisPerFrame = GetValue(anim->TotalDuration()).ToMilliseconds() / frames;
182         BASE_NS::vector<BASE_NS::vector<float>> propsValues(keepAliveProperties.size(), {});
183 
184         auto recordFrame = [this](BASE_NS::vector<BASE_NS::vector<float>>& out) {
185             int i = 0;
186             for (const auto& prop : keepAliveProperties) {
187                 out[i++].push_back(GetValue<float>(prop));
188             }
189         };
190 
191         if (auto startable = interface_cast<IStartableAnimation>(anim)) {
192             startable->Restart();
193         }
194         anim->Step(GetTestClock());
195         recordFrame(propsValues);
196         StepAnimations(
197             { anim },
198             frames,
199             millisPerFrame,
200             [&propsValues, recordFrame](int frame) {
201                 recordFrame(propsValues);
202             });
203 
204         return propsValues;
205     }
206 };
207 
BuildTestName(const testing::TestParamInfo<LoopAnimationModifierTest::ParamType> & info)208 std::string BuildTestName(const testing::TestParamInfo<LoopAnimationModifierTest::ParamType>& info)
209 {
210     return std::get<0>(info.param).name + "Animation" + std::to_string(info.index);
211 }
212 
CreateKeyFrameAnimation(AnimationModifierTestBase & test)213 IAnimation::Ptr CreateKeyFrameAnimation(AnimationModifierTestBase& test)
214 {
215     KeyframeAnimation<float> animation(CreateInstance(ClassId::KeyframeAnimation));
216 
217     auto start = 10.0f;
218     float to = 20.0f;
219 
220     auto property = ConstructProperty<float>("test", 5.0f);
221     test.keepAliveProperties.push_back(property);
222 
223     animation.SetFrom(start);
224     animation.SetTo(to);
225     animation.SetDuration(TimeSpan::Milliseconds(1000)); // 1000: param
226     animation.SetProperty(property);
227 
228     return animation;
229 }
230 
CreatePropertyAnimation(AnimationModifierTestBase & test)231 IAnimation::Ptr CreatePropertyAnimation(AnimationModifierTestBase& test)
232 {
233     auto animation = PropertyAnimation(CreateInstance(ClassId::PropertyAnimation));
234     auto start = 10.0f;
235     float to = 20.0f;
236 
237     auto property = ConstructProperty<float>("test", start);
238     test.keepAliveProperties.push_back(property);
239 
240     animation.SetProperty(property);
241     animation.SetDuration(TimeSpan::Milliseconds(1000)); // 1000: param
242 
243     return animation;
244 }
245 
CreateTrackAnimation(AnimationModifierTestBase & test)246 IAnimation::Ptr CreateTrackAnimation(AnimationModifierTestBase& test)
247 {
248     BASE_NS::vector<float> timestamps = { 0.1f, 0.3f, 0.8f, 1.f };
249     BASE_NS::vector<float> keyframes = { 50.0f, 100.0f, 170.0f, 190.0f };
250     const float initialValue = 10.0f;
251 
252     auto property = ConstructProperty<float>("Prop", initialValue);
253     test.keepAliveProperties.push_back(property);
254 
255     BASE_NS::array_view<float> kf = keyframes;
256 
257     auto animation = TrackAnimation<float>(CreateInstance(ClassId::TrackAnimation))
258                          .SetKeyframes(keyframes)
259                          .SetTimestamps(timestamps)
260                          .SetProperty(property)
261                          .SetDuration(TimeSpan::Milliseconds(1000));
262 
263     return animation;
264 }
265 
CreateParallelAnimation(AnimationModifierTestBase & test)266 IAnimation::Ptr CreateParallelAnimation(AnimationModifierTestBase& test)
267 {
268     auto anim1 = CreateKeyFrameAnimation(test);
269     auto anim2 = CreateTrackAnimation(test);
270 
271     auto staggered = ParallelAnimation(CreateInstance(ClassId::ParallelAnimation)).Add(anim1).Add(anim2);
272 
273     return staggered;
274 }
275 
CreateSequentialAnimation(AnimationModifierTestBase & test)276 IAnimation::Ptr CreateSequentialAnimation(AnimationModifierTestBase& test)
277 {
278     auto anim1 = CreateKeyFrameAnimation(test);
279     auto anim2 = CreateTrackAnimation(test);
280 
281     auto staggered = SequentialAnimation(CreateInstance(ClassId::SequentialAnimation)).Add(anim1).Add(anim2);
282 
283     return staggered;
284 }
285 
Serialize(AnimationModifierTestBase & test,IAnimation::Ptr anim)286 IAnimation::Ptr Serialize(AnimationModifierTestBase& test, IAnimation::Ptr anim)
287 {
288     TestSerialiser ser;
289 
290     {
291         Object obj(CreateInstance(ClassId::Object));
292         AttachmentContainer(obj).Attach(interface_pointer_cast<IAttachment>(anim));
293 
294         for (auto&& v : test.keepAliveProperties) {
295             Metadata(obj).AddProperty(v);
296         }
297 
298         ser.Export(obj);
299     }
300     test.keepAliveProperties.clear();
301 
302     auto meta = ser.Import<IMetadata>();
303     for (auto& p : meta->GetProperties()) {
304         test.keepAliveProperties.push_back(p);
305     }
306     if (auto att = interface_pointer_cast<IAttach>(meta)) {
307         auto vec = att->GetAttachments<IAnimation>();
308         return vec.empty() ? nullptr : vec[0];
309     }
310     return nullptr;
311 }
312 
313 /**
314  * @tc.name: ReversedAnimationIsPlayedBackward
315  * @tc.desc: test ReversedAnimationIsPlayedBackward
316  * @tc.type: FUNC
317  */
318 HWTEST_P(ReverseAnimationModifierTest, ReversedAnimationIsPlayedBackward, TestSize.Level1)
319 {
320     using ::testing::FloatNear;
321     using ::testing::Pointwise;
322 
323     auto anim = GetAnimation();
324     const auto forwardFrames = CollectFrames(anim);
325     {
326         auto reverse = AnimationModifiers::Reverse(CreateInstance(ClassId::ReverseAnimationModifier));
327         auto attach = interface_pointer_cast<IAttach>(anim);
328         attach->Attach(interface_pointer_cast<IObject>(reverse));
329     }
330     anim = Transform(anim);
331     ASSERT_TRUE(anim);
332 
333     const auto reverseFrames = CollectFrames(anim);
334 
335     for (decltype(forwardFrames.size()) i = 0, end = forwardFrames.size(); i < end; ++i) {
336         EXPECT_THAT(
337             reverseFrames[i], Pointwise(FloatNear(0.001),
338                                   decltype(forwardFrames[i]) { forwardFrames[i].rbegin(), forwardFrames[i].rend() }))
339             << "i: " << i;
340     }
341 }
342 
GetAnimAttachment(IAnimation::Ptr anim)343 static IObject::Ptr GetAnimAttachment(IAnimation::Ptr anim)
344 {
345     auto attach = interface_pointer_cast<IAttach>(anim);
346     auto vec = attach->GetAttachments<IAnimationModifier>();
347     return vec.empty() ? nullptr : interface_pointer_cast<IObject>(vec[0]);
348 }
349 
350 /**
351  * @tc.name: LoopCountModifiesDuration
352  * @tc.desc: test LoopCountModifiesDuration
353  * @tc.type: FUNC
354  */
355 HWTEST_P(LoopAnimationModifierTest, LoopCountModifiesDuration, TestSize.Level1)
356 {
357     auto anim = GetAnimation();
358     int loopCount = GetLoopCount();
359     auto originalDuration = GetValue(anim->TotalDuration());
360 
361     {
362         auto loop = AnimationModifiers::Loop(CreateInstance(ClassId::LoopAnimationModifier)).SetLoopCount(loopCount);
363         auto attach = interface_pointer_cast<IAttach>(anim);
364         EXPECT_TRUE(attach->Attach(interface_pointer_cast<IObject>(loop)));
365     }
366 
367     anim = Transform(anim);
368     ASSERT_TRUE(anim);
369     AnimationModifiers::Loop loop(GetAnimAttachment(anim));
370     ASSERT_TRUE(loop);
371 
372     EXPECT_EQ(GetValue(anim->TotalDuration()), loopCount * originalDuration);
373     loop.SetLoopCount(loopCount * 2);
374     EXPECT_EQ(GetValue(anim->TotalDuration()), loopCount * 2 * originalDuration);
375     loop.SetLoopCount(loopCount);
376     EXPECT_EQ(GetValue(anim->TotalDuration()), loopCount * originalDuration);
377 
378     loop.SetLoopCount(-1);
379     EXPECT_EQ(GetValue(anim->TotalDuration()), TimeSpan::Infinite());
380 }
381 
382 /**
383  * @tc.name: AnimationIsLoopingRegardlessOfSpeedModificator
384  * @tc.desc: test AnimationIsLoopingRegardlessOfSpeedModificator
385  * @tc.type: FUNC
386  */
387 HWTEST_P(LoopAnimationModifierTest, AnimationIsLoopingRegardlessOfSpeedModificator, TestSize.Level1)
388 {
389     static constexpr int64_t frameStepMs = 10;
390     static constexpr float speedFactor = 2.7;
391     const auto expectedLoops = GetLoopCount();
392     auto anim = GetAnimation();
393     const auto animPlayTime = (static_cast<float>(GetValue(anim->TotalDuration()).ToMilliseconds()) / speedFactor) *
394                               static_cast<float>(expectedLoops);
395     const auto animTotalFrames = static_cast<int64_t>(animPlayTime) / frameStepMs;
396 
397     {
398         const auto attach = interface_pointer_cast<META_NS::IAttach>(anim);
399         attach->Attach(META_NS::AnimationModifiers::Loop(CreateNew).LoopIndefinitely().GetPtr());
400         attach->Attach(META_NS::AnimationModifiers::Speed(CreateNew).SetSpeedFactor(speedFactor).GetPtr());
401     }
402     anim = Transform(anim);
403     ASSERT_TRUE(anim);
404 
405     uint32_t actualLoops = 0;
406     auto previousProgress = GetValue(anim->Progress());
407     StartOrSetPropertyValue(anim);
__anonab38eef20702(uint32_t frame) 408     StepAnimations({ anim }, animTotalFrames, frameStepMs, [&](uint32_t frame) {
409         actualLoops = actualLoops == 0 ? 1 : actualLoops;
410         const auto currentProgress = GetValue(anim->Progress());
411         if (previousProgress > currentProgress) {
412             ++actualLoops;
413         }
414         previousProgress = currentProgress;
415     });
416 
417     EXPECT_EQ(actualLoops, expectedLoops);
418 }
419 
420 /**
421  * @tc.name: AnimationIslooping
422  * @tc.desc: test AnimationIslooping
423  * @tc.type: FUNC
424  */
425 HWTEST_P(LoopAnimationModifierTest, AnimationIslooping, TestSize.Level1)
426 {
427     auto anim = GetAnimation();
428     int loopCount = GetLoopCount();
429     auto originalDuration = GetValue(anim->TotalDuration());
430 
431     // Don't test zero loopcount
432     if (loopCount == 0) {
433         return;
434     }
435 
436     // round up
437     const int frames = (originalDuration.ToMilliseconds() + 9) / 10;
438     const int totalFrames = frames * loopCount;
439 
440     EXPECT_TRUE(GetValue(anim->Valid()));
441     {
442         auto loop =
443             META_NS::AnimationModifiers::Loop(CreateInstance(ClassId::LoopAnimationModifier)).SetLoopCount(loopCount);
444         auto attach = interface_pointer_cast<META_NS::IAttach>(anim);
445         attach->Attach(loop.GetPtr());
446     }
447 
448     anim = Transform(anim);
449     ASSERT_TRUE(anim);
450 
451     EXPECT_TRUE(GetValue(anim->Valid()));
452 
453     StartOrSetPropertyValue(anim);
454     anim->Step(GetTestClock());
455 
456     EXPECT_TRUE(GetValue(anim->Valid()));
457     EXPECT_TRUE(GetValue(anim->Running()));
458 
459     for (int i = 0; i < loopCount; ++i) {
460         const int frameOffset = i * 10;
461         EXPECT_TRUE(GetValue(anim->Running()));
462         auto previousProgress = 0.f;
463 
__anonab38eef20802(int frame) 464         StepAnimations({ anim }, frames, [&](int frame) {
465             frame = i * frames + frame;
466             auto progress = GetValue(anim->Progress());
467             if (i == (loopCount - 1) && frame == totalFrames) {
468                 // Last frame
469                 ASSERT_FALSE(GetValue(anim->Running())) << "Frame " << frame;
470             } else {
471                 ASSERT_TRUE(GetValue(anim->Running())) << "Frame " << frame;
472                 ASSERT_GT(progress, previousProgress) << "Frame " << frame;
473             }
474 
475             previousProgress = progress;
476         });
477     }
478 
479     ASSERT_FALSE(GetValue(anim->Running()));
480 
481     // Animation is stopped, it should not advance any further
482     for (int i = 0; i < 10; ++i) {
483         IncrementClockTime(META_NS::TimeSpan::Milliseconds(10));
484         anim->Step(GetTestClock());
485 
486         EXPECT_FALSE(GetValue(anim->Running()));
487         EXPECT_FLOAT_EQ(1.0f, GetValue(anim->Progress()));
488     }
489 }
490 
491 /**
492  * @tc.name: DuplicateProperties
493  * @tc.desc: test DuplicateProperties
494  * @tc.type: FUNC
495  */
496 HWTEST_P(LoopAnimationModifierTest, DuplicateProperties, TestSize.Level1)
497 {
498     auto animation = GetAnimation();
499     animation = Transform(animation);
500 
501     auto meta = interface_pointer_cast<META_NS::IMetadata>(animation);
502 
503     for (const auto& prop : meta->GetProperties()) {
504         for (const auto& rhs : meta->GetProperties()) {
505             if (prop == rhs) {
506                 continue;
507             }
508 
509             ASSERT_NE(prop->GetName(), rhs->GetName());
510         }
511     }
512 }
513 
514 /**
515  * @tc.name: SpeedFactorModifiesDuration
516  * @tc.desc: test SpeedFactorModifiesDuration
517  * @tc.type: FUNC
518  */
519 HWTEST_P(SpeedAnimationModifierTest, SpeedFactorModifiesDuration, TestSize.Level1)
520 {
521     auto anim = GetAnimation();
522     float speedFactor = GetSpeedFactor();
523     auto originalDuration = GetValue(anim->TotalDuration());
524     auto expectedDuration = originalDuration / BASE_NS::Math::abs(speedFactor);
525 
526     {
527         auto speedModifier = META_NS::AnimationModifiers::Speed(CreateNew).SetSpeedFactor(speedFactor);
528         auto attach = interface_pointer_cast<META_NS::IAttach>(anim);
529         ASSERT_TRUE(attach->Attach(speedModifier.GetPtr()));
530     }
531     anim = Transform(anim);
532     ASSERT_TRUE(anim);
533     META_NS::AnimationModifiers::Speed speedModifier(GetAnimAttachment(anim));
534     ASSERT_TRUE(speedModifier);
535 
536     EXPECT_TRUE(GetValue(anim->Valid()));
537 
538     EXPECT_EQ(GetValue(anim->TotalDuration()), expectedDuration);
539 
540     // Change speed factor, total duration should follow
541     speedModifier.SetSpeedFactor(speedFactor * 2);
542     EXPECT_EQ(GetValue(anim->TotalDuration()).ToMilliseconds(), (expectedDuration / 2).ToMilliseconds());
543     speedModifier.SetSpeedFactor(speedFactor);
544     EXPECT_EQ(GetValue(anim->TotalDuration()), expectedDuration);
545 
546     speedModifier.SetSpeedFactor(-speedFactor * 2);
547     EXPECT_EQ(GetValue(anim->TotalDuration()).ToMilliseconds(), (expectedDuration / 2).ToMilliseconds());
548     speedModifier.SetSpeedFactor(-speedFactor);
549     EXPECT_EQ(GetValue(anim->TotalDuration()), expectedDuration);
550 
551     speedModifier.SetSpeedFactor(0);
552     EXPECT_EQ(GetValue(anim->TotalDuration()), TimeSpan::Infinite());
553 }
554 
555 /**
556  * @tc.name: SpeedFactorAffectsPlayback
557  * @tc.desc: test SpeedFactorAffectsPlayback
558  * @tc.type: FUNC
559  */
560 HWTEST_P(SpeedAnimationModifierTest, SpeedFactorAffectsPlayback, TestSize.Level1)
561 {
562     auto anim = GetAnimation();
563     const float speedFactor = GetSpeedFactor();
564     if (speedFactor == 0.f) {
565         return;
566     }
567 
568     auto originalDuration = GetValue(anim->TotalDuration());
569     auto expectedDuration = originalDuration / BASE_NS::Math::abs(speedFactor);
570 
571     {
572         auto speedModifier = META_NS::AnimationModifiers::Speed(CreateInstance(ClassId::SpeedAnimationModifier))
573                                  .SetSpeedFactor(speedFactor);
574 
575         auto attach = interface_pointer_cast<META_NS::IAttach>(anim);
576         ASSERT_NE(attach, nullptr);
577         attach->Attach(speedModifier.GetPtr());
578     }
579     anim = Transform(anim);
580     ASSERT_TRUE(anim);
581     META_NS::AnimationModifiers::Speed speedModifier(GetAnimAttachment(anim));
582     ASSERT_TRUE(speedModifier);
583 
584     EXPECT_TRUE(GetValue(anim->Valid()));
585 
586     StartOrSetPropertyValue(anim);
587 
588     EXPECT_TRUE(GetValue(anim->Valid()));
589     EXPECT_TRUE(GetValue(anim->Running()));
590     anim->Step(GetTestClock());
591 
592     if (speedFactor == 0.f) {
593         EXPECT_EQ(GetValue(anim->TotalDuration()), META_NS::TimeSpan::Infinite());
594         EXPECT_EQ(GetValue(anim->Progress()), 0);
595         return;
596     }
597     // Figure out how many milliseconds we must progress at each frame
598     // to cover the whole animation in 10 frames
599     int64_t millisPerFrame =
600         BASE_NS::Math::round(static_cast<float>(GetValue(anim->TotalDuration()).ToMilliseconds()) / 10.f);
601     EXPECT_EQ(millisPerFrame, (expectedDuration / 10).ToMilliseconds());
602 
603     float previousProgress = GetValue(anim->Progress());
604     EXPECT_EQ(previousProgress, 0);
605 
__anonab38eef20902(int frame) 606     StepAnimations({ anim }, 10, millisPerFrame, [millisPerFrame, &anim, &previousProgress](int frame) {
607         float progress = GetValue(anim->Progress());
608         EXPECT_GT(progress, previousProgress);
609         EXPECT_NEAR(progress, frame / 10.f, 0.05);
610         previousProgress = progress;
611     });
612 
613     // Animation is stopped, it should not advance any further
__anonab38eef20a02(int frame) 614     StepAnimations({ anim }, 10, millisPerFrame, [millisPerFrame, &anim, &previousProgress](int frame) {
615         EXPECT_FALSE(GetValue(anim->Running()));
616         EXPECT_FLOAT_EQ(1.0f, GetValue(anim->Progress()));
617     });
618 }
619 
620 INSTANTIATE_TEST_SUITE_P(LoopAnimationModifierSuite, LoopAnimationModifierTest,
621     testing::Combine(
622         testing::Values(TestDefinition { "Keyframe", CreateKeyFrameAnimation },
623             TestDefinition { "Track", CreateTrackAnimation }, TestDefinition { "Parallel", CreateParallelAnimation },
624             TestDefinition { "Sequential", CreateSequentialAnimation },
625             TestDefinition { "Property", CreatePropertyAnimation },
626             TestDefinition { "KeyframeSerialize", CreateKeyFrameAnimation, Serialize },
627             TestDefinition { "TrackSerialize", CreateTrackAnimation, Serialize },
628             TestDefinition { "ParallelSerialize", CreateParallelAnimation, Serialize },
629             TestDefinition { "SequentialSerialize", CreateSequentialAnimation, Serialize },
630             TestDefinition { "PropertySerialize", CreatePropertyAnimation, Serialize }),
631         testing::Range(1, 10)),
632     BuildTestName);
633 
634 INSTANTIATE_TEST_SUITE_P(SpeedAnimationModifierSuite, SpeedAnimationModifierTest,
635     testing::Combine(
636         testing::Values(TestDefinition { "Keyframe", CreateKeyFrameAnimation },
637             TestDefinition { "Track", CreateTrackAnimation }, TestDefinition { "Parallel", CreateParallelAnimation },
638             TestDefinition { "Sequential", CreateSequentialAnimation },
639             TestDefinition { "Property", CreatePropertyAnimation },
640             TestDefinition { "KeyframeSerialize", CreateKeyFrameAnimation, Serialize },
641             TestDefinition { "TrackSerialize", CreateTrackAnimation, Serialize },
642             TestDefinition { "ParallelSerialize", CreateParallelAnimation, Serialize },
643             TestDefinition { "SequentialSerialize", CreateSequentialAnimation, Serialize },
644             TestDefinition { "PropertySerialize", CreatePropertyAnimation, Serialize }),
645         testing::Range(-20, 20, 5)),
646     BuildTestName);
647 
648 INSTANTIATE_TEST_SUITE_P(ReverseAnimationModifierSuite, ReverseAnimationModifierTest,
649     testing::Combine(
650         testing::Values(TestDefinition { "Keyframe", CreateKeyFrameAnimation },
651             TestDefinition { "Track", CreateTrackAnimation }, TestDefinition { "Parallel", CreateParallelAnimation },
652             TestDefinition { "KeyframeSerialize", CreateKeyFrameAnimation, Serialize },
653             TestDefinition { "TrackSerialize", CreateTrackAnimation, Serialize },
654             TestDefinition { "ParallelSerialize", CreateParallelAnimation, Serialize }),
655         testing::Range(10, 20, 10)),
656     BuildTestName);
657 
658 META_END_NAMESPACE()
659