1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "remoting/client/ui/fling_animation.h"
6 
7 #include <cmath>
8 
9 #include "base/bind.h"
10 #include "base/memory/ptr_util.h"
11 #include "base/test/simple_test_tick_clock.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13 
14 namespace remoting {
15 
16 namespace {
17 
18 const float kFlingTimeConstant = 325.f;
19 
20 }  // namespace
21 
22 class FlingAnimationTest : public testing::Test {
23  public:
24   void SetUp() override;
25   void TearDown() override;
26 
27  protected:
28   void TickAnimation(base::TimeDelta time_delta);
29 
30   // Must be called after the animation ticks.
31   void AssertDeltaChanged();
32 
33   FlingAnimation fling_animation_{
34       kFlingTimeConstant,
35       base::BindRepeating(&FlingAnimationTest::OnDeltaChanged,
36                           base::Unretained(this))};
37 
38   float received_dx_ = 0.f;
39   float received_dy_ = 0.f;
40 
41  private:
42   void OnDeltaChanged(float dx, float dy);
43 
44   bool change_received_ = false;
45 
46   base::SimpleTestTickClock mock_clock_;
47 };
48 
SetUp()49 void FlingAnimationTest::SetUp() {
50   fling_animation_.SetTickClockForTest(&mock_clock_);
51 }
52 
TearDown()53 void FlingAnimationTest::TearDown() {
54   ASSERT_FALSE(change_received_);
55 }
56 
TickAnimation(base::TimeDelta time_delta)57 void FlingAnimationTest::TickAnimation(base::TimeDelta time_delta) {
58   mock_clock_.Advance(time_delta);
59   fling_animation_.Tick();
60 }
61 
AssertDeltaChanged()62 void FlingAnimationTest::AssertDeltaChanged() {
63   ASSERT_TRUE(change_received_);
64   change_received_ = false;
65 }
66 
OnDeltaChanged(float dx,float dy)67 void FlingAnimationTest::OnDeltaChanged(float dx, float dy) {
68   received_dx_ = dx;
69   received_dy_ = dy;
70   change_received_ = true;
71 }
72 
TEST_F(FlingAnimationTest,TestNoFling)73 TEST_F(FlingAnimationTest, TestNoFling) {
74   EXPECT_FALSE(fling_animation_.IsAnimationInProgress());
75 
76   // This should not change the delta.
77   TickAnimation(base::TimeDelta::FromMilliseconds(100));
78 }
79 
TEST_F(FlingAnimationTest,TestFlingWillEventuallyStop)80 TEST_F(FlingAnimationTest, TestFlingWillEventuallyStop) {
81   fling_animation_.SetVelocity(1500.f, 1200.f);
82 
83   EXPECT_TRUE(fling_animation_.IsAnimationInProgress());
84 
85   TickAnimation(base::TimeDelta::FromMinutes(1));
86 
87   EXPECT_FALSE(fling_animation_.IsAnimationInProgress());
88 }
89 
TEST_F(FlingAnimationTest,TestFlingDeltaIsDecreasing)90 TEST_F(FlingAnimationTest, TestFlingDeltaIsDecreasing) {
91   fling_animation_.SetVelocity(1500.f, 1200.f);
92 
93   float previous_dx = std::numeric_limits<float>::infinity();
94   float previous_dy = std::numeric_limits<float>::infinity();
95 
96   while (true) {
97     TickAnimation(base::TimeDelta::FromMilliseconds(16));
98     if (!fling_animation_.IsAnimationInProgress()) {
99       break;
100     }
101     AssertDeltaChanged();
102     float hyp =
103         std::sqrt(received_dx_ * received_dx_ + received_dy_ * received_dy_);
104     float prev_hyp =
105         std::sqrt(previous_dx * previous_dx + previous_dy * previous_dy);
106     EXPECT_LT(hyp, prev_hyp);
107     previous_dx = received_dx_;
108     previous_dy = received_dy_;
109   }
110 }
111 
TEST_F(FlingAnimationTest,TestIgnoreLowVelocity)112 TEST_F(FlingAnimationTest, TestIgnoreLowVelocity) {
113   fling_animation_.SetVelocity(5.f, 5.f);
114 
115   EXPECT_FALSE(fling_animation_.IsAnimationInProgress());
116 
117   // This should not change the delta.
118   TickAnimation(base::TimeDelta::FromMilliseconds(5));
119 }
120 
TEST_F(FlingAnimationTest,TestAbortAnimation)121 TEST_F(FlingAnimationTest, TestAbortAnimation) {
122   fling_animation_.SetVelocity(1500.f, 1200.f);
123 
124   EXPECT_TRUE(fling_animation_.IsAnimationInProgress());
125 
126   TickAnimation(base::TimeDelta::FromMilliseconds(16));
127   AssertDeltaChanged();
128   EXPECT_TRUE(fling_animation_.IsAnimationInProgress());
129 
130   fling_animation_.Abort();
131   EXPECT_FALSE(fling_animation_.IsAnimationInProgress());
132 }
133 
TEST_F(FlingAnimationTest,TestResetVelocity)134 TEST_F(FlingAnimationTest, TestResetVelocity) {
135   fling_animation_.SetVelocity(1000.f, -1000.f);
136   EXPECT_TRUE(fling_animation_.IsAnimationInProgress());
137   TickAnimation(base::TimeDelta::FromMilliseconds(16));
138   EXPECT_TRUE(fling_animation_.IsAnimationInProgress());
139   AssertDeltaChanged();
140   EXPECT_GT(received_dx_, 0);
141   EXPECT_LT(received_dy_, 0);
142 
143   fling_animation_.SetVelocity(-1000.f, 1000.f);
144   EXPECT_TRUE(fling_animation_.IsAnimationInProgress());
145   TickAnimation(base::TimeDelta::FromMilliseconds(16));
146   EXPECT_TRUE(fling_animation_.IsAnimationInProgress());
147   AssertDeltaChanged();
148   EXPECT_LT(received_dx_, 0);
149   EXPECT_GT(received_dy_, 0);
150 }
151 
152 }  // namespace remoting
153