Home | History | Annotate | Download | only in app_list
      1 // Copyright (c) 2012 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 "ui/app_list/pagination_model.h"
      6 
      7 #include <string>
      8 
      9 #include "base/basictypes.h"
     10 #include "base/compiler_specific.h"
     11 #include "base/message_loop/message_loop.h"
     12 #include "base/strings/stringprintf.h"
     13 #include "testing/gtest/include/gtest/gtest.h"
     14 #include "ui/app_list/pagination_model_observer.h"
     15 
     16 namespace app_list {
     17 namespace test {
     18 
     19 class TestPaginationModelObserver : public PaginationModelObserver {
     20  public:
     21   TestPaginationModelObserver()
     22       : model_(NULL),
     23         expected_page_selection_(0),
     24         expected_transition_start_(0),
     25         expected_transition_end_(0),
     26         transition_page_(-1) {
     27     Reset();
     28   }
     29   virtual ~TestPaginationModelObserver() {}
     30 
     31   void Reset() {
     32     selection_count_ = 0;
     33     transition_start_count_ = 0;
     34     transition_end_count_ = 0;
     35     selected_pages_.clear();
     36   }
     37 
     38   void set_model(PaginationModel* model) { model_ = model; }
     39 
     40   void set_expected_page_selection(int expected_page_selection) {
     41     expected_page_selection_ = expected_page_selection;
     42   }
     43   void set_expected_transition_start(int expected_transition_start) {
     44     expected_transition_start_ = expected_transition_start;
     45   }
     46   void set_expected_transition_end(int expected_transition_end) {
     47     expected_transition_end_ = expected_transition_end;
     48   }
     49   void set_transition_page(int page) { transition_page_ = page; }
     50 
     51   const std::string& selected_pages() const { return selected_pages_; }
     52   int selection_count() const { return selection_count_; }
     53   int transition_start_count() const { return transition_start_count_; }
     54   int transition_end_count() const { return transition_end_count_; }
     55 
     56  private:
     57   void AppendSelectedPage(int page) {
     58     if (selected_pages_.length())
     59       selected_pages_.append(std::string(" "));
     60     selected_pages_.append(base::StringPrintf("%d", page));
     61   }
     62 
     63   // PaginationModelObserver overrides:
     64   virtual void TotalPagesChanged() OVERRIDE {}
     65   virtual void SelectedPageChanged(int old_selected,
     66                                    int new_selected) OVERRIDE {
     67     AppendSelectedPage(new_selected);
     68     ++selection_count_;
     69     if (expected_page_selection_ &&
     70         selection_count_ == expected_page_selection_) {
     71       base::MessageLoop::current()->Quit();
     72     }
     73   }
     74 
     75   virtual void TransitionStarted() OVERRIDE {
     76   }
     77 
     78   virtual void TransitionChanged() OVERRIDE {
     79     if (transition_page_ == -1 ||
     80         model_->transition().target_page == transition_page_) {
     81       if (model_->transition().progress == 0)
     82         ++transition_start_count_;
     83       if (model_->transition().progress == 1)
     84         ++transition_end_count_;
     85     }
     86 
     87     if ((expected_transition_start_ &&
     88          transition_start_count_ == expected_transition_start_) ||
     89         (expected_transition_end_ &&
     90          transition_end_count_ == expected_transition_end_)) {
     91       base::MessageLoop::current()->Quit();
     92     }
     93   }
     94 
     95   PaginationModel* model_;
     96 
     97   int expected_page_selection_;
     98   int expected_transition_start_;
     99   int expected_transition_end_;
    100 
    101   int selection_count_;
    102   int transition_start_count_;
    103   int transition_end_count_;
    104 
    105   // Indicate which page index should be counted for |transition_start_count_|
    106   // and |transition_end_count_|. -1 means all the pages should be counted.
    107   int transition_page_;
    108 
    109   std::string selected_pages_;
    110 
    111   DISALLOW_COPY_AND_ASSIGN(TestPaginationModelObserver);
    112 };
    113 
    114 class PaginationModelTest : public testing::Test {
    115  public:
    116   PaginationModelTest() {}
    117   virtual ~PaginationModelTest() {}
    118 
    119   // testing::Test overrides:
    120   virtual void SetUp() OVERRIDE {
    121     pagination_.SetTotalPages(5);
    122     pagination_.SetTransitionDurations(1, 1);
    123     observer_.set_model(&pagination_);
    124     pagination_.AddObserver(&observer_);
    125   }
    126   virtual void TearDown() OVERRIDE {
    127     pagination_.RemoveObserver(&observer_);
    128     observer_.set_model(NULL);
    129   }
    130 
    131  protected:
    132   void SetStartPageAndExpects(int start_page,
    133                               int expected_selection,
    134                               int expected_transition_start,
    135                               int expected_transition_end) {
    136     observer_.set_expected_page_selection(0);
    137     pagination_.SelectPage(start_page, false /* animate */);
    138     observer_.Reset();
    139     observer_.set_expected_page_selection(expected_selection);
    140     observer_.set_expected_transition_start(expected_transition_start);
    141     observer_.set_expected_transition_end(expected_transition_end);
    142   }
    143 
    144   PaginationModel pagination_;
    145   TestPaginationModelObserver observer_;
    146 
    147  private:
    148   base::MessageLoopForUI message_loop_;
    149 
    150   DISALLOW_COPY_AND_ASSIGN(PaginationModelTest);
    151 };
    152 
    153 TEST_F(PaginationModelTest, SelectPage) {
    154   pagination_.SelectPage(2, false /* animate */);
    155   pagination_.SelectPage(4, false /* animate */);
    156   pagination_.SelectPage(3, false /* animate */);
    157   pagination_.SelectPage(1, false /* animate */);
    158 
    159   EXPECT_EQ(0, observer_.transition_start_count());
    160   EXPECT_EQ(0, observer_.transition_end_count());
    161   EXPECT_EQ(4, observer_.selection_count());
    162   EXPECT_EQ(std::string("2 4 3 1"), observer_.selected_pages());
    163 
    164   // Nothing happens if select the same page.
    165   pagination_.SelectPage(1, false /* animate */);
    166   EXPECT_EQ(4, observer_.selection_count());
    167   EXPECT_EQ(std::string("2 4 3 1"), observer_.selected_pages());
    168 }
    169 
    170 TEST_F(PaginationModelTest, SelectPageAnimated) {
    171   const int kStartPage = 0;
    172 
    173   // One transition.
    174   SetStartPageAndExpects(kStartPage, 1, 0, 0);
    175   pagination_.SelectPage(1, true /* animate */);
    176   base::MessageLoop::current()->Run();
    177   EXPECT_EQ(1, observer_.transition_start_count());
    178   EXPECT_EQ(1, observer_.transition_end_count());
    179   EXPECT_EQ(1, observer_.selection_count());
    180   EXPECT_EQ(std::string("1"), observer_.selected_pages());
    181 
    182   // Two transitions in a row.
    183   SetStartPageAndExpects(kStartPage, 2, 0, 0);
    184   pagination_.SelectPage(1, true /* animate */);
    185   pagination_.SelectPage(3, true /* animate */);
    186   base::MessageLoop::current()->Run();
    187   EXPECT_EQ(2, observer_.transition_start_count());
    188   EXPECT_EQ(2, observer_.transition_end_count());
    189   EXPECT_EQ(2, observer_.selection_count());
    190   EXPECT_EQ(std::string("1 3"), observer_.selected_pages());
    191 
    192   // Transition to same page twice and only one should happen.
    193   SetStartPageAndExpects(kStartPage, 1, 0, 0);
    194   pagination_.SelectPage(1, true /* animate */);
    195   pagination_.SelectPage(1, true /* animate */);  // Ignored.
    196   base::MessageLoop::current()->Run();
    197   EXPECT_EQ(1, observer_.transition_start_count());
    198   EXPECT_EQ(1, observer_.transition_end_count());
    199   EXPECT_EQ(1, observer_.selection_count());
    200   EXPECT_EQ(std::string("1"), observer_.selected_pages());
    201 
    202   // More than two transitions and only the first and last would happen.
    203   SetStartPageAndExpects(kStartPage, 2, 0, 0);
    204   pagination_.SelectPage(1, true /* animate */);
    205   pagination_.SelectPage(3, true /* animate */);  // Ignored
    206   pagination_.SelectPage(4, true /* animate */);  // Ignored
    207   pagination_.SelectPage(2, true /* animate */);
    208   base::MessageLoop::current()->Run();
    209   EXPECT_EQ(2, observer_.transition_start_count());
    210   EXPECT_EQ(2, observer_.transition_end_count());
    211   EXPECT_EQ(2, observer_.selection_count());
    212   EXPECT_EQ(std::string("1 2"), observer_.selected_pages());
    213 
    214   // Multiple transitions with one transition that goes back to the original
    215   // and followed by a new transition. Two transitions would happen. The first
    216   // one will be reversed by the kStart transition and the second one will be
    217   // finished.
    218   SetStartPageAndExpects(kStartPage, 1, 0, 0);
    219   pagination_.SelectPage(1, true /* animate */);
    220   pagination_.SelectPage(2, true /* animate */);  // Ignored
    221   pagination_.SelectPage(kStartPage, true /* animate */);
    222   pagination_.SelectPage(3, true /* animate */);
    223   base::MessageLoop::current()->Run();
    224   EXPECT_EQ(std::string("3"), observer_.selected_pages());
    225 }
    226 
    227 TEST_F(PaginationModelTest, SimpleScroll) {
    228   const int kStartPage = 2;
    229 
    230   // Scroll to the next page (negative delta) and finish it.
    231   SetStartPageAndExpects(kStartPage, 1, 0, 0);
    232   pagination_.StartScroll();
    233   pagination_.UpdateScroll(-0.1);
    234   EXPECT_EQ(kStartPage + 1, pagination_.transition().target_page);
    235   pagination_.EndScroll(false);  // Finish transition
    236   base::MessageLoop::current()->Run();
    237   EXPECT_EQ(1, observer_.selection_count());
    238 
    239   // Scroll to the previous page (positive delta) and finish it.
    240   SetStartPageAndExpects(kStartPage, 1, 0, 0);
    241   pagination_.StartScroll();
    242   pagination_.UpdateScroll(0.1);
    243   EXPECT_EQ(kStartPage - 1, pagination_.transition().target_page);
    244   pagination_.EndScroll(false);  // Finish transition
    245   base::MessageLoop::current()->Run();
    246   EXPECT_EQ(1, observer_.selection_count());
    247 
    248   // Scroll to the next page (negative delta) and cancel it.
    249   SetStartPageAndExpects(kStartPage, 0, 1, 0);
    250   pagination_.StartScroll();
    251   pagination_.UpdateScroll(-0.1);
    252   EXPECT_EQ(kStartPage + 1, pagination_.transition().target_page);
    253   pagination_.EndScroll(true);  // Cancel transition
    254   base::MessageLoop::current()->Run();
    255   EXPECT_EQ(0, observer_.selection_count());
    256 
    257   // Scroll to the previous page (position delta) and cancel it.
    258   SetStartPageAndExpects(kStartPage, 0, 1, 0);
    259   pagination_.StartScroll();
    260   pagination_.UpdateScroll(0.1);
    261   EXPECT_EQ(kStartPage - 1, pagination_.transition().target_page);
    262   pagination_.EndScroll(true);  // Cancel transition
    263   base::MessageLoop::current()->Run();
    264   EXPECT_EQ(0, observer_.selection_count());
    265 }
    266 
    267 TEST_F(PaginationModelTest, ScrollWithTransition) {
    268   const int kStartPage = 2;
    269 
    270   // Scroll to the next page (negative delta) with a transition in the same
    271   // direction.
    272   SetStartPageAndExpects(kStartPage, 1, 0, 0);
    273   pagination_.SetTransition(PaginationModel::Transition(kStartPage + 1, 0.5));
    274   pagination_.StartScroll();
    275   pagination_.UpdateScroll(-0.1);
    276   EXPECT_EQ(kStartPage + 1, pagination_.transition().target_page);
    277   EXPECT_EQ(0.6, pagination_.transition().progress);
    278   pagination_.EndScroll(false);
    279   base::MessageLoop::current()->Run();
    280   EXPECT_EQ(1, observer_.selection_count());
    281 
    282   // Scroll to the next page (negative delta) with a transition in a different
    283   // direction.
    284   SetStartPageAndExpects(kStartPage, 0, 1, 0);
    285   pagination_.SetTransition(PaginationModel::Transition(kStartPage - 1, 0.5));
    286   pagination_.StartScroll();
    287   pagination_.UpdateScroll(-0.1);
    288   EXPECT_EQ(kStartPage - 1, pagination_.transition().target_page);
    289   EXPECT_EQ(0.4, pagination_.transition().progress);
    290   pagination_.EndScroll(true);
    291 
    292   // Scroll to the previous page (positive delta) with a transition in the same
    293   // direction.
    294   SetStartPageAndExpects(kStartPage, 1, 0, 0);
    295   pagination_.SetTransition(PaginationModel::Transition(kStartPage - 1, 0.5));
    296   pagination_.StartScroll();
    297   pagination_.UpdateScroll(0.1);
    298   EXPECT_EQ(kStartPage - 1, pagination_.transition().target_page);
    299   EXPECT_EQ(0.6, pagination_.transition().progress);
    300   pagination_.EndScroll(false);
    301   base::MessageLoop::current()->Run();
    302   EXPECT_EQ(1, observer_.selection_count());
    303 
    304   // Scroll to the previous page (positive delta) with a transition in a
    305   // different direction.
    306   SetStartPageAndExpects(kStartPage, 0, 1, 0);
    307   pagination_.SetTransition(PaginationModel::Transition(kStartPage + 1, 0.5));
    308   pagination_.StartScroll();
    309   pagination_.UpdateScroll(0.1);
    310   EXPECT_EQ(kStartPage + 1, pagination_.transition().target_page);
    311   EXPECT_EQ(0.4, pagination_.transition().progress);
    312   pagination_.EndScroll(true);
    313 }
    314 
    315 TEST_F(PaginationModelTest, LongScroll) {
    316   const int kStartPage = 2;
    317 
    318   // Scroll to the next page (negative delta) with a transition in the same
    319   // direction. And scroll enough to change page twice.
    320   SetStartPageAndExpects(kStartPage, 2, 0, 0);
    321   pagination_.SetTransition(PaginationModel::Transition(kStartPage + 1, 0.5));
    322   pagination_.StartScroll();
    323   pagination_.UpdateScroll(-0.1);
    324   EXPECT_EQ(kStartPage + 1, pagination_.transition().target_page);
    325   EXPECT_EQ(0.6, pagination_.transition().progress);
    326   pagination_.UpdateScroll(-0.5);
    327   EXPECT_EQ(1, observer_.selection_count());
    328   pagination_.UpdateScroll(-0.5);
    329   EXPECT_EQ(kStartPage + 2, pagination_.transition().target_page);
    330   pagination_.EndScroll(false);
    331   base::MessageLoop::current()->Run();
    332   EXPECT_EQ(2, observer_.selection_count());
    333 
    334   // Scroll to the next page (negative delta) with a transition in a different
    335   // direction. And scroll enough to revert it and switch page once.
    336   SetStartPageAndExpects(kStartPage, 1, 0, 0);
    337   pagination_.SetTransition(PaginationModel::Transition(kStartPage - 1, 0.5));
    338   pagination_.StartScroll();
    339   pagination_.UpdateScroll(-0.1);
    340   EXPECT_EQ(kStartPage - 1, pagination_.transition().target_page);
    341   EXPECT_EQ(0.4, pagination_.transition().progress);
    342   pagination_.UpdateScroll(-0.5);  // This clears the transition.
    343   pagination_.UpdateScroll(-0.5);  // This starts a new transition.
    344   EXPECT_EQ(kStartPage + 1, pagination_.transition().target_page);
    345   pagination_.EndScroll(false);
    346   base::MessageLoop::current()->Run();
    347   EXPECT_EQ(1, observer_.selection_count());
    348 
    349   // Similar cases as above but in the opposite direction.
    350   // Scroll to the previous page (positive delta) with a transition in the same
    351   // direction. And scroll enough to change page twice.
    352   SetStartPageAndExpects(kStartPage, 2, 0, 0);
    353   pagination_.SetTransition(PaginationModel::Transition(kStartPage - 1, 0.5));
    354   pagination_.StartScroll();
    355   pagination_.UpdateScroll(0.1);
    356   EXPECT_EQ(kStartPage - 1, pagination_.transition().target_page);
    357   EXPECT_EQ(0.6, pagination_.transition().progress);
    358   pagination_.UpdateScroll(0.5);
    359   EXPECT_EQ(1, observer_.selection_count());
    360   pagination_.UpdateScroll(0.5);
    361   EXPECT_EQ(kStartPage - 2, pagination_.transition().target_page);
    362   pagination_.EndScroll(false);
    363   base::MessageLoop::current()->Run();
    364   EXPECT_EQ(2, observer_.selection_count());
    365 
    366   // Scroll to the previous page (positive delta) with a transition in a
    367   // different direction. And scroll enough to revert it and switch page once.
    368   SetStartPageAndExpects(kStartPage, 1, 0, 0);
    369   pagination_.SetTransition(PaginationModel::Transition(kStartPage + 1, 0.5));
    370   pagination_.StartScroll();
    371   pagination_.UpdateScroll(0.1);
    372   EXPECT_EQ(kStartPage + 1, pagination_.transition().target_page);
    373   EXPECT_EQ(0.4, pagination_.transition().progress);
    374   pagination_.UpdateScroll(0.5);  // This clears the transition.
    375   pagination_.UpdateScroll(0.5);  // This starts a new transition.
    376   EXPECT_EQ(kStartPage - 1, pagination_.transition().target_page);
    377   pagination_.EndScroll(false);
    378   base::MessageLoop::current()->Run();
    379   EXPECT_EQ(1, observer_.selection_count());
    380 }
    381 
    382 TEST_F(PaginationModelTest, FireTransitionZero) {
    383   const int kStartPage = 2;
    384 
    385   // Scroll to next page then revert the scroll and make sure transition
    386   // progress 0 is fired when previous scroll is cleared.
    387   SetStartPageAndExpects(kStartPage, 0, 0, 0);
    388   pagination_.StartScroll();
    389   pagination_.UpdateScroll(-0.1);
    390 
    391   int target_page = kStartPage + 1;
    392   EXPECT_EQ(target_page, pagination_.transition().target_page);
    393   observer_.set_transition_page(target_page);
    394 
    395   pagination_.UpdateScroll(0.2);  // This clears the transition.
    396   EXPECT_EQ(1, observer_.transition_start_count());
    397   pagination_.EndScroll(true);  // Cancel transition.
    398 
    399   // Similar to above but in the other direction.
    400   SetStartPageAndExpects(kStartPage, 0, 0, 0);
    401   pagination_.StartScroll();
    402   pagination_.UpdateScroll(0.1);
    403 
    404   target_page = kStartPage - 1;
    405   EXPECT_EQ(target_page, pagination_.transition().target_page);
    406   observer_.set_transition_page(target_page);
    407 
    408   pagination_.UpdateScroll(-0.2);  // This clears the transition.
    409   EXPECT_EQ(1, observer_.transition_start_count());
    410   pagination_.EndScroll(true);  // Cancel transition.
    411 }
    412 
    413 TEST_F(PaginationModelTest, SelectedPageIsLost) {
    414   pagination_.SetTotalPages(2);
    415   // The selected page is set to 0 once the total number of pages are set.
    416   EXPECT_EQ(0, pagination_.selected_page());
    417 
    418   pagination_.SelectPage(1, false /* animate */);
    419   EXPECT_EQ(1, pagination_.selected_page());
    420 
    421   // The selected page is unchanged if it's still valid.
    422   pagination_.SetTotalPages(3);
    423   EXPECT_EQ(1, pagination_.selected_page());
    424   pagination_.SetTotalPages(2);
    425   EXPECT_EQ(1, pagination_.selected_page());
    426 
    427   // But if the currently selected_page exceeds the total number of pages,
    428   // it automatically switches to the last page.
    429   pagination_.SetTotalPages(1);
    430   EXPECT_EQ(0, pagination_.selected_page());
    431 }
    432 
    433 }  // namespace test
    434 }  // namespace app_list
    435