| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ui/app_list/pagination_model.h" |
| |
| #include <string> |
| |
| #include "base/compiler_specific.h" |
| #include "base/macros.h" |
| #include "base/message_loop/message_loop.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "ui/app_list/pagination_model_observer.h" |
| |
| namespace app_list { |
| namespace test { |
| |
| class TestPaginationModelObserver : public PaginationModelObserver { |
| public: |
| TestPaginationModelObserver() |
| : model_(NULL), |
| expected_page_selection_(0), |
| expected_transition_start_(0), |
| expected_transition_end_(0), |
| transition_page_(-1) { |
| Reset(); |
| } |
| ~TestPaginationModelObserver() override {} |
| |
| void Reset() { |
| selection_count_ = 0; |
| transition_start_count_ = 0; |
| transition_end_count_ = 0; |
| selected_pages_.clear(); |
| } |
| |
| void set_model(PaginationModel* model) { model_ = model; } |
| |
| void set_expected_page_selection(int expected_page_selection) { |
| expected_page_selection_ = expected_page_selection; |
| } |
| void set_expected_transition_start(int expected_transition_start) { |
| expected_transition_start_ = expected_transition_start; |
| } |
| void set_expected_transition_end(int expected_transition_end) { |
| expected_transition_end_ = expected_transition_end; |
| } |
| void set_transition_page(int page) { transition_page_ = page; } |
| |
| const std::string& selected_pages() const { return selected_pages_; } |
| int selection_count() const { return selection_count_; } |
| int transition_start_count() const { return transition_start_count_; } |
| int transition_end_count() const { return transition_end_count_; } |
| |
| private: |
| void AppendSelectedPage(int page) { |
| if (selected_pages_.length()) |
| selected_pages_.append(std::string(" ")); |
| selected_pages_.append(base::IntToString(page)); |
| } |
| |
| // PaginationModelObserver overrides: |
| void TotalPagesChanged() override {} |
| void SelectedPageChanged(int old_selected, int new_selected) override { |
| AppendSelectedPage(new_selected); |
| ++selection_count_; |
| if (expected_page_selection_ && |
| selection_count_ == expected_page_selection_) { |
| base::MessageLoop::current()->QuitWhenIdle(); |
| } |
| } |
| |
| void TransitionStarted() override {} |
| |
| void TransitionChanged() override { |
| if (transition_page_ == -1 || |
| model_->transition().target_page == transition_page_) { |
| if (model_->transition().progress == 0) |
| ++transition_start_count_; |
| if (model_->transition().progress == 1) |
| ++transition_end_count_; |
| } |
| |
| if ((expected_transition_start_ && |
| transition_start_count_ == expected_transition_start_) || |
| (expected_transition_end_ && |
| transition_end_count_ == expected_transition_end_)) { |
| base::MessageLoop::current()->QuitWhenIdle(); |
| } |
| } |
| |
| PaginationModel* model_; |
| |
| int expected_page_selection_; |
| int expected_transition_start_; |
| int expected_transition_end_; |
| |
| int selection_count_; |
| int transition_start_count_; |
| int transition_end_count_; |
| |
| // Indicate which page index should be counted for |transition_start_count_| |
| // and |transition_end_count_|. -1 means all the pages should be counted. |
| int transition_page_; |
| |
| std::string selected_pages_; |
| |
| DISALLOW_COPY_AND_ASSIGN(TestPaginationModelObserver); |
| }; |
| |
| class PaginationModelTest : public testing::Test { |
| public: |
| PaginationModelTest() {} |
| ~PaginationModelTest() override {} |
| |
| // testing::Test overrides: |
| void SetUp() override { |
| pagination_.SetTotalPages(5); |
| pagination_.SetTransitionDurations(1, 1); |
| observer_.set_model(&pagination_); |
| pagination_.AddObserver(&observer_); |
| } |
| void TearDown() override { |
| pagination_.RemoveObserver(&observer_); |
| observer_.set_model(NULL); |
| } |
| |
| protected: |
| void SetStartPageAndExpects(int start_page, |
| int expected_selection, |
| int expected_transition_start, |
| int expected_transition_end) { |
| observer_.set_expected_page_selection(0); |
| pagination_.SelectPage(start_page, false /* animate */); |
| observer_.Reset(); |
| observer_.set_expected_page_selection(expected_selection); |
| observer_.set_expected_transition_start(expected_transition_start); |
| observer_.set_expected_transition_end(expected_transition_end); |
| } |
| |
| PaginationModel pagination_; |
| TestPaginationModelObserver observer_; |
| |
| private: |
| base::MessageLoopForUI message_loop_; |
| |
| DISALLOW_COPY_AND_ASSIGN(PaginationModelTest); |
| }; |
| |
| TEST_F(PaginationModelTest, SelectPage) { |
| pagination_.SelectPage(2, false /* animate */); |
| pagination_.SelectPage(4, false /* animate */); |
| pagination_.SelectPage(3, false /* animate */); |
| pagination_.SelectPage(1, false /* animate */); |
| |
| EXPECT_EQ(0, observer_.transition_start_count()); |
| EXPECT_EQ(0, observer_.transition_end_count()); |
| EXPECT_EQ(4, observer_.selection_count()); |
| EXPECT_EQ(std::string("2 4 3 1"), observer_.selected_pages()); |
| |
| // Nothing happens if select the same page. |
| pagination_.SelectPage(1, false /* animate */); |
| EXPECT_EQ(4, observer_.selection_count()); |
| EXPECT_EQ(std::string("2 4 3 1"), observer_.selected_pages()); |
| } |
| |
| TEST_F(PaginationModelTest, SelectPageAnimated) { |
| const int kStartPage = 0; |
| |
| // One transition. |
| SetStartPageAndExpects(kStartPage, 1, 0, 0); |
| pagination_.SelectPage(1, true /* animate */); |
| base::MessageLoop::current()->Run(); |
| EXPECT_EQ(1, observer_.transition_start_count()); |
| EXPECT_EQ(1, observer_.transition_end_count()); |
| EXPECT_EQ(1, observer_.selection_count()); |
| EXPECT_EQ(std::string("1"), observer_.selected_pages()); |
| |
| // Two transitions in a row. |
| SetStartPageAndExpects(kStartPage, 2, 0, 0); |
| pagination_.SelectPage(1, true /* animate */); |
| pagination_.SelectPage(3, true /* animate */); |
| base::MessageLoop::current()->Run(); |
| EXPECT_EQ(2, observer_.transition_start_count()); |
| EXPECT_EQ(2, observer_.transition_end_count()); |
| EXPECT_EQ(2, observer_.selection_count()); |
| EXPECT_EQ(std::string("1 3"), observer_.selected_pages()); |
| |
| // Transition to same page twice and only one should happen. |
| SetStartPageAndExpects(kStartPage, 1, 0, 0); |
| pagination_.SelectPage(1, true /* animate */); |
| pagination_.SelectPage(1, true /* animate */); // Ignored. |
| base::MessageLoop::current()->Run(); |
| EXPECT_EQ(1, observer_.transition_start_count()); |
| EXPECT_EQ(1, observer_.transition_end_count()); |
| EXPECT_EQ(1, observer_.selection_count()); |
| EXPECT_EQ(std::string("1"), observer_.selected_pages()); |
| |
| // More than two transitions and only the first and last would happen. |
| SetStartPageAndExpects(kStartPage, 2, 0, 0); |
| pagination_.SelectPage(1, true /* animate */); |
| pagination_.SelectPage(3, true /* animate */); // Ignored |
| pagination_.SelectPage(4, true /* animate */); // Ignored |
| pagination_.SelectPage(2, true /* animate */); |
| base::MessageLoop::current()->Run(); |
| EXPECT_EQ(2, observer_.transition_start_count()); |
| EXPECT_EQ(2, observer_.transition_end_count()); |
| EXPECT_EQ(2, observer_.selection_count()); |
| EXPECT_EQ(std::string("1 2"), observer_.selected_pages()); |
| |
| // Multiple transitions with one transition that goes back to the original |
| // and followed by a new transition. Two transitions would happen. The first |
| // one will be reversed by the kStart transition and the second one will be |
| // finished. |
| SetStartPageAndExpects(kStartPage, 1, 0, 0); |
| pagination_.SelectPage(1, true /* animate */); |
| pagination_.SelectPage(2, true /* animate */); // Ignored |
| pagination_.SelectPage(kStartPage, true /* animate */); |
| pagination_.SelectPage(3, true /* animate */); |
| base::MessageLoop::current()->Run(); |
| EXPECT_EQ(std::string("3"), observer_.selected_pages()); |
| } |
| |
| TEST_F(PaginationModelTest, SimpleScroll) { |
| const int kStartPage = 2; |
| |
| // Scroll to the next page (negative delta) and finish it. |
| SetStartPageAndExpects(kStartPage, 1, 0, 0); |
| pagination_.StartScroll(); |
| pagination_.UpdateScroll(-0.1); |
| EXPECT_EQ(kStartPage + 1, pagination_.transition().target_page); |
| pagination_.EndScroll(false); // Finish transition |
| base::MessageLoop::current()->Run(); |
| EXPECT_EQ(1, observer_.selection_count()); |
| |
| // Scroll to the previous page (positive delta) and finish it. |
| SetStartPageAndExpects(kStartPage, 1, 0, 0); |
| pagination_.StartScroll(); |
| pagination_.UpdateScroll(0.1); |
| EXPECT_EQ(kStartPage - 1, pagination_.transition().target_page); |
| pagination_.EndScroll(false); // Finish transition |
| base::MessageLoop::current()->Run(); |
| EXPECT_EQ(1, observer_.selection_count()); |
| |
| // Scroll to the next page (negative delta) and cancel it. |
| SetStartPageAndExpects(kStartPage, 0, 1, 0); |
| pagination_.StartScroll(); |
| pagination_.UpdateScroll(-0.1); |
| EXPECT_EQ(kStartPage + 1, pagination_.transition().target_page); |
| pagination_.EndScroll(true); // Cancel transition |
| base::MessageLoop::current()->Run(); |
| EXPECT_EQ(0, observer_.selection_count()); |
| |
| // Scroll to the previous page (position delta) and cancel it. |
| SetStartPageAndExpects(kStartPage, 0, 1, 0); |
| pagination_.StartScroll(); |
| pagination_.UpdateScroll(0.1); |
| EXPECT_EQ(kStartPage - 1, pagination_.transition().target_page); |
| pagination_.EndScroll(true); // Cancel transition |
| base::MessageLoop::current()->Run(); |
| EXPECT_EQ(0, observer_.selection_count()); |
| } |
| |
| TEST_F(PaginationModelTest, ScrollWithTransition) { |
| const int kStartPage = 2; |
| |
| // Scroll to the next page (negative delta) with a transition in the same |
| // direction. |
| SetStartPageAndExpects(kStartPage, 1, 0, 0); |
| pagination_.SetTransition(PaginationModel::Transition(kStartPage + 1, 0.5)); |
| pagination_.StartScroll(); |
| pagination_.UpdateScroll(-0.1); |
| EXPECT_EQ(kStartPage + 1, pagination_.transition().target_page); |
| EXPECT_EQ(0.6, pagination_.transition().progress); |
| pagination_.EndScroll(false); |
| base::MessageLoop::current()->Run(); |
| EXPECT_EQ(1, observer_.selection_count()); |
| |
| // Scroll to the next page (negative delta) with a transition in a different |
| // direction. |
| SetStartPageAndExpects(kStartPage, 0, 1, 0); |
| pagination_.SetTransition(PaginationModel::Transition(kStartPage - 1, 0.5)); |
| pagination_.StartScroll(); |
| pagination_.UpdateScroll(-0.1); |
| EXPECT_EQ(kStartPage - 1, pagination_.transition().target_page); |
| EXPECT_EQ(0.4, pagination_.transition().progress); |
| pagination_.EndScroll(true); |
| |
| // Scroll to the previous page (positive delta) with a transition in the same |
| // direction. |
| SetStartPageAndExpects(kStartPage, 1, 0, 0); |
| pagination_.SetTransition(PaginationModel::Transition(kStartPage - 1, 0.5)); |
| pagination_.StartScroll(); |
| pagination_.UpdateScroll(0.1); |
| EXPECT_EQ(kStartPage - 1, pagination_.transition().target_page); |
| EXPECT_EQ(0.6, pagination_.transition().progress); |
| pagination_.EndScroll(false); |
| base::MessageLoop::current()->Run(); |
| EXPECT_EQ(1, observer_.selection_count()); |
| |
| // Scroll to the previous page (positive delta) with a transition in a |
| // different direction. |
| SetStartPageAndExpects(kStartPage, 0, 1, 0); |
| pagination_.SetTransition(PaginationModel::Transition(kStartPage + 1, 0.5)); |
| pagination_.StartScroll(); |
| pagination_.UpdateScroll(0.1); |
| EXPECT_EQ(kStartPage + 1, pagination_.transition().target_page); |
| EXPECT_EQ(0.4, pagination_.transition().progress); |
| pagination_.EndScroll(true); |
| } |
| |
| TEST_F(PaginationModelTest, LongScroll) { |
| const int kStartPage = 2; |
| |
| // Scroll to the next page (negative delta) with a transition in the same |
| // direction. And scroll enough to change page twice. |
| SetStartPageAndExpects(kStartPage, 2, 0, 0); |
| pagination_.SetTransition(PaginationModel::Transition(kStartPage + 1, 0.5)); |
| pagination_.StartScroll(); |
| pagination_.UpdateScroll(-0.1); |
| EXPECT_EQ(kStartPage + 1, pagination_.transition().target_page); |
| EXPECT_EQ(0.6, pagination_.transition().progress); |
| pagination_.UpdateScroll(-0.5); |
| EXPECT_EQ(1, observer_.selection_count()); |
| pagination_.UpdateScroll(-0.5); |
| EXPECT_EQ(kStartPage + 2, pagination_.transition().target_page); |
| pagination_.EndScroll(false); |
| base::MessageLoop::current()->Run(); |
| EXPECT_EQ(2, observer_.selection_count()); |
| |
| // Scroll to the next page (negative delta) with a transition in a different |
| // direction. And scroll enough to revert it and switch page once. |
| SetStartPageAndExpects(kStartPage, 1, 0, 0); |
| pagination_.SetTransition(PaginationModel::Transition(kStartPage - 1, 0.5)); |
| pagination_.StartScroll(); |
| pagination_.UpdateScroll(-0.1); |
| EXPECT_EQ(kStartPage - 1, pagination_.transition().target_page); |
| EXPECT_EQ(0.4, pagination_.transition().progress); |
| pagination_.UpdateScroll(-0.5); // This clears the transition. |
| pagination_.UpdateScroll(-0.5); // This starts a new transition. |
| EXPECT_EQ(kStartPage + 1, pagination_.transition().target_page); |
| pagination_.EndScroll(false); |
| base::MessageLoop::current()->Run(); |
| EXPECT_EQ(1, observer_.selection_count()); |
| |
| // Similar cases as above but in the opposite direction. |
| // Scroll to the previous page (positive delta) with a transition in the same |
| // direction. And scroll enough to change page twice. |
| SetStartPageAndExpects(kStartPage, 2, 0, 0); |
| pagination_.SetTransition(PaginationModel::Transition(kStartPage - 1, 0.5)); |
| pagination_.StartScroll(); |
| pagination_.UpdateScroll(0.1); |
| EXPECT_EQ(kStartPage - 1, pagination_.transition().target_page); |
| EXPECT_EQ(0.6, pagination_.transition().progress); |
| pagination_.UpdateScroll(0.5); |
| EXPECT_EQ(1, observer_.selection_count()); |
| pagination_.UpdateScroll(0.5); |
| EXPECT_EQ(kStartPage - 2, pagination_.transition().target_page); |
| pagination_.EndScroll(false); |
| base::MessageLoop::current()->Run(); |
| EXPECT_EQ(2, observer_.selection_count()); |
| |
| // Scroll to the previous page (positive delta) with a transition in a |
| // different direction. And scroll enough to revert it and switch page once. |
| SetStartPageAndExpects(kStartPage, 1, 0, 0); |
| pagination_.SetTransition(PaginationModel::Transition(kStartPage + 1, 0.5)); |
| pagination_.StartScroll(); |
| pagination_.UpdateScroll(0.1); |
| EXPECT_EQ(kStartPage + 1, pagination_.transition().target_page); |
| EXPECT_EQ(0.4, pagination_.transition().progress); |
| pagination_.UpdateScroll(0.5); // This clears the transition. |
| pagination_.UpdateScroll(0.5); // This starts a new transition. |
| EXPECT_EQ(kStartPage - 1, pagination_.transition().target_page); |
| pagination_.EndScroll(false); |
| base::MessageLoop::current()->Run(); |
| EXPECT_EQ(1, observer_.selection_count()); |
| } |
| |
| TEST_F(PaginationModelTest, FireTransitionZero) { |
| const int kStartPage = 2; |
| |
| // Scroll to next page then revert the scroll and make sure transition |
| // progress 0 is fired when previous scroll is cleared. |
| SetStartPageAndExpects(kStartPage, 0, 0, 0); |
| pagination_.StartScroll(); |
| pagination_.UpdateScroll(-0.1); |
| |
| int target_page = kStartPage + 1; |
| EXPECT_EQ(target_page, pagination_.transition().target_page); |
| observer_.set_transition_page(target_page); |
| |
| pagination_.UpdateScroll(0.2); // This clears the transition. |
| EXPECT_EQ(1, observer_.transition_start_count()); |
| pagination_.EndScroll(true); // Cancel transition. |
| |
| // Similar to above but in the other direction. |
| SetStartPageAndExpects(kStartPage, 0, 0, 0); |
| pagination_.StartScroll(); |
| pagination_.UpdateScroll(0.1); |
| |
| target_page = kStartPage - 1; |
| EXPECT_EQ(target_page, pagination_.transition().target_page); |
| observer_.set_transition_page(target_page); |
| |
| pagination_.UpdateScroll(-0.2); // This clears the transition. |
| EXPECT_EQ(1, observer_.transition_start_count()); |
| pagination_.EndScroll(true); // Cancel transition. |
| } |
| |
| TEST_F(PaginationModelTest, SelectedPageIsLost) { |
| pagination_.SetTotalPages(2); |
| // The selected page is set to 0 once the total number of pages are set. |
| EXPECT_EQ(0, pagination_.selected_page()); |
| |
| pagination_.SelectPage(1, false /* animate */); |
| EXPECT_EQ(1, pagination_.selected_page()); |
| |
| // The selected page is unchanged if it's still valid. |
| pagination_.SetTotalPages(3); |
| EXPECT_EQ(1, pagination_.selected_page()); |
| pagination_.SetTotalPages(2); |
| EXPECT_EQ(1, pagination_.selected_page()); |
| |
| // But if the currently selected_page exceeds the total number of pages, |
| // it automatically switches to the last page. |
| pagination_.SetTotalPages(1); |
| EXPECT_EQ(0, pagination_.selected_page()); |
| } |
| |
| } // namespace test |
| } // namespace app_list |