blob: 8a9c84b348dbef90869a7ee28a1aac00e1f14e1d [file] [log] [blame]
// Copyright 2019 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 "ios/chrome/browser/ui/translate/translate_infobar_mediator.h"
#include <memory>
#import "base/mac/foundation_util.h"
#include "base/strings/utf_string_conversions.h"
#include "components/translate/core/browser/mock_translate_infobar_delegate.h"
#import "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
#include "ios/chrome/browser/translate/chrome_ios_translate_client.h"
#import "ios/chrome/browser/translate/language_selection_handler.h"
#import "ios/chrome/browser/translate/translate_option_selection_handler.h"
#import "ios/chrome/browser/ui/popup_menu/public/popup_menu_consumer.h"
#import "ios/chrome/browser/ui/translate/cells/select_language_popup_menu_item.h"
#import "ios/chrome/browser/ui/translate/cells/translate_popup_menu_item.h"
#import "ios/chrome/browser/ui/translate/translate_notification_handler.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/test/fakes/crw_test_js_injection_receiver.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_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
using translate::testing::MockTranslateInfoBarDelegate;
using translate::testing::MockTranslateInfoBarDelegateFactory;
// A protocol used to mock a
// id<LanguageSelectionHandler,TranslateOptionSelectionHandler>.
@protocol TestSelectionHandlerProtocol <LanguageSelectionHandler,
TranslateOptionSelectionHandler>
@end
// Test class that conforms to PopupMenuConsumer and exposes the menu items.
@interface TestPopupMenuConsumer : NSObject <PopupMenuConsumer>
@property(nonatomic, strong)
NSMutableArray<TableViewItem<PopupMenuItem>*>* items;
@end
@implementation TestPopupMenuConsumer
@synthesize itemToHighlight;
- (void)setPopupMenuItems:
(NSArray<NSArray<TableViewItem<PopupMenuItem>*>*>*)items {
_items = [[NSMutableArray alloc] init];
for (NSArray* innerArray in items) {
[_items addObjectsFromArray:innerArray];
}
}
- (void)itemsHaveChanged:(NSArray<TableViewItem<PopupMenuItem>*>*)items {
EXPECT_TRUE(false) << "This method should not be called.";
}
@end
class TranslateInfobarMediatorTest : public PlatformTest {
protected:
TranslateInfobarMediatorTest()
: browser_state_(TestChromeBrowserState::Builder().Build()),
web_state_list_(
std::make_unique<WebStateList>(&web_state_list_delegate_)),
delegate_factory_("fr", "en"),
selection_handler_([OCMockObject
niceMockForProtocol:@protocol(TestSelectionHandlerProtocol)]),
notification_handler_([OCMockObject
niceMockForProtocol:@protocol(TranslateNotificationHandler)]),
mediator_([[TranslateInfobarMediator alloc]
initWithSelectionHandler:selection_handler_
notificationHandler:notification_handler_]) {
CreateTranslateClient();
}
WebStateList* web_state_list() { return web_state_list_.get(); }
id selection_handler() { return selection_handler_; }
id notification_handler() { return notification_handler_; }
TranslateInfobarMediator* mediator() { return mediator_; }
void CreateTranslateClient() {
auto web_state = std::make_unique<web::TestWebState>();
// Set up browser state.
web_state->SetBrowserState(browser_state_.get());
// Set up navigation manager.
std::unique_ptr<web::TestNavigationManager> navigation_manager =
std::make_unique<web::TestNavigationManager>();
navigation_manager->SetBrowserState(browser_state_.get());
web_state->SetNavigationManager(std::move(navigation_manager));
// Set up JS injection receiver.
CRWTestJSInjectionReceiver* injectionReceiver =
[[CRWTestJSInjectionReceiver alloc] init];
web_state->SetJSInjectionReceiver(injectionReceiver);
// Create ChromeIOSTranslateClient.
ChromeIOSTranslateClient::CreateForWebState(web_state.get());
int effective_index = web_state_list_->InsertWebState(
0, std::move(web_state), WebStateList::INSERT_NO_FLAGS,
WebStateOpener());
web_state_list_->ActivateWebStateAt(effective_index);
}
ChromeIOSTranslateClient* GetTranslateClient() {
return ChromeIOSTranslateClient::FromWebState(
web_state_list_->GetActiveWebState());
}
MockTranslateInfoBarDelegate* GetDelegate() {
return delegate_factory_.GetMockTranslateInfoBarDelegate();
}
private:
web::TestWebThreadBundle web_thread_bundle_;
std::unique_ptr<TestChromeBrowserState> browser_state_;
FakeWebStateListDelegate web_state_list_delegate_;
std::unique_ptr<WebStateList> web_state_list_;
MockTranslateInfoBarDelegateFactory delegate_factory_;
id selection_handler_;
id notification_handler_;
TranslateInfobarMediator* mediator_;
DISALLOW_COPY_AND_ASSIGN(TranslateInfobarMediatorTest);
};
// Tests that the mediator installs UI handlers on existing
// ChromeIOSTranslateClient instances as well as new ones that become available.
TEST_F(TranslateInfobarMediatorTest, InstallHandlers) {
ChromeIOSTranslateClient* translate_client = GetTranslateClient();
// Make sure the handlers are not set.
EXPECT_EQ(nil, translate_client->language_selection_handler());
EXPECT_EQ(nil, translate_client->translate_option_selection_handler());
EXPECT_EQ(nil, translate_client->translate_notification_handler());
TranslateInfobarMediator* translate_infobar_mediator = mediator();
translate_infobar_mediator.webStateList = web_state_list();
EXPECT_EQ(selection_handler(),
translate_client->language_selection_handler());
EXPECT_EQ(selection_handler(),
translate_client->translate_option_selection_handler());
EXPECT_EQ(notification_handler(),
translate_client->translate_notification_handler());
CreateTranslateClient();
ChromeIOSTranslateClient* new_translate_client = GetTranslateClient();
EXPECT_NE(new_translate_client, translate_client);
EXPECT_EQ(selection_handler(),
new_translate_client->language_selection_handler());
EXPECT_EQ(selection_handler(),
new_translate_client->translate_option_selection_handler());
EXPECT_EQ(notification_handler(),
new_translate_client->translate_notification_handler());
}
// Tests that the mediator sets the expected menu items for the translate
// options popup menu on its consumer.
TEST_F(TranslateInfobarMediatorTest, TranslateOptionMenuItems) {
// Set up what TranslateInfoBarDelegate should return.
EXPECT_CALL(*GetDelegate(), original_language_name())
.WillRepeatedly(testing::Return(base::UTF8ToUTF16("French")));
EXPECT_CALL(*GetDelegate(), ShouldAlwaysTranslate())
.WillOnce(testing::Return(true));
TranslateInfobarMediator* translate_infobar_mediator = mediator();
translate_infobar_mediator.type =
TranslatePopupMenuTypeTranslateOptionSelection;
translate_infobar_mediator.infobarDelegate = GetDelegate();
TestPopupMenuConsumer* consumer = [[TestPopupMenuConsumer alloc] init];
translate_infobar_mediator.consumer = consumer;
ASSERT_EQ(5U, consumer.items.count);
TranslatePopupMenuItem* firstItem =
base::mac::ObjCCastStrict<TranslatePopupMenuItem>(consumer.items[0]);
EXPECT_EQ(PopupMenuActionChangeTargetLanguage, firstItem.actionIdentifier);
EXPECT_FALSE(firstItem.selected);
TranslatePopupMenuItem* secondItem =
base::mac::ObjCCastStrict<TranslatePopupMenuItem>(consumer.items[1]);
EXPECT_EQ(PopupMenuActionAlwaysTranslateSourceLanguage,
secondItem.actionIdentifier);
EXPECT_TRUE(secondItem.selected);
TranslatePopupMenuItem* thirdItem =
base::mac::ObjCCastStrict<TranslatePopupMenuItem>(consumer.items[2]);
EXPECT_EQ(PopupMenuActionNeverTranslateSourceLanguage,
thirdItem.actionIdentifier);
EXPECT_FALSE(thirdItem.selected);
TranslatePopupMenuItem* fourthItem =
base::mac::ObjCCastStrict<TranslatePopupMenuItem>(consumer.items[3]);
EXPECT_EQ(PopupMenuActionNeverTranslateSite, fourthItem.actionIdentifier);
EXPECT_FALSE(fourthItem.selected);
TranslatePopupMenuItem* fifthItem =
base::mac::ObjCCastStrict<TranslatePopupMenuItem>(consumer.items[4]);
EXPECT_EQ(PopupMenuActionChangeSourceLanguage, fifthItem.actionIdentifier);
EXPECT_FALSE(fifthItem.selected);
}
// Tests that the mediator sets the expected menu items for the language
// selection popup menu on its consumer.
TEST_F(TranslateInfobarMediatorTest, LanguageSelectionMenuItems) {
// Set up what TranslateInfoBarDelegate should return.
EXPECT_CALL(*GetDelegate(), num_languages())
.WillRepeatedly(testing::Return(3ul));
EXPECT_CALL(*GetDelegate(), language_code_at(0))
.WillOnce(testing::Return("en"));
EXPECT_CALL(*GetDelegate(), language_name_at(0))
.WillOnce(testing::Return(base::UTF8ToUTF16("English")));
EXPECT_CALL(*GetDelegate(), language_code_at(2))
.WillOnce(testing::Return("fr"));
EXPECT_CALL(*GetDelegate(), language_name_at(2))
.WillOnce(testing::Return(base::UTF8ToUTF16("French")));
TranslateInfobarMediator* translate_infobar_mediator = mediator();
translate_infobar_mediator.type = TranslatePopupMenuTypeLanguageSelection;
translate_infobar_mediator.infobarDelegate = GetDelegate();
translate_infobar_mediator.unavailableLanguageIndex = 1;
TestPopupMenuConsumer* consumer = [[TestPopupMenuConsumer alloc] init];
translate_infobar_mediator.consumer = consumer;
ASSERT_EQ(2U, consumer.items.count);
SelectLanguagePopupMenuItem* firstItem =
base::mac::ObjCCastStrict<SelectLanguagePopupMenuItem>(consumer.items[0]);
EXPECT_EQ(PopupMenuActionSelectLanguage, firstItem.actionIdentifier);
EXPECT_FALSE(firstItem.selected);
EXPECT_TRUE([firstItem.languageCode isEqualToString:@"en"]);
EXPECT_TRUE([firstItem.title isEqualToString:@"English"]);
SelectLanguagePopupMenuItem* secondItem =
base::mac::ObjCCastStrict<SelectLanguagePopupMenuItem>(consumer.items[1]);
EXPECT_EQ(PopupMenuActionSelectLanguage, secondItem.actionIdentifier);
EXPECT_FALSE(secondItem.selected);
EXPECT_TRUE([secondItem.languageCode isEqualToString:@"fr"]);
EXPECT_TRUE([secondItem.title isEqualToString:@"French"]);
}