blob: 6e08b6efad37b62589d0df34c6ca80d176a31bd3 [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.
#import <objc/runtime.h>
#include "base/feature_list.h"
#include "base/files/file_path.h"
#include "base/run_loop.h"
#include "base/strings/sys_string_conversions.h"
#include "base/test/scoped_feature_list.h"
#include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
#include "ios/chrome/browser/browser_state/test_chrome_browser_state_manager.h"
#include "ios/chrome/browser/chrome_url_constants.h"
#include "ios/chrome/browser/infobars/infobar_manager_impl.h"
#import "ios/chrome/browser/ntp/new_tab_page_tab_helper.h"
#import "ios/chrome/browser/ntp/new_tab_page_tab_helper_delegate.h"
#include "ios/chrome/browser/sessions/ios_chrome_session_tab_helper.h"
#import "ios/chrome/browser/sessions/session_ios.h"
#import "ios/chrome/browser/sessions/session_window_ios.h"
#import "ios/chrome/browser/sessions/test_session_service.h"
#import "ios/chrome/browser/tabs/legacy_tab_helper.h"
#import "ios/chrome/browser/tabs/tab.h"
#import "ios/chrome/browser/tabs/tab_helper_util.h"
#import "ios/chrome/browser/tabs/tab_model.h"
#import "ios/chrome/browser/web/chrome_web_client.h"
#import "ios/chrome/browser/web_state_list/web_state_list.h"
#import "ios/chrome/browser/web_state_list/web_state_opener.h"
#import "ios/chrome/browser/web_state_list/web_usage_enabler/web_state_list_web_usage_enabler.h"
#import "ios/chrome/browser/web_state_list/web_usage_enabler/web_state_list_web_usage_enabler_factory.h"
#import "ios/chrome/test/fakes/fake_web_state_list_observing_delegate.h"
#include "ios/chrome/test/ios_chrome_scoped_testing_chrome_browser_state_manager.h"
#include "ios/web/common/features.h"
#import "ios/web/navigation/navigation_manager_impl.h"
#import "ios/web/public/navigation_manager.h"
#include "ios/web/public/referrer.h"
#import "ios/web/public/session/crw_session_storage.h"
#import "ios/web/public/session/serializable_user_data_manager.h"
#include "ios/web/public/test/scoped_testing_web_client.h"
#include "ios/web/public/test/test_web_thread_bundle.h"
#include "ios/web/public/thread/web_thread.h"
#import "ios/web/web_state/web_state_impl.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/gtest_mac.h"
#include "testing/platform_test.h"
#import "third_party/ocmock/OCMock/OCMock.h"
#include "third_party/ocmock/gtest_support.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace {
const char kURL1[] = "https://www.some.url.com";
const char kURL2[] = "https://www.some.url2.com";
// TabModelTest is parameterized on this enum to test both
// LegacyNavigationManager and WKBasedNavigationManager.
enum class NavigationManagerChoice {
LEGACY,
WK_BASED,
};
class TabModelTest
: public PlatformTest,
public ::testing::WithParamInterface<NavigationManagerChoice> {
public:
TabModelTest()
: scoped_browser_state_manager_(
std::make_unique<TestChromeBrowserStateManager>(base::FilePath())),
web_client_(std::make_unique<ChromeWebClient>()) {
DCHECK_CURRENTLY_ON(web::WebThread::UI);
if (GetParam() == NavigationManagerChoice::LEGACY) {
scoped_feature_list_.InitAndDisableFeature(
web::features::kSlimNavigationManager);
} else {
scoped_feature_list_.InitAndEnableFeature(
web::features::kSlimNavigationManager);
}
TestChromeBrowserState::Builder test_cbs_builder;
chrome_browser_state_ = test_cbs_builder.Build();
// Web usage is disabled during these tests.
web_usage_enabler_ =
WebStateListWebUsageEnablerFactory::GetInstance()->GetForBrowserState(
chrome_browser_state_.get());
web_usage_enabler_->SetWebUsageEnabled(false);
session_window_ = [[SessionWindowIOS alloc] init];
// Create tab model with just a dummy session service so the async state
// saving doesn't trigger unless actually wanted.
SetTabModel(CreateTabModel([[TestSessionService alloc] init], nil));
}
~TabModelTest() override = default;
void TearDown() override {
SetTabModel(nil);
PlatformTest::TearDown();
}
void SetTabModel(TabModel* tab_model) {
if (tab_model_) {
web_usage_enabler_->SetWebStateList(nullptr);
@autoreleasepool {
[tab_model_ browserStateDestroyed];
tab_model_ = nil;
}
}
tab_model_ = tab_model;
web_usage_enabler_->SetWebStateList(tab_model_.webStateList);
}
TabModel* CreateTabModel(SessionServiceIOS* session_service,
SessionWindowIOS* session_window) {
TabModel* tab_model([[TabModel alloc]
initWithSessionService:session_service
browserState:chrome_browser_state_.get()]);
[tab_model restoreSessionWindow:session_window forInitialRestore:YES];
[tab_model setPrimary:YES];
return tab_model;
}
protected:
// Creates a session window with entries named "restored window 1",
// "restored window 2" and "restored window 3" and the second entry
// marked as selected.
SessionWindowIOS* CreateSessionWindow() {
NSMutableArray<CRWSessionStorage*>* sessions = [NSMutableArray array];
for (int i = 0; i < 3; i++) {
CRWSessionStorage* session_storage = [[CRWSessionStorage alloc] init];
session_storage.lastCommittedItemIndex = -1;
[sessions addObject:session_storage];
}
return [[SessionWindowIOS alloc] initWithSessions:sessions selectedIndex:1];
}
web::TestWebThreadBundle thread_bundle_;
IOSChromeScopedTestingChromeBrowserStateManager scoped_browser_state_manager_;
web::ScopedTestingWebClient web_client_;
SessionWindowIOS* session_window_;
std::unique_ptr<TestChromeBrowserState> chrome_browser_state_;
WebStateListWebUsageEnabler* web_usage_enabler_;
TabModel* tab_model_;
base::test::ScopedFeatureList scoped_feature_list_;
};
TEST_P(TabModelTest, IsEmpty) {
EXPECT_EQ([tab_model_ count], 0U);
EXPECT_TRUE([tab_model_ isEmpty]);
[tab_model_ insertWebStateWithURL:GURL(kURL1)
referrer:web::Referrer()
transition:ui::PAGE_TRANSITION_TYPED
opener:nil
openedByDOM:NO
atIndex:0
inBackground:NO];
ASSERT_EQ(1U, [tab_model_ count]);
EXPECT_FALSE([tab_model_ isEmpty]);
}
TEST_P(TabModelTest, InsertUrlSingle) {
web::WebState* web_state =
[tab_model_ insertWebStateWithURL:GURL(kURL1)
referrer:web::Referrer()
transition:ui::PAGE_TRANSITION_TYPED
opener:nil
openedByDOM:NO
atIndex:0
inBackground:NO];
ASSERT_EQ(1U, [tab_model_ count]);
EXPECT_EQ(web_state, tab_model_.webStateList->GetWebStateAt(0));
}
TEST_P(TabModelTest, InsertUrlMultiple) {
web::WebState* web_state0 =
[tab_model_ insertWebStateWithURL:GURL(kURL1)
referrer:web::Referrer()
transition:ui::PAGE_TRANSITION_TYPED
opener:nil
openedByDOM:NO
atIndex:0
inBackground:NO];
web::WebState* web_state1 =
[tab_model_ insertWebStateWithURL:GURL(kURL1)
referrer:web::Referrer()
transition:ui::PAGE_TRANSITION_TYPED
opener:nil
openedByDOM:NO
atIndex:0
inBackground:NO];
web::WebState* web_state2 =
[tab_model_ insertWebStateWithURL:GURL(kURL1)
referrer:web::Referrer()
transition:ui::PAGE_TRANSITION_TYPED
opener:nil
openedByDOM:NO
atIndex:1
inBackground:NO];
ASSERT_EQ(3U, [tab_model_ count]);
EXPECT_EQ(web_state1, tab_model_.webStateList->GetWebStateAt(0));
EXPECT_EQ(web_state2, tab_model_.webStateList->GetWebStateAt(1));
EXPECT_EQ(web_state0, tab_model_.webStateList->GetWebStateAt(2));
}
TEST_P(TabModelTest, AppendUrlSingle) {
web::WebState* web_state =
[tab_model_ insertWebStateWithURL:GURL(kURL1)
referrer:web::Referrer()
transition:ui::PAGE_TRANSITION_TYPED
opener:nil
openedByDOM:NO
atIndex:[tab_model_ count]
inBackground:NO];
ASSERT_EQ(1U, [tab_model_ count]);
EXPECT_EQ(web_state, tab_model_.webStateList->GetWebStateAt(0));
}
TEST_P(TabModelTest, AppendUrlMultiple) {
web::WebState* web_state0 =
[tab_model_ insertWebStateWithURL:GURL(kURL1)
referrer:web::Referrer()
transition:ui::PAGE_TRANSITION_TYPED
opener:nil
openedByDOM:NO
atIndex:[tab_model_ count]
inBackground:NO];
web::WebState* web_state1 =
[tab_model_ insertWebStateWithURL:GURL(kURL1)
referrer:web::Referrer()
transition:ui::PAGE_TRANSITION_TYPED
opener:nil
openedByDOM:NO
atIndex:[tab_model_ count]
inBackground:NO];
web::WebState* web_state2 =
[tab_model_ insertWebStateWithURL:GURL(kURL1)
referrer:web::Referrer()
transition:ui::PAGE_TRANSITION_TYPED
opener:nil
openedByDOM:NO
atIndex:[tab_model_ count]
inBackground:NO];
ASSERT_EQ(3U, [tab_model_ count]);
EXPECT_EQ(web_state0, tab_model_.webStateList->GetWebStateAt(0));
EXPECT_EQ(web_state1, tab_model_.webStateList->GetWebStateAt(1));
EXPECT_EQ(web_state2, tab_model_.webStateList->GetWebStateAt(2));
}
TEST_P(TabModelTest, CloseTabAtIndexBeginning) {
[tab_model_ insertWebStateWithURL:GURL(kURL1)
referrer:web::Referrer()
transition:ui::PAGE_TRANSITION_TYPED
opener:nil
openedByDOM:NO
atIndex:[tab_model_ count]
inBackground:NO];
web::WebState* web_state1 =
[tab_model_ insertWebStateWithURL:GURL(kURL1)
referrer:web::Referrer()
transition:ui::PAGE_TRANSITION_TYPED
opener:nil
openedByDOM:NO
atIndex:[tab_model_ count]
inBackground:NO];
web::WebState* web_state2 =
[tab_model_ insertWebStateWithURL:GURL(kURL1)
referrer:web::Referrer()
transition:ui::PAGE_TRANSITION_TYPED
opener:nil
openedByDOM:NO
atIndex:[tab_model_ count]
inBackground:NO];
[tab_model_ closeTabAtIndex:0];
ASSERT_EQ(2U, [tab_model_ count]);
EXPECT_EQ(web_state1, tab_model_.webStateList->GetWebStateAt(0));
EXPECT_EQ(web_state2, tab_model_.webStateList->GetWebStateAt(1));
}
TEST_P(TabModelTest, CloseTabAtIndexMiddle) {
web::WebState* web_state0 =
[tab_model_ insertWebStateWithURL:GURL(kURL1)
referrer:web::Referrer()
transition:ui::PAGE_TRANSITION_TYPED
opener:nil
openedByDOM:NO
atIndex:[tab_model_ count]
inBackground:NO];
[tab_model_ insertWebStateWithURL:GURL(kURL1)
referrer:web::Referrer()
transition:ui::PAGE_TRANSITION_TYPED
opener:nil
openedByDOM:NO
atIndex:[tab_model_ count]
inBackground:NO];
web::WebState* web_state2 =
[tab_model_ insertWebStateWithURL:GURL(kURL1)
referrer:web::Referrer()
transition:ui::PAGE_TRANSITION_TYPED
opener:nil
openedByDOM:NO
atIndex:[tab_model_ count]
inBackground:NO];
[tab_model_ closeTabAtIndex:1];
ASSERT_EQ(2U, [tab_model_ count]);
EXPECT_EQ(web_state0, tab_model_.webStateList->GetWebStateAt(0));
EXPECT_EQ(web_state2, tab_model_.webStateList->GetWebStateAt(1));
}
TEST_P(TabModelTest, CloseTabAtIndexLast) {
web::WebState* web_state0 =
[tab_model_ insertWebStateWithURL:GURL(kURL1)
referrer:web::Referrer()
transition:ui::PAGE_TRANSITION_TYPED
opener:nil
openedByDOM:NO
atIndex:[tab_model_ count]
inBackground:NO];
web::WebState* web_state1 =
[tab_model_ insertWebStateWithURL:GURL(kURL1)
referrer:web::Referrer()
transition:ui::PAGE_TRANSITION_TYPED
opener:nil
openedByDOM:NO
atIndex:[tab_model_ count]
inBackground:NO];
[tab_model_ insertWebStateWithURL:GURL(kURL1)
referrer:web::Referrer()
transition:ui::PAGE_TRANSITION_TYPED
opener:nil
openedByDOM:NO
atIndex:[tab_model_ count]
inBackground:NO];
[tab_model_ closeTabAtIndex:2];
ASSERT_EQ(2U, [tab_model_ count]);
EXPECT_EQ(web_state0, tab_model_.webStateList->GetWebStateAt(0));
EXPECT_EQ(web_state1, tab_model_.webStateList->GetWebStateAt(1));
}
TEST_P(TabModelTest, CloseTabAtIndexOnlyOne) {
[tab_model_ insertWebStateWithURL:GURL(kURL1)
referrer:web::Referrer()
transition:ui::PAGE_TRANSITION_TYPED
opener:nil
openedByDOM:NO
atIndex:[tab_model_ count]
inBackground:NO];
[tab_model_ closeTabAtIndex:0];
EXPECT_EQ(0U, [tab_model_ count]);
}
TEST_P(TabModelTest, RestoreSessionOnNTPTest) {
// TODO(crbug.com/888674): migrate this to EG test so it can be tested with
// WKBasedNavigationManager.
if (web_client_.Get()->IsSlimNavigationManagerEnabled())
return;
web::WebState* web_state =
[tab_model_ insertWebStateWithURL:GURL(kChromeUINewTabURL)
referrer:web::Referrer()
transition:ui::PAGE_TRANSITION_TYPED
opener:nil
openedByDOM:NO
atIndex:0
inBackground:NO];
web::WebStateImpl* web_state_impl =
static_cast<web::WebStateImpl*>(web_state);
// Create NTPTabHelper to ensure VisibleURL is set to kChromeUINewTabURL.
id delegate = OCMProtocolMock(@protocol(NewTabPageTabHelperDelegate));
NewTabPageTabHelper::CreateForWebState(web_state, delegate);
web_state_impl->GetNavigationManagerImpl().CommitPendingItem();
SessionWindowIOS* window(CreateSessionWindow());
[tab_model_ restoreSessionWindow:window forInitialRestore:NO];
ASSERT_EQ(3U, [tab_model_ count]);
EXPECT_NSEQ([tab_model_ tabAtIndex:1], [tab_model_ currentTab]);
EXPECT_NE(web_state, tab_model_.webStateList->GetWebStateAt(0));
EXPECT_NE(web_state, tab_model_.webStateList->GetWebStateAt(1));
EXPECT_NE(web_state, tab_model_.webStateList->GetWebStateAt(2));
}
TEST_P(TabModelTest, RestoreSessionOn2NtpTest) {
// TODO(crbug.com/888674): migrate this to EG test so it can be tested with
// WKBasedNavigationManager.
if (web_client_.Get()->IsSlimNavigationManagerEnabled())
return;
web::WebState* web_state0 =
[tab_model_ insertWebStateWithURL:GURL(kChromeUINewTabURL)
referrer:web::Referrer()
transition:ui::PAGE_TRANSITION_TYPED
opener:nil
openedByDOM:NO
atIndex:0
inBackground:NO];
web::WebStateImpl* web_state_impl =
static_cast<web::WebStateImpl*>(web_state0);
web_state_impl->GetNavigationManagerImpl().CommitPendingItem();
web::WebState* web_state1 =
[tab_model_ insertWebStateWithURL:GURL(kChromeUINewTabURL)
referrer:web::Referrer()
transition:ui::PAGE_TRANSITION_TYPED
opener:nil
openedByDOM:NO
atIndex:1
inBackground:NO];
web_state_impl = static_cast<web::WebStateImpl*>(web_state1);
web_state_impl->GetNavigationManagerImpl().CommitPendingItem();
SessionWindowIOS* window(CreateSessionWindow());
[tab_model_ restoreSessionWindow:window forInitialRestore:NO];
ASSERT_EQ(5U, [tab_model_ count]);
EXPECT_NSEQ([tab_model_ tabAtIndex:3], [tab_model_ currentTab]);
EXPECT_EQ(web_state0, tab_model_.webStateList->GetWebStateAt(0));
EXPECT_EQ(web_state1, tab_model_.webStateList->GetWebStateAt(1));
EXPECT_NE(web_state0, tab_model_.webStateList->GetWebStateAt(2));
EXPECT_NE(web_state0, tab_model_.webStateList->GetWebStateAt(3));
EXPECT_NE(web_state0, tab_model_.webStateList->GetWebStateAt(4));
EXPECT_NE(web_state1, tab_model_.webStateList->GetWebStateAt(2));
EXPECT_NE(web_state1, tab_model_.webStateList->GetWebStateAt(3));
EXPECT_NE(web_state1, tab_model_.webStateList->GetWebStateAt(4));
}
TEST_P(TabModelTest, RestoreSessionOnAnyTest) {
// TODO(crbug.com/888674): migrate this to EG test so it can be tested with
// WKBasedNavigationManager.
if (web_client_.Get()->IsSlimNavigationManagerEnabled())
return;
web::WebState* web_state =
[tab_model_ insertWebStateWithURL:GURL(kURL1)
referrer:web::Referrer()
transition:ui::PAGE_TRANSITION_TYPED
opener:nil
openedByDOM:NO
atIndex:0
inBackground:NO];
web::WebStateImpl* web_state_impl =
static_cast<web::WebStateImpl*>(web_state);
web_state_impl->GetNavigationManagerImpl().CommitPendingItem();
SessionWindowIOS* window(CreateSessionWindow());
[tab_model_ restoreSessionWindow:window forInitialRestore:NO];
ASSERT_EQ(4U, [tab_model_ count]);
EXPECT_NSEQ([tab_model_ tabAtIndex:2], [tab_model_ currentTab]);
EXPECT_EQ(web_state, tab_model_.webStateList->GetWebStateAt(0));
EXPECT_NE(web_state, tab_model_.webStateList->GetWebStateAt(1));
EXPECT_NE(web_state, tab_model_.webStateList->GetWebStateAt(2));
EXPECT_NE(web_state, tab_model_.webStateList->GetWebStateAt(3));
}
TEST_P(TabModelTest, CloseAllTabs) {
[tab_model_ insertWebStateWithURL:GURL(kURL1)
referrer:web::Referrer()
transition:ui::PAGE_TRANSITION_TYPED
opener:nil
openedByDOM:NO
atIndex:[tab_model_ count]
inBackground:NO];
[tab_model_ insertWebStateWithURL:GURL(kURL2)
referrer:web::Referrer()
transition:ui::PAGE_TRANSITION_TYPED
opener:nil
openedByDOM:NO
atIndex:[tab_model_ count]
inBackground:NO];
[tab_model_ insertWebStateWithURL:GURL(kURL1)
referrer:web::Referrer()
transition:ui::PAGE_TRANSITION_TYPED
opener:nil
openedByDOM:NO
atIndex:[tab_model_ count]
inBackground:NO];
[tab_model_ closeAllTabs];
EXPECT_EQ(0U, [tab_model_ count]);
}
TEST_P(TabModelTest, CloseAllTabsWithNoTabs) {
[tab_model_ closeAllTabs];
EXPECT_EQ(0U, [tab_model_ count]);
}
TEST_P(TabModelTest, InsertWithSessionController) {
EXPECT_EQ([tab_model_ count], 0U);
EXPECT_TRUE([tab_model_ isEmpty]);
web::WebState* new_web_state =
[tab_model_ insertWebStateWithURL:GURL(kURL1)
referrer:web::Referrer()
transition:ui::PAGE_TRANSITION_TYPED
opener:nil
openedByDOM:NO
atIndex:[tab_model_ count]
inBackground:NO];
EXPECT_EQ([tab_model_ count], 1U);
EXPECT_EQ(new_web_state, tab_model_.webStateList->GetWebStateAt(0));
tab_model_.webStateList->ActivateWebStateAt(0);
Tab* current_tab = [tab_model_ currentTab];
EXPECT_TRUE(current_tab);
}
TEST_P(TabModelTest, AddWithOrderController) {
// Create a few tabs with the controller at the front.
web::WebState* parent =
[tab_model_ insertWebStateWithURL:GURL(kURL1)
referrer:web::Referrer()
transition:ui::PAGE_TRANSITION_TYPED
opener:nil
openedByDOM:NO
atIndex:[tab_model_ count]
inBackground:NO];
[tab_model_ insertWebStateWithURL:GURL(kURL1)
referrer:web::Referrer()
transition:ui::PAGE_TRANSITION_TYPED
opener:nil
openedByDOM:NO
atIndex:[tab_model_ count]
inBackground:NO];
[tab_model_ insertWebStateWithURL:GURL(kURL1)
referrer:web::Referrer()
transition:ui::PAGE_TRANSITION_TYPED
opener:nil
openedByDOM:NO
atIndex:[tab_model_ count]
inBackground:NO];
// Add a new tab, it should be added behind the parent.
web::WebState* child = [tab_model_
insertWebStateWithURL:GURL(kURL1)
referrer:web::Referrer()
transition:ui::PAGE_TRANSITION_LINK
opener:parent
openedByDOM:NO
atIndex:TabModelConstants::kTabPositionAutomatically
inBackground:NO];
EXPECT_EQ(tab_model_.webStateList->GetIndexOfWebState(parent), 0);
EXPECT_EQ(tab_model_.webStateList->GetIndexOfWebState(child), 1);
// Add another new tab without a parent, should go at the end.
web::WebState* web_state = [tab_model_
insertWebStateWithURL:GURL(kURL1)
referrer:web::Referrer()
transition:ui::PAGE_TRANSITION_LINK
opener:nil
openedByDOM:NO
atIndex:TabModelConstants::kTabPositionAutomatically
inBackground:NO];
EXPECT_EQ(tab_model_.webStateList->GetIndexOfWebState(web_state),
static_cast<int>([tab_model_ count]) - 1);
// Same for a tab that's not opened via a LINK transition.
web::WebState* web_state2 =
[tab_model_ insertWebStateWithURL:GURL(kURL1)
referrer:web::Referrer()
transition:ui::PAGE_TRANSITION_TYPED
opener:nil
openedByDOM:NO
atIndex:[tab_model_ count]
inBackground:NO];
EXPECT_EQ(tab_model_.webStateList->GetIndexOfWebState(web_state2),
static_cast<int>([tab_model_ count]) - 1);
// Add a tab in the background. It should appear behind the opening tab.
web::WebState* web_state3 = [tab_model_
insertWebStateWithURL:GURL(kURL1)
referrer:web::Referrer()
transition:ui::PAGE_TRANSITION_LINK
opener:web_state
openedByDOM:NO
atIndex:TabModelConstants::kTabPositionAutomatically
inBackground:NO];
EXPECT_EQ(tab_model_.webStateList->GetIndexOfWebState(web_state3),
tab_model_.webStateList->GetIndexOfWebState(web_state) + 1);
// Add another background tab behind the one we just opened.
web::WebState* web_state4 = [tab_model_
insertWebStateWithURL:GURL(kURL1)
referrer:web::Referrer()
transition:ui::PAGE_TRANSITION_LINK
opener:web_state3
openedByDOM:NO
atIndex:TabModelConstants::kTabPositionAutomatically
inBackground:NO];
EXPECT_EQ(tab_model_.webStateList->GetIndexOfWebState(web_state4),
tab_model_.webStateList->GetIndexOfWebState(web_state3) + 1);
}
TEST_P(TabModelTest, MoveTabs) {
web::WebState* web_state0 =
[tab_model_ insertWebStateWithURL:GURL(kURL1)
referrer:web::Referrer()
transition:ui::PAGE_TRANSITION_TYPED
opener:nil
openedByDOM:NO
atIndex:[tab_model_ count]
inBackground:NO];
web::WebState* web_state1 =
[tab_model_ insertWebStateWithURL:GURL(kURL1)
referrer:web::Referrer()
transition:ui::PAGE_TRANSITION_TYPED
opener:nil
openedByDOM:NO
atIndex:[tab_model_ count]
inBackground:NO];
web::WebState* web_state2 =
[tab_model_ insertWebStateWithURL:GURL(kURL1)
referrer:web::Referrer()
transition:ui::PAGE_TRANSITION_TYPED
opener:nil
openedByDOM:NO
atIndex:[tab_model_ count]
inBackground:NO];
// Basic sanity checks before moving on.
ASSERT_EQ(3U, [tab_model_ count]);
EXPECT_EQ(web_state0, tab_model_.webStateList->GetWebStateAt(0));
EXPECT_EQ(web_state1, tab_model_.webStateList->GetWebStateAt(1));
EXPECT_EQ(web_state2, tab_model_.webStateList->GetWebStateAt(2));
// Check that observer methods are called.
FakeWebStateListObservingDelegate* web_state_list_observer =
[[FakeWebStateListObservingDelegate alloc] init];
[web_state_list_observer observeWebStateList:tab_model_.webStateList];
// Move a tab from index 1 to index 0 (move tab left by one).
[web_state_list_observer setDidMoveWebStateWasCalled:NO];
[tab_model_ moveTab:[tab_model_ tabAtIndex:1] toIndex:0];
ASSERT_EQ(3U, [tab_model_ count]);
EXPECT_EQ(web_state1, tab_model_.webStateList->GetWebStateAt(0));
EXPECT_EQ(web_state0, tab_model_.webStateList->GetWebStateAt(1));
EXPECT_EQ(web_state2, tab_model_.webStateList->GetWebStateAt(2));
EXPECT_TRUE([web_state_list_observer didMoveWebStateWasCalled]);
// Move a tab from index 1 to index 2 (move tab right by one).
[web_state_list_observer setDidMoveWebStateWasCalled:NO];
[tab_model_ moveTab:[tab_model_ tabAtIndex:1] toIndex:2];
ASSERT_EQ(3U, [tab_model_ count]);
EXPECT_EQ(web_state1, tab_model_.webStateList->GetWebStateAt(0));
EXPECT_EQ(web_state2, tab_model_.webStateList->GetWebStateAt(1));
EXPECT_EQ(web_state0, tab_model_.webStateList->GetWebStateAt(2));
EXPECT_TRUE([web_state_list_observer didMoveWebStateWasCalled]);
// Move a tab from index 0 to index 2 (move tab right by more than one).
[web_state_list_observer setDidMoveWebStateWasCalled:NO];
[tab_model_ moveTab:[tab_model_ tabAtIndex:0] toIndex:2];
ASSERT_EQ(3U, [tab_model_ count]);
EXPECT_EQ(web_state2, tab_model_.webStateList->GetWebStateAt(0));
EXPECT_EQ(web_state0, tab_model_.webStateList->GetWebStateAt(1));
EXPECT_EQ(web_state1, tab_model_.webStateList->GetWebStateAt(2));
EXPECT_TRUE([web_state_list_observer didMoveWebStateWasCalled]);
// Move a tab from index 2 to index 0 (move tab left by more than one).
[web_state_list_observer setDidMoveWebStateWasCalled:NO];
[tab_model_ moveTab:[tab_model_ tabAtIndex:2] toIndex:0];
ASSERT_EQ(3U, [tab_model_ count]);
EXPECT_EQ(web_state1, tab_model_.webStateList->GetWebStateAt(0));
EXPECT_EQ(web_state2, tab_model_.webStateList->GetWebStateAt(1));
EXPECT_EQ(web_state0, tab_model_.webStateList->GetWebStateAt(2));
EXPECT_TRUE([web_state_list_observer didMoveWebStateWasCalled]);
// Move a tab from index 2 to index 2 (move tab to the same index).
[web_state_list_observer setDidMoveWebStateWasCalled:NO];
[tab_model_ moveTab:[tab_model_ tabAtIndex:2] toIndex:2];
ASSERT_EQ(3U, [tab_model_ count]);
EXPECT_EQ(web_state1, tab_model_.webStateList->GetWebStateAt(0));
EXPECT_EQ(web_state2, tab_model_.webStateList->GetWebStateAt(1));
EXPECT_EQ(web_state0, tab_model_.webStateList->GetWebStateAt(2));
EXPECT_FALSE([web_state_list_observer didMoveWebStateWasCalled]);
// TabModel asserts that there are no observer when it is deallocated,
// so remove the observer before the end of the method.
[web_state_list_observer stopObservingWebStateList:tab_model_.webStateList];
}
TEST_P(TabModelTest, TabCreatedOnInsertion) {
std::unique_ptr<web::WebState> web_state = web::WebState::Create(
web::WebState::CreateParams(chrome_browser_state_.get()));
EXPECT_NSEQ(nil, LegacyTabHelper::GetTabForWebState(web_state.get()));
web::WebState* web_state_ptr = web_state.get();
[tab_model_ webStateList]->InsertWebState(0, std::move(web_state),
WebStateList::INSERT_FORCE_INDEX,
WebStateOpener());
EXPECT_NSNE(nil, LegacyTabHelper::GetTabForWebState(web_state_ptr));
}
TEST_P(TabModelTest, DISABLED_PersistSelectionChange) {
NSString* stashPath =
base::SysUTF8ToNSString(chrome_browser_state_->GetStatePath().value());
// Reset the TabModel with a custom SessionServiceIOS (to control whether
// data is saved to disk).
TestSessionService* test_session_service = [[TestSessionService alloc] init];
SetTabModel(CreateTabModel(test_session_service, nil));
[tab_model_ insertWebStateWithURL:GURL(kURL1)
referrer:web::Referrer()
transition:ui::PAGE_TRANSITION_TYPED
opener:nil
openedByDOM:NO
atIndex:tab_model_.webStateList->count()
inBackground:NO];
[tab_model_ insertWebStateWithURL:GURL(kURL1)
referrer:web::Referrer()
transition:ui::PAGE_TRANSITION_TYPED
opener:tab_model_.webStateList->GetWebStateAt(0)
openedByDOM:NO
atIndex:[tab_model_ count]
inBackground:NO];
[tab_model_ insertWebStateWithURL:GURL(kURL1)
referrer:web::Referrer()
transition:ui::PAGE_TRANSITION_TYPED
opener:tab_model_.webStateList->GetWebStateAt(0)
openedByDOM:NO
atIndex:0
inBackground:NO];
ASSERT_EQ(3U, [tab_model_ count]);
[tab_model_ setCurrentTab:[tab_model_ tabAtIndex:1]];
// Force state to flush to disk on the main thread so it can be immediately
// tested below.
[test_session_service setPerformIO:YES];
[tab_model_ saveSessionImmediately:YES];
[test_session_service setPerformIO:NO];
NSString* state_path = base::SysUTF8ToNSString(
chrome_browser_state_->GetStatePath().AsUTF8Unsafe());
SessionIOS* session =
[test_session_service loadSessionFromDirectory:state_path];
ASSERT_EQ(1u, session.sessionWindows.count);
SessionWindowIOS* session_window = session.sessionWindows[0];
// Create tab model from saved session.
SetTabModel(CreateTabModel(test_session_service, session_window));
ASSERT_EQ(3u, [tab_model_ count]);
EXPECT_EQ([tab_model_ tabAtIndex:1], [tab_model_ currentTab]);
// Clean up.
EXPECT_TRUE([[NSFileManager defaultManager] removeItemAtPath:stashPath
error:nullptr]);
}
INSTANTIATE_TEST_SUITE_P(ProgrammaticTabModelTest,
TabModelTest,
::testing::Values(NavigationManagerChoice::LEGACY,
NavigationManagerChoice::WK_BASED));
} // anonymous namespace