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. 4 5 #import <Cocoa/Cocoa.h> 6 7 #import "base/memory/scoped_nsobject.h" 8 #import "base/string_util.h" 9 #include "base/utf_string_conversions.h" 10 #import "chrome/app/chrome_command_ids.h" // For translate menu command ids. 11 #import "chrome/browser/translate/translate_infobar_delegate.h" 12 #import "chrome/browser/ui/cocoa/browser_test_helper.h" 13 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h" 14 #import "chrome/browser/ui/cocoa/infobars/infobar.h" 15 #import "chrome/browser/ui/cocoa/translate/translate_infobar_base.h" 16 #import "chrome/browser/ui/cocoa/translate/before_translate_infobar_controller.h" 17 #import "content/browser/site_instance.h" 18 #import "content/browser/tab_contents/tab_contents.h" 19 #import "testing/gmock/include/gmock/gmock.h" 20 #import "testing/gtest/include/gtest/gtest.h" 21 #import "testing/platform_test.h" 22 23 namespace { 24 25 // All states the translate toolbar can assume. 26 TranslateInfoBarDelegate::Type kTranslateToolbarStates[] = { 27 TranslateInfoBarDelegate::BEFORE_TRANSLATE, 28 TranslateInfoBarDelegate::AFTER_TRANSLATE, 29 TranslateInfoBarDelegate::TRANSLATING, 30 TranslateInfoBarDelegate::TRANSLATION_ERROR 31 }; 32 33 class MockTranslateInfoBarDelegate : public TranslateInfoBarDelegate { 34 public: 35 MockTranslateInfoBarDelegate(TranslateInfoBarDelegate::Type type, 36 TranslateErrors::Type error, 37 TabContents* contents) 38 : TranslateInfoBarDelegate(type, error, contents, "en", "es"){ 39 // Start out in the "Before Translate" state. 40 type_ = type; 41 42 } 43 44 virtual string16 GetDisplayNameForLocale(const std::string& language_code) { 45 return ASCIIToUTF16("Foo"); 46 } 47 48 virtual bool IsLanguageBlacklisted() { 49 return false; 50 } 51 52 virtual bool IsSiteBlacklisted() { 53 return false; 54 } 55 56 virtual bool ShouldAlwaysTranslate() { 57 return false; 58 } 59 60 MOCK_METHOD0(Translate, void()); 61 MOCK_METHOD0(RevertTranslation, void()); 62 MOCK_METHOD0(TranslationDeclined, void()); 63 MOCK_METHOD0(ToggleLanguageBlacklist, void()); 64 MOCK_METHOD0(ToggleSiteBlacklist, void()); 65 MOCK_METHOD0(ToggleAlwaysTranslate, void()); 66 }; 67 68 class TranslationInfoBarTest : public CocoaTest { 69 public: 70 BrowserTestHelper browser_helper_; 71 scoped_ptr<TabContents> tab_contents; 72 scoped_ptr<MockTranslateInfoBarDelegate> infobar_delegate; 73 scoped_nsobject<TranslateInfoBarControllerBase> infobar_controller; 74 75 public: 76 // Each test gets a single Mock translate delegate for the lifetime of 77 // the test. 78 virtual void SetUp() { 79 CocoaTest::SetUp(); 80 tab_contents.reset( 81 new TabContents(browser_helper_.profile(), 82 NULL, 83 MSG_ROUTING_NONE, 84 NULL, 85 NULL)); 86 CreateInfoBar(); 87 } 88 89 void CreateInfoBar() { 90 CreateInfoBar(TranslateInfoBarDelegate::BEFORE_TRANSLATE); 91 } 92 93 void CreateInfoBar(TranslateInfoBarDelegate::Type type) { 94 TranslateErrors::Type error = TranslateErrors::NONE; 95 if (type == TranslateInfoBarDelegate::TRANSLATION_ERROR) 96 error = TranslateErrors::NETWORK; 97 infobar_delegate.reset( 98 new MockTranslateInfoBarDelegate(type, error, tab_contents.get())); 99 [[infobar_controller view] removeFromSuperview]; 100 scoped_ptr<InfoBar> infobar( 101 static_cast<InfoBarDelegate*>(infobar_delegate.get())->CreateInfoBar()); 102 infobar_controller.reset( 103 reinterpret_cast<TranslateInfoBarControllerBase*>( 104 infobar->controller())); 105 // We need to set the window to be wide so that the options button 106 // doesn't overlap the other buttons. 107 [test_window() setContentSize:NSMakeSize(2000, 500)]; 108 [[infobar_controller view] setFrame:NSMakeRect(0, 0, 2000, 500)]; 109 [[test_window() contentView] addSubview:[infobar_controller view]]; 110 } 111 }; 112 113 // Check that we can instantiate a Translate Infobar correctly. 114 TEST_F(TranslationInfoBarTest, Instantiate) { 115 CreateInfoBar(); 116 ASSERT_TRUE(infobar_controller.get()); 117 } 118 119 // Check that clicking the Translate button calls Translate(). 120 TEST_F(TranslationInfoBarTest, TranslateCalledOnButtonPress) { 121 CreateInfoBar(); 122 123 EXPECT_CALL(*infobar_delegate, Translate()).Times(1); 124 [infobar_controller ok:nil]; 125 } 126 127 // Check that clicking the "Retry" button calls Translate() when we're 128 // in the error mode - http://crbug.com/41315 . 129 TEST_F(TranslationInfoBarTest, TranslateCalledInErrorMode) { 130 CreateInfoBar(TranslateInfoBarDelegate::TRANSLATION_ERROR); 131 132 EXPECT_CALL(*infobar_delegate, Translate()).Times(1); 133 134 [infobar_controller ok:nil]; 135 } 136 137 // Check that clicking the "Show Original button calls RevertTranslation(). 138 TEST_F(TranslationInfoBarTest, RevertCalledOnButtonPress) { 139 CreateInfoBar(); 140 141 EXPECT_CALL(*infobar_delegate, RevertTranslation()).Times(1); 142 [infobar_controller showOriginal:nil]; 143 } 144 145 // Check that items in the options menu are hooked up correctly. 146 TEST_F(TranslationInfoBarTest, OptionsMenuItemsHookedUp) { 147 EXPECT_CALL(*infobar_delegate, Translate()) 148 .Times(0); 149 150 [infobar_controller rebuildOptionsMenu:NO]; 151 NSMenu* optionsMenu = [infobar_controller optionsMenu]; 152 NSArray* optionsMenuItems = [optionsMenu itemArray]; 153 154 EXPECT_EQ(7U, [optionsMenuItems count]); 155 156 // First item is the options menu button's title, so there's no need to test 157 // that the target on that is setup correctly. 158 for (NSUInteger i = 1; i < [optionsMenuItems count]; ++i) { 159 NSMenuItem* item = [optionsMenuItems objectAtIndex:i]; 160 if (![item isSeparatorItem]) 161 EXPECT_EQ([item target], infobar_controller.get()); 162 } 163 NSMenuItem* alwaysTranslateLanguateItem = [optionsMenuItems objectAtIndex:1]; 164 NSMenuItem* neverTranslateLanguateItem = [optionsMenuItems objectAtIndex:2]; 165 NSMenuItem* neverTranslateSiteItem = [optionsMenuItems objectAtIndex:3]; 166 // Separator at 4. 167 NSMenuItem* reportBadLanguageItem = [optionsMenuItems objectAtIndex:5]; 168 NSMenuItem* aboutTranslateItem = [optionsMenuItems objectAtIndex:6]; 169 170 { 171 EXPECT_CALL(*infobar_delegate, ToggleAlwaysTranslate()) 172 .Times(1); 173 [infobar_controller optionsMenuChanged:alwaysTranslateLanguateItem]; 174 } 175 176 { 177 EXPECT_CALL(*infobar_delegate, ToggleLanguageBlacklist()) 178 .Times(1); 179 [infobar_controller optionsMenuChanged:neverTranslateLanguateItem]; 180 } 181 182 { 183 EXPECT_CALL(*infobar_delegate, ToggleSiteBlacklist()) 184 .Times(1); 185 [infobar_controller optionsMenuChanged:neverTranslateSiteItem]; 186 } 187 188 { 189 // Can't mock these effectively, so just check that the tag is set 190 // correctly. 191 EXPECT_EQ(IDC_TRANSLATE_REPORT_BAD_LANGUAGE_DETECTION, 192 [reportBadLanguageItem tag]); 193 EXPECT_EQ(IDC_TRANSLATE_OPTIONS_ABOUT, [aboutTranslateItem tag]); 194 } 195 } 196 197 // Check that selecting a new item from the "Source Language" popup in "before 198 // translate" mode doesn't trigger a translation or change state. 199 // http://crbug.com/36666 200 TEST_F(TranslationInfoBarTest, Bug36666) { 201 EXPECT_CALL(*infobar_delegate, Translate()) 202 .Times(0); 203 204 CreateInfoBar(); 205 int arbitrary_index = 2; 206 [infobar_controller sourceLanguageModified:arbitrary_index]; 207 EXPECT_CALL(*infobar_delegate, Translate()) 208 .Times(0); 209 } 210 211 // Check that the infobar lays itself out correctly when instantiated in 212 // each of the states. 213 // http://crbug.com/36895 214 TEST_F(TranslationInfoBarTest, Bug36895) { 215 EXPECT_CALL(*infobar_delegate, Translate()) 216 .Times(0); 217 218 for (size_t i = 0; i < arraysize(kTranslateToolbarStates); ++i) { 219 CreateInfoBar(kTranslateToolbarStates[i]); 220 EXPECT_TRUE( 221 [infobar_controller verifyLayout]) << "Layout wrong, for state #" << i; 222 } 223 } 224 225 // Verify that the infobar shows the "Always translate this language" button 226 // after doing 3 translations. 227 TEST_F(TranslationInfoBarTest, TriggerShowAlwaysTranslateButton) { 228 TranslatePrefs translate_prefs(browser_helper_.profile()->GetPrefs()); 229 translate_prefs.ResetTranslationAcceptedCount("en"); 230 for (int i = 0; i < 4; ++i) { 231 translate_prefs.IncrementTranslationAcceptedCount("en"); 232 } 233 CreateInfoBar(TranslateInfoBarDelegate::BEFORE_TRANSLATE); 234 BeforeTranslateInfobarController* controller = 235 (BeforeTranslateInfobarController*)infobar_controller.get(); 236 EXPECT_TRUE([[controller alwaysTranslateButton] superview] != nil); 237 EXPECT_TRUE([[controller neverTranslateButton] superview] == nil); 238 } 239 240 // Verify that the infobar shows the "Never translate this language" button 241 // after denying 3 translations. 242 TEST_F(TranslationInfoBarTest, TriggerShowNeverTranslateButton) { 243 TranslatePrefs translate_prefs(browser_helper_.profile()->GetPrefs()); 244 translate_prefs.ResetTranslationDeniedCount("en"); 245 for (int i = 0; i < 4; ++i) { 246 translate_prefs.IncrementTranslationDeniedCount("en"); 247 } 248 CreateInfoBar(TranslateInfoBarDelegate::BEFORE_TRANSLATE); 249 BeforeTranslateInfobarController* controller = 250 (BeforeTranslateInfobarController*)infobar_controller.get(); 251 EXPECT_TRUE([[controller alwaysTranslateButton] superview] == nil); 252 EXPECT_TRUE([[controller neverTranslateButton] superview] != nil); 253 } 254 255 } // namespace 256