screen_orientation_dispatcher_unittest.cc revision 46d4c2bc3267f3f028f39e7e311b0f89aba2e4fd
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 "screen_orientation_dispatcher.h"
6
7#include <list>
8
9#include "base/logging.h"
10#include "base/memory/scoped_ptr.h"
11#include "content/common/screen_orientation_messages.h"
12#include "content/public/test/mock_render_thread.h"
13#include "content/public/test/test_utils.h"
14#include "testing/gtest/include/gtest/gtest.h"
15#include "third_party/WebKit/public/platform/WebLockOrientationCallback.h"
16#include "third_party/WebKit/public/platform/WebScreenOrientationListener.h"
17
18namespace content {
19
20class MockScreenOrientationListener :
21    public blink::WebScreenOrientationListener {
22 public:
23  MockScreenOrientationListener();
24  virtual ~MockScreenOrientationListener() {}
25
26  virtual void didChangeScreenOrientation(
27      blink::WebScreenOrientationType) OVERRIDE;
28
29  bool did_change_screen_orientation() const {
30    return did_change_screen_orientation_;
31  }
32
33  blink::WebScreenOrientationType screen_orientation() const {
34    return screen_orientation_;
35  }
36
37 private:
38  bool did_change_screen_orientation_;
39  blink::WebScreenOrientationType screen_orientation_;
40
41  DISALLOW_COPY_AND_ASSIGN(MockScreenOrientationListener);
42};
43
44// MockLockOrientationCallback is an implementation of
45// WebLockOrientationCallback and takes a LockOrientationResultHolder* as a
46// parameter when being constructed. The |results_| pointer is owned by the
47// caller and not by the callback object. The intent being that as soon as the
48// callback is resolved, it will be killed so we use the
49// LockOrientationResultHolder to know in which state the callback object is at
50// any time.
51class MockLockOrientationCallback :
52    public blink::WebLockOrientationCallback {
53 public:
54  struct LockOrientationResultHolder {
55    LockOrientationResultHolder()
56        : succeeded_(false), failed_(false) {}
57
58    bool succeeded_;
59    bool failed_;
60    unsigned angle_;
61    blink::WebScreenOrientationType orientation_;
62    blink::WebLockOrientationCallback::ErrorType error_;
63  };
64
65  static scoped_ptr<blink::WebLockOrientationCallback> CreateScoped(
66      LockOrientationResultHolder* results) {
67    return scoped_ptr<blink::WebLockOrientationCallback>(
68        new MockLockOrientationCallback(results));
69  }
70
71  virtual void onSuccess(unsigned angle,
72                         blink::WebScreenOrientationType orientation) {
73    results_->succeeded_ = true;
74    results_->angle_ = angle;
75    results_->orientation_ = orientation;
76  }
77
78  virtual void onError(
79      blink::WebLockOrientationCallback::ErrorType error) {
80    results_->failed_ = true;
81    results_->error_ = error;
82  }
83
84 private:
85  explicit MockLockOrientationCallback(LockOrientationResultHolder* results)
86      : results_(results) {}
87
88  virtual ~MockLockOrientationCallback() {}
89
90  LockOrientationResultHolder* results_;
91};
92
93MockScreenOrientationListener::MockScreenOrientationListener()
94    : did_change_screen_orientation_(false),
95      screen_orientation_(blink::WebScreenOrientationPortraitPrimary) {
96}
97
98void MockScreenOrientationListener::didChangeScreenOrientation(
99    blink::WebScreenOrientationType orientation) {
100  did_change_screen_orientation_ = true;
101  screen_orientation_ = orientation;
102}
103
104class ScreenOrientationDispatcherTest : public testing::Test {
105 protected:
106  virtual void SetUp() OVERRIDE {
107    render_thread_.reset(new MockRenderThread);
108    listener_.reset(new MockScreenOrientationListener);
109    dispatcher_.reset(new ScreenOrientationDispatcher);
110    dispatcher_->setListener(listener_.get());
111  }
112
113  int GetFirstLockRequestIdFromSink() {
114    const IPC::Message* msg = render_thread_->sink().GetFirstMessageMatching(
115        ScreenOrientationHostMsg_LockRequest::ID);
116    EXPECT_TRUE(msg != NULL);
117
118    Tuple2<blink::WebScreenOrientationLockType,int> params;
119    ScreenOrientationHostMsg_LockRequest::Read(msg, &params);
120    return params.b;
121  }
122
123  scoped_ptr<MockRenderThread> render_thread_;
124  scoped_ptr<MockScreenOrientationListener> listener_;
125  scoped_ptr<ScreenOrientationDispatcher> dispatcher_;
126};
127
128TEST_F(ScreenOrientationDispatcherTest, ListensToMessages) {
129  EXPECT_TRUE(render_thread_->observers().HasObserver(dispatcher_.get()));
130
131  render_thread_->OnControlMessageReceived(
132      ScreenOrientationMsg_OrientationChange(
133          blink::WebScreenOrientationPortraitPrimary));
134
135  EXPECT_TRUE(listener_->did_change_screen_orientation());
136}
137
138TEST_F(ScreenOrientationDispatcherTest, NullListener) {
139  dispatcher_->setListener(NULL);
140
141  render_thread_->OnControlMessageReceived(
142      ScreenOrientationMsg_OrientationChange(
143          blink::WebScreenOrientationPortraitPrimary));
144
145  EXPECT_FALSE(listener_->did_change_screen_orientation());
146}
147
148TEST_F(ScreenOrientationDispatcherTest, ValidValues) {
149  render_thread_->OnControlMessageReceived(
150      ScreenOrientationMsg_OrientationChange(
151          blink::WebScreenOrientationPortraitPrimary));
152  EXPECT_EQ(blink::WebScreenOrientationPortraitPrimary,
153               listener_->screen_orientation());
154
155  render_thread_->OnControlMessageReceived(
156      ScreenOrientationMsg_OrientationChange(
157          blink::WebScreenOrientationLandscapePrimary));
158  EXPECT_EQ(blink::WebScreenOrientationLandscapePrimary,
159               listener_->screen_orientation());
160
161  render_thread_->OnControlMessageReceived(
162      ScreenOrientationMsg_OrientationChange(
163          blink::WebScreenOrientationPortraitSecondary));
164  EXPECT_EQ(blink::WebScreenOrientationPortraitSecondary,
165               listener_->screen_orientation());
166
167  render_thread_->OnControlMessageReceived(
168      ScreenOrientationMsg_OrientationChange(
169          blink::WebScreenOrientationLandscapeSecondary));
170  EXPECT_EQ(blink::WebScreenOrientationLandscapeSecondary,
171               listener_->screen_orientation());
172}
173
174// Test that calling LockOrientation() followed by UnlockOrientation() cancel
175// the LockOrientation().
176TEST_F(ScreenOrientationDispatcherTest, CancelPending_Unlocking) {
177  MockLockOrientationCallback::LockOrientationResultHolder callback_results;
178  dispatcher_->LockOrientation(
179      blink::WebScreenOrientationLockPortraitPrimary,
180      MockLockOrientationCallback::CreateScoped(&callback_results));
181  dispatcher_->UnlockOrientation();
182
183  EXPECT_FALSE(callback_results.succeeded_);
184  EXPECT_TRUE(callback_results.failed_);
185  EXPECT_EQ(blink::WebLockOrientationCallback::ErrorTypeCanceled,
186            callback_results.error_);
187}
188
189// Test that calling LockOrientation() twice cancel the first LockOrientation().
190TEST_F(ScreenOrientationDispatcherTest, CancelPending_DoubleLock) {
191  MockLockOrientationCallback::LockOrientationResultHolder callback_results;
192  // We create the object to prevent leaks but never actually use it.
193  MockLockOrientationCallback::LockOrientationResultHolder callback_results2;
194
195  dispatcher_->LockOrientation(
196      blink::WebScreenOrientationLockPortraitPrimary,
197      MockLockOrientationCallback::CreateScoped(&callback_results));
198  dispatcher_->LockOrientation(
199      blink::WebScreenOrientationLockPortraitPrimary,
200      MockLockOrientationCallback::CreateScoped(&callback_results2));
201
202  EXPECT_FALSE(callback_results.succeeded_);
203  EXPECT_TRUE(callback_results.failed_);
204  EXPECT_EQ(blink::WebLockOrientationCallback::ErrorTypeCanceled,
205            callback_results.error_);
206}
207
208// Test that when a LockError message is received, the request is set as failed
209// with the correct values.
210TEST_F(ScreenOrientationDispatcherTest, LockRequest_Error) {
211  std::list<blink::WebLockOrientationCallback::ErrorType> errors;
212  errors.push_back(blink::WebLockOrientationCallback::ErrorTypeNotAvailable);
213  errors.push_back(
214      blink::WebLockOrientationCallback::ErrorTypeFullScreenRequired);
215  errors.push_back(blink::WebLockOrientationCallback::ErrorTypeCanceled);
216
217  for (std::list<blink::WebLockOrientationCallback::ErrorType>::const_iterator
218          it = errors.begin(); it != errors.end(); ++it) {
219    render_thread_->sink().ClearMessages();
220
221    MockLockOrientationCallback::LockOrientationResultHolder callback_results;
222    dispatcher_->LockOrientation(
223        blink::WebScreenOrientationLockPortraitPrimary,
224        MockLockOrientationCallback::CreateScoped(&callback_results));
225
226    int request_id = GetFirstLockRequestIdFromSink();
227    render_thread_->OnControlMessageReceived(
228        ScreenOrientationMsg_LockError(request_id, *it));
229
230    EXPECT_FALSE(callback_results.succeeded_);
231    EXPECT_TRUE(callback_results.failed_);
232    EXPECT_EQ(*it, callback_results.error_);
233  }
234}
235
236// Test that when a LockSuccess message is received, the request is set as
237// succeeded with the correct values.
238TEST_F(ScreenOrientationDispatcherTest, LockRequest_Success) {
239  struct ScreenOrientationInformation {
240    unsigned angle;
241    blink::WebScreenOrientationType type;
242  } orientations[] = {
243    { 0, blink::WebScreenOrientationPortraitPrimary },
244    { 0, blink::WebScreenOrientationLandscapePrimary },
245    { 90, blink::WebScreenOrientationPortraitSecondary },
246    { 90, blink::WebScreenOrientationLandscapePrimary }
247  };
248
249  int orientationsCount = 4;
250
251  for (int i = 0; i < orientationsCount; ++i) {
252    render_thread_->sink().ClearMessages();
253
254    MockLockOrientationCallback::LockOrientationResultHolder callback_results;
255    dispatcher_->LockOrientation(
256        blink::WebScreenOrientationLockPortraitPrimary,
257        MockLockOrientationCallback::CreateScoped(&callback_results));
258
259    int request_id = GetFirstLockRequestIdFromSink();
260    render_thread_->OnControlMessageReceived(
261        ScreenOrientationMsg_LockSuccess(request_id,
262                                         orientations[i].angle,
263                                         orientations[i].type));
264
265    EXPECT_TRUE(callback_results.succeeded_);
266    EXPECT_FALSE(callback_results.failed_);
267    EXPECT_EQ(orientations[i].angle, callback_results.angle_);
268    EXPECT_EQ(orientations[i].type, callback_results.orientation_);
269  }
270}
271
272// Test an edge case: a LockSuccess is received but it matches no pending
273// callback.
274TEST_F(ScreenOrientationDispatcherTest, SuccessForUnknownRequest) {
275  MockLockOrientationCallback::LockOrientationResultHolder callback_results;
276  dispatcher_->LockOrientation(
277      blink::WebScreenOrientationLockPortraitPrimary,
278      MockLockOrientationCallback::CreateScoped(&callback_results));
279
280  int request_id = GetFirstLockRequestIdFromSink();
281  render_thread_->OnControlMessageReceived(ScreenOrientationMsg_LockSuccess(
282      request_id + 1,
283      90,
284      blink::WebScreenOrientationLandscapePrimary));
285
286  EXPECT_FALSE(callback_results.succeeded_);
287  EXPECT_FALSE(callback_results.failed_);
288}
289
290// Test an edge case: a LockError is received but it matches no pending
291// callback.
292TEST_F(ScreenOrientationDispatcherTest, ErrorForUnknownRequest) {
293  MockLockOrientationCallback::LockOrientationResultHolder callback_results;
294  dispatcher_->LockOrientation(
295      blink::WebScreenOrientationLockPortraitPrimary,
296      MockLockOrientationCallback::CreateScoped(&callback_results));
297
298  int request_id = GetFirstLockRequestIdFromSink();
299  render_thread_->OnControlMessageReceived(ScreenOrientationMsg_LockError(
300      request_id + 1,
301      blink::WebLockOrientationCallback::ErrorTypeCanceled));
302
303  EXPECT_FALSE(callback_results.succeeded_);
304  EXPECT_FALSE(callback_results.failed_);
305}
306
307// Test the following scenario:
308// - request1 is received by the dispatcher;
309// - request2 is received by the dispatcher;
310// - request1 is rejected;
311// - request1 success response is received.
312// Expected: request1 is still rejected, request2 has not been set as succeeded.
313TEST_F(ScreenOrientationDispatcherTest, RaceScenario) {
314  MockLockOrientationCallback::LockOrientationResultHolder callback_results1;
315  MockLockOrientationCallback::LockOrientationResultHolder callback_results2;
316
317  dispatcher_->LockOrientation(
318      blink::WebScreenOrientationLockPortraitPrimary,
319      MockLockOrientationCallback::CreateScoped(&callback_results1));
320  int request_id1 = GetFirstLockRequestIdFromSink();
321
322  dispatcher_->LockOrientation(
323      blink::WebScreenOrientationLockLandscapePrimary,
324      MockLockOrientationCallback::CreateScoped(&callback_results2));
325
326  // callback_results1 must be rejected, tested in CancelPending_DoubleLock.
327
328  render_thread_->OnControlMessageReceived(ScreenOrientationMsg_LockSuccess(
329      request_id1,
330      0,
331      blink::WebScreenOrientationPortraitPrimary));
332
333  // First request is still rejected.
334  EXPECT_FALSE(callback_results1.succeeded_);
335  EXPECT_TRUE(callback_results1.failed_);
336  EXPECT_EQ(blink::WebLockOrientationCallback::ErrorTypeCanceled,
337            callback_results1.error_);
338
339  // Second request is still pending.
340  EXPECT_FALSE(callback_results2.succeeded_);
341  EXPECT_FALSE(callback_results2.failed_);
342}
343
344}  // namespace content
345