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, ¶ms); 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