blob: 8c6c329bcaf583ba58343e6ff100e7e743831c3e [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 <Foundation/Foundation.h>
#include <memory>
#include "base/strings/sys_string_conversions.h"
#include "ios/chrome/browser/browser_state/test_chrome_browser_state.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_model.h"
#import "ios/chrome/browser/ui/tabs/tab_strip_controller.h"
#import "ios/chrome/browser/ui/tabs/tab_strip_view.h"
#import "ios/chrome/browser/ui/tabs/tab_view.h"
#include "ios/chrome/browser/ui/util/ui_util.h"
#import "ios/chrome/browser/web_state_list/fake_web_state_list_delegate.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/web/public/navigation_item.h"
#import "ios/web/public/test/fakes/test_navigation_manager.h"
#import "ios/web/public/test/fakes/test_web_state.h"
#include "ios/web/public/test/test_web_thread_bundle.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"
#import "third_party/ocmock/gtest_support.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
@interface TabStripControllerTestTab : NSObject
- (instancetype)initWithWebState:(web::WebState*)webState
NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@end
@implementation TabStripControllerTestTab {
web::WebState* _webState;
}
- (instancetype)initWithWebState:(web::WebState*)webState {
if ((self = [super init])) {
DCHECK(webState);
_webState = webState;
}
return self;
}
- (web::WebState*)webState {
return _webState;
}
@end
@interface TabStripControllerTestTabModel : NSObject
@property(nonatomic, assign) ios::ChromeBrowserState* browserState;
@end
@implementation TabStripControllerTestTabModel {
FakeWebStateListDelegate _webStateListDelegate;
std::unique_ptr<WebStateList> _webStateList;
std::unique_ptr<web::NavigationItem> _visibleNavigationItem;
}
@synthesize browserState = _browserState;
- (instancetype)init {
if ((self = [super init])) {
_webStateList = std::make_unique<WebStateList>(&_webStateListDelegate);
_visibleNavigationItem = web::NavigationItem::Create();
}
return self;
}
- (void)browserStateDestroyed {
_webStateList->CloseAllWebStates(WebStateList::CLOSE_NO_FLAGS);
_webStateList.reset();
_browserState = nullptr;
}
- (TabStripControllerTestTab*)addTabForTestingWithTitle:(NSString*)title {
auto testWebState = std::make_unique<web::TestWebState>();
testWebState->SetTitle(base::SysNSStringToUTF16(title));
auto testNavigationManager = std::make_unique<web::TestNavigationManager>();
testNavigationManager->SetVisibleItem(_visibleNavigationItem.get());
testWebState->SetNavigationManager(std::move(testNavigationManager));
TabStripControllerTestTab* tab =
[[TabStripControllerTestTab alloc] initWithWebState:testWebState.get()];
LegacyTabHelper::CreateForWebStateForTesting(testWebState.get(),
static_cast<Tab*>(tab));
_webStateList->InsertWebState(0, std::move(testWebState),
WebStateList::INSERT_NO_FLAGS,
WebStateOpener());
return tab;
}
- (Tab*)currentTab {
web::WebState* activeWebState = _webStateList->GetActiveWebState();
return activeWebState ? LegacyTabHelper::GetTabForWebState(activeWebState)
: nil;
}
- (Tab*)tabAtIndex:(NSUInteger)index {
DCHECK(index < static_cast<NSUInteger>(INT_MAX));
DCHECK(static_cast<int>(index) < _webStateList->count());
return LegacyTabHelper::GetTabForWebState(
_webStateList->GetWebStateAt(static_cast<int>(index)));
}
- (NSUInteger)indexOfTab:(Tab*)tab {
const int index = _webStateList->GetIndexOfWebState(tab.webState);
return index == WebStateList::kInvalidIndex ? NSNotFound
: static_cast<NSUInteger>(index);
}
- (BOOL)isEmpty {
return _webStateList->empty();
}
- (NSUInteger)count {
return static_cast<NSUInteger>(_webStateList->count());
}
- (void)closeTabAtIndex:(NSUInteger)index {
DCHECK(index < static_cast<NSUInteger>(INT_MAX));
DCHECK(static_cast<int>(index) < _webStateList->count());
_webStateList->CloseWebStateAt(static_cast<int>(index),
WebStateList::CLOSE_NO_FLAGS);
}
- (void)addObserver:(id<TabModelObserver>)observer {
// Do nothing.
}
- (void)removeObserver:(id<TabModelObserver>)observer {
// Do nothing.
}
- (WebStateList*)webStateList {
return _webStateList.get();
}
@end
namespace {
class TabStripControllerTest : public PlatformTest {
protected:
void SetUp() override {
if (!IsIPadIdiom())
return;
// Need a ChromeBrowserState for the tab model.
TestChromeBrowserState::Builder test_cbs_builder;
chrome_browser_state_ = test_cbs_builder.Build();
// Setup mock TabModel.
tab_model_ = [[TabStripControllerTestTabModel alloc] init];
tab_model_.browserState = chrome_browser_state_.get();
// Populate the TabModel.
tab1_ = [tab_model_ addTabForTestingWithTitle:@"Tab Title 1"];
tab2_ = [tab_model_ addTabForTestingWithTitle:@"Tab Title 2"];
controller_ = [[TabStripController alloc]
initWithTabModel:static_cast<TabModel*>(tab_model_)
style:NORMAL
dispatcher:nil];
// Force the view to load.
UIWindow* window = [[UIWindow alloc] initWithFrame:CGRectZero];
[window addSubview:[controller_ view]];
window_ = window;
}
void TearDown() override {
if (!IsIPadIdiom())
return;
[tab_model_ browserStateDestroyed];
}
web::TestWebThreadBundle thread_bundle_;
std::unique_ptr<TestChromeBrowserState> chrome_browser_state_;
TabStripController* controller_;
UIWindow* window_;
TabStripControllerTestTabModel* tab_model_;
TabStripControllerTestTab* tab1_;
TabStripControllerTestTab* tab2_;
};
TEST_F(TabStripControllerTest, LoadAndDisplay) {
if (!IsIPadIdiom())
return;
// There should be two TabViews and one new tab button nested within the
// parent view (which contains exactly one scroll view).
EXPECT_EQ(3U,
[[[[[controller_ view] subviews] objectAtIndex:0] subviews] count]);
}
} // namespace