- add sources.
[platform/framework/web/crosswalk.git] / src / remoting / host / resizing_host_observer_unittest.cc
1 // Copyright (c) 2012 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 <list>
6
7 #include "base/compiler_specific.h"
8 #include "base/logging.h"
9 #include "base/memory/ref_counted.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/run_loop.h"
12 #include "remoting/host/desktop_resizer.h"
13 #include "remoting/host/resizing_host_observer.h"
14 #include "remoting/host/screen_resolution.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 #include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h"
17
18 namespace remoting {
19
20 std::ostream& operator<<(std::ostream& os, const ScreenResolution& resolution) {
21   return os << resolution.dimensions().width() << "x"
22             << resolution.dimensions().height() << " @ "
23             << resolution.dpi().x() << "x" << resolution.dpi().y();
24 }
25
26 bool operator==(const ScreenResolution& a, const ScreenResolution& b) {
27   return a.Equals(b);
28 }
29
30 const int kDefaultDPI = 96;
31
32 ScreenResolution MakeResolution(int width, int height) {
33   return ScreenResolution(webrtc::DesktopSize(width, height),
34                           webrtc::DesktopVector(kDefaultDPI, kDefaultDPI));
35 }
36
37 class FakeDesktopResizer : public DesktopResizer {
38  public:
39   FakeDesktopResizer(const ScreenResolution& initial_resolution,
40                      bool exact_size_supported,
41                      const ScreenResolution* supported_resolutions,
42                      int num_supported_resolutions)
43       : initial_resolution_(initial_resolution),
44         current_resolution_(initial_resolution),
45         exact_size_supported_(exact_size_supported),
46         set_resolution_call_count_(0) {
47     for (int i = 0; i < num_supported_resolutions; ++i) {
48       supported_resolutions_.push_back(supported_resolutions[i]);
49     }
50   }
51
52   virtual ~FakeDesktopResizer() {
53     EXPECT_EQ(initial_resolution_, GetCurrentResolution());
54   }
55
56   int set_resolution_call_count() { return set_resolution_call_count_; }
57
58   // remoting::DesktopResizer interface
59   virtual ScreenResolution GetCurrentResolution() OVERRIDE {
60     return current_resolution_;
61   }
62   virtual std::list<ScreenResolution> GetSupportedResolutions(
63       const ScreenResolution& preferred) OVERRIDE {
64     std::list<ScreenResolution> result = supported_resolutions_;
65     if (exact_size_supported_) {
66       result.push_back(preferred);
67     }
68     return result;
69   }
70   virtual void SetResolution(const ScreenResolution& resolution) OVERRIDE {
71     current_resolution_ = resolution;
72     ++set_resolution_call_count_;
73   }
74   virtual void RestoreResolution(const ScreenResolution& resolution) OVERRIDE {
75     current_resolution_ = resolution;
76   }
77
78  private:
79   ScreenResolution initial_resolution_;
80   ScreenResolution current_resolution_;
81   bool exact_size_supported_;
82   std::list<ScreenResolution> supported_resolutions_;
83
84   int set_resolution_call_count_;
85 };
86
87 class ResizingHostObserverTest : public testing::Test {
88  public:
89   ResizingHostObserverTest()
90       : desktop_resizer_(NULL),
91         now_(base::Time::Now()) {
92   }
93
94   // This needs to be public because the derived test-case class needs to
95   // pass it to Bind, which fails if it's protected.
96   base::Time GetTime() {
97     return now_;
98   }
99
100  protected:
101   void SetDesktopResizer(scoped_ptr<FakeDesktopResizer> desktop_resizer) {
102     CHECK(!desktop_resizer_) << "Call SetDeskopResizer once per test";
103     desktop_resizer_ = desktop_resizer.get();
104
105     resizing_host_observer_.reset(
106         new ResizingHostObserver(desktop_resizer.PassAs<DesktopResizer>()));
107     resizing_host_observer_->SetNowFunctionForTesting(
108         base::Bind(&ResizingHostObserverTest::GetTimeAndIncrement,
109                    base::Unretained(this)));
110   }
111
112   ScreenResolution GetBestResolution(const ScreenResolution& client_size) {
113     resizing_host_observer_->SetScreenResolution(client_size);
114     return desktop_resizer_->GetCurrentResolution();
115   }
116
117   void VerifySizes(const ScreenResolution* client_sizes,
118                    const ScreenResolution* expected_sizes,
119                    int number_of_sizes) {
120     for (int i = 0; i < number_of_sizes; ++i) {
121       ScreenResolution best_size = GetBestResolution(client_sizes[i]);
122       EXPECT_EQ(expected_sizes[i], best_size)
123           << "Input resolution = " << client_sizes[i];
124     }
125   }
126
127   base::Time GetTimeAndIncrement() {
128     base::Time result = now_;
129     now_ += base::TimeDelta::FromSeconds(1);
130     return result;
131   }
132
133   scoped_ptr<ResizingHostObserver> resizing_host_observer_;
134   FakeDesktopResizer* desktop_resizer_;
135   base::Time now_;
136 };
137
138 // Check that the host is not resized if GetSupportedSizes returns an empty
139 // list (even if GetCurrentSize is supported).
140 TEST_F(ResizingHostObserverTest, EmptyGetSupportedSizes) {
141   ScreenResolution initial = MakeResolution(640, 480);
142   scoped_ptr<FakeDesktopResizer> desktop_resizer(
143       new FakeDesktopResizer(initial, false, NULL, 0));
144   SetDesktopResizer(desktop_resizer.Pass());
145
146   ScreenResolution client_sizes[] = { MakeResolution(200, 100),
147                                       MakeResolution(100, 200) };
148   ScreenResolution expected_sizes[] = { initial, initial };
149   VerifySizes(client_sizes, expected_sizes, arraysize(client_sizes));
150 }
151
152 // Check that if the implementation supports exact size matching, it is used.
153 TEST_F(ResizingHostObserverTest, SelectExactSize) {
154   scoped_ptr<FakeDesktopResizer> desktop_resizer(
155       new FakeDesktopResizer(MakeResolution(640, 480), true, NULL, 0));
156   SetDesktopResizer(desktop_resizer.Pass());
157
158   ScreenResolution client_sizes[] = { MakeResolution(200, 100),
159                                       MakeResolution(100, 200),
160                                       MakeResolution(640, 480),
161                                       MakeResolution(480, 640),
162                                       MakeResolution(1280, 1024) };
163   VerifySizes(client_sizes, client_sizes, arraysize(client_sizes));
164 }
165
166 // Check that if the implementation supports a size that is no larger than
167 // the requested size, then the largest such size is used.
168 TEST_F(ResizingHostObserverTest, SelectBestSmallerSize) {
169   ScreenResolution supported_sizes[] = { MakeResolution(639, 479),
170                                          MakeResolution(640, 480) };
171   scoped_ptr<FakeDesktopResizer> desktop_resizer(
172       new FakeDesktopResizer(MakeResolution(640, 480), false,
173                              supported_sizes, arraysize(supported_sizes)));
174   SetDesktopResizer(desktop_resizer.Pass());
175
176   ScreenResolution client_sizes[] = { MakeResolution(639, 479),
177                                       MakeResolution(640, 480),
178                                       MakeResolution(641, 481),
179                                       MakeResolution(999, 999) };
180   ScreenResolution expected_sizes[] = { supported_sizes[0], supported_sizes[1],
181                                supported_sizes[1], supported_sizes[1] };
182   VerifySizes(client_sizes, expected_sizes, arraysize(client_sizes));
183 }
184
185 // Check that if the implementation supports only sizes that are larger than
186 // the requested size, then the one that requires the least down-scaling.
187 TEST_F(ResizingHostObserverTest, SelectBestScaleFactor) {
188   ScreenResolution supported_sizes[] = { MakeResolution(100, 100),
189                                          MakeResolution(200, 100) };
190   scoped_ptr<FakeDesktopResizer> desktop_resizer(
191       new FakeDesktopResizer(MakeResolution(200, 100), false,
192                              supported_sizes, arraysize(supported_sizes)));
193   SetDesktopResizer(desktop_resizer.Pass());
194
195   ScreenResolution client_sizes[] = { MakeResolution(1, 1),
196                                       MakeResolution(99, 99),
197                                       MakeResolution(199, 99) };
198   ScreenResolution expected_sizes[] = { supported_sizes[0], supported_sizes[0],
199                                supported_sizes[1] };
200   VerifySizes(client_sizes, expected_sizes, arraysize(client_sizes));
201 }
202
203 // Check that if the implementation supports two sizes that have the same
204 // resultant scale factor, then the widest one is selected.
205 TEST_F(ResizingHostObserverTest, SelectWidest) {
206   ScreenResolution supported_sizes[] = { MakeResolution(640, 480),
207                                          MakeResolution(480, 640) };
208   scoped_ptr<FakeDesktopResizer> desktop_resizer(
209       new FakeDesktopResizer(MakeResolution(480, 640), false,
210                              supported_sizes, arraysize(supported_sizes)));
211   SetDesktopResizer(desktop_resizer.Pass());
212
213   ScreenResolution client_sizes[] = { MakeResolution(100, 100),
214                                       MakeResolution(480, 480),
215                                       MakeResolution(500, 500),
216                                       MakeResolution(640, 640),
217                                       MakeResolution(1000, 1000) };
218   ScreenResolution expected_sizes[] = { supported_sizes[0], supported_sizes[0],
219                                supported_sizes[0], supported_sizes[0],
220                                supported_sizes[0] };
221   VerifySizes(client_sizes, expected_sizes, arraysize(client_sizes));
222 }
223
224 // Check that if the best match for the client size doesn't change, then we
225 // don't call SetSize.
226 TEST_F(ResizingHostObserverTest, NoSetSizeForSameSize) {
227   ScreenResolution supported_sizes[] = { MakeResolution(640, 480),
228                                          MakeResolution(480, 640) };
229   FakeDesktopResizer* desktop_resizer =
230       new FakeDesktopResizer(MakeResolution(640, 480), false,
231                              supported_sizes, arraysize(supported_sizes));
232   SetDesktopResizer(scoped_ptr<FakeDesktopResizer>(desktop_resizer));
233
234   ScreenResolution client_sizes[] = { MakeResolution(640, 640),
235                                       MakeResolution(1024, 768),
236                                       MakeResolution(640, 480) };
237   ScreenResolution expected_sizes[] = { MakeResolution(640, 480),
238                                         MakeResolution(640, 480),
239                                         MakeResolution(640, 480) };
240   VerifySizes(client_sizes, expected_sizes, arraysize(client_sizes));
241   EXPECT_EQ(desktop_resizer->set_resolution_call_count(), 0);
242 }
243
244 // Check that desktop resizes are rate-limited, and that if multiple resize
245 // requests are received in the time-out period, the most recent is respected.
246 TEST_F(ResizingHostObserverTest, RateLimited) {
247   FakeDesktopResizer* desktop_resizer =
248       new FakeDesktopResizer(MakeResolution(640, 480), true, NULL, 0);
249   SetDesktopResizer(scoped_ptr<FakeDesktopResizer>(desktop_resizer));
250   resizing_host_observer_->SetNowFunctionForTesting(
251       base::Bind(&ResizingHostObserverTest::GetTime, base::Unretained(this)));
252
253   base::MessageLoop message_loop;
254   base::RunLoop run_loop;
255
256   EXPECT_EQ(GetBestResolution(MakeResolution(100, 100)),
257             MakeResolution(100, 100));
258   now_ += base::TimeDelta::FromMilliseconds(900);
259   EXPECT_EQ(GetBestResolution(MakeResolution(200, 200)),
260             MakeResolution(100, 100));
261   now_ += base::TimeDelta::FromMilliseconds(99);
262   EXPECT_EQ(GetBestResolution(MakeResolution(300, 300)),
263             MakeResolution(100, 100));
264   now_ += base::TimeDelta::FromMilliseconds(1);
265
266   // Due to the kMinimumResizeIntervalMs constant in resizing_host_observer.cc,
267   // We need to wait a total of 1000ms for the final resize to be processed.
268   // Since it was queued 900 + 99 ms after the first, we need to wait an
269   // additional 1ms. However, since RunLoop is not guaranteed to process tasks
270   // with the same due time in FIFO order, wait an additional 1ms for safety.
271   message_loop.PostDelayedTask(
272       FROM_HERE,
273       run_loop.QuitClosure(),
274       base::TimeDelta::FromMilliseconds(2));
275   run_loop.Run();
276
277   // If the QuitClosure fired before the final resize, it's a test failure.
278   EXPECT_EQ(desktop_resizer_->GetCurrentResolution(), MakeResolution(300, 300));
279 }
280
281 }  // namespace remoting