| // 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 "chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.h" |
| |
| #include "chrome/app/chrome_command_ids.h" |
| #include "chrome/browser/sessions/session_types.h" |
| #include "chrome/browser/sessions/persistent_tab_restore_service.h" |
| #include "chrome/browser/sessions/tab_restore_service_factory.h" |
| #include "chrome/browser/sync/glue/session_model_associator.h" |
| #include "chrome/browser/sync/glue/synced_session.h" |
| #include "chrome/browser/sync/profile_sync_service_mock.h" |
| #include "chrome/browser/ui/browser.h" |
| #include "chrome/browser/ui/browser_tabstrip.h" |
| #include "chrome/browser/ui/tabs/tab_strip_model.h" |
| #include "chrome/browser/ui/toolbar/recent_tabs_builder_test_helper.h" |
| #include "chrome/test/base/browser_with_test_window_test.h" |
| #include "chrome/test/base/menu_model_test.h" |
| #include "chrome/test/base/testing_profile.h" |
| #include "grit/generated_resources.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace { |
| |
| // This copies parts of MenuModelTest::Delegate and combines them with the |
| // RecentTabsSubMenuModel since RecentTabsSubMenuModel is a |
| // SimpleMenuModel::Delegate and not just derived from SimpleMenuModel. |
| class TestRecentTabsSubMenuModel : public RecentTabsSubMenuModel { |
| public: |
| TestRecentTabsSubMenuModel(ui::AcceleratorProvider* provider, |
| Browser* browser, |
| browser_sync::SessionModelAssociator* associator) |
| : RecentTabsSubMenuModel(provider, browser, associator), |
| execute_count_(0), |
| enable_count_(0) { |
| } |
| |
| // Testing overrides to ui::SimpleMenuModel::Delegate: |
| virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE { |
| bool val = RecentTabsSubMenuModel::IsCommandIdEnabled(command_id); |
| if (val) |
| ++enable_count_; |
| return val; |
| } |
| |
| virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE { |
| ++execute_count_; |
| } |
| |
| int execute_count_; |
| int mutable enable_count_; // Mutable because IsCommandIdEnabledAt is const. |
| }; |
| |
| } // namespace |
| |
| class RecentTabsSubMenuModelTest : public BrowserWithTestWindowTest { |
| public: |
| RecentTabsSubMenuModelTest() |
| : sync_service_(&testing_profile_), |
| associator_(&sync_service_, true) { |
| associator_.SetCurrentMachineTagForTesting("RecentTabsSubMenuModelTest"); |
| } |
| |
| static BrowserContextKeyedService* GetTabRestoreService( |
| content::BrowserContext* browser_context) { |
| // Ownership is tranfered to the profile. |
| return new PersistentTabRestoreService( |
| Profile::FromBrowserContext(browser_context), NULL);; |
| } |
| private: |
| TestingProfile testing_profile_; |
| testing::NiceMock<ProfileSyncServiceMock> sync_service_; |
| |
| protected: |
| browser_sync::SessionModelAssociator associator_; |
| }; |
| |
| // Test disabled "Reopen closed tab" with no foreign tabs. |
| TEST_F(RecentTabsSubMenuModelTest, NoTabs) { |
| TestRecentTabsSubMenuModel model(NULL, browser(), NULL); |
| |
| // Expected menu: |
| // Menu index Menu items |
| // -------------------------------------- |
| // 0 Reopen closed tab |
| // 1 <separator> |
| // 2 No tabs from other Devices |
| |
| int num_items = model.GetItemCount(); |
| EXPECT_EQ(3, num_items); |
| EXPECT_FALSE(model.IsEnabledAt(0)); |
| EXPECT_FALSE(model.IsEnabledAt(2)); |
| EXPECT_EQ(0, model.enable_count_); |
| } |
| |
| // Test enabled "Reopen closed tab" with no foreign tabs. |
| TEST_F(RecentTabsSubMenuModelTest, ReopenClosedTab) { |
| TabRestoreServiceFactory::GetInstance()->SetTestingFactory( |
| browser()->profile(), RecentTabsSubMenuModelTest::GetTabRestoreService); |
| |
| // Add a tab and close it. |
| GURL url1("http://foo/1"); |
| AddTab(browser(), url1); |
| browser()->tab_strip_model()->CloseWebContentsAt( |
| 0, TabStripModel::CLOSE_CREATE_HISTORICAL_TAB); |
| |
| TestRecentTabsSubMenuModel model(NULL, browser(), NULL); |
| // Expected menu: |
| // Menu index Menu items |
| // -------------------------------------- |
| // 0 Recently Closed Header |
| // 1 Single entry to restore |
| // 2 <separator> |
| // 3 No tabs from other Devices |
| int num_items = model.GetItemCount(); |
| EXPECT_EQ(4, num_items); |
| EXPECT_FALSE(model.IsEnabledAt(0)); |
| EXPECT_TRUE(model.IsEnabledAt(1)); |
| model.ActivatedAt(1); |
| EXPECT_FALSE(model.IsEnabledAt(3)); |
| EXPECT_EQ(1, model.enable_count_); |
| EXPECT_EQ(1, model.execute_count_); |
| } |
| |
| // Test enabled "Reopen closed tab" with multiple sessions, multiple windows, |
| // and multiple enabled tabs from other devices. |
| TEST_F(RecentTabsSubMenuModelTest, OtherDevices) { |
| // Tabs are populated in decreasing timestamp. |
| base::Time timestamp = base::Time::Now(); |
| const base::TimeDelta time_delta = base::TimeDelta::FromMinutes(10); |
| |
| RecentTabsBuilderTestHelper recent_tabs_builder; |
| |
| // Create 1st session : 1 window, 3 tabs |
| recent_tabs_builder.AddSession(); |
| recent_tabs_builder.AddWindow(0); |
| for (int i = 0; i < 3; ++i) { |
| timestamp -= time_delta; |
| recent_tabs_builder.AddTabWithInfo(0, 0, timestamp, string16()); |
| } |
| |
| // Create 2nd session : 2 windows, 1 tab in 1st window, 2 tabs in 2nd window |
| recent_tabs_builder.AddSession(); |
| recent_tabs_builder.AddWindow(1); |
| recent_tabs_builder.AddWindow(1); |
| timestamp -= time_delta; |
| recent_tabs_builder.AddTabWithInfo(1, 0, timestamp, string16()); |
| timestamp -= time_delta; |
| recent_tabs_builder.AddTabWithInfo(1, 1, timestamp, string16()); |
| timestamp -= time_delta; |
| recent_tabs_builder.AddTabWithInfo(1, 1, timestamp, string16()); |
| |
| recent_tabs_builder.RegisterRecentTabs(&associator_); |
| |
| // Verify that data is populated correctly in RecentTabsSubMenuModel. |
| // Expected menu: |
| // - first inserted tab is most recent and hence is top |
| // Menu index Menu items |
| // -------------------------------------- |
| // 0 Reopen closed tab |
| // 1 <separator> |
| // 2 <section header for 1st session> |
| // 3-5 <3 tabs of the only window of session 0> |
| // 6 <separator> |
| // 7 <section header for 2nd session> |
| // 8 <the only tab of window 0 of session 1> |
| // 9-10 <2 tabs of window 1 of session 2> |
| // 11 <separator> |
| // 12 More... |
| |
| TestRecentTabsSubMenuModel model(NULL, browser(), &associator_); |
| int num_items = model.GetItemCount(); |
| EXPECT_EQ(13, num_items); |
| model.ActivatedAt(0); |
| EXPECT_FALSE(model.IsEnabledAt(0)); |
| model.ActivatedAt(3); |
| EXPECT_TRUE(model.IsEnabledAt(3)); |
| model.ActivatedAt(4); |
| EXPECT_TRUE(model.IsEnabledAt(4)); |
| model.ActivatedAt(5); |
| EXPECT_TRUE(model.IsEnabledAt(5)); |
| model.ActivatedAt(8); |
| EXPECT_TRUE(model.IsEnabledAt(8)); |
| model.ActivatedAt(9); |
| EXPECT_TRUE(model.IsEnabledAt(9)); |
| model.ActivatedAt(10); |
| EXPECT_TRUE(model.IsEnabledAt(10)); |
| EXPECT_TRUE(model.IsEnabledAt(12)); |
| EXPECT_EQ(7, model.enable_count_); |
| EXPECT_EQ(7, model.execute_count_); |
| } |
| |
| TEST_F(RecentTabsSubMenuModelTest, MaxSessionsAndRecency) { |
| // Create 4 sessions : each session has 1 window with 1 tab each. |
| RecentTabsBuilderTestHelper recent_tabs_builder; |
| for (int s = 0; s < 4; ++s) { |
| recent_tabs_builder.AddSession(); |
| recent_tabs_builder.AddWindow(s); |
| recent_tabs_builder.AddTab(s, 0); |
| } |
| recent_tabs_builder.RegisterRecentTabs(&associator_); |
| |
| // Verify that data is populated correctly in RecentTabsSubMenuModel. |
| // Expected menu: |
| // - max sessions is 3, so only 3 most-recent sessions will show. |
| // Menu index Menu items |
| // -------------------------------------- |
| // 0 Reopen closed tab |
| // 1 <separator> |
| // 2 <section header for 1st session> |
| // 3 <the only tab of the only window of session 3> |
| // 4 <separator> |
| // 5 <section header for 2nd session> |
| // 6 <the only tab of the only window of session 2> |
| // 7 <separator> |
| // 8 <section header for 3rd session> |
| // 9 <the only tab of the only window of session 1> |
| // 10 <separator> |
| // 11 More... |
| |
| TestRecentTabsSubMenuModel model(NULL, browser(), &associator_); |
| int num_items = model.GetItemCount(); |
| EXPECT_EQ(12, num_items); |
| |
| std::vector<string16> tab_titles = |
| recent_tabs_builder.GetTabTitlesSortedByRecency(); |
| EXPECT_EQ(tab_titles[0], model.GetLabelAt(3)); |
| EXPECT_EQ(tab_titles[1], model.GetLabelAt(6)); |
| EXPECT_EQ(tab_titles[2], model.GetLabelAt(9)); |
| } |
| |
| TEST_F(RecentTabsSubMenuModelTest, MaxTabsPerSessionAndRecency) { |
| // Create a session: 2 windows with 5 tabs each. |
| RecentTabsBuilderTestHelper recent_tabs_builder; |
| recent_tabs_builder.AddSession(); |
| for (int w = 0; w < 2; ++w) { |
| recent_tabs_builder.AddWindow(0); |
| for (int t = 0; t < 5; ++t) |
| recent_tabs_builder.AddTab(0, w); |
| } |
| recent_tabs_builder.RegisterRecentTabs(&associator_); |
| |
| // Verify that data is populated correctly in RecentTabsSubMenuModel. |
| // Expected menu: |
| // - max tabs per session is 4, so only 4 most-recent tabs will show, |
| // independent of which window they came from. |
| // Menu index Menu items |
| // -------------------------------------- |
| // 0 Reopen closed tab |
| // 1 <separator> |
| // 2 <section header for session> |
| // 3-6 <4 most-recent tabs of session> |
| // 7 <separator> |
| // 8 More... |
| |
| TestRecentTabsSubMenuModel model(NULL, browser(), &associator_); |
| int num_items = model.GetItemCount(); |
| EXPECT_EQ(9, num_items); |
| |
| std::vector<string16> tab_titles = |
| recent_tabs_builder.GetTabTitlesSortedByRecency(); |
| for (int i = 0; i < 4; ++i) |
| EXPECT_EQ(tab_titles[i], model.GetLabelAt(i + 3)); |
| } |
| |
| TEST_F(RecentTabsSubMenuModelTest, MaxWidth) { |
| // Create 1 session with 1 window and 1 tab. |
| RecentTabsBuilderTestHelper recent_tabs_builder; |
| recent_tabs_builder.AddSession(); |
| recent_tabs_builder.AddWindow(0); |
| recent_tabs_builder.AddTab(0, 0); |
| recent_tabs_builder.RegisterRecentTabs(&associator_); |
| |
| // Menu index Menu items |
| // -------------------------------------- |
| // 0 Reopen closed tab |
| // 1 <separator> |
| // 2 <section header for 1st session> |
| // 3 <the only tab of the only window of session 1> |
| // 4 <separator> |
| // 5 More... |
| |
| TestRecentTabsSubMenuModel model(NULL, browser(), &associator_); |
| EXPECT_EQ(6, model.GetItemCount()); |
| EXPECT_EQ(-1, model.GetMaxWidthForItemAtIndex(0)); |
| EXPECT_NE(-1, model.GetMaxWidthForItemAtIndex(1)); |
| EXPECT_NE(-1, model.GetMaxWidthForItemAtIndex(2)); |
| EXPECT_NE(-1, model.GetMaxWidthForItemAtIndex(3)); |
| } |
| |
| TEST_F(RecentTabsSubMenuModelTest, MaxWidthNoDevices) { |
| // Expected menu: |
| // Menu index Menu items |
| // -------------------------------------- |
| // 0 Reopen closed tab |
| // 1 <separator> |
| // 2 No tabs from other Devices |
| |
| TestRecentTabsSubMenuModel model(NULL, browser(), NULL); |
| EXPECT_EQ(3, model.GetItemCount()); |
| EXPECT_EQ(-1, model.GetMaxWidthForItemAtIndex(0)); |
| EXPECT_NE(-1, model.GetMaxWidthForItemAtIndex(1)); |
| EXPECT_EQ(-1, model.GetMaxWidthForItemAtIndex(2)); |
| } |