// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_mediator_test.h"
#import "base/containers/contains.h"
#import "base/test/ios/wait_util.h"
#import "components/saved_tab_groups/mock_tab_group_sync_service.h"
#import "components/unified_consent/pref_names.h"
#import "ios/chrome/browser/history/model/history_service_factory.h"
#import "ios/chrome/browser/main/model/browser_web_state_list_delegate.h"
#import "ios/chrome/browser/saved_tab_groups/model/tab_group_sync_service_factory.h"
#import "ios/chrome/browser/sessions/model/fake_tab_restore_service.h"
#import "ios/chrome/browser/sessions/model/ios_chrome_tab_restore_service_factory.h"
#import "ios/chrome/browser/sessions/model/session_restoration_service_factory.h"
#import "ios/chrome/browser/sessions/model/test_session_restoration_service.h"
#import "ios/chrome/browser/shared/coordinator/scene/scene_state.h"
#import "ios/chrome/browser/shared/model/application_context/application_context.h"
#import "ios/chrome/browser/shared/model/browser/browser_list.h"
#import "ios/chrome/browser/shared/model/browser/browser_list_factory.h"
#import "ios/chrome/browser/shared/model/browser/test/test_browser.h"
#import "ios/chrome/browser/shared/model/profile/test/test_profile_ios.h"
#import "ios/chrome/browser/shared/model/web_state_list/test/fake_web_state_list_delegate.h"
#import "ios/chrome/browser/shared/model/web_state_list/web_state_opener.h"
#import "ios/chrome/browser/signin/model/authentication_service.h"
#import "ios/chrome/browser/signin/model/authentication_service_factory.h"
#import "ios/chrome/browser/signin/model/fake_authentication_service_delegate.h"
#import "ios/chrome/browser/signin/model/fake_system_identity.h"
#import "ios/chrome/browser/signin/model/fake_system_identity_manager.h"
#import "ios/chrome/browser/snapshots/model/snapshot_browser_agent.h"
#import "ios/chrome/browser/sync/model/mock_sync_service_utils.h"
#import "ios/chrome/browser/sync/model/sync_service_factory.h"
#import "ios/chrome/browser/tabs/model/closing_web_state_observer_browser_agent.h"
#import "ios/chrome/browser/ui/tab_switcher/tab_grid/grid/base_grid_mediator.h"
#import "ios/chrome/browser/ui/tab_switcher/tab_grid/toolbars/test/fake_tab_grid_toolbars_mediator.h"
#import "ios/chrome/browser/ui/tab_switcher/test/fake_tab_collection_consumer.h"
#import "ios/chrome/browser/web_state_list/model/web_usage_enabler/web_usage_enabler_browser_agent.h"
#import "ios/web/public/test/fakes/fake_navigation_manager.h"
#import "ios/web/public/test/fakes/fake_web_frames_manager.h"
#import "ios/web/public/test/fakes/fake_web_state.h"
#import "third_party/ocmock/OCMock/OCMock.h"
using base::test::ios::WaitUntilConditionOrTimeout;
namespace {
// Timeout for waiting for the TabCollectionConsumer updates.
constexpr base::TimeDelta kWaitForTabCollectionConsumerUpdateTimeout =
base::Seconds(1);
// Name of the directory where snapshots are saved.
const char kIdentifier[] = "Identifier";
// List all ContentWorlds. Necessary because calling SetWebFramesManager(...)
// with a kAllContentWorlds is not enough with FakeWebState.
constexpr web::ContentWorld kContentWorlds[] = {
web::ContentWorld::kAllContentWorlds,
web::ContentWorld::kPageContentWorld,
web::ContentWorld::kIsolatedWorld,
};
// Returns a `MockTabGroupSyncService`.
std::unique_ptr<KeyedService> CreateMockTabGroupSyncService(
web::BrowserState* context) {
return std::make_unique<tab_groups::MockTabGroupSyncService>();
}
} // namespace
GridMediatorTestClass::GridMediatorTestClass() {
InitializeFeatureFlags();
}
GridMediatorTestClass::~GridMediatorTestClass() = default;
void GridMediatorTestClass::SetUp() {
PlatformTest::SetUp();
TestChromeBrowserState::Builder builder;
builder.AddTestingFactory(IOSChromeTabRestoreServiceFactory::GetInstance(),
FakeTabRestoreService::GetTestingFactory());
builder.AddTestingFactory(SyncServiceFactory::GetInstance(),
base::BindRepeating(&CreateMockSyncService));
builder.AddTestingFactory(AuthenticationServiceFactory::GetInstance(),
AuthenticationServiceFactory::GetDefaultFactory());
builder.AddTestingFactory(ios::HistoryServiceFactory::GetInstance(),
ios::HistoryServiceFactory::GetDefaultFactory());
builder.AddTestingFactory(SessionRestorationServiceFactory::GetInstance(),
TestSessionRestorationService::GetTestingFactory());
builder.AddTestingFactory(
tab_groups::TabGroupSyncServiceFactory::GetInstance(),
base::BindRepeating(&CreateMockTabGroupSyncService));
browser_state_ = std::move(builder).Build();
AuthenticationServiceFactory::CreateAndInitializeForBrowserState(
browser_state_.get(),
std::make_unique<FakeAuthenticationServiceDelegate>());
// Price Drops are only available to signed in MSBB users.
browser_state_->GetPrefs()->SetBoolean(
unified_consent::prefs::kUrlKeyedAnonymizedDataCollectionEnabled, true);
id<SystemIdentity> identity = [FakeSystemIdentity fakeIdentity1];
FakeSystemIdentityManager* system_identity_manager =
FakeSystemIdentityManager::FromSystemIdentityManager(
GetApplicationContext()->GetSystemIdentityManager());
system_identity_manager->AddIdentity(identity);
auth_service_ = static_cast<AuthenticationService*>(
AuthenticationServiceFactory::GetInstance()->GetForBrowserState(
browser_state_.get()));
auth_service_->SignIn(identity,
signin_metrics::AccessPoint::ACCESS_POINT_UNKNOWN);
scene_state_ = OCMClassMock([SceneState class]);
OCMStub([scene_state_ sceneSessionID]).andReturn(@(kIdentifier));
browser_ = std::make_unique<TestBrowser>(
browser_state_.get(), scene_state_,
std::make_unique<BrowserWebStateListDelegate>());
other_browser_ = std::make_unique<TestBrowser>(
browser_state_.get(), nil,
std::make_unique<BrowserWebStateListDelegate>());
WebUsageEnablerBrowserAgent::CreateForBrowser(browser_.get());
ClosingWebStateObserverBrowserAgent::CreateForBrowser(browser_.get());
SnapshotBrowserAgent::CreateForBrowser(browser_.get());
SnapshotBrowserAgent::FromBrowser(browser_.get())->SetSessionID(kIdentifier);
SessionRestorationServiceFactory::GetForBrowserState(browser_state_.get())
->SetSessionID(browser_.get(), kIdentifier);
browser_list_ = BrowserListFactory::GetForBrowserState(browser_state_.get());
browser_list_->AddBrowser(browser_.get());
browser_list_->AddBrowser(other_browser_.get());
// Insert some web states.
std::vector<std::string> urls{"https://foo/bar", "https://car/tar",
"https://hello/world"};
std::vector<web::WebStateID> identifiers;
for (int i = 0; i < 3; i++) {
auto web_state = CreateFakeWebStateWithURL(GURL(urls[i]));
web::WebStateID identifier = web_state.get()->GetUniqueIdentifier();
// Tab IDs should be unique.
ASSERT_FALSE(base::Contains(identifiers, identifier));
identifiers.push_back(identifier);
browser_->GetWebStateList()->InsertWebState(
std::move(web_state), WebStateList::InsertionParams::AtIndex(i));
}
original_identifiers_ = identifiers;
browser_->GetWebStateList()->ActivateWebStateAt(1);
original_selected_identifier_ =
browser_->GetWebStateList()->GetWebStateAt(1)->GetUniqueIdentifier();
consumer_ = [[FakeTabCollectionConsumer alloc] init];
fake_toolbars_mediator_ = [[FakeTabGridToolbarsMediator alloc] init];
}
std::unique_ptr<web::FakeWebState>
GridMediatorTestClass::CreateFakeWebStateWithURL(const GURL& url) {
auto web_state = std::make_unique<web::FakeWebState>();
auto navigation_manager = std::make_unique<web::FakeNavigationManager>();
navigation_manager->AddItem(url, ui::PAGE_TRANSITION_LINK);
navigation_manager->SetLastCommittedItem(
navigation_manager->GetItemAtIndex(0));
web_state->SetNavigationManager(std::move(navigation_manager));
for (const web::ContentWorld content_world : kContentWorlds) {
web_state->SetWebFramesManager(
content_world, std::make_unique<web::FakeWebFramesManager>());
}
web_state->SetBrowserState(browser_state_.get());
web_state->SetNavigationItemCount(1);
web_state->SetCurrentURL(url);
return web_state;
}
void GridMediatorTestClass::TearDown() {
PlatformTest::TearDown();
SessionRestorationServiceFactory::GetForBrowserState(browser_state_.get())
->Disconnect(browser_.get());
}
bool GridMediatorTestClass::WaitForConsumerUpdates(size_t expected_count) {
return WaitUntilConditionOrTimeout(
kWaitForTabCollectionConsumerUpdateTimeout, ^{
base::RunLoop().RunUntilIdle();
return expected_count == consumer_.items.size();
});
}
void GridMediatorTestClass::InitializeFeatureFlags() {}