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