Home | History | Annotate | Download | only in screen_orientation
      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, &params);
     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