1 // Copyright (c) 2011 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 "chrome/browser/ui/toolbar/back_forward_menu_model.h" 6 7 #include "base/path_service.h" 8 #include "base/string_util.h" 9 #include "base/utf_string_conversions.h" 10 #include "chrome/browser/history/history.h" 11 #include "chrome/browser/profiles/profile_manager.h" 12 #include "chrome/browser/ui/browser.h" 13 #include "chrome/common/url_constants.h" 14 #include "chrome/test/testing_profile.h" 15 #include "content/browser/browser_thread.h" 16 #include "content/browser/renderer_host/test_render_view_host.h" 17 #include "content/browser/tab_contents/navigation_controller.h" 18 #include "content/browser/tab_contents/navigation_entry.h" 19 #include "content/browser/tab_contents/tab_contents.h" 20 #include "content/browser/tab_contents/test_tab_contents.h" 21 #include "testing/gtest/include/gtest/gtest.h" 22 #include "third_party/skia/include/core/SkBitmap.h" 23 #include "ui/gfx/codec/png_codec.h" 24 25 namespace { 26 27 // Creates a bitmap of the specified color. 28 SkBitmap CreateBitmap(SkColor color) { 29 SkBitmap bitmap; 30 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 16, 16); 31 bitmap.allocPixels(); 32 bitmap.eraseColor(color); 33 return bitmap; 34 } 35 36 class FaviconDelegate : public ui::MenuModelDelegate { 37 public: 38 FaviconDelegate() : was_called_(false) {} 39 40 void OnIconChanged(int model_index) { 41 was_called_ = true; 42 MessageLoop::current()->Quit(); 43 } 44 45 bool was_called() const { return was_called_; } 46 47 private: 48 bool was_called_; 49 50 DISALLOW_COPY_AND_ASSIGN(FaviconDelegate); 51 }; 52 53 } // namespace 54 55 class BackFwdMenuModelTest : public RenderViewHostTestHarness { 56 public: 57 BackFwdMenuModelTest() 58 : ui_thread_(BrowserThread::UI, &message_loop_) { 59 } 60 61 void ValidateModel(BackForwardMenuModel* model, int history_items, 62 int chapter_stops) { 63 int h = std::min(BackForwardMenuModel::kMaxHistoryItems, history_items); 64 int c = std::min(BackForwardMenuModel::kMaxChapterStops, chapter_stops); 65 EXPECT_EQ(h, model->GetHistoryItemCount()); 66 EXPECT_EQ(c, model->GetChapterStopCount(h)); 67 if (h > 0) 68 h += 2; // Separator and View History link. 69 if (c > 0) 70 ++c; 71 EXPECT_EQ(h + c, model->GetItemCount()); 72 } 73 74 void LoadURLAndUpdateState(const char* url, const char* title) { 75 NavigateAndCommit(GURL(url)); 76 controller().GetLastCommittedEntry()->set_title(UTF8ToUTF16(title)); 77 } 78 79 // Navigate back or forward the given amount and commits the entry (which 80 // will be pending after we ask to navigate there). 81 void NavigateToOffset(int offset) { 82 controller().GoToOffset(offset); 83 contents()->CommitPendingNavigation(); 84 } 85 86 // Same as NavigateToOffset but goes to an absolute index. 87 void NavigateToIndex(int index) { 88 controller().GoToIndex(index); 89 contents()->CommitPendingNavigation(); 90 } 91 92 // Goes back/forward and commits the load. 93 void GoBack() { 94 controller().GoBack(); 95 contents()->CommitPendingNavigation(); 96 } 97 void GoForward() { 98 controller().GoForward(); 99 contents()->CommitPendingNavigation(); 100 } 101 102 BrowserThread ui_thread_; 103 }; 104 105 TEST_F(BackFwdMenuModelTest, BasicCase) { 106 scoped_ptr<BackForwardMenuModel> back_model(new BackForwardMenuModel( 107 NULL, BackForwardMenuModel::BACKWARD_MENU)); 108 back_model->set_test_tab_contents(contents()); 109 110 scoped_ptr<BackForwardMenuModel> forward_model(new BackForwardMenuModel( 111 NULL, BackForwardMenuModel::FORWARD_MENU)); 112 forward_model->set_test_tab_contents(contents()); 113 114 EXPECT_EQ(0, back_model->GetItemCount()); 115 EXPECT_EQ(0, forward_model->GetItemCount()); 116 EXPECT_FALSE(back_model->ItemHasCommand(1)); 117 118 // Seed the controller with a few URLs 119 LoadURLAndUpdateState("http://www.a.com/1", "A1"); 120 LoadURLAndUpdateState("http://www.a.com/2", "A2"); 121 LoadURLAndUpdateState("http://www.a.com/3", "A3"); 122 LoadURLAndUpdateState("http://www.b.com/1", "B1"); 123 LoadURLAndUpdateState("http://www.b.com/2", "B2"); 124 LoadURLAndUpdateState("http://www.c.com/1", "C1"); 125 LoadURLAndUpdateState("http://www.c.com/2", "C2"); 126 LoadURLAndUpdateState("http://www.c.com/3", "C3"); 127 128 // There're two more items here: a separator and a "Show Full History". 129 EXPECT_EQ(9, back_model->GetItemCount()); 130 EXPECT_EQ(0, forward_model->GetItemCount()); 131 EXPECT_EQ(ASCIIToUTF16("C2"), back_model->GetLabelAt(0)); 132 EXPECT_EQ(ASCIIToUTF16("A1"), back_model->GetLabelAt(6)); 133 EXPECT_EQ(back_model->GetShowFullHistoryLabel(), 134 back_model->GetLabelAt(8)); 135 136 EXPECT_TRUE(back_model->ItemHasCommand(0)); 137 EXPECT_TRUE(back_model->ItemHasCommand(6)); 138 EXPECT_TRUE(back_model->IsSeparator(7)); 139 EXPECT_TRUE(back_model->ItemHasCommand(8)); 140 EXPECT_FALSE(back_model->ItemHasCommand(9)); 141 EXPECT_FALSE(back_model->ItemHasCommand(9)); 142 143 NavigateToOffset(-7); 144 145 EXPECT_EQ(0, back_model->GetItemCount()); 146 EXPECT_EQ(9, forward_model->GetItemCount()); 147 EXPECT_EQ(ASCIIToUTF16("A2"), forward_model->GetLabelAt(0)); 148 EXPECT_EQ(ASCIIToUTF16("C3"), forward_model->GetLabelAt(6)); 149 EXPECT_EQ(forward_model->GetShowFullHistoryLabel(), 150 forward_model->GetLabelAt(8)); 151 152 EXPECT_TRUE(forward_model->ItemHasCommand(0)); 153 EXPECT_TRUE(forward_model->ItemHasCommand(6)); 154 EXPECT_TRUE(forward_model->IsSeparator(7)); 155 EXPECT_TRUE(forward_model->ItemHasCommand(8)); 156 EXPECT_FALSE(forward_model->ItemHasCommand(7)); 157 EXPECT_FALSE(forward_model->ItemHasCommand(9)); 158 159 NavigateToOffset(4); 160 161 EXPECT_EQ(6, back_model->GetItemCount()); 162 EXPECT_EQ(5, forward_model->GetItemCount()); 163 EXPECT_EQ(ASCIIToUTF16("B1"), back_model->GetLabelAt(0)); 164 EXPECT_EQ(ASCIIToUTF16("A1"), back_model->GetLabelAt(3)); 165 EXPECT_EQ(back_model->GetShowFullHistoryLabel(), 166 back_model->GetLabelAt(5)); 167 EXPECT_EQ(ASCIIToUTF16("C1"), forward_model->GetLabelAt(0)); 168 EXPECT_EQ(ASCIIToUTF16("C3"), forward_model->GetLabelAt(2)); 169 EXPECT_EQ(forward_model->GetShowFullHistoryLabel(), 170 forward_model->GetLabelAt(4)); 171 } 172 173 TEST_F(BackFwdMenuModelTest, MaxItemsTest) { 174 scoped_ptr<BackForwardMenuModel> back_model(new BackForwardMenuModel( 175 NULL, BackForwardMenuModel::BACKWARD_MENU)); 176 back_model->set_test_tab_contents(contents()); 177 178 scoped_ptr<BackForwardMenuModel> forward_model(new BackForwardMenuModel( 179 NULL, BackForwardMenuModel::FORWARD_MENU)); 180 forward_model->set_test_tab_contents(contents()); 181 182 // Seed the controller with 32 URLs 183 LoadURLAndUpdateState("http://www.a.com/1", "A1"); 184 LoadURLAndUpdateState("http://www.a.com/2", "A2"); 185 LoadURLAndUpdateState("http://www.a.com/3", "A3"); 186 LoadURLAndUpdateState("http://www.b.com/1", "B1"); 187 LoadURLAndUpdateState("http://www.b.com/2", "B2"); 188 LoadURLAndUpdateState("http://www.b.com/3", "B3"); 189 LoadURLAndUpdateState("http://www.c.com/1", "C1"); 190 LoadURLAndUpdateState("http://www.c.com/2", "C2"); 191 LoadURLAndUpdateState("http://www.c.com/3", "C3"); 192 LoadURLAndUpdateState("http://www.d.com/1", "D1"); 193 LoadURLAndUpdateState("http://www.d.com/2", "D2"); 194 LoadURLAndUpdateState("http://www.d.com/3", "D3"); 195 LoadURLAndUpdateState("http://www.e.com/1", "E1"); 196 LoadURLAndUpdateState("http://www.e.com/2", "E2"); 197 LoadURLAndUpdateState("http://www.e.com/3", "E3"); 198 LoadURLAndUpdateState("http://www.f.com/1", "F1"); 199 LoadURLAndUpdateState("http://www.f.com/2", "F2"); 200 LoadURLAndUpdateState("http://www.f.com/3", "F3"); 201 LoadURLAndUpdateState("http://www.g.com/1", "G1"); 202 LoadURLAndUpdateState("http://www.g.com/2", "G2"); 203 LoadURLAndUpdateState("http://www.g.com/3", "G3"); 204 LoadURLAndUpdateState("http://www.h.com/1", "H1"); 205 LoadURLAndUpdateState("http://www.h.com/2", "H2"); 206 LoadURLAndUpdateState("http://www.h.com/3", "H3"); 207 LoadURLAndUpdateState("http://www.i.com/1", "I1"); 208 LoadURLAndUpdateState("http://www.i.com/2", "I2"); 209 LoadURLAndUpdateState("http://www.i.com/3", "I3"); 210 LoadURLAndUpdateState("http://www.j.com/1", "J1"); 211 LoadURLAndUpdateState("http://www.j.com/2", "J2"); 212 LoadURLAndUpdateState("http://www.j.com/3", "J3"); 213 LoadURLAndUpdateState("http://www.k.com/1", "K1"); 214 LoadURLAndUpdateState("http://www.k.com/2", "K2"); 215 216 // Also there're two more for a separator and a "Show Full History". 217 int chapter_stop_offset = 6; 218 EXPECT_EQ(BackForwardMenuModel::kMaxHistoryItems + 2 + chapter_stop_offset, 219 back_model->GetItemCount()); 220 EXPECT_EQ(0, forward_model->GetItemCount()); 221 EXPECT_EQ(ASCIIToUTF16("K1"), back_model->GetLabelAt(0)); 222 EXPECT_EQ(back_model->GetShowFullHistoryLabel(), 223 back_model->GetLabelAt(BackForwardMenuModel::kMaxHistoryItems + 1 + 224 chapter_stop_offset)); 225 226 // Test for out of bounds (beyond Show Full History). 227 EXPECT_FALSE(back_model->ItemHasCommand( 228 BackForwardMenuModel::kMaxHistoryItems + chapter_stop_offset + 2)); 229 230 EXPECT_TRUE(back_model->ItemHasCommand( 231 BackForwardMenuModel::kMaxHistoryItems - 1)); 232 EXPECT_TRUE(back_model->IsSeparator( 233 BackForwardMenuModel::kMaxHistoryItems)); 234 235 NavigateToIndex(0); 236 237 EXPECT_EQ(BackForwardMenuModel::kMaxHistoryItems + 2 + chapter_stop_offset, 238 forward_model->GetItemCount()); 239 EXPECT_EQ(0, back_model->GetItemCount()); 240 EXPECT_EQ(ASCIIToUTF16("A2"), forward_model->GetLabelAt(0)); 241 EXPECT_EQ(forward_model->GetShowFullHistoryLabel(), 242 forward_model->GetLabelAt(BackForwardMenuModel::kMaxHistoryItems + 1 + 243 chapter_stop_offset)); 244 245 // Out of bounds 246 EXPECT_FALSE(forward_model->ItemHasCommand( 247 BackForwardMenuModel::kMaxHistoryItems + 2 + chapter_stop_offset)); 248 249 EXPECT_TRUE(forward_model->ItemHasCommand( 250 BackForwardMenuModel::kMaxHistoryItems - 1)); 251 EXPECT_TRUE(forward_model->IsSeparator( 252 BackForwardMenuModel::kMaxHistoryItems)); 253 } 254 255 TEST_F(BackFwdMenuModelTest, ChapterStops) { 256 scoped_ptr<BackForwardMenuModel> back_model(new BackForwardMenuModel( 257 NULL, BackForwardMenuModel::BACKWARD_MENU)); 258 back_model->set_test_tab_contents(contents()); 259 260 scoped_ptr<BackForwardMenuModel> forward_model(new BackForwardMenuModel( 261 NULL, BackForwardMenuModel::FORWARD_MENU)); 262 forward_model->set_test_tab_contents(contents()); 263 264 // Seed the controller with 32 URLs. 265 int i = 0; 266 LoadURLAndUpdateState("http://www.a.com/1", "A1"); 267 ValidateModel(back_model.get(), i++, 0); 268 LoadURLAndUpdateState("http://www.a.com/2", "A2"); 269 ValidateModel(back_model.get(), i++, 0); 270 LoadURLAndUpdateState("http://www.a.com/3", "A3"); 271 ValidateModel(back_model.get(), i++, 0); 272 LoadURLAndUpdateState("http://www.b.com/1", "B1"); 273 ValidateModel(back_model.get(), i++, 0); 274 LoadURLAndUpdateState("http://www.b.com/2", "B2"); 275 ValidateModel(back_model.get(), i++, 0); 276 // i = 5 277 LoadURLAndUpdateState("http://www.b.com/3", "B3"); 278 ValidateModel(back_model.get(), i++, 0); 279 LoadURLAndUpdateState("http://www.c.com/1", "C1"); 280 ValidateModel(back_model.get(), i++, 0); 281 LoadURLAndUpdateState("http://www.c.com/2", "C2"); 282 ValidateModel(back_model.get(), i++, 0); 283 LoadURLAndUpdateState("http://www.c.com/3", "C3"); 284 ValidateModel(back_model.get(), i++, 0); 285 LoadURLAndUpdateState("http://www.d.com/1", "D1"); 286 ValidateModel(back_model.get(), i++, 0); 287 // i = 10 288 LoadURLAndUpdateState("http://www.d.com/2", "D2"); 289 ValidateModel(back_model.get(), i++, 0); 290 LoadURLAndUpdateState("http://www.d.com/3", "D3"); 291 ValidateModel(back_model.get(), i++, 0); 292 LoadURLAndUpdateState("http://www.e.com/1", "E1"); 293 ValidateModel(back_model.get(), i++, 0); 294 LoadURLAndUpdateState("http://www.e.com/2", "E2"); 295 ValidateModel(back_model.get(), i++, 0); 296 LoadURLAndUpdateState("http://www.e.com/3", "E3"); 297 ValidateModel(back_model.get(), i++, 0); 298 // i = 15 299 LoadURLAndUpdateState("http://www.f.com/1", "F1"); 300 ValidateModel(back_model.get(), i++, 1); 301 LoadURLAndUpdateState("http://www.f.com/2", "F2"); 302 ValidateModel(back_model.get(), i++, 1); 303 LoadURLAndUpdateState("http://www.f.com/3", "F3"); 304 ValidateModel(back_model.get(), i++, 1); 305 LoadURLAndUpdateState("http://www.g.com/1", "G1"); 306 ValidateModel(back_model.get(), i++, 2); 307 LoadURLAndUpdateState("http://www.g.com/2", "G2"); 308 ValidateModel(back_model.get(), i++, 2); 309 // i = 20 310 LoadURLAndUpdateState("http://www.g.com/3", "G3"); 311 ValidateModel(back_model.get(), i++, 2); 312 LoadURLAndUpdateState("http://www.h.com/1", "H1"); 313 ValidateModel(back_model.get(), i++, 3); 314 LoadURLAndUpdateState("http://www.h.com/2", "H2"); 315 ValidateModel(back_model.get(), i++, 3); 316 LoadURLAndUpdateState("http://www.h.com/3", "H3"); 317 ValidateModel(back_model.get(), i++, 3); 318 LoadURLAndUpdateState("http://www.i.com/1", "I1"); 319 ValidateModel(back_model.get(), i++, 4); 320 // i = 25 321 LoadURLAndUpdateState("http://www.i.com/2", "I2"); 322 ValidateModel(back_model.get(), i++, 4); 323 LoadURLAndUpdateState("http://www.i.com/3", "I3"); 324 ValidateModel(back_model.get(), i++, 4); 325 LoadURLAndUpdateState("http://www.j.com/1", "J1"); 326 ValidateModel(back_model.get(), i++, 5); 327 LoadURLAndUpdateState("http://www.j.com/2", "J2"); 328 ValidateModel(back_model.get(), i++, 5); 329 LoadURLAndUpdateState("http://www.j.com/3", "J3"); 330 ValidateModel(back_model.get(), i++, 5); 331 // i = 30 332 LoadURLAndUpdateState("http://www.k.com/1", "K1"); 333 ValidateModel(back_model.get(), i++, 6); 334 LoadURLAndUpdateState("http://www.k.com/2", "K2"); 335 ValidateModel(back_model.get(), i++, 6); 336 // i = 32 337 LoadURLAndUpdateState("http://www.k.com/3", "K3"); 338 ValidateModel(back_model.get(), i++, 6); 339 340 // A chapter stop is defined as the last page the user 341 // browsed to within the same domain. 342 343 // Check to see if the chapter stops have the right labels. 344 int index = BackForwardMenuModel::kMaxHistoryItems; 345 // Empty string indicates item is a separator. 346 EXPECT_EQ(ASCIIToUTF16(""), back_model->GetLabelAt(index++)); 347 EXPECT_EQ(ASCIIToUTF16("F3"), back_model->GetLabelAt(index++)); 348 EXPECT_EQ(ASCIIToUTF16("E3"), back_model->GetLabelAt(index++)); 349 EXPECT_EQ(ASCIIToUTF16("D3"), back_model->GetLabelAt(index++)); 350 EXPECT_EQ(ASCIIToUTF16("C3"), back_model->GetLabelAt(index++)); 351 // The menu should only show a maximum of 5 chapter stops. 352 EXPECT_EQ(ASCIIToUTF16("B3"), back_model->GetLabelAt(index)); 353 // Empty string indicates item is a separator. 354 EXPECT_EQ(ASCIIToUTF16(""), back_model->GetLabelAt(index + 1)); 355 EXPECT_EQ(back_model->GetShowFullHistoryLabel(), 356 back_model->GetLabelAt(index + 2)); 357 358 // If we go back two we should still see the same chapter stop at the end. 359 GoBack(); 360 EXPECT_EQ(ASCIIToUTF16("B3"), back_model->GetLabelAt(index)); 361 GoBack(); 362 EXPECT_EQ(ASCIIToUTF16("B3"), back_model->GetLabelAt(index)); 363 // But if we go back again, it should change. 364 GoBack(); 365 EXPECT_EQ(ASCIIToUTF16("A3"), back_model->GetLabelAt(index)); 366 GoBack(); 367 EXPECT_EQ(ASCIIToUTF16("A3"), back_model->GetLabelAt(index)); 368 GoBack(); 369 EXPECT_EQ(ASCIIToUTF16("A3"), back_model->GetLabelAt(index)); 370 GoBack(); 371 // It is now a separator. 372 EXPECT_EQ(ASCIIToUTF16(""), back_model->GetLabelAt(index)); 373 // Undo our position change. 374 NavigateToOffset(6); 375 376 // Go back enough to make sure no chapter stops should appear. 377 NavigateToOffset(-BackForwardMenuModel::kMaxHistoryItems); 378 ValidateModel(forward_model.get(), BackForwardMenuModel::kMaxHistoryItems, 0); 379 // Go forward (still no chapter stop) 380 GoForward(); 381 ValidateModel(forward_model.get(), 382 BackForwardMenuModel::kMaxHistoryItems - 1, 0); 383 // Go back two (one chapter stop should show up) 384 GoBack(); 385 GoBack(); 386 ValidateModel(forward_model.get(), 387 BackForwardMenuModel::kMaxHistoryItems, 1); 388 389 // Go to beginning. 390 NavigateToIndex(0); 391 392 // Check to see if the chapter stops have the right labels. 393 index = BackForwardMenuModel::kMaxHistoryItems; 394 // Empty string indicates item is a separator. 395 EXPECT_EQ(ASCIIToUTF16(""), forward_model->GetLabelAt(index++)); 396 EXPECT_EQ(ASCIIToUTF16("E3"), forward_model->GetLabelAt(index++)); 397 EXPECT_EQ(ASCIIToUTF16("F3"), forward_model->GetLabelAt(index++)); 398 EXPECT_EQ(ASCIIToUTF16("G3"), forward_model->GetLabelAt(index++)); 399 EXPECT_EQ(ASCIIToUTF16("H3"), forward_model->GetLabelAt(index++)); 400 // The menu should only show a maximum of 5 chapter stops. 401 EXPECT_EQ(ASCIIToUTF16("I3"), forward_model->GetLabelAt(index)); 402 // Empty string indicates item is a separator. 403 EXPECT_EQ(ASCIIToUTF16(""), forward_model->GetLabelAt(index + 1)); 404 EXPECT_EQ(forward_model->GetShowFullHistoryLabel(), 405 forward_model->GetLabelAt(index + 2)); 406 407 // If we advance one we should still see the same chapter stop at the end. 408 GoForward(); 409 EXPECT_EQ(ASCIIToUTF16("I3"), forward_model->GetLabelAt(index)); 410 // But if we advance one again, it should change. 411 GoForward(); 412 EXPECT_EQ(ASCIIToUTF16("J3"), forward_model->GetLabelAt(index)); 413 GoForward(); 414 EXPECT_EQ(ASCIIToUTF16("J3"), forward_model->GetLabelAt(index)); 415 GoForward(); 416 EXPECT_EQ(ASCIIToUTF16("J3"), forward_model->GetLabelAt(index)); 417 GoForward(); 418 EXPECT_EQ(ASCIIToUTF16("K3"), forward_model->GetLabelAt(index)); 419 420 // Now test the boundary cases by using the chapter stop function directly. 421 // Out of bounds, first too far right (incrementing), then too far left. 422 EXPECT_EQ(-1, back_model->GetIndexOfNextChapterStop(33, false)); 423 EXPECT_EQ(-1, back_model->GetIndexOfNextChapterStop(-1, true)); 424 // Test being at end and going right, then at beginning going left. 425 EXPECT_EQ(-1, back_model->GetIndexOfNextChapterStop(32, true)); 426 EXPECT_EQ(-1, back_model->GetIndexOfNextChapterStop(0, false)); 427 // Test success: beginning going right and end going left. 428 EXPECT_EQ(2, back_model->GetIndexOfNextChapterStop(0, true)); 429 EXPECT_EQ(29, back_model->GetIndexOfNextChapterStop(32, false)); 430 // Now see when the chapter stops begin to show up. 431 EXPECT_EQ(-1, back_model->GetIndexOfNextChapterStop(1, false)); 432 EXPECT_EQ(-1, back_model->GetIndexOfNextChapterStop(2, false)); 433 EXPECT_EQ(2, back_model->GetIndexOfNextChapterStop(3, false)); 434 // Now see when the chapter stops end. 435 EXPECT_EQ(32, back_model->GetIndexOfNextChapterStop(30, true)); 436 EXPECT_EQ(32, back_model->GetIndexOfNextChapterStop(31, true)); 437 EXPECT_EQ(-1, back_model->GetIndexOfNextChapterStop(32, true)); 438 439 // Bug found during review (two different sites, but first wasn't considered 440 // a chapter-stop). 441 // Go to A1; 442 NavigateToIndex(0); 443 LoadURLAndUpdateState("http://www.b.com/1", "B1"); 444 EXPECT_EQ(0, back_model->GetIndexOfNextChapterStop(1, false)); 445 EXPECT_EQ(1, back_model->GetIndexOfNextChapterStop(0, true)); 446 447 // Now see if it counts 'www.x.com' and 'mail.x.com' as same domain, which 448 // it should. 449 // Go to A1. 450 NavigateToIndex(0); 451 LoadURLAndUpdateState("http://mail.a.com/2", "A2-mai"); 452 LoadURLAndUpdateState("http://www.b.com/1", "B1"); 453 LoadURLAndUpdateState("http://mail.b.com/2", "B2-mai"); 454 LoadURLAndUpdateState("http://new.site.com", "new"); 455 EXPECT_EQ(1, back_model->GetIndexOfNextChapterStop(0, true)); 456 EXPECT_EQ(3, back_model->GetIndexOfNextChapterStop(1, true)); 457 EXPECT_EQ(3, back_model->GetIndexOfNextChapterStop(2, true)); 458 EXPECT_EQ(4, back_model->GetIndexOfNextChapterStop(3, true)); 459 // And try backwards as well. 460 EXPECT_EQ(3, back_model->GetIndexOfNextChapterStop(4, false)); 461 EXPECT_EQ(1, back_model->GetIndexOfNextChapterStop(3, false)); 462 EXPECT_EQ(1, back_model->GetIndexOfNextChapterStop(2, false)); 463 EXPECT_EQ(-1, back_model->GetIndexOfNextChapterStop(1, false)); 464 } 465 466 TEST_F(BackFwdMenuModelTest, EscapeLabel) { 467 scoped_ptr<BackForwardMenuModel> back_model(new BackForwardMenuModel( 468 NULL, BackForwardMenuModel::BACKWARD_MENU)); 469 back_model->set_test_tab_contents(contents()); 470 471 EXPECT_EQ(0, back_model->GetItemCount()); 472 EXPECT_FALSE(back_model->ItemHasCommand(1)); 473 474 LoadURLAndUpdateState("http://www.a.com/1", "A B"); 475 LoadURLAndUpdateState("http://www.a.com/1", "A & B"); 476 LoadURLAndUpdateState("http://www.a.com/2", "A && B"); 477 LoadURLAndUpdateState("http://www.a.com/2", "A &&& B"); 478 LoadURLAndUpdateState("http://www.a.com/3", ""); 479 480 EXPECT_EQ(6, back_model->GetItemCount()); 481 482 // On Mac ui::MenuModel::GetLabelAt should return unescaped strings. 483 #if defined(OS_MACOSX) 484 EXPECT_EQ(ASCIIToUTF16("A B"), back_model->GetLabelAt(3)); 485 EXPECT_EQ(ASCIIToUTF16("A & B"), back_model->GetLabelAt(2)); 486 EXPECT_EQ(ASCIIToUTF16("A && B"), back_model->GetLabelAt(1)); 487 EXPECT_EQ(ASCIIToUTF16("A &&& B"), back_model->GetLabelAt(0)); 488 #else 489 EXPECT_EQ(ASCIIToUTF16("A B"), back_model->GetLabelAt(3)); 490 EXPECT_EQ(ASCIIToUTF16("A && B"), back_model->GetLabelAt(2)); 491 EXPECT_EQ(ASCIIToUTF16("A &&&& B"), back_model->GetLabelAt(1)); 492 EXPECT_EQ(ASCIIToUTF16("A &&&&&& B"), back_model->GetLabelAt(0)); 493 #endif // defined(OS_MACOSX) 494 } 495 496 // Test asynchronous loading of favicon from history service. 497 TEST_F(BackFwdMenuModelTest, FaviconLoadTest) { 498 profile()->CreateHistoryService(true, false); 499 profile()->CreateFaviconService(); 500 Browser browser(Browser::TYPE_NORMAL, profile()); 501 FaviconDelegate favicon_delegate; 502 503 BackForwardMenuModel back_model( 504 &browser, BackForwardMenuModel::BACKWARD_MENU); 505 back_model.set_test_tab_contents(controller().tab_contents()); 506 back_model.SetMenuModelDelegate(&favicon_delegate); 507 508 SkBitmap new_icon(CreateBitmap(SK_ColorRED)); 509 std::vector<unsigned char> icon_data; 510 gfx::PNGCodec::EncodeBGRASkBitmap(new_icon, false, &icon_data); 511 512 GURL url1 = GURL("http://www.a.com/1"); 513 GURL url2 = GURL("http://www.a.com/2"); 514 GURL url1_favicon("http://www.a.com/1/favicon.ico"); 515 516 NavigateAndCommit(url1); 517 // Navigate to a new URL so that url1 will be in the BackForwardMenuModel. 518 NavigateAndCommit(url2); 519 520 // Set the desired favicon for url1. 521 profile()->GetHistoryService(Profile::EXPLICIT_ACCESS)->AddPage(url1, 522 history::SOURCE_BROWSED); 523 profile()->GetFaviconService(Profile::EXPLICIT_ACCESS)->SetFavicon(url1, 524 url1_favicon, icon_data, history::FAVICON); 525 526 // Will return the current icon (default) but start an anync call 527 // to retrieve the favicon from the favicon service. 528 SkBitmap default_icon; 529 back_model.GetIconAt(0, &default_icon); 530 531 // Make the favicon service run GetFavIconForURL, 532 // FaviconDelegate.OnIconChanged will be called. 533 MessageLoop::current()->Run(); 534 535 // Verify that the callback executed. 536 EXPECT_TRUE(favicon_delegate.was_called()); 537 538 // Verify the bitmaps match. 539 SkBitmap valid_icon; 540 // This time we will get the new favicon returned. 541 back_model.GetIconAt(0, &valid_icon); 542 SkAutoLockPixels a(new_icon); 543 SkAutoLockPixels b(valid_icon); 544 SkAutoLockPixels c(default_icon); 545 // Verify we did not get the default favicon. 546 EXPECT_NE(0, memcmp(default_icon.getPixels(), valid_icon.getPixels(), 547 default_icon.getSize())); 548 // Verify we did get the expected favicon. 549 EXPECT_EQ(0, memcmp(new_icon.getPixels(), valid_icon.getPixels(), 550 new_icon.getSize())); 551 552 // Make sure the browser deconstructor doesn't have problems. 553 browser.CloseAllTabs(); 554 // This is required to prevent the message loop from hanging. 555 profile()->DestroyHistoryService(); 556 } 557 558