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 "chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.h" 6 7#include "base/command_line.h" 8#include "base/run_loop.h" 9#include "chrome/app/chrome_command_ids.h" 10#include "chrome/browser/sessions/session_service.h" 11#include "chrome/browser/sessions/session_service_factory.h" 12#include "chrome/browser/sessions/session_types.h" 13#include "chrome/browser/sessions/persistent_tab_restore_service.h" 14#include "chrome/browser/sessions/tab_restore_service_factory.h" 15#include "chrome/browser/sync/glue/synced_session.h" 16#include "chrome/browser/sync/profile_sync_service_mock.h" 17#include "chrome/browser/sync/sessions/sessions_sync_manager.h" 18#include "chrome/browser/ui/browser.h" 19#include "chrome/browser/ui/browser_tabstrip.h" 20#include "chrome/browser/ui/tabs/tab_strip_model.h" 21#include "chrome/browser/ui/toolbar/recent_tabs_builder_test_helper.h" 22#include "chrome/common/chrome_switches.h" 23#include "chrome/test/base/browser_with_test_window_test.h" 24#include "chrome/test/base/menu_model_test.h" 25#include "chrome/test/base/testing_profile.h" 26#include "components/sessions/serialized_navigation_entry_test_helper.h" 27#include "content/public/browser/browser_thread.h" 28#include "grit/generated_resources.h" 29#include "sync/api/fake_sync_change_processor.h" 30#include "sync/api/sync_error_factory_mock.h" 31#include "testing/gmock/include/gmock/gmock.h" 32#include "testing/gtest/include/gtest/gtest.h" 33 34namespace { 35 36// This copies parts of MenuModelTest::Delegate and combines them with the 37// RecentTabsSubMenuModel since RecentTabsSubMenuModel is a 38// SimpleMenuModel::Delegate and not just derived from SimpleMenuModel. 39class TestRecentTabsSubMenuModel : public RecentTabsSubMenuModel { 40 public: 41 TestRecentTabsSubMenuModel(ui::AcceleratorProvider* provider, 42 Browser* browser, 43 browser_sync::OpenTabsUIDelegate* delegate) 44 : RecentTabsSubMenuModel(provider, browser, delegate), 45 execute_count_(0), 46 enable_count_(0) { 47 } 48 49 // Testing overrides to ui::SimpleMenuModel::Delegate: 50 virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE { 51 bool val = RecentTabsSubMenuModel::IsCommandIdEnabled(command_id); 52 if (val) 53 ++enable_count_; 54 return val; 55 } 56 57 virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE { 58 ++execute_count_; 59 } 60 61 int execute_count() const { return execute_count_; } 62 int enable_count() const { return enable_count_; } 63 64 private: 65 int execute_count_; 66 int mutable enable_count_; // Mutable because IsCommandIdEnabledAt is const. 67 68 DISALLOW_COPY_AND_ASSIGN(TestRecentTabsSubMenuModel); 69}; 70 71class TestRecentTabsMenuModelDelegate : public ui::MenuModelDelegate { 72 public: 73 explicit TestRecentTabsMenuModelDelegate(ui::MenuModel* model) 74 : model_(model), 75 got_changes_(false) { 76 model_->SetMenuModelDelegate(this); 77 } 78 79 virtual ~TestRecentTabsMenuModelDelegate() { 80 model_->SetMenuModelDelegate(NULL); 81 } 82 83 // ui::MenuModelDelegate implementation: 84 85 virtual void OnIconChanged(int index) OVERRIDE { 86 } 87 88 virtual void OnMenuStructureChanged() OVERRIDE { 89 got_changes_ = true; 90 } 91 92 bool got_changes() const { return got_changes_; } 93 94 private: 95 ui::MenuModel* model_; 96 bool got_changes_; 97 98 DISALLOW_COPY_AND_ASSIGN(TestRecentTabsMenuModelDelegate); 99}; 100 101class DummyRouter : public browser_sync::LocalSessionEventRouter { 102 public: 103 virtual ~DummyRouter() {} 104 virtual void StartRoutingTo( 105 browser_sync::LocalSessionEventHandler* handler) OVERRIDE {} 106 virtual void Stop() OVERRIDE {} 107}; 108 109} // namespace 110 111class RecentTabsSubMenuModelTest 112 : public BrowserWithTestWindowTest, 113 public browser_sync::SessionsSyncManager::SyncInternalApiDelegate { 114 public: 115 RecentTabsSubMenuModelTest() 116 : sync_service_(&testing_profile_) { 117 manager_.reset(new browser_sync::SessionsSyncManager( 118 &testing_profile_, 119 this, 120 scoped_ptr<browser_sync::LocalSessionEventRouter>( 121 new DummyRouter()))); 122 manager_->MergeDataAndStartSyncing( 123 syncer::SESSIONS, 124 syncer::SyncDataList(), 125 scoped_ptr<syncer::SyncChangeProcessor>( 126 new syncer::FakeSyncChangeProcessor), 127 scoped_ptr<syncer::SyncErrorFactory>( 128 new syncer::SyncErrorFactoryMock)); 129 } 130 131 void WaitForLoadFromLastSession() { 132 content::BrowserThread::GetBlockingPool()->FlushForTesting(); 133 base::RunLoop().RunUntilIdle(); 134 content::BrowserThread::GetBlockingPool()->FlushForTesting(); 135 } 136 137 static KeyedService* GetTabRestoreService( 138 content::BrowserContext* browser_context) { 139 // Ownership is tranfered to the profile. 140 return new PersistentTabRestoreService( 141 Profile::FromBrowserContext(browser_context), NULL); 142 } 143 144 145 browser_sync::OpenTabsUIDelegate* GetOpenTabsDelegate() { 146 return manager_.get(); 147 } 148 149 void RegisterRecentTabs(RecentTabsBuilderTestHelper* helper) { 150 helper->ExportToSessionsSyncManager(manager_.get()); 151 } 152 153 virtual scoped_ptr<browser_sync::DeviceInfo> GetLocalDeviceInfo() 154 const OVERRIDE { 155 return scoped_ptr<browser_sync::DeviceInfo>( 156 new browser_sync::DeviceInfo(GetLocalSyncCacheGUID(), 157 "Test Machine", 158 "Chromium 10k", 159 "Chrome 10k", 160 sync_pb::SyncEnums_DeviceType_TYPE_LINUX)); 161 } 162 163 virtual std::string GetLocalSyncCacheGUID() const OVERRIDE { 164 return "RecentTabsSubMenuModelTest"; 165 } 166 167 private: 168 TestingProfile testing_profile_; 169 testing::NiceMock<ProfileSyncServiceMock> sync_service_; 170 171 scoped_ptr<browser_sync::SessionsSyncManager> manager_; 172}; 173 174// Test disabled "Recently closed" header with no foreign tabs. 175TEST_F(RecentTabsSubMenuModelTest, NoTabs) { 176 TestRecentTabsSubMenuModel model(NULL, browser(), NULL); 177 178 // Expected menu: 179 // Menu index Menu items 180 // --------------------------------------------- 181 // 0 Recently closed header (disabled) 182 // 1 <separator> 183 // 2 No tabs from other Devices 184 185 int num_items = model.GetItemCount(); 186 EXPECT_EQ(3, num_items); 187 EXPECT_FALSE(model.IsEnabledAt(0)); 188 EXPECT_FALSE(model.IsEnabledAt(2)); 189 EXPECT_EQ(0, model.enable_count()); 190 191 EXPECT_EQ(NULL, model.GetLabelFontListAt(0)); 192 EXPECT_EQ(NULL, model.GetLabelFontListAt(1)); 193 EXPECT_EQ(NULL, model.GetLabelFontListAt(2)); 194 195 std::string url; 196 base::string16 title; 197 EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(0, &url, &title)); 198 EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(1, &url, &title)); 199 EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(2, &url, &title)); 200} 201 202// Test enabled "Recently closed" header with no foreign tabs. 203TEST_F(RecentTabsSubMenuModelTest, RecentlyClosedTabsFromCurrentSession) { 204 TabRestoreServiceFactory::GetInstance()->SetTestingFactory( 205 profile(), RecentTabsSubMenuModelTest::GetTabRestoreService); 206 207 // Add 2 tabs and close them. 208 AddTab(browser(), GURL("http://foo/1")); 209 AddTab(browser(), GURL("http://foo/2")); 210 browser()->tab_strip_model()->CloseAllTabs(); 211 212 TestRecentTabsSubMenuModel model(NULL, browser(), NULL); 213 // Expected menu: 214 // Menu index Menu items 215 // -------------------------------------- 216 // 0 Recently closed header 217 // 1 <tab for http://foo/2> 218 // 2 <tab for http://foo/1> 219 // 3 <separator> 220 // 4 No tabs from other Devices 221 int num_items = model.GetItemCount(); 222 EXPECT_EQ(5, num_items); 223 EXPECT_FALSE(model.IsEnabledAt(0)); 224 EXPECT_TRUE(model.IsEnabledAt(1)); 225 EXPECT_TRUE(model.IsEnabledAt(2)); 226 model.ActivatedAt(1); 227 model.ActivatedAt(2); 228 EXPECT_FALSE(model.IsEnabledAt(4)); 229 EXPECT_EQ(2, model.enable_count()); 230 EXPECT_EQ(2, model.execute_count()); 231 232 EXPECT_TRUE(model.GetLabelFontListAt(0) != NULL); 233 EXPECT_EQ(NULL, model.GetLabelFontListAt(1)); 234 EXPECT_EQ(NULL, model.GetLabelFontListAt(2)); 235 EXPECT_EQ(NULL, model.GetLabelFontListAt(3)); 236 EXPECT_EQ(NULL, model.GetLabelFontListAt(4)); 237 238 std::string url; 239 base::string16 title; 240 EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(0, &url, &title)); 241 EXPECT_TRUE(model.GetURLAndTitleForItemAtIndex(1, &url, &title)); 242 EXPECT_TRUE(model.GetURLAndTitleForItemAtIndex(2, &url, &title)); 243 EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(3, &url, &title)); 244 EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(4, &url, &title)); 245} 246 247// TODO(sail): enable this test when dynamic model is enabled in 248// RecentTabsSubMenuModel. 249#if defined(OS_MACOSX) 250#define MAYBE_RecentlyClosedTabsAndWindowsFromLastSession \ 251 DISABLED_RecentlyClosedTabsAndWindowsFromLastSession 252#else 253#define MAYBE_RecentlyClosedTabsAndWindowsFromLastSession \ 254 RecentlyClosedTabsAndWindowsFromLastSession 255#endif 256TEST_F(RecentTabsSubMenuModelTest, 257 MAYBE_RecentlyClosedTabsAndWindowsFromLastSession) { 258 TabRestoreServiceFactory::GetInstance()->SetTestingFactory( 259 profile(), RecentTabsSubMenuModelTest::GetTabRestoreService); 260 261 // Add 2 tabs and close them. 262 AddTab(browser(), GURL("http://wnd/tab0")); 263 AddTab(browser(), GURL("http://wnd/tab1")); 264 browser()->tab_strip_model()->CloseAllTabs(); 265 266 // Create a SessionService for the profile (profile owns the service) and add 267 // a window with a tab to this session. 268 SessionService* session_service = new SessionService(profile()); 269 SessionServiceFactory::SetForTestProfile(profile(), session_service); 270 SessionID tab_id; 271 SessionID window_id; 272 session_service->SetWindowType( 273 window_id, Browser::TYPE_TABBED, SessionService::TYPE_NORMAL); 274 session_service->SetTabWindow(window_id, tab_id); 275 session_service->SetTabIndexInWindow(window_id, tab_id, 0); 276 session_service->SetSelectedTabInWindow(window_id, 0); 277 session_service->UpdateTabNavigation( 278 window_id, tab_id, 279 sessions::SerializedNavigationEntryTestHelper::CreateNavigation( 280 "http://wnd1/tab0", "title")); 281 // Set this, otherwise previous session won't be loaded. 282 profile()->set_last_session_exited_cleanly(false); 283 // Move this session to the last so that TabRestoreService will load it as the 284 // last session. 285 SessionServiceFactory::GetForProfile(profile())-> 286 MoveCurrentSessionToLastSession(); 287 288 // Create a new TabRestoreService so that it'll load the recently closed tabs 289 // and windows afresh. 290 TabRestoreServiceFactory::GetInstance()->SetTestingFactory( 291 profile(), RecentTabsSubMenuModelTest::GetTabRestoreService); 292 // Let the shutdown of previous TabRestoreService run. 293 content::BrowserThread::GetBlockingPool()->FlushForTesting(); 294 295 TestRecentTabsSubMenuModel model(NULL, browser(), NULL); 296 TestRecentTabsMenuModelDelegate delegate(&model); 297 EXPECT_FALSE(delegate.got_changes()); 298 299 // Expected menu before tabs/windows from last session are loaded: 300 // Menu index Menu items 301 // ---------------------------------------------------------------- 302 // 0 Recently closed header 303 // 1 <separator> 304 // 2 No tabs from other Devices 305 306 int num_items = model.GetItemCount(); 307 EXPECT_EQ(3, num_items); 308 EXPECT_FALSE(model.IsEnabledAt(0)); 309 EXPECT_EQ(ui::MenuModel::TYPE_SEPARATOR, model.GetTypeAt(1)); 310 EXPECT_FALSE(model.IsEnabledAt(2)); 311 EXPECT_EQ(0, model.enable_count()); 312 313 // Wait for tabs from last session to be loaded. 314 WaitForLoadFromLastSession(); 315 316 // Expected menu after tabs/windows from last session are loaded: 317 // Menu index Menu items 318 // -------------------------------------------------------------- 319 // 0 Recently closed header 320 // 1 <window for the tab http://wnd1/tab0> 321 // 2 <tab for http://wnd0/tab1> 322 // 3 <tab for http://wnd0/tab0> 323 // 4 <separator> 324 // 5 No tabs from other Devices 325 326 EXPECT_TRUE(delegate.got_changes()); 327 328 num_items = model.GetItemCount(); 329 EXPECT_EQ(6, num_items); 330 EXPECT_FALSE(model.IsEnabledAt(0)); 331 EXPECT_TRUE(model.IsEnabledAt(1)); 332 EXPECT_TRUE(model.IsEnabledAt(2)); 333 EXPECT_TRUE(model.IsEnabledAt(3)); 334 model.ActivatedAt(1); 335 model.ActivatedAt(2); 336 model.ActivatedAt(3); 337 EXPECT_EQ(ui::MenuModel::TYPE_SEPARATOR, model.GetTypeAt(4)); 338 EXPECT_FALSE(model.IsEnabledAt(5)); 339 EXPECT_EQ(3, model.enable_count()); 340 EXPECT_EQ(3, model.execute_count()); 341 342 EXPECT_TRUE(model.GetLabelFontListAt(0) != NULL); 343 EXPECT_EQ(NULL, model.GetLabelFontListAt(1)); 344 EXPECT_EQ(NULL, model.GetLabelFontListAt(2)); 345 EXPECT_EQ(NULL, model.GetLabelFontListAt(3)); 346 EXPECT_EQ(NULL, model.GetLabelFontListAt(4)); 347 EXPECT_EQ(NULL, model.GetLabelFontListAt(5)); 348 349 std::string url; 350 base::string16 title; 351 EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(0, &url, &title)); 352 EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(1, &url, &title)); 353 EXPECT_TRUE(model.GetURLAndTitleForItemAtIndex(2, &url, &title)); 354 EXPECT_TRUE(model.GetURLAndTitleForItemAtIndex(3, &url, &title)); 355 EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(4, &url, &title)); 356 EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(5, &url, &title)); 357} 358 359// Test disabled "Recently closed" header with multiple sessions, multiple 360// windows, and multiple enabled tabs from other devices. 361TEST_F(RecentTabsSubMenuModelTest, OtherDevices) { 362 // Tabs are populated in decreasing timestamp. 363 base::Time timestamp = base::Time::Now(); 364 const base::TimeDelta time_delta = base::TimeDelta::FromMinutes(10); 365 366 RecentTabsBuilderTestHelper recent_tabs_builder; 367 368 // Create 1st session : 1 window, 3 tabs 369 recent_tabs_builder.AddSession(); 370 recent_tabs_builder.AddWindow(0); 371 for (int i = 0; i < 3; ++i) { 372 timestamp -= time_delta; 373 recent_tabs_builder.AddTabWithInfo(0, 0, timestamp, base::string16()); 374 } 375 376 // Create 2nd session : 2 windows, 1 tab in 1st window, 2 tabs in 2nd window 377 recent_tabs_builder.AddSession(); 378 recent_tabs_builder.AddWindow(1); 379 recent_tabs_builder.AddWindow(1); 380 timestamp -= time_delta; 381 recent_tabs_builder.AddTabWithInfo(1, 0, timestamp, base::string16()); 382 timestamp -= time_delta; 383 recent_tabs_builder.AddTabWithInfo(1, 1, timestamp, base::string16()); 384 timestamp -= time_delta; 385 recent_tabs_builder.AddTabWithInfo(1, 1, timestamp, base::string16()); 386 387 RegisterRecentTabs(&recent_tabs_builder); 388 389 // Verify that data is populated correctly in RecentTabsSubMenuModel. 390 // Expected menu: 391 // - first inserted tab is most recent and hence is top 392 // Menu index Menu items 393 // ----------------------------------------------------- 394 // 0 Recently closed header (disabled) 395 // 1 <separator> 396 // 2 <section header for 1st session> 397 // 3-5 <3 tabs of the only window of session 0> 398 // 6 <separator> 399 // 7 <section header for 2nd session> 400 // 8 <the only tab of window 0 of session 1> 401 // 9-10 <2 tabs of window 1 of session 2> 402 // 11 <separator> 403 // 12 More... 404 405 TestRecentTabsSubMenuModel model(NULL, browser(), GetOpenTabsDelegate()); 406 int num_items = model.GetItemCount(); 407 EXPECT_EQ(13, num_items); 408 model.ActivatedAt(0); 409 EXPECT_FALSE(model.IsEnabledAt(0)); 410 model.ActivatedAt(3); 411 EXPECT_TRUE(model.IsEnabledAt(3)); 412 model.ActivatedAt(4); 413 EXPECT_TRUE(model.IsEnabledAt(4)); 414 model.ActivatedAt(5); 415 EXPECT_TRUE(model.IsEnabledAt(5)); 416 model.ActivatedAt(8); 417 EXPECT_TRUE(model.IsEnabledAt(8)); 418 model.ActivatedAt(9); 419 EXPECT_TRUE(model.IsEnabledAt(9)); 420 model.ActivatedAt(10); 421 EXPECT_TRUE(model.IsEnabledAt(10)); 422 EXPECT_TRUE(model.IsEnabledAt(12)); 423 EXPECT_EQ(7, model.enable_count()); 424 EXPECT_EQ(7, model.execute_count()); 425 426 EXPECT_EQ(NULL, model.GetLabelFontListAt(0)); 427 EXPECT_EQ(NULL, model.GetLabelFontListAt(1)); 428 EXPECT_TRUE(model.GetLabelFontListAt(2) != NULL); 429 EXPECT_EQ(NULL, model.GetLabelFontListAt(3)); 430 EXPECT_EQ(NULL, model.GetLabelFontListAt(4)); 431 EXPECT_EQ(NULL, model.GetLabelFontListAt(5)); 432 EXPECT_EQ(NULL, model.GetLabelFontListAt(6)); 433 EXPECT_TRUE(model.GetLabelFontListAt(7) != NULL); 434 EXPECT_EQ(NULL, model.GetLabelFontListAt(8)); 435 EXPECT_EQ(NULL, model.GetLabelFontListAt(9)); 436 EXPECT_EQ(NULL, model.GetLabelFontListAt(10)); 437 EXPECT_EQ(NULL, model.GetLabelFontListAt(11)); 438 EXPECT_EQ(NULL, model.GetLabelFontListAt(12)); 439 440 std::string url; 441 base::string16 title; 442 EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(0, &url, &title)); 443 EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(1, &url, &title)); 444 EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(2, &url, &title)); 445 EXPECT_TRUE(model.GetURLAndTitleForItemAtIndex(3, &url, &title)); 446 EXPECT_TRUE(model.GetURLAndTitleForItemAtIndex(4, &url, &title)); 447 EXPECT_TRUE(model.GetURLAndTitleForItemAtIndex(5, &url, &title)); 448 EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(6, &url, &title)); 449 EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(7, &url, &title)); 450 EXPECT_TRUE(model.GetURLAndTitleForItemAtIndex(8, &url, &title)); 451 EXPECT_TRUE(model.GetURLAndTitleForItemAtIndex(9, &url, &title)); 452 EXPECT_TRUE(model.GetURLAndTitleForItemAtIndex(10, &url, &title)); 453 EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(11, &url, &title)); 454 EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(12, &url, &title)); 455} 456 457TEST_F(RecentTabsSubMenuModelTest, MaxSessionsAndRecency) { 458 // Create 4 sessions : each session has 1 window with 1 tab each. 459 RecentTabsBuilderTestHelper recent_tabs_builder; 460 for (int s = 0; s < 4; ++s) { 461 recent_tabs_builder.AddSession(); 462 recent_tabs_builder.AddWindow(s); 463 recent_tabs_builder.AddTab(s, 0); 464 } 465 RegisterRecentTabs(&recent_tabs_builder); 466 467 // Verify that data is populated correctly in RecentTabsSubMenuModel. 468 // Expected menu: 469 // - max sessions is 3, so only 3 most-recent sessions will show. 470 // Menu index Menu items 471 // ---------------------------------------------------------- 472 // 0 Recently closed header (disabled) 473 // 1 <separator> 474 // 2 <section header for 1st session> 475 // 3 <the only tab of the only window of session 3> 476 // 4 <separator> 477 // 5 <section header for 2nd session> 478 // 6 <the only tab of the only window of session 2> 479 // 7 <separator> 480 // 8 <section header for 3rd session> 481 // 9 <the only tab of the only window of session 1> 482 // 10 <separator> 483 // 11 More... 484 485 TestRecentTabsSubMenuModel model(NULL, browser(), GetOpenTabsDelegate()); 486 int num_items = model.GetItemCount(); 487 EXPECT_EQ(12, num_items); 488 489 std::vector<base::string16> tab_titles = 490 recent_tabs_builder.GetTabTitlesSortedByRecency(); 491 EXPECT_EQ(tab_titles[0], model.GetLabelAt(3)); 492 EXPECT_EQ(tab_titles[1], model.GetLabelAt(6)); 493 EXPECT_EQ(tab_titles[2], model.GetLabelAt(9)); 494} 495 496TEST_F(RecentTabsSubMenuModelTest, MaxTabsPerSessionAndRecency) { 497 // Create a session: 2 windows with 5 tabs each. 498 RecentTabsBuilderTestHelper recent_tabs_builder; 499 recent_tabs_builder.AddSession(); 500 for (int w = 0; w < 2; ++w) { 501 recent_tabs_builder.AddWindow(0); 502 for (int t = 0; t < 5; ++t) 503 recent_tabs_builder.AddTab(0, w); 504 } 505 RegisterRecentTabs(&recent_tabs_builder); 506 507 // Verify that data is populated correctly in RecentTabsSubMenuModel. 508 // Expected menu: 509 // - max tabs per session is 4, so only 4 most-recent tabs will show, 510 // independent of which window they came from. 511 // Menu index Menu items 512 // --------------------------------------------- 513 // 0 Recently closed header (disabled) 514 // 1 <separator> 515 // 2 <section header for session> 516 // 3-6 <4 most-recent tabs of session> 517 // 7 <separator> 518 // 8 More... 519 520 TestRecentTabsSubMenuModel model(NULL, browser(), GetOpenTabsDelegate()); 521 int num_items = model.GetItemCount(); 522 EXPECT_EQ(9, num_items); 523 524 std::vector<base::string16> tab_titles = 525 recent_tabs_builder.GetTabTitlesSortedByRecency(); 526 for (int i = 0; i < 4; ++i) 527 EXPECT_EQ(tab_titles[i], model.GetLabelAt(i + 3)); 528} 529 530TEST_F(RecentTabsSubMenuModelTest, MaxWidth) { 531 // Create 1 session with 1 window and 1 tab. 532 RecentTabsBuilderTestHelper recent_tabs_builder; 533 recent_tabs_builder.AddSession(); 534 recent_tabs_builder.AddWindow(0); 535 recent_tabs_builder.AddTab(0, 0); 536 RegisterRecentTabs(&recent_tabs_builder); 537 538 // Menu index Menu items 539 // ---------------------------------------------------------- 540 // 0 Recently closed header (disabled) 541 // 1 <separator> 542 // 2 <section header for 1st session> 543 // 3 <the only tab of the only window of session 1> 544 // 4 <separator> 545 // 5 More... 546 547 TestRecentTabsSubMenuModel model(NULL, browser(), GetOpenTabsDelegate()); 548 EXPECT_EQ(6, model.GetItemCount()); 549 EXPECT_EQ(-1, model.GetMaxWidthForItemAtIndex(0)); 550 EXPECT_NE(-1, model.GetMaxWidthForItemAtIndex(1)); 551 EXPECT_NE(-1, model.GetMaxWidthForItemAtIndex(2)); 552 EXPECT_NE(-1, model.GetMaxWidthForItemAtIndex(3)); 553} 554 555TEST_F(RecentTabsSubMenuModelTest, MaxWidthNoDevices) { 556 // Expected menu: 557 // Menu index Menu items 558 // -------------------------------------------- 559 // 0 Recently closed heaer (disabled) 560 // 1 <separator> 561 // 2 No tabs from other Devices 562 563 TestRecentTabsSubMenuModel model(NULL, browser(), NULL); 564 EXPECT_EQ(3, model.GetItemCount()); 565 EXPECT_EQ(-1, model.GetMaxWidthForItemAtIndex(0)); 566 EXPECT_NE(-1, model.GetMaxWidthForItemAtIndex(1)); 567 EXPECT_EQ(-1, model.GetMaxWidthForItemAtIndex(2)); 568} 569