1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #import <Cocoa/Cocoa.h>
7 #import "base/mac/scoped_nsobject.h"
8 #import "base/strings/string_util.h"
9 #include "base/strings/utf_string_conversions.h"
10 #import "chrome/app/chrome_command_ids.h" // For translate menu command ids.
11 #include "chrome/browser/infobars/infobar_service.h"
12 #import "chrome/browser/translate/translate_infobar_delegate.h"
13 #import "chrome/browser/translate/translate_tab_helper.h"
14 #include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
15 #import "chrome/browser/ui/cocoa/infobars/before_translate_infobar_controller.h"
16 #import "chrome/browser/ui/cocoa/infobars/infobar_cocoa.h"
17 #import "chrome/browser/ui/cocoa/infobars/translate_infobar_base.h"
18 #include "chrome/test/base/testing_profile.h"
19 #include "components/translate/core/browser/translate_language_list.h"
20 #import "content/public/browser/web_contents.h"
21 #include "ipc/ipc_message.h"
22 #import "testing/gmock/include/gmock/gmock.h"
23 #import "testing/gtest/include/gtest/gtest.h"
24 #import "testing/platform_test.h"
26 using content::WebContents;
30 // All states the translate toolbar can assume.
31 TranslateTabHelper::TranslateStep kTranslateToolbarStates[] = {
32 TranslateTabHelper::BEFORE_TRANSLATE,
33 TranslateTabHelper::AFTER_TRANSLATE,
34 TranslateTabHelper::TRANSLATING,
35 TranslateTabHelper::TRANSLATE_ERROR
38 class MockTranslateInfoBarDelegate : public TranslateInfoBarDelegate {
40 MockTranslateInfoBarDelegate(content::WebContents* web_contents,
41 TranslateTabHelper::TranslateStep step,
42 TranslateErrors::Type error,
44 : TranslateInfoBarDelegate(web_contents, step, NULL, "en", "es", error,
48 MOCK_METHOD0(Translate, void());
49 MOCK_METHOD0(RevertTranslation, void());
51 MOCK_METHOD0(TranslationDeclined, void());
53 virtual bool IsTranslatableLanguageByPrefs() OVERRIDE { return true; }
54 MOCK_METHOD0(ToggleTranslatableLanguageByPrefs, void());
55 virtual bool IsSiteBlacklisted() OVERRIDE { return false; }
56 MOCK_METHOD0(ToggleSiteBlacklist, void());
57 virtual bool ShouldAlwaysTranslate() OVERRIDE { return false; }
58 MOCK_METHOD0(ToggleAlwaysTranslate, void());
63 class TranslationInfoBarTest : public CocoaProfileTest {
65 TranslationInfoBarTest() : CocoaProfileTest(), infobar_(NULL) {
68 // Each test gets a single Mock translate delegate for the lifetime of
70 virtual void SetUp() OVERRIDE {
71 TranslateLanguageList::DisableUpdate();
72 CocoaProfileTest::SetUp();
74 WebContents::Create(WebContents::CreateParams(profile())));
75 InfoBarService::CreateForWebContents(web_contents_.get());
78 virtual void TearDown() OVERRIDE {
80 infobar_->CloseSoon();
83 CocoaProfileTest::TearDown();
86 void CreateInfoBar(TranslateTabHelper::TranslateStep type) {
87 TranslateErrors::Type error = TranslateErrors::NONE;
88 if (type == TranslateTabHelper::TRANSLATE_ERROR)
89 error = TranslateErrors::NETWORK;
91 Profile::FromBrowserContext(web_contents_->GetBrowserContext());
92 [[infobar_controller_ view] removeFromSuperview];
94 scoped_ptr<TranslateInfoBarDelegate> delegate(
95 new MockTranslateInfoBarDelegate(web_contents_.get(), type, error,
96 profile->GetPrefs()));
97 scoped_ptr<InfoBar> infobar(
98 TranslateInfoBarDelegate::CreateInfoBar(delegate.Pass()));
100 infobar_->CloseSoon();
101 infobar_ = static_cast<InfoBarCocoa*>(infobar.release());
102 infobar_->SetOwner(InfoBarService::FromWebContents(web_contents_.get()));
104 infobar_controller_.reset([static_cast<TranslateInfoBarControllerBase*>(
105 infobar_->controller()) retain]);
107 // We need to set the window to be wide so that the options button
108 // doesn't overlap the other buttons.
109 [test_window() setContentSize:NSMakeSize(2000, 500)];
110 [[infobar_controller_ view] setFrame:NSMakeRect(0, 0, 2000, 500)];
111 [[test_window() contentView] addSubview:[infobar_controller_ view]];
114 MockTranslateInfoBarDelegate* infobar_delegate() const {
115 return static_cast<MockTranslateInfoBarDelegate*>(infobar_->delegate());
118 scoped_ptr<WebContents> web_contents_;
119 InfoBarCocoa* infobar_; // weak, deletes itself
120 base::scoped_nsobject<TranslateInfoBarControllerBase> infobar_controller_;
123 // Check that we can instantiate a Translate Infobar correctly.
124 TEST_F(TranslationInfoBarTest, Instantiate) {
125 CreateInfoBar(TranslateTabHelper::BEFORE_TRANSLATE);
126 ASSERT_TRUE(infobar_controller_.get());
129 // Check that clicking the Translate button calls Translate().
130 TEST_F(TranslationInfoBarTest, TranslateCalledOnButtonPress) {
131 CreateInfoBar(TranslateTabHelper::BEFORE_TRANSLATE);
133 EXPECT_CALL(*infobar_delegate(), Translate()).Times(1);
134 [infobar_controller_ ok:nil];
137 // Check that clicking the "Retry" button calls Translate() when we're
138 // in the error mode - http://crbug.com/41315 .
139 TEST_F(TranslationInfoBarTest, TranslateCalledInErrorMode) {
140 CreateInfoBar(TranslateTabHelper::TRANSLATE_ERROR);
142 EXPECT_CALL(*infobar_delegate(), Translate()).Times(1);
144 [infobar_controller_ ok:nil];
147 // Check that clicking the "Show Original button calls RevertTranslation().
148 TEST_F(TranslationInfoBarTest, RevertCalledOnButtonPress) {
149 CreateInfoBar(TranslateTabHelper::BEFORE_TRANSLATE);
151 EXPECT_CALL(*infobar_delegate(), RevertTranslation()).Times(1);
152 [infobar_controller_ showOriginal:nil];
155 // Check that items in the options menu are hooked up correctly.
156 TEST_F(TranslationInfoBarTest, OptionsMenuItemsHookedUp) {
157 CreateInfoBar(TranslateTabHelper::BEFORE_TRANSLATE);
158 EXPECT_CALL(*infobar_delegate(), Translate())
161 [infobar_controller_ rebuildOptionsMenu:NO];
162 NSMenu* optionsMenu = [infobar_controller_ optionsMenu];
163 NSArray* optionsMenuItems = [optionsMenu itemArray];
165 EXPECT_EQ(7U, [optionsMenuItems count]);
167 // First item is the options menu button's title, so there's no need to test
168 // that the target on that is setup correctly.
169 for (NSUInteger i = 1; i < [optionsMenuItems count]; ++i) {
170 NSMenuItem* item = [optionsMenuItems objectAtIndex:i];
171 if (![item isSeparatorItem])
172 EXPECT_EQ([item target], infobar_controller_.get());
174 NSMenuItem* alwaysTranslateLanguateItem = [optionsMenuItems objectAtIndex:1];
175 NSMenuItem* neverTranslateLanguateItem = [optionsMenuItems objectAtIndex:2];
176 NSMenuItem* neverTranslateSiteItem = [optionsMenuItems objectAtIndex:3];
178 NSMenuItem* reportBadLanguageItem = [optionsMenuItems objectAtIndex:5];
179 NSMenuItem* aboutTranslateItem = [optionsMenuItems objectAtIndex:6];
182 EXPECT_CALL(*infobar_delegate(), ToggleAlwaysTranslate())
184 [infobar_controller_ optionsMenuChanged:alwaysTranslateLanguateItem];
188 EXPECT_CALL(*infobar_delegate(), ToggleTranslatableLanguageByPrefs())
190 [infobar_controller_ optionsMenuChanged:neverTranslateLanguateItem];
194 EXPECT_CALL(*infobar_delegate(), ToggleSiteBlacklist())
196 [infobar_controller_ optionsMenuChanged:neverTranslateSiteItem];
200 // Can't mock these effectively, so just check that the tag is set
202 EXPECT_EQ(IDC_TRANSLATE_REPORT_BAD_LANGUAGE_DETECTION,
203 [reportBadLanguageItem tag]);
204 EXPECT_EQ(IDC_TRANSLATE_OPTIONS_ABOUT, [aboutTranslateItem tag]);
208 // Check that selecting a new item from the "Source Language" popup in "before
209 // translate" mode doesn't trigger a translation or change state.
210 // http://crbug.com/36666
211 TEST_F(TranslationInfoBarTest, Bug36666) {
212 CreateInfoBar(TranslateTabHelper::BEFORE_TRANSLATE);
213 EXPECT_CALL(*infobar_delegate(), Translate())
216 int arbitrary_index = 2;
217 [infobar_controller_ sourceLanguageModified:arbitrary_index];
218 EXPECT_CALL(*infobar_delegate(), Translate())
222 // Check that the infobar lays itself out correctly when instantiated in
223 // each of the states.
224 // http://crbug.com/36895
225 TEST_F(TranslationInfoBarTest, Bug36895) {
226 for (size_t i = 0; i < arraysize(kTranslateToolbarStates); ++i) {
227 CreateInfoBar(kTranslateToolbarStates[i]);
228 EXPECT_CALL(*infobar_delegate(), Translate())
231 [infobar_controller_ verifyLayout]) << "Layout wrong, for state #" << i;
235 // Verify that the infobar shows the "Always translate this language" button
236 // after doing 3 translations.
237 TEST_F(TranslationInfoBarTest, TriggerShowAlwaysTranslateButton) {
238 scoped_ptr<TranslatePrefs> translate_prefs(
239 TranslateTabHelper::CreateTranslatePrefs(profile()->GetPrefs()));
240 translate_prefs->ResetTranslationAcceptedCount("en");
241 for (int i = 0; i < 4; ++i) {
242 translate_prefs->IncrementTranslationAcceptedCount("en");
244 CreateInfoBar(TranslateTabHelper::BEFORE_TRANSLATE);
245 BeforeTranslateInfobarController* controller =
246 (BeforeTranslateInfobarController*)infobar_controller_.get();
247 EXPECT_TRUE([[controller alwaysTranslateButton] superview] != nil);
248 EXPECT_TRUE([[controller neverTranslateButton] superview] == nil);
251 // Verify that the infobar shows the "Never translate this language" button
252 // after denying 3 translations.
253 TEST_F(TranslationInfoBarTest, TriggerShowNeverTranslateButton) {
254 scoped_ptr<TranslatePrefs> translate_prefs(
255 TranslateTabHelper::CreateTranslatePrefs(profile()->GetPrefs()));
256 translate_prefs->ResetTranslationDeniedCount("en");
257 for (int i = 0; i < 4; ++i) {
258 translate_prefs->IncrementTranslationDeniedCount("en");
260 CreateInfoBar(TranslateTabHelper::BEFORE_TRANSLATE);
261 BeforeTranslateInfobarController* controller =
262 (BeforeTranslateInfobarController*)infobar_controller_.get();
263 EXPECT_TRUE([[controller alwaysTranslateButton] superview] == nil);
264 EXPECT_TRUE([[controller neverTranslateButton] superview] != nil);