blob: f744ab88ee661df05862ff6086b82085163e92e6 [file] [log] [blame]
// Copyright 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 <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/bind.h"
#include "base/command_line.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/bind_test_util.h"
#include "build/build_config.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/sessions/chrome_tab_restore_service_client.h"
#include "chrome/browser/sessions/session_service.h"
#include "chrome/browser/sessions/session_service_factory.h"
#include "chrome/browser/sessions/tab_restore_service_factory.h"
#include "chrome/browser/sync/profile_sync_service_factory.h"
#include "chrome/browser/sync/session_sync_service_factory.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/common/chrome_switches.h"
#include "chrome/test/base/browser_with_test_window_test.h"
#include "chrome/test/base/menu_model_test.h"
#include "components/browser_sync/profile_sync_service.h"
#include "components/sessions/core/serialized_navigation_entry_test_helper.h"
#include "components/sessions/core/session_types.h"
#include "components/sessions/core/tab_restore_service_impl.h"
#include "components/sync/device_info/local_device_info_provider_mock.h"
#include "components/sync/driver/data_type_controller.h"
#include "components/sync/engine/data_type_activation_response.h"
#include "components/sync/model/data_type_activation_request.h"
#include "components/sync_sessions/session_sync_service_impl.h"
#include "components/sync_sessions/synced_session.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/test/test_utils.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)
: RecentTabsSubMenuModel(provider, browser),
execute_count_(0),
enable_count_(0) {}
// Testing overrides to ui::SimpleMenuModel::Delegate:
bool IsCommandIdEnabled(int command_id) const override {
bool val = RecentTabsSubMenuModel::IsCommandIdEnabled(command_id);
if (val)
++enable_count_;
return val;
}
void ExecuteCommand(int command_id, int event_flags) override {
++execute_count_;
}
int execute_count() const { return execute_count_; }
int enable_count() const { return enable_count_; }
private:
int execute_count_;
int mutable enable_count_; // Mutable because IsCommandIdEnabledAt is const.
DISALLOW_COPY_AND_ASSIGN(TestRecentTabsSubMenuModel);
};
class TestRecentTabsMenuModelDelegate : public ui::MenuModelDelegate {
public:
explicit TestRecentTabsMenuModelDelegate(ui::MenuModel* model)
: model_(model),
got_changes_(false) {
model_->SetMenuModelDelegate(this);
}
~TestRecentTabsMenuModelDelegate() override {
model_->SetMenuModelDelegate(NULL);
}
// ui::MenuModelDelegate implementation:
void OnIconChanged(int index) override {}
void OnMenuStructureChanged() override { got_changes_ = true; }
bool got_changes() const { return got_changes_; }
private:
ui::MenuModel* model_;
bool got_changes_;
DISALLOW_COPY_AND_ASSIGN(TestRecentTabsMenuModelDelegate);
};
} // namespace
class RecentTabsSubMenuModelTest
: public BrowserWithTestWindowTest {
public:
RecentTabsSubMenuModelTest() {}
void WaitForLoadFromLastSession() { content::RunAllTasksUntilIdle(); }
void SetUp() override {
BrowserWithTestWindowTest::SetUp();
session_sync_service_ = SessionSyncServiceFactory::GetForProfile(profile());
syncer::DataTypeActivationRequest activation_request;
activation_request.cache_guid = "test_cache_guid";
activation_request.error_handler = base::DoNothing();
ProfileSyncServiceFactory::GetForProfile(profile())
->GetLocalDeviceInfoProviderForTest()
->Initialize(activation_request.cache_guid, "Test Machine",
"device_id");
std::unique_ptr<syncer::DataTypeActivationResponse> activation_response;
base::RunLoop loop;
session_sync_service_->GetControllerDelegate()->OnSyncStarting(
activation_request,
base::BindLambdaForTesting(
[&](std::unique_ptr<syncer::DataTypeActivationResponse> response) {
activation_response = std::move(response);
loop.Quit();
}));
loop.Run();
ASSERT_NE(nullptr, activation_response);
ASSERT_NE(nullptr, activation_response->type_processor);
sync_processor_ = std::move(activation_response->type_processor);
EnableSync();
}
void EnableSync() {
session_sync_service_->ProxyTabsStateChanged(
syncer::DataTypeController::RUNNING);
}
void DisableSync() {
session_sync_service_->ProxyTabsStateChanged(
syncer::DataTypeController::NOT_RUNNING);
}
static std::unique_ptr<KeyedService> GetTabRestoreService(
content::BrowserContext* browser_context) {
return std::make_unique<sessions::TabRestoreServiceImpl>(
base::WrapUnique(new ChromeTabRestoreServiceClient(
Profile::FromBrowserContext(browser_context))),
nullptr);
}
void RegisterRecentTabs(RecentTabsBuilderTestHelper* helper) {
helper->ExportToSessionSync(
sync_processor_.get(),
static_cast<sync_sessions::SessionSyncServiceImpl*>(
session_sync_service_)
->GetUnderlyingOpenTabsUIDelegateForTest());
}
private:
sync_sessions::SessionSyncService* session_sync_service_;
std::unique_ptr<syncer::ModelTypeProcessor> sync_processor_;
DISALLOW_COPY_AND_ASSIGN(RecentTabsSubMenuModelTest);
};
// Test disabled "Recently closed" header with no foreign tabs.
TEST_F(RecentTabsSubMenuModelTest, NoTabs) {
DisableSync();
TestRecentTabsSubMenuModel model(nullptr, browser());
// Expected menu:
// Menu index Menu items
// ---------------------------------------------
// 0 History
// 1 <separator>
// 2 Recently closed header (disabled)
// 3 <separator>
// 4 No tabs from other Devices
int num_items = model.GetItemCount();
EXPECT_EQ(5, num_items);
EXPECT_FALSE(model.IsEnabledAt(2));
EXPECT_FALSE(model.IsEnabledAt(4));
EXPECT_EQ(0, model.enable_count());
EXPECT_EQ(NULL, model.GetLabelFontListAt(0));
EXPECT_EQ(NULL, model.GetLabelFontListAt(1));
EXPECT_EQ(NULL, model.GetLabelFontListAt(2));
EXPECT_EQ(NULL, model.GetLabelFontListAt(3));
EXPECT_EQ(NULL, model.GetLabelFontListAt(4));
std::string url;
base::string16 title;
EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(0, &url, &title));
EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(1, &url, &title));
EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(2, &url, &title));
EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(3, &url, &title));
EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(4, &url, &title));
}
// Test enabled "Recently closed" header with no foreign tabs.
TEST_F(RecentTabsSubMenuModelTest, RecentlyClosedTabsFromCurrentSession) {
DisableSync();
TabRestoreServiceFactory::GetInstance()->SetTestingFactory(
profile(),
base::BindRepeating(&RecentTabsSubMenuModelTest::GetTabRestoreService));
// Add 2 tabs and close them.
AddTab(browser(), GURL("http://foo/1"));
AddTab(browser(), GURL("http://foo/2"));
browser()->tab_strip_model()->CloseAllTabs();
TestRecentTabsSubMenuModel model(nullptr, browser());
// Expected menu:
// Menu index Menu items
// --------------------------------------
// 0 History
// 1 <separator>
// 2 Recently closed header
// 3 <tab for http://foo/2>
// 4 <tab for http://foo/1>
// 5 <separator>
// 6 No tabs from other Devices
int num_items = model.GetItemCount();
EXPECT_EQ(7, num_items);
EXPECT_TRUE(model.IsEnabledAt(0));
model.ActivatedAt(0);
EXPECT_TRUE(model.IsEnabledAt(1));
EXPECT_FALSE(model.IsEnabledAt(2));
EXPECT_TRUE(model.IsEnabledAt(3));
EXPECT_TRUE(model.IsEnabledAt(4));
model.ActivatedAt(3);
model.ActivatedAt(4);
EXPECT_FALSE(model.IsEnabledAt(6));
EXPECT_EQ(3, model.enable_count());
EXPECT_EQ(3, model.execute_count());
EXPECT_EQ(NULL, model.GetLabelFontListAt(0));
EXPECT_EQ(NULL, model.GetLabelFontListAt(1));
EXPECT_TRUE(model.GetLabelFontListAt(2) != nullptr);
EXPECT_EQ(NULL, model.GetLabelFontListAt(3));
EXPECT_EQ(NULL, model.GetLabelFontListAt(4));
EXPECT_EQ(NULL, model.GetLabelFontListAt(5));
EXPECT_EQ(NULL, model.GetLabelFontListAt(6));
std::string url;
base::string16 title;
EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(0, &url, &title));
EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(1, &url, &title));
EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(2, &url, &title));
EXPECT_TRUE(model.GetURLAndTitleForItemAtIndex(3, &url, &title));
EXPECT_TRUE(model.GetURLAndTitleForItemAtIndex(4, &url, &title));
EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(5, &url, &title));
EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(6, &url, &title));
}
// TODO(sail): enable this test when dynamic model is enabled in
// RecentTabsSubMenuModel.
#if defined(OS_MACOSX)
#define MAYBE_RecentlyClosedTabsAndWindowsFromLastSession \
DISABLED_RecentlyClosedTabsAndWindowsFromLastSession
#else
#define MAYBE_RecentlyClosedTabsAndWindowsFromLastSession \
RecentlyClosedTabsAndWindowsFromLastSession
#endif
TEST_F(RecentTabsSubMenuModelTest,
MAYBE_RecentlyClosedTabsAndWindowsFromLastSession) {
DisableSync();
TabRestoreServiceFactory::GetInstance()->SetTestingFactory(
profile(),
base::BindRepeating(&RecentTabsSubMenuModelTest::GetTabRestoreService));
// Add 2 tabs and close them.
AddTab(browser(), GURL("http://wnd/tab0"));
AddTab(browser(), GURL("http://wnd/tab1"));
browser()->tab_strip_model()->CloseAllTabs();
// Create a SessionService for the profile (profile owns the service) and add
// a window with a tab to this session.
SessionService* session_service = new SessionService(profile());
SessionServiceFactory::SetForTestProfile(profile(),
base::WrapUnique(session_service));
SessionID tab_id = SessionID::FromSerializedValue(1);
SessionID window_id = SessionID::FromSerializedValue(2);
session_service->SetWindowType(window_id,
Browser::TYPE_TABBED,
SessionService::TYPE_NORMAL);
session_service->SetTabWindow(window_id, tab_id);
session_service->SetTabIndexInWindow(window_id, tab_id, 0);
session_service->SetSelectedTabInWindow(window_id, 0);
session_service->UpdateTabNavigation(
window_id, tab_id,
sessions::SerializedNavigationEntryTestHelper::CreateNavigation(
"http://wnd1/tab0", "title"));
// Set this, otherwise previous session won't be loaded.
profile()->set_last_session_exited_cleanly(false);
// Move this session to the last so that TabRestoreService will load it as the
// last session.
SessionServiceFactory::GetForProfile(profile())->
MoveCurrentSessionToLastSession();
// Create a new TabRestoreService so that it'll load the recently closed tabs
// and windows afresh.
TabRestoreServiceFactory::GetInstance()->SetTestingFactory(
profile(),
base::BindRepeating(&RecentTabsSubMenuModelTest::GetTabRestoreService));
// Let the shutdown of previous TabRestoreService run.
content::RunAllTasksUntilIdle();
TestRecentTabsSubMenuModel model(nullptr, browser());
TestRecentTabsMenuModelDelegate delegate(&model);
EXPECT_FALSE(delegate.got_changes());
// Expected menu before tabs/windows from last session are loaded:
// Menu index Menu items
// ----------------------------------------------------------------
// 0 History
// 1 <separator>
// 2 Recently closed header
// 3 <separator>
// 4 No tabs from other Devices
int num_items = model.GetItemCount();
EXPECT_EQ(5, num_items);
EXPECT_TRUE(model.IsEnabledAt(0));
EXPECT_EQ(ui::MenuModel::TYPE_SEPARATOR, model.GetTypeAt(1));
EXPECT_FALSE(model.IsEnabledAt(2));
EXPECT_EQ(ui::MenuModel::TYPE_SEPARATOR, model.GetTypeAt(3));
EXPECT_FALSE(model.IsEnabledAt(4));
EXPECT_EQ(1, model.enable_count());
// Wait for tabs from last session to be loaded.
WaitForLoadFromLastSession();
// Expected menu after tabs/windows from last session are loaded:
// Menu index Menu items
// --------------------------------------------------------------
// 0 History
// 1 <separator>
// 2 Recently closed header
// 3 <window for the tab http://wnd1/tab0>
// 4 <tab for http://wnd0/tab1>
// 5 <tab for http://wnd0/tab0>
// 6 <separator>
// 7 No tabs from other Devices
EXPECT_TRUE(delegate.got_changes());
num_items = model.GetItemCount();
EXPECT_EQ(8, num_items);
EXPECT_TRUE(model.IsEnabledAt(0));
model.ActivatedAt(0);
EXPECT_TRUE(model.IsEnabledAt(1));
EXPECT_EQ(ui::MenuModel::TYPE_SEPARATOR, model.GetTypeAt(1));
EXPECT_FALSE(model.IsEnabledAt(2));
EXPECT_TRUE(model.IsEnabledAt(3));
EXPECT_TRUE(model.IsEnabledAt(4));
EXPECT_TRUE(model.IsEnabledAt(5));
model.ActivatedAt(3);
model.ActivatedAt(4);
model.ActivatedAt(5);
EXPECT_EQ(ui::MenuModel::TYPE_SEPARATOR, model.GetTypeAt(6));
EXPECT_FALSE(model.IsEnabledAt(7));
EXPECT_EQ(5, model.enable_count());
EXPECT_EQ(4, model.execute_count());
EXPECT_EQ(NULL, model.GetLabelFontListAt(0));
EXPECT_EQ(NULL, model.GetLabelFontListAt(1));
EXPECT_TRUE(model.GetLabelFontListAt(2) != nullptr);
EXPECT_EQ(NULL, model.GetLabelFontListAt(3));
EXPECT_EQ(NULL, model.GetLabelFontListAt(4));
EXPECT_EQ(NULL, model.GetLabelFontListAt(5));
EXPECT_EQ(NULL, model.GetLabelFontListAt(6));
EXPECT_EQ(NULL, model.GetLabelFontListAt(7));
std::string url;
base::string16 title;
EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(0, &url, &title));
EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(1, &url, &title));
EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(2, &url, &title));
EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(3, &url, &title));
EXPECT_TRUE(model.GetURLAndTitleForItemAtIndex(4, &url, &title));
EXPECT_TRUE(model.GetURLAndTitleForItemAtIndex(5, &url, &title));
EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(6, &url, &title));
EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(7, &url, &title));
}
// Test disabled "Recently closed" header 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, base::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, base::string16());
timestamp -= time_delta;
recent_tabs_builder.AddTabWithInfo(1, 1, timestamp, base::string16());
timestamp -= time_delta;
recent_tabs_builder.AddTabWithInfo(1, 1, timestamp, base::string16());
RegisterRecentTabs(&recent_tabs_builder);
// 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 History
// 1 <separator>
// 2 Recently closed header (disabled)
// 3 <separator>
// 4 <section header for 1st session>
// 5-7 <3 tabs of the only window of session 0>
// 8 <separator>
// 9 <section header for 2nd session>
// 10 <the only tab of window 0 of session 1>
// 11-12 <2 tabs of window 1 of session 2>
TestRecentTabsSubMenuModel model(nullptr, browser());
int num_items = model.GetItemCount();
EXPECT_EQ(13, num_items);
model.ActivatedAt(0);
EXPECT_TRUE(model.IsEnabledAt(0));
model.ActivatedAt(1);
EXPECT_TRUE(model.IsEnabledAt(1));
model.ActivatedAt(2);
EXPECT_FALSE(model.IsEnabledAt(2));
model.ActivatedAt(3);
EXPECT_TRUE(model.IsEnabledAt(3));
model.ActivatedAt(5);
EXPECT_TRUE(model.IsEnabledAt(5));
model.ActivatedAt(6);
EXPECT_TRUE(model.IsEnabledAt(6));
model.ActivatedAt(7);
EXPECT_TRUE(model.IsEnabledAt(7));
model.ActivatedAt(10);
EXPECT_TRUE(model.IsEnabledAt(10));
model.ActivatedAt(11);
EXPECT_TRUE(model.IsEnabledAt(11));
model.ActivatedAt(12);
EXPECT_TRUE(model.IsEnabledAt(12));
EXPECT_EQ(7, model.enable_count());
EXPECT_EQ(10, model.execute_count());
EXPECT_EQ(NULL, model.GetLabelFontListAt(0));
EXPECT_EQ(NULL, model.GetLabelFontListAt(1));
EXPECT_EQ(NULL, model.GetLabelFontListAt(2));
EXPECT_EQ(NULL, model.GetLabelFontListAt(3));
EXPECT_TRUE(model.GetLabelFontListAt(4) != nullptr);
EXPECT_EQ(NULL, model.GetLabelFontListAt(5));
EXPECT_EQ(NULL, model.GetLabelFontListAt(6));
EXPECT_EQ(NULL, model.GetLabelFontListAt(7));
EXPECT_EQ(NULL, model.GetLabelFontListAt(8));
EXPECT_TRUE(model.GetLabelFontListAt(9) != nullptr);
EXPECT_EQ(NULL, model.GetLabelFontListAt(10));
EXPECT_EQ(NULL, model.GetLabelFontListAt(11));
EXPECT_EQ(NULL, model.GetLabelFontListAt(12));
std::string url;
base::string16 title;
EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(0, &url, &title));
EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(1, &url, &title));
EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(2, &url, &title));
EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(3, &url, &title));
EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(4, &url, &title));
EXPECT_TRUE(model.GetURLAndTitleForItemAtIndex(5, &url, &title));
EXPECT_TRUE(model.GetURLAndTitleForItemAtIndex(6, &url, &title));
EXPECT_TRUE(model.GetURLAndTitleForItemAtIndex(7, &url, &title));
EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(8, &url, &title));
EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(9, &url, &title));
EXPECT_TRUE(model.GetURLAndTitleForItemAtIndex(10, &url, &title));
EXPECT_TRUE(model.GetURLAndTitleForItemAtIndex(11, &url, &title));
EXPECT_TRUE(model.GetURLAndTitleForItemAtIndex(12, &url, &title));
}
// Mac doesn't support the dynamic menu.
#if defined(OS_MACOSX)
#define MAYBE_OtherDevicesDynamicUpdate DISABLED_OtherDevicesDynamicUpdate
#else
#define MAYBE_OtherDevicesDynamicUpdate OtherDevicesDynamicUpdate
#endif
TEST_F(RecentTabsSubMenuModelTest, MAYBE_OtherDevicesDynamicUpdate) {
// Create menu with disabled synchronization.
DisableSync();
// Before creating menu fill foreign sessions.
base::Time update_timestamp =
base::Time::Now() - base::TimeDelta::FromMinutes(10);
RecentTabsBuilderTestHelper recent_tabs_builder;
// Create one session with one window and one tab.
recent_tabs_builder.AddSession();
recent_tabs_builder.AddWindow(0);
recent_tabs_builder.AddTabWithInfo(0, 0, update_timestamp, base::string16());
RegisterRecentTabs(&recent_tabs_builder);
// Verify that data is populated correctly in RecentTabsSubMenuModel.
// Expected menu:
// Menu index Menu items
// -----------------------------------------------------
// 0 History
// 1 <separator>
// 2 Recently closed header (disabled)
// 3 <separator>
// 4 No tabs from other Devices
TestRecentTabsSubMenuModel model(nullptr, browser());
EXPECT_EQ(5, model.GetItemCount());
model.ActivatedAt(4);
EXPECT_FALSE(model.IsEnabledAt(4));
EXPECT_EQ(0, model.enable_count());
EXPECT_EQ(1, model.execute_count());
EXPECT_EQ(nullptr, model.GetLabelFontListAt(4));
std::string url;
base::string16 title;
EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(4, &url, &title));
// Enable synchronization and notify menu that synchronization was enabled.
int previous_enable_count = model.enable_count();
int previous_execute_count = model.execute_count();
EnableSync();
// Verify that data is populated correctly in RecentTabsSubMenuModel.
// Expected menu:
// Menu index Menu items
// -----------------------------------------------------
// 0 History
// 1 <separator>
// 2 Recently closed header (disabled)
// 3 <separator>
// 4 <section header for 1st session>
// 5 <tab of the only window of session 0>
EXPECT_EQ(6, model.GetItemCount());
model.ActivatedAt(4);
EXPECT_FALSE(model.IsEnabledAt(4));
model.ActivatedAt(5);
EXPECT_TRUE(model.IsEnabledAt(5));
EXPECT_EQ(previous_enable_count + 1, model.enable_count());
EXPECT_EQ(previous_execute_count + 2, model.execute_count());
EXPECT_NE(nullptr, model.GetLabelFontListAt(4));
EXPECT_EQ(nullptr, model.GetLabelFontListAt(5));
EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(4, &url, &title));
EXPECT_TRUE(model.GetURLAndTitleForItemAtIndex(5, &url, &title));
// Make changes dynamically.
previous_enable_count = model.enable_count();
previous_execute_count = model.execute_count();
update_timestamp = base::Time::Now() - base::TimeDelta::FromMinutes(5);
// Add tab to the only window.
recent_tabs_builder.AddTabWithInfo(0, 0, update_timestamp, base::string16());
RegisterRecentTabs(&recent_tabs_builder);
// Verify that data is populated correctly in RecentTabsSubMenuModel.
// Expected menu:
// Menu index Menu items
// -----------------------------------------------------
// 0 History
// 1 <separator>
// 2 Recently closed header (disabled)
// 3 <separator>
// 4 <section header for 1st session>
// 5 <new added tab of the only window of session 0>
// 6 <tab of the only window of session 0>
EXPECT_EQ(7, model.GetItemCount());
model.ActivatedAt(4);
EXPECT_FALSE(model.IsEnabledAt(4));
model.ActivatedAt(5);
EXPECT_TRUE(model.IsEnabledAt(5));
model.ActivatedAt(6);
EXPECT_TRUE(model.IsEnabledAt(6));
EXPECT_EQ(previous_enable_count + 2, model.enable_count());
EXPECT_EQ(previous_execute_count + 3, model.execute_count());
EXPECT_NE(nullptr, model.GetLabelFontListAt(4));
EXPECT_EQ(nullptr, model.GetLabelFontListAt(5));
EXPECT_EQ(nullptr, model.GetLabelFontListAt(6));
EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(4, &url, &title));
EXPECT_TRUE(model.GetURLAndTitleForItemAtIndex(5, &url, &title));
EXPECT_TRUE(model.GetURLAndTitleForItemAtIndex(6, &url, &title));
}
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);
}
RegisterRecentTabs(&recent_tabs_builder);
// 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 History
// 1 <separator>
// 2 Recently closed header (disabled)
// 3 <separator>
// 4 <section header for 1st session>
// 5 <the only tab of the only window of session 3>
// 6 <separator>
// 7 <section header for 2nd session>
// 8 <the only tab of the only window of session 2>
// 9 <separator>
// 10 <section header for 3rd session>
// 11 <the only tab of the only window of session 1>
TestRecentTabsSubMenuModel model(nullptr, browser());
int num_items = model.GetItemCount();
EXPECT_EQ(12, num_items);
std::vector<base::string16> tab_titles =
recent_tabs_builder.GetTabTitlesSortedByRecency();
EXPECT_EQ(tab_titles[0], model.GetLabelAt(5));
EXPECT_EQ(tab_titles[1], model.GetLabelAt(8));
EXPECT_EQ(tab_titles[2], model.GetLabelAt(11));
}
TEST_F(RecentTabsSubMenuModelTest, MaxTabsPerSessionAndRecency) {
EnableSync();
// 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);
}
RegisterRecentTabs(&recent_tabs_builder);
// 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 History
// 1 <separator>
// 2 Recently closed header (disabled)
// 3 <separator>
// 4 <section header for session>
// 5-8 <4 most-recent tabs of session>
TestRecentTabsSubMenuModel model(nullptr, browser());
int num_items = model.GetItemCount();
EXPECT_EQ(9, num_items);
std::vector<base::string16> tab_titles =
recent_tabs_builder.GetTabTitlesSortedByRecency();
for (int i = 0; i < 4; ++i)
EXPECT_EQ(tab_titles[i], model.GetLabelAt(i + 5));
}
TEST_F(RecentTabsSubMenuModelTest, MaxWidth) {
EnableSync();
// 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);
RegisterRecentTabs(&recent_tabs_builder);
// Menu index Menu items
// ----------------------------------------------------------
// 0 History
// 1 <separator>
// 2 Recently closed header (disabled)
// 3 <separator>
// 4 <section header for 1st session>
// 5 <the only tab of the only window of session 1>
TestRecentTabsSubMenuModel model(nullptr, browser());
EXPECT_EQ(6, model.GetItemCount());
EXPECT_EQ(-1, model.GetMaxWidthForItemAtIndex(2));
EXPECT_NE(-1, model.GetMaxWidthForItemAtIndex(3));
EXPECT_NE(-1, model.GetMaxWidthForItemAtIndex(4));
EXPECT_NE(-1, model.GetMaxWidthForItemAtIndex(5));
}
TEST_F(RecentTabsSubMenuModelTest, MaxWidthNoDevices) {
DisableSync();
// Expected menu:
// Menu index Menu items
// --------------------------------------------
// 0 History
// 1 <separator>
// 2 Recently closed heaer (disabled)
// 3 <separator>
// 4 No tabs from other Devices
TestRecentTabsSubMenuModel model(nullptr, browser());
EXPECT_EQ(5, model.GetItemCount());
EXPECT_EQ(-1, model.GetMaxWidthForItemAtIndex(2));
EXPECT_NE(-1, model.GetMaxWidthForItemAtIndex(3));
EXPECT_EQ(-1, model.GetMaxWidthForItemAtIndex(4));
}