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 17 namespace 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. 26 class 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 unsigned angle_; 36 blink::WebScreenOrientationType orientation_; 37 blink::WebLockOrientationCallback::ErrorType error_; 38 }; 39 40 explicit MockLockOrientationCallback(LockOrientationResultHolder* results) 41 : results_(results) {} 42 43 virtual void onSuccess(unsigned angle, 44 blink::WebScreenOrientationType orientation) { 45 results_->succeeded_ = true; 46 results_->angle_ = angle; 47 results_->orientation_ = orientation; 48 } 49 50 virtual void onError( 51 blink::WebLockOrientationCallback::ErrorType error) { 52 results_->failed_ = true; 53 results_->error_ = error; 54 } 55 56 private: 57 virtual ~MockLockOrientationCallback() {} 58 59 LockOrientationResultHolder* results_; 60 }; 61 62 class ScreenOrientationDispatcherWithSink : public ScreenOrientationDispatcher { 63 public: 64 explicit ScreenOrientationDispatcherWithSink(IPC::TestSink* sink) 65 :ScreenOrientationDispatcher(NULL) , sink_(sink) { 66 } 67 68 virtual bool Send(IPC::Message* message) OVERRIDE { 69 return sink_->Send(message); 70 } 71 72 IPC::TestSink* sink_; 73 }; 74 75 class ScreenOrientationDispatcherTest : public testing::Test { 76 protected: 77 virtual void SetUp() OVERRIDE { 78 dispatcher_.reset(new ScreenOrientationDispatcherWithSink(&sink_)); 79 } 80 81 int GetFirstLockRequestIdFromSink() { 82 const IPC::Message* msg = sink().GetFirstMessageMatching( 83 ScreenOrientationHostMsg_LockRequest::ID); 84 EXPECT_TRUE(msg != NULL); 85 86 Tuple2<blink::WebScreenOrientationLockType,int> params; 87 ScreenOrientationHostMsg_LockRequest::Read(msg, ¶ms); 88 return params.b; 89 } 90 91 IPC::TestSink& sink() { 92 return sink_; 93 } 94 95 void LockOrientation(blink::WebScreenOrientationLockType orientation, 96 blink::WebLockOrientationCallback* callback) { 97 dispatcher_->lockOrientation(orientation, callback); 98 } 99 100 void UnlockOrientation() { 101 dispatcher_->unlockOrientation(); 102 } 103 104 void OnMessageReceived(const IPC::Message& message) { 105 dispatcher_->OnMessageReceived(message); 106 } 107 108 int routing_id() const { 109 // We return a fake routing_id() in the context of this test. 110 return 0; 111 } 112 113 IPC::TestSink sink_; 114 scoped_ptr<ScreenOrientationDispatcher> dispatcher_; 115 }; 116 117 // Test that calling lockOrientation() followed by unlockOrientation() cancel 118 // the lockOrientation(). 119 TEST_F(ScreenOrientationDispatcherTest, CancelPending_Unlocking) { 120 MockLockOrientationCallback::LockOrientationResultHolder callback_results; 121 LockOrientation(blink::WebScreenOrientationLockPortraitPrimary, 122 new MockLockOrientationCallback(&callback_results)); 123 UnlockOrientation(); 124 125 EXPECT_FALSE(callback_results.succeeded_); 126 EXPECT_TRUE(callback_results.failed_); 127 EXPECT_EQ(blink::WebLockOrientationCallback::ErrorTypeCanceled, 128 callback_results.error_); 129 } 130 131 // Test that calling lockOrientation() twice cancel the first lockOrientation(). 132 TEST_F(ScreenOrientationDispatcherTest, CancelPending_DoubleLock) { 133 MockLockOrientationCallback::LockOrientationResultHolder callback_results; 134 // We create the object to prevent leaks but never actually use it. 135 MockLockOrientationCallback::LockOrientationResultHolder callback_results2; 136 137 LockOrientation(blink::WebScreenOrientationLockPortraitPrimary, 138 new MockLockOrientationCallback(&callback_results)); 139 LockOrientation(blink::WebScreenOrientationLockPortraitPrimary, 140 new MockLockOrientationCallback(&callback_results2)); 141 142 EXPECT_FALSE(callback_results.succeeded_); 143 EXPECT_TRUE(callback_results.failed_); 144 EXPECT_EQ(blink::WebLockOrientationCallback::ErrorTypeCanceled, 145 callback_results.error_); 146 } 147 148 // Test that when a LockError message is received, the request is set as failed 149 // with the correct values. 150 TEST_F(ScreenOrientationDispatcherTest, LockRequest_Error) { 151 std::list<blink::WebLockOrientationCallback::ErrorType> errors; 152 errors.push_back(blink::WebLockOrientationCallback::ErrorTypeNotAvailable); 153 errors.push_back( 154 blink::WebLockOrientationCallback::ErrorTypeFullScreenRequired); 155 errors.push_back(blink::WebLockOrientationCallback::ErrorTypeCanceled); 156 157 for (std::list<blink::WebLockOrientationCallback::ErrorType>::const_iterator 158 it = errors.begin(); it != errors.end(); ++it) { 159 MockLockOrientationCallback::LockOrientationResultHolder callback_results; 160 LockOrientation(blink::WebScreenOrientationLockPortraitPrimary, 161 new MockLockOrientationCallback(&callback_results)); 162 163 int request_id = GetFirstLockRequestIdFromSink(); 164 OnMessageReceived( 165 ScreenOrientationMsg_LockError(routing_id(), request_id, *it)); 166 167 EXPECT_FALSE(callback_results.succeeded_); 168 EXPECT_TRUE(callback_results.failed_); 169 EXPECT_EQ(*it, callback_results.error_); 170 171 sink().ClearMessages(); 172 } 173 } 174 175 // Test that when a LockSuccess message is received, the request is set as 176 // succeeded with the correct values. 177 TEST_F(ScreenOrientationDispatcherTest, LockRequest_Success) { 178 struct ScreenOrientationInformation { 179 unsigned angle; 180 blink::WebScreenOrientationType type; 181 } orientations[] = { 182 { 0, blink::WebScreenOrientationPortraitPrimary }, 183 { 0, blink::WebScreenOrientationLandscapePrimary }, 184 { 90, blink::WebScreenOrientationPortraitSecondary }, 185 { 90, blink::WebScreenOrientationLandscapePrimary } 186 }; 187 188 int orientationsCount = 4; 189 190 for (int i = 0; i < orientationsCount; ++i) { 191 MockLockOrientationCallback::LockOrientationResultHolder callback_results; 192 LockOrientation(blink::WebScreenOrientationLockPortraitPrimary, 193 new MockLockOrientationCallback(&callback_results)); 194 195 int request_id = GetFirstLockRequestIdFromSink(); 196 OnMessageReceived(ScreenOrientationMsg_LockSuccess(routing_id(), 197 request_id, 198 orientations[i].angle, 199 orientations[i].type)); 200 201 EXPECT_TRUE(callback_results.succeeded_); 202 EXPECT_FALSE(callback_results.failed_); 203 EXPECT_EQ(orientations[i].angle, callback_results.angle_); 204 EXPECT_EQ(orientations[i].type, callback_results.orientation_); 205 206 sink().ClearMessages(); 207 } 208 } 209 210 // Test an edge case: a LockSuccess is received but it matches no pending 211 // callback. 212 TEST_F(ScreenOrientationDispatcherTest, SuccessForUnknownRequest) { 213 MockLockOrientationCallback::LockOrientationResultHolder callback_results; 214 LockOrientation(blink::WebScreenOrientationLockPortraitPrimary, 215 new MockLockOrientationCallback(&callback_results)); 216 217 int request_id = GetFirstLockRequestIdFromSink(); 218 OnMessageReceived(ScreenOrientationMsg_LockSuccess( 219 routing_id(), 220 request_id + 1, 221 90, 222 blink::WebScreenOrientationLandscapePrimary)); 223 224 EXPECT_FALSE(callback_results.succeeded_); 225 EXPECT_FALSE(callback_results.failed_); 226 } 227 228 // Test an edge case: a LockError is received but it matches no pending 229 // callback. 230 TEST_F(ScreenOrientationDispatcherTest, ErrorForUnknownRequest) { 231 MockLockOrientationCallback::LockOrientationResultHolder callback_results; 232 LockOrientation(blink::WebScreenOrientationLockPortraitPrimary, 233 new MockLockOrientationCallback(&callback_results)); 234 235 int request_id = GetFirstLockRequestIdFromSink(); 236 OnMessageReceived(ScreenOrientationMsg_LockError( 237 routing_id(), 238 request_id + 1, 239 blink::WebLockOrientationCallback::ErrorTypeCanceled)); 240 241 EXPECT_FALSE(callback_results.succeeded_); 242 EXPECT_FALSE(callback_results.failed_); 243 } 244 245 // Test the following scenario: 246 // - request1 is received by the dispatcher; 247 // - request2 is received by the dispatcher; 248 // - request1 is rejected; 249 // - request1 success response is received. 250 // Expected: request1 is still rejected, request2 has not been set as succeeded. 251 TEST_F(ScreenOrientationDispatcherTest, RaceScenario) { 252 MockLockOrientationCallback::LockOrientationResultHolder callback_results1; 253 MockLockOrientationCallback::LockOrientationResultHolder callback_results2; 254 255 LockOrientation(blink::WebScreenOrientationLockPortraitPrimary, 256 new MockLockOrientationCallback(&callback_results1)); 257 int request_id1 = GetFirstLockRequestIdFromSink(); 258 259 LockOrientation(blink::WebScreenOrientationLockLandscapePrimary, 260 new MockLockOrientationCallback(&callback_results2)); 261 262 // callback_results1 must be rejected, tested in CancelPending_DoubleLock. 263 264 OnMessageReceived(ScreenOrientationMsg_LockSuccess( 265 routing_id(), 266 request_id1, 267 0, 268 blink::WebScreenOrientationPortraitPrimary)); 269 270 // First request is still rejected. 271 EXPECT_FALSE(callback_results1.succeeded_); 272 EXPECT_TRUE(callback_results1.failed_); 273 EXPECT_EQ(blink::WebLockOrientationCallback::ErrorTypeCanceled, 274 callback_results1.error_); 275 276 // Second request is still pending. 277 EXPECT_FALSE(callback_results2.succeeded_); 278 EXPECT_FALSE(callback_results2.failed_); 279 } 280 281 } // namespace content 282