blob: c76170f46a45db6653791a067900da614cc52cf8 [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 "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
#import "ios/chrome/browser/sessions/test_session_service.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/ui_util.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 ArrayBackedTabModel : TabModel {
@private
NSMutableArray* tabsForTesting_;
}
@end
@implementation ArrayBackedTabModel
- (instancetype)initWithSessionWindow:(SessionWindowIOS*)window
sessionService:(SessionServiceIOS*)service
browserState:(ios::ChromeBrowserState*)browserState {
if ((self = [super initWithSessionWindow:window
sessionService:service
browserState:browserState])) {
tabsForTesting_ = [[NSMutableArray alloc] initWithCapacity:5];
}
return self;
}
- (void)addTabForTesting:(Tab*)tab {
[tabsForTesting_ addObject:tab];
}
- (Tab*)tabAtIndex:(NSUInteger)index {
return (Tab*)[tabsForTesting_ objectAtIndex:index];
}
- (NSUInteger)indexOfTab:(Tab*)tab {
return [tabsForTesting_ indexOfObject:tab];
}
- (BOOL)isEmpty {
return [tabsForTesting_ count] == 0;
}
- (NSUInteger)count {
return [tabsForTesting_ count];
}
// Pass along fast enumeration calls to the tab array.
- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState*)state
objects:(id __unsafe_unretained*)stackbuf
count:(NSUInteger)len {
return [tabsForTesting_ countByEnumeratingWithState:state
objects:stackbuf
count:len];
}
- (void)closeTabAtIndex:(NSUInteger)index {
DCHECK(index < [tabsForTesting_ count]);
[self closeTab:[tabsForTesting_ objectAtIndex:index]];
}
@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, sessionService, and Tabs.
TestSessionService* test_service = [[TestSessionService alloc] init];
real_tab_model_ = [[ArrayBackedTabModel alloc]
initWithSessionWindow:nil
sessionService:test_service
browserState:chrome_browser_state_.get()];
id tabModel = [OCMockObject partialMockForObject:real_tab_model_];
id tab1 = [OCMockObject mockForClass:[Tab class]];
id tab2 = [OCMockObject mockForClass:[Tab class]];
// Populate the tab model.
[real_tab_model_ addTabForTesting:tab1];
[real_tab_model_ addTabForTesting:tab2];
// Stub methods for TabModel.
[[[tabModel stub] andDo:^(NSInvocation* invocation) {
// Return the raw pointer to the C++ object.
ios::ChromeBrowserState* browser_state = chrome_browser_state_.get();
[invocation setReturnValue:&browser_state];
}] browserState];
[[tabModel stub] addObserver:[OCMArg any]];
[[tabModel stub] removeObserver:[OCMArg any]];
// Stub methods for Tabs.
[[[tab1 stub] andReturn:@"Tab Title 1"] title];
[[[tab2 stub] andReturn:@"Tab Title 2"] title];
[[[tab1 stub] andReturn:nil] favicon];
[[[tab2 stub] andReturn:nil] favicon];
tabModel_ = tabModel;
tab1_ = tab1;
tab2_ = tab2;
controller_ =
[[TabStripController alloc] initWithTabModel:(TabModel*)tabModel_
style:TabStrip::kStyleDark];
// Force the view to load.
UIWindow* window = [[UIWindow alloc] initWithFrame:CGRectZero];
[window addSubview:[controller_ view]];
window_ = window;
}
void TearDown() override {
if (!IsIPadIdiom())
return;
[real_tab_model_ browserStateDestroyed];
}
web::TestWebThreadBundle thread_bundle_;
OCMockObject* tab1_;
OCMockObject* tab2_;
std::unique_ptr<TestChromeBrowserState> chrome_browser_state_;
OCMockObject* tabModel_;
TabStripController* controller_;
UIWindow* window_;
ArrayBackedTabModel* real_tab_model_;
};
TEST_F(TabStripControllerTest, LoadAndDisplay) {
if (!IsIPadIdiom())
return;
// If this doesn't crash, we're good.
ASSERT_OCMOCK_VERIFY(tabModel_);
ASSERT_OCMOCK_VERIFY(tab1_);
ASSERT_OCMOCK_VERIFY(tab2_);
// 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