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/test_utils.h" 13#include "ipc/ipc_test_sink.h" 14#include "testing/gtest/include/gtest/gtest.h" 15#include "third_party/WebKit/public/platform/WebLockOrientationCallback.h" 16 17namespace content { 18 19// MockLockOrientationCallback is an implementation of 20// WebLockOrientationCallback and takes a LockOrientationResultHolder* as a 21// parameter when being constructed. The |results_| pointer is owned by the 22// caller and not by the callback object. The intent being that as soon as the 23// callback is resolved, it will be killed so we use the 24// LockOrientationResultHolder to know in which state the callback object is at 25// any time. 26class MockLockOrientationCallback : 27 public blink::WebLockOrientationCallback { 28 public: 29 struct LockOrientationResultHolder { 30 LockOrientationResultHolder() 31 : succeeded_(false), failed_(false) {} 32 33 bool succeeded_; 34 bool failed_; 35 blink::WebLockOrientationError error_; 36 }; 37 38 explicit MockLockOrientationCallback(LockOrientationResultHolder* results) 39 : results_(results) {} 40 41 virtual void onSuccess() { 42 results_->succeeded_ = true; 43 } 44 45 virtual void onError(blink::WebLockOrientationError error) { 46 results_->failed_ = true; 47 results_->error_ = error; 48 } 49 50 private: 51 virtual ~MockLockOrientationCallback() {} 52 53 LockOrientationResultHolder* results_; 54}; 55 56class ScreenOrientationDispatcherWithSink : public ScreenOrientationDispatcher { 57 public: 58 explicit ScreenOrientationDispatcherWithSink(IPC::TestSink* sink) 59 :ScreenOrientationDispatcher(NULL) , sink_(sink) { 60 } 61 62 virtual bool Send(IPC::Message* message) OVERRIDE { 63 return sink_->Send(message); 64 } 65 66 IPC::TestSink* sink_; 67}; 68 69class ScreenOrientationDispatcherTest : public testing::Test { 70 protected: 71 virtual void SetUp() OVERRIDE { 72 dispatcher_.reset(new ScreenOrientationDispatcherWithSink(&sink_)); 73 } 74 75 int GetFirstLockRequestIdFromSink() { 76 const IPC::Message* msg = sink().GetFirstMessageMatching( 77 ScreenOrientationHostMsg_LockRequest::ID); 78 EXPECT_TRUE(msg != NULL); 79 80 Tuple2<blink::WebScreenOrientationLockType,int> params; 81 ScreenOrientationHostMsg_LockRequest::Read(msg, ¶ms); 82 return params.b; 83 } 84 85 IPC::TestSink& sink() { 86 return sink_; 87 } 88 89 void LockOrientation(blink::WebScreenOrientationLockType orientation, 90 blink::WebLockOrientationCallback* callback) { 91 dispatcher_->lockOrientation(orientation, callback); 92 } 93 94 void UnlockOrientation() { 95 dispatcher_->unlockOrientation(); 96 } 97 98 void OnMessageReceived(const IPC::Message& message) { 99 dispatcher_->OnMessageReceived(message); 100 } 101 102 int routing_id() const { 103 // We return a fake routing_id() in the context of this test. 104 return 0; 105 } 106 107 IPC::TestSink sink_; 108 scoped_ptr<ScreenOrientationDispatcher> dispatcher_; 109}; 110 111// Test that calling lockOrientation() followed by unlockOrientation() cancel 112// the lockOrientation(). 113TEST_F(ScreenOrientationDispatcherTest, CancelPending_Unlocking) { 114 MockLockOrientationCallback::LockOrientationResultHolder callback_results; 115 LockOrientation(blink::WebScreenOrientationLockPortraitPrimary, 116 new MockLockOrientationCallback(&callback_results)); 117 UnlockOrientation(); 118 119 EXPECT_FALSE(callback_results.succeeded_); 120 EXPECT_TRUE(callback_results.failed_); 121 EXPECT_EQ(blink::WebLockOrientationErrorCanceled, callback_results.error_); 122} 123 124// Test that calling lockOrientation() twice cancel the first lockOrientation(). 125TEST_F(ScreenOrientationDispatcherTest, CancelPending_DoubleLock) { 126 MockLockOrientationCallback::LockOrientationResultHolder callback_results; 127 // We create the object to prevent leaks but never actually use it. 128 MockLockOrientationCallback::LockOrientationResultHolder callback_results2; 129 130 LockOrientation(blink::WebScreenOrientationLockPortraitPrimary, 131 new MockLockOrientationCallback(&callback_results)); 132 LockOrientation(blink::WebScreenOrientationLockPortraitPrimary, 133 new MockLockOrientationCallback(&callback_results2)); 134 135 EXPECT_FALSE(callback_results.succeeded_); 136 EXPECT_TRUE(callback_results.failed_); 137 EXPECT_EQ(blink::WebLockOrientationErrorCanceled, callback_results.error_); 138} 139 140// Test that when a LockError message is received, the request is set as failed 141// with the correct values. 142TEST_F(ScreenOrientationDispatcherTest, LockRequest_Error) { 143 std::list<blink::WebLockOrientationError> errors; 144 errors.push_back(blink::WebLockOrientationErrorNotAvailable); 145 errors.push_back( 146 blink::WebLockOrientationErrorFullScreenRequired); 147 errors.push_back(blink::WebLockOrientationErrorCanceled); 148 149 for (std::list<blink::WebLockOrientationError>::const_iterator 150 it = errors.begin(); it != errors.end(); ++it) { 151 MockLockOrientationCallback::LockOrientationResultHolder callback_results; 152 LockOrientation(blink::WebScreenOrientationLockPortraitPrimary, 153 new MockLockOrientationCallback(&callback_results)); 154 155 int request_id = GetFirstLockRequestIdFromSink(); 156 OnMessageReceived( 157 ScreenOrientationMsg_LockError(routing_id(), request_id, *it)); 158 159 EXPECT_FALSE(callback_results.succeeded_); 160 EXPECT_TRUE(callback_results.failed_); 161 EXPECT_EQ(*it, callback_results.error_); 162 163 sink().ClearMessages(); 164 } 165} 166 167// Test that when a LockSuccess message is received, the request is set as 168// succeeded. 169TEST_F(ScreenOrientationDispatcherTest, LockRequest_Success) { 170 MockLockOrientationCallback::LockOrientationResultHolder callback_results; 171 LockOrientation(blink::WebScreenOrientationLockPortraitPrimary, 172 new MockLockOrientationCallback(&callback_results)); 173 174 int request_id = GetFirstLockRequestIdFromSink(); 175 OnMessageReceived(ScreenOrientationMsg_LockSuccess(routing_id(), 176 request_id)); 177 178 EXPECT_TRUE(callback_results.succeeded_); 179 EXPECT_FALSE(callback_results.failed_); 180 181 sink().ClearMessages(); 182} 183 184// Test an edge case: a LockSuccess is received but it matches no pending 185// callback. 186TEST_F(ScreenOrientationDispatcherTest, SuccessForUnknownRequest) { 187 MockLockOrientationCallback::LockOrientationResultHolder callback_results; 188 LockOrientation(blink::WebScreenOrientationLockPortraitPrimary, 189 new MockLockOrientationCallback(&callback_results)); 190 191 int request_id = GetFirstLockRequestIdFromSink(); 192 OnMessageReceived(ScreenOrientationMsg_LockSuccess(routing_id(), 193 request_id + 1)); 194 195 EXPECT_FALSE(callback_results.succeeded_); 196 EXPECT_FALSE(callback_results.failed_); 197} 198 199// Test an edge case: a LockError is received but it matches no pending 200// callback. 201TEST_F(ScreenOrientationDispatcherTest, ErrorForUnknownRequest) { 202 MockLockOrientationCallback::LockOrientationResultHolder callback_results; 203 LockOrientation(blink::WebScreenOrientationLockPortraitPrimary, 204 new MockLockOrientationCallback(&callback_results)); 205 206 int request_id = GetFirstLockRequestIdFromSink(); 207 OnMessageReceived(ScreenOrientationMsg_LockError( 208 routing_id(), request_id + 1, blink::WebLockOrientationErrorCanceled)); 209 210 EXPECT_FALSE(callback_results.succeeded_); 211 EXPECT_FALSE(callback_results.failed_); 212} 213 214// Test the following scenario: 215// - request1 is received by the dispatcher; 216// - request2 is received by the dispatcher; 217// - request1 is rejected; 218// - request1 success response is received. 219// Expected: request1 is still rejected, request2 has not been set as succeeded. 220TEST_F(ScreenOrientationDispatcherTest, RaceScenario) { 221 MockLockOrientationCallback::LockOrientationResultHolder callback_results1; 222 MockLockOrientationCallback::LockOrientationResultHolder callback_results2; 223 224 LockOrientation(blink::WebScreenOrientationLockPortraitPrimary, 225 new MockLockOrientationCallback(&callback_results1)); 226 int request_id1 = GetFirstLockRequestIdFromSink(); 227 228 LockOrientation(blink::WebScreenOrientationLockLandscapePrimary, 229 new MockLockOrientationCallback(&callback_results2)); 230 231 // callback_results1 must be rejected, tested in CancelPending_DoubleLock. 232 233 OnMessageReceived(ScreenOrientationMsg_LockSuccess(routing_id(), 234 request_id1)); 235 236 // First request is still rejected. 237 EXPECT_FALSE(callback_results1.succeeded_); 238 EXPECT_TRUE(callback_results1.failed_); 239 EXPECT_EQ(blink::WebLockOrientationErrorCanceled, callback_results1.error_); 240 241 // Second request is still pending. 242 EXPECT_FALSE(callback_results2.succeeded_); 243 EXPECT_FALSE(callback_results2.failed_); 244} 245 246} // namespace content 247