d43a630713994b8ad7bab71dd762327548d941e9
[platform/framework/web/crosswalk.git] / src / ui / display / chromeos / x11 / native_display_event_dispatcher_x11_unittest.cc
1 // Copyright 2014 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 <X11/extensions/Xrandr.h>
6
7 #undef Bool
8 #undef None
9
10 #include "base/test/simple_test_tick_clock.h"
11 #include "testing/gtest/include/gtest/gtest.h"
12 #include "ui/display/chromeos/x11/display_mode_x11.h"
13 #include "ui/display/chromeos/x11/display_snapshot_x11.h"
14 #include "ui/display/chromeos/x11/native_display_delegate_x11.h"
15 #include "ui/display/chromeos/x11/native_display_event_dispatcher_x11.h"
16
17 namespace ui {
18
19 namespace {
20
21 const DisplayModeX11 kDefaultDisplayMode(gfx::Size(1, 1), false, 60.0f, 20);
22
23 DisplaySnapshotX11* CreateOutput(RROutput output, RRCrtc crtc) {
24   DisplaySnapshotX11* snapshot = new DisplaySnapshotX11(
25       0,
26       false,
27       gfx::Point(0, 0),
28       gfx::Size(0, 0),
29       OUTPUT_TYPE_UNKNOWN,
30       false,
31       std::vector<const DisplayMode*>(1, &kDefaultDisplayMode),
32       &kDefaultDisplayMode,
33       NULL,
34       output,
35       crtc,
36       0);
37
38   return snapshot;
39 }
40
41 class TestHelperDelegate : public NativeDisplayDelegateX11::HelperDelegate {
42  public:
43   TestHelperDelegate();
44   virtual ~TestHelperDelegate();
45
46   int num_calls_update_xrandr_config() const {
47     return num_calls_update_xrandr_config_;
48   }
49
50   int num_calls_notify_observers() const { return num_calls_notify_observers_; }
51
52   void set_cached_outputs(const std::vector<DisplaySnapshot*>& outputs) {
53     cached_outputs_ = outputs;
54   }
55
56   // NativeDisplayDelegateX11::HelperDelegate overrides:
57   virtual void UpdateXRandRConfiguration(const base::NativeEvent& event)
58       OVERRIDE;
59   virtual const std::vector<DisplaySnapshot*>& GetCachedOutputs() const
60       OVERRIDE;
61   virtual void NotifyDisplayObservers() OVERRIDE;
62
63  private:
64   int num_calls_update_xrandr_config_;
65   int num_calls_notify_observers_;
66
67   std::vector<DisplaySnapshot*> cached_outputs_;
68
69   DISALLOW_COPY_AND_ASSIGN(TestHelperDelegate);
70 };
71
72 TestHelperDelegate::TestHelperDelegate()
73     : num_calls_update_xrandr_config_(0), num_calls_notify_observers_(0) {}
74
75 TestHelperDelegate::~TestHelperDelegate() {}
76
77 void TestHelperDelegate::UpdateXRandRConfiguration(
78     const base::NativeEvent& event) {
79   ++num_calls_update_xrandr_config_;
80 }
81
82 const std::vector<DisplaySnapshot*>& TestHelperDelegate::GetCachedOutputs()
83     const {
84   return cached_outputs_;
85 }
86
87 void TestHelperDelegate::NotifyDisplayObservers() {
88   ++num_calls_notify_observers_;
89 }
90
91 ////////////////////////////////////////////////////////////////////////////////
92 // NativeDisplayEventDispatcherX11Test
93
94 class NativeDisplayEventDispatcherX11Test : public testing::Test {
95  public:
96   NativeDisplayEventDispatcherX11Test();
97   virtual ~NativeDisplayEventDispatcherX11Test();
98
99  protected:
100   void DispatchScreenChangeEvent();
101   void DispatchOutputChangeEvent(RROutput output,
102                                  RRCrtc crtc,
103                                  RRMode mode,
104                                  bool connected);
105
106   int xrandr_event_base_;
107   scoped_ptr<TestHelperDelegate> helper_delegate_;
108   scoped_ptr<NativeDisplayEventDispatcherX11> dispatcher_;
109   base::SimpleTestTickClock* test_tick_clock_;  // Owned by |dispatcher_|.
110
111  private:
112   DISALLOW_COPY_AND_ASSIGN(NativeDisplayEventDispatcherX11Test);
113 };
114
115 NativeDisplayEventDispatcherX11Test::NativeDisplayEventDispatcherX11Test()
116     : xrandr_event_base_(10),
117       helper_delegate_(new TestHelperDelegate()),
118       dispatcher_(new NativeDisplayEventDispatcherX11(helper_delegate_.get(),
119                                                       xrandr_event_base_)),
120       test_tick_clock_(new base::SimpleTestTickClock) {
121   test_tick_clock_->Advance(base::TimeDelta::FromMilliseconds(1));
122   dispatcher_->SetTickClockForTest(
123       scoped_ptr<base::TickClock>(test_tick_clock_));
124 }
125
126 NativeDisplayEventDispatcherX11Test::~NativeDisplayEventDispatcherX11Test() {}
127
128 void NativeDisplayEventDispatcherX11Test::DispatchScreenChangeEvent() {
129   XRRScreenChangeNotifyEvent event = {0};
130   event.type = xrandr_event_base_ + RRScreenChangeNotify;
131
132   dispatcher_->Dispatch(reinterpret_cast<const base::NativeEvent>(&event));
133 }
134
135 void NativeDisplayEventDispatcherX11Test::DispatchOutputChangeEvent(
136     RROutput output,
137     RRCrtc crtc,
138     RRMode mode,
139     bool connected) {
140   XRROutputChangeNotifyEvent event = {0};
141   event.type = xrandr_event_base_ + RRNotify;
142   event.subtype = RRNotify_OutputChange;
143   event.output = output;
144   event.crtc = crtc;
145   event.mode = mode;
146   event.connection = connected ? RR_Connected : RR_Disconnected;
147
148   dispatcher_->Dispatch(reinterpret_cast<const base::NativeEvent>(&event));
149 }
150
151 }  // namespace
152
153 TEST_F(NativeDisplayEventDispatcherX11Test, OnScreenChangedEvent) {
154   DispatchScreenChangeEvent();
155   EXPECT_EQ(1, helper_delegate_->num_calls_update_xrandr_config());
156   EXPECT_EQ(0, helper_delegate_->num_calls_notify_observers());
157 }
158
159 TEST_F(NativeDisplayEventDispatcherX11Test, CheckNotificationOnFirstEvent) {
160   DispatchOutputChangeEvent(1, 10, 20, true);
161   EXPECT_EQ(0, helper_delegate_->num_calls_update_xrandr_config());
162   EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers());
163 }
164
165 TEST_F(NativeDisplayEventDispatcherX11Test, CheckNotificationAfterSecondEvent) {
166   DispatchOutputChangeEvent(1, 10, 20, true);
167
168   // Simulate addition of the first output to the cached output list.
169   ScopedVector<DisplaySnapshot> outputs;
170   outputs.push_back(CreateOutput(1, 10));
171   helper_delegate_->set_cached_outputs(outputs.get());
172
173   DispatchOutputChangeEvent(2, 11, 20, true);
174   EXPECT_EQ(2, helper_delegate_->num_calls_notify_observers());
175 }
176
177 TEST_F(NativeDisplayEventDispatcherX11Test, AvoidNotificationOnDuplicateEvent) {
178   ScopedVector<DisplaySnapshot> outputs;
179   outputs.push_back(CreateOutput(1, 10));
180   helper_delegate_->set_cached_outputs(outputs.get());
181
182   // Very first event will not be ignored.
183   DispatchOutputChangeEvent(1, 10, 20, true);
184   EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers());
185
186   DispatchOutputChangeEvent(1, 10, 20, true);
187   EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers());
188 }
189
190 TEST_F(NativeDisplayEventDispatcherX11Test, CheckNotificationOnDisconnect) {
191   ScopedVector<DisplaySnapshot> outputs;
192   outputs.push_back(CreateOutput(1, 10));
193   helper_delegate_->set_cached_outputs(outputs.get());
194
195   DispatchOutputChangeEvent(1, 10, 20, false);
196   EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers());
197 }
198
199 TEST_F(NativeDisplayEventDispatcherX11Test, CheckNotificationOnModeChange) {
200   ScopedVector<DisplaySnapshot> outputs;
201   outputs.push_back(CreateOutput(1, 10));
202   helper_delegate_->set_cached_outputs(outputs.get());
203
204   DispatchOutputChangeEvent(1, 10, 21, true);
205   EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers());
206 }
207
208 TEST_F(NativeDisplayEventDispatcherX11Test, CheckNotificationOnSecondOutput) {
209   ScopedVector<DisplaySnapshot> outputs;
210   outputs.push_back(CreateOutput(1, 10));
211   helper_delegate_->set_cached_outputs(outputs.get());
212
213   DispatchOutputChangeEvent(2, 11, 20, true);
214   EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers());
215 }
216
217 TEST_F(NativeDisplayEventDispatcherX11Test, CheckNotificationOnDifferentCrtc) {
218   ScopedVector<DisplaySnapshot> outputs;
219   outputs.push_back(CreateOutput(1, 10));
220   helper_delegate_->set_cached_outputs(outputs.get());
221
222   DispatchOutputChangeEvent(1, 11, 20, true);
223   EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers());
224 }
225
226 TEST_F(NativeDisplayEventDispatcherX11Test,
227        CheckNotificationOnSecondOutputDisconnect) {
228   ScopedVector<DisplaySnapshot> outputs;
229   outputs.push_back(CreateOutput(1, 10));
230   outputs.push_back(CreateOutput(2, 11));
231   helper_delegate_->set_cached_outputs(outputs.get());
232
233   DispatchOutputChangeEvent(2, 11, 20, false);
234   EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers());
235 }
236
237 TEST_F(NativeDisplayEventDispatcherX11Test,
238        AvoidDuplicateNotificationOnSecondOutputDisconnect) {
239   ScopedVector<DisplaySnapshot> outputs;
240   outputs.push_back(CreateOutput(1, 10));
241   outputs.push_back(CreateOutput(2, 11));
242   helper_delegate_->set_cached_outputs(outputs.get());
243
244   DispatchOutputChangeEvent(2, 11, 20, false);
245   EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers());
246
247   // Simulate removal of second output from cached output list.
248   outputs.erase(outputs.begin() + 1);
249   helper_delegate_->set_cached_outputs(outputs.get());
250
251   DispatchOutputChangeEvent(2, 11, 20, false);
252   EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers());
253 }
254
255 TEST_F(NativeDisplayEventDispatcherX11Test,
256        ForceUpdateAfterCacheExpiration) {
257   // +1 to compenstate a possible rounding error.
258   const int kHalfOfExpirationMs =
259       NativeDisplayEventDispatcherX11::kCachedOutputsExpirationMs / 2 + 1;
260
261   ScopedVector<DisplaySnapshot> outputs;
262   outputs.push_back(CreateOutput(1, 10));
263   outputs.push_back(CreateOutput(2, 11));
264   helper_delegate_->set_cached_outputs(outputs.get());
265
266   EXPECT_EQ(0, helper_delegate_->num_calls_notify_observers());
267
268   DispatchOutputChangeEvent(2, 11, 20, true);
269   EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers());
270
271   // Duplicated event will be ignored.
272   DispatchOutputChangeEvent(2, 11, 20, true);
273   EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers());
274
275   test_tick_clock_->Advance(base::TimeDelta::FromMilliseconds(
276       kHalfOfExpirationMs));
277
278   // Duplicated event will still be ignored.
279   DispatchOutputChangeEvent(2, 11, 20, true);
280   EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers());
281
282   // Duplicated event does notify after expiration timeout.
283   test_tick_clock_->Advance(
284       base::TimeDelta::FromMilliseconds(kHalfOfExpirationMs));
285   DispatchOutputChangeEvent(2, 11, 20, true);
286   EXPECT_EQ(2, helper_delegate_->num_calls_notify_observers());
287
288   // Last update time has been updated, so next duplicated change event
289   // will be ignored.
290   DispatchOutputChangeEvent(2, 11, 20, true);
291   EXPECT_EQ(2, helper_delegate_->num_calls_notify_observers());
292
293   // Another duplicated change event arrived within expiration time will
294   // be ignored again.
295   test_tick_clock_->Advance(base::TimeDelta::FromMilliseconds(
296       kHalfOfExpirationMs));
297   DispatchOutputChangeEvent(2, 11, 20, true);
298   EXPECT_EQ(2, helper_delegate_->num_calls_notify_observers());
299 }
300
301 }  // namespace ui