1 // Copyright 2013 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 #include "chrome/browser/ui/views/translate/translate_bubble_view.h" 6 7 #include "base/memory/scoped_ptr.h" 8 #include "chrome/browser/ui/translate/translate_bubble_model.h" 9 #include "chrome/browser/ui/translate/translate_bubble_view_state_transition.h" 10 #include "testing/gtest/include/gtest/gtest.h" 11 #include "ui/views/controls/button/checkbox.h" 12 #include "ui/views/controls/combobox/combobox.h" 13 #include "ui/views/test/views_test_base.h" 14 #include "ui/views/widget/widget.h" 15 16 namespace { 17 18 class MockTranslateBubbleModel : public TranslateBubbleModel { 19 public: 20 explicit MockTranslateBubbleModel(TranslateBubbleModel::ViewState view_state) 21 : view_state_transition_(view_state), 22 error_type_(TranslateErrors::NONE), 23 original_language_index_(0), 24 target_language_index_(1), 25 never_translate_language_(false), 26 never_translate_site_(false), 27 should_always_translate_(false), 28 set_always_translate_called_count_(0), 29 translate_called_(false), 30 revert_translation_called_(false), 31 translation_declined_called_(false), 32 original_language_index_on_translation_(-1), 33 target_language_index_on_translation_(-1) { 34 } 35 36 virtual TranslateBubbleModel::ViewState GetViewState() const OVERRIDE { 37 return view_state_transition_.view_state(); 38 } 39 40 virtual void SetViewState(TranslateBubbleModel::ViewState view_state) 41 OVERRIDE { 42 view_state_transition_.SetViewState(view_state); 43 } 44 45 virtual void ShowError(TranslateErrors::Type error_type) OVERRIDE { 46 error_type_ = error_type; 47 } 48 49 virtual void GoBackFromAdvanced() OVERRIDE { 50 view_state_transition_.GoBackFromAdvanced(); 51 } 52 53 virtual int GetNumberOfLanguages() const OVERRIDE { 54 return 1000; 55 } 56 57 virtual base::string16 GetLanguageNameAt(int index) const OVERRIDE { 58 return base::string16(); 59 } 60 61 virtual int GetOriginalLanguageIndex() const OVERRIDE { 62 return original_language_index_; 63 } 64 65 virtual void UpdateOriginalLanguageIndex(int index) OVERRIDE { 66 original_language_index_ = index; 67 } 68 69 virtual int GetTargetLanguageIndex() const OVERRIDE { 70 return target_language_index_; 71 } 72 73 virtual void UpdateTargetLanguageIndex(int index) OVERRIDE { 74 target_language_index_ = index; 75 } 76 77 virtual void SetNeverTranslateLanguage(bool value) OVERRIDE { 78 never_translate_language_ = value; 79 } 80 81 virtual void SetNeverTranslateSite(bool value) OVERRIDE { 82 never_translate_site_ = value; 83 } 84 85 virtual bool ShouldAlwaysTranslate() const OVERRIDE { 86 return should_always_translate_; 87 } 88 89 virtual void SetAlwaysTranslate(bool value) OVERRIDE { 90 should_always_translate_ = value; 91 set_always_translate_called_count_++; 92 } 93 94 virtual void Translate() OVERRIDE { 95 translate_called_ = true; 96 original_language_index_on_translation_ = original_language_index_; 97 target_language_index_on_translation_ = target_language_index_; 98 } 99 100 virtual void RevertTranslation() OVERRIDE { 101 revert_translation_called_ = true; 102 } 103 104 virtual void TranslationDeclined(bool explicitly_closed) OVERRIDE { 105 translation_declined_called_ = true; 106 } 107 108 virtual bool IsPageTranslatedInCurrentLanguages() const OVERRIDE { 109 return original_language_index_on_translation_ == 110 original_language_index_ && 111 target_language_index_on_translation_ == target_language_index_; 112 } 113 114 TranslateBubbleViewStateTransition view_state_transition_; 115 TranslateErrors::Type error_type_; 116 int original_language_index_; 117 int target_language_index_; 118 bool never_translate_language_; 119 bool never_translate_site_; 120 bool should_always_translate_; 121 int set_always_translate_called_count_; 122 bool translate_called_; 123 bool revert_translation_called_; 124 bool translation_declined_called_; 125 int original_language_index_on_translation_; 126 int target_language_index_on_translation_; 127 }; 128 129 } // namespace 130 131 class TranslateBubbleViewTest : public views::ViewsTestBase { 132 public: 133 TranslateBubbleViewTest() { 134 } 135 136 protected: 137 virtual void SetUp() OVERRIDE { 138 views::ViewsTestBase::SetUp(); 139 140 // The bubble needs the parent as an anchor. 141 views::Widget::InitParams params = 142 CreateParams(views::Widget::InitParams::TYPE_WINDOW); 143 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 144 145 anchor_widget_.reset(new views::Widget()); 146 anchor_widget_->Init(params); 147 anchor_widget_->Show(); 148 149 mock_model_ = new MockTranslateBubbleModel( 150 TranslateBubbleModel::VIEW_STATE_BEFORE_TRANSLATE); 151 scoped_ptr<TranslateBubbleModel> model(mock_model_); 152 bubble_ = new TranslateBubbleView(anchor_widget_->GetContentsView(), 153 model.Pass(), 154 TranslateErrors::NONE, 155 NULL); 156 views::BubbleDelegateView::CreateBubble(bubble_)->Show(); 157 } 158 159 virtual void TearDown() OVERRIDE { 160 bubble_->GetWidget()->CloseNow(); 161 anchor_widget_.reset(); 162 163 views::ViewsTestBase::TearDown(); 164 } 165 166 scoped_ptr<views::Widget> anchor_widget_; 167 MockTranslateBubbleModel* mock_model_; 168 TranslateBubbleView* bubble_; 169 }; 170 171 TEST_F(TranslateBubbleViewTest, TranslateButton) { 172 EXPECT_FALSE(mock_model_->translate_called_); 173 174 // Press the "Translate" button. 175 bubble_->HandleButtonPressed(TranslateBubbleView::BUTTON_ID_TRANSLATE); 176 EXPECT_TRUE(mock_model_->translate_called_); 177 } 178 179 TEST_F(TranslateBubbleViewTest, AdvancedLink) { 180 EXPECT_EQ(TranslateBubbleModel::VIEW_STATE_BEFORE_TRANSLATE, 181 bubble_->GetViewState()); 182 183 // Click the "Advanced" link. 184 bubble_->HandleLinkClicked(TranslateBubbleView::LINK_ID_ADVANCED); 185 EXPECT_EQ(TranslateBubbleModel::VIEW_STATE_ADVANCED, bubble_->GetViewState()); 186 } 187 188 TEST_F(TranslateBubbleViewTest, ShowOriginalButton) { 189 bubble_->SwitchView(TranslateBubbleModel::VIEW_STATE_AFTER_TRANSLATE); 190 191 // Click the "Show original" button to revert translation. 192 EXPECT_FALSE(mock_model_->revert_translation_called_); 193 bubble_->HandleButtonPressed(TranslateBubbleView::BUTTON_ID_SHOW_ORIGINAL); 194 EXPECT_TRUE(mock_model_->revert_translation_called_); 195 } 196 197 TEST_F(TranslateBubbleViewTest, TryAgainButton) { 198 bubble_->SwitchToErrorView(TranslateErrors::NETWORK); 199 200 EXPECT_EQ(TranslateErrors::NETWORK, mock_model_->error_type_); 201 202 // Click the "Try again" button to translate. 203 EXPECT_FALSE(mock_model_->translate_called_); 204 bubble_->HandleButtonPressed(TranslateBubbleView::BUTTON_ID_TRY_AGAIN); 205 EXPECT_TRUE(mock_model_->translate_called_); 206 } 207 208 TEST_F(TranslateBubbleViewTest, AlwaysTranslateCheckboxAndCancelButton) { 209 bubble_->SwitchView(TranslateBubbleModel::VIEW_STATE_ADVANCED); 210 211 // Click the "Always Translate" checkbox. Changing the state of this checkbox 212 // should NOT affect the model after pressing the cancel button. 213 214 // Check the initial state. 215 EXPECT_FALSE(mock_model_->should_always_translate_); 216 EXPECT_EQ(0, mock_model_->set_always_translate_called_count_); 217 EXPECT_FALSE(bubble_->always_translate_checkbox_->checked()); 218 219 // Click the checkbox. The state is not saved yet. 220 bubble_->always_translate_checkbox_->SetChecked(true); 221 bubble_->HandleButtonPressed(TranslateBubbleView::BUTTON_ID_ALWAYS_TRANSLATE); 222 EXPECT_FALSE(mock_model_->should_always_translate_); 223 EXPECT_EQ(0, mock_model_->set_always_translate_called_count_); 224 225 // Click the cancel button. The state is not saved. 226 bubble_->HandleButtonPressed(TranslateBubbleView::BUTTON_ID_CANCEL); 227 EXPECT_FALSE(mock_model_->should_always_translate_); 228 EXPECT_EQ(0, mock_model_->set_always_translate_called_count_); 229 } 230 231 TEST_F(TranslateBubbleViewTest, AlwaysTranslateCheckboxAndDoneButton) { 232 bubble_->SwitchView(TranslateBubbleModel::VIEW_STATE_ADVANCED); 233 234 // Click the "Always Translate" checkbox. Changing the state of this checkbox 235 // should affect the model after pressing the done button. 236 237 // Check the initial state. 238 EXPECT_FALSE(mock_model_->should_always_translate_); 239 EXPECT_EQ(0, mock_model_->set_always_translate_called_count_); 240 EXPECT_FALSE(bubble_->always_translate_checkbox_->checked()); 241 242 // Click the checkbox. The state is not saved yet. 243 bubble_->always_translate_checkbox_->SetChecked(true); 244 bubble_->HandleButtonPressed(TranslateBubbleView::BUTTON_ID_ALWAYS_TRANSLATE); 245 EXPECT_FALSE(mock_model_->should_always_translate_); 246 EXPECT_EQ(0, mock_model_->set_always_translate_called_count_); 247 248 // Click the done button. The state is saved. 249 bubble_->HandleButtonPressed(TranslateBubbleView::BUTTON_ID_DONE); 250 EXPECT_TRUE(mock_model_->should_always_translate_); 251 EXPECT_EQ(1, mock_model_->set_always_translate_called_count_); 252 } 253 254 TEST_F(TranslateBubbleViewTest, DoneButton) { 255 bubble_->SwitchView(TranslateBubbleModel::VIEW_STATE_ADVANCED); 256 257 // Click the "Done" button to translate. The selected languages by the user 258 // are applied. 259 EXPECT_FALSE(mock_model_->translate_called_); 260 bubble_->source_language_combobox_->SetSelectedIndex(10); 261 bubble_->HandleComboboxPerformAction( 262 TranslateBubbleView::COMBOBOX_ID_SOURCE_LANGUAGE); 263 bubble_->target_language_combobox_->SetSelectedIndex(20); 264 bubble_->HandleComboboxPerformAction( 265 TranslateBubbleView::COMBOBOX_ID_TARGET_LANGUAGE); 266 bubble_->HandleButtonPressed(TranslateBubbleView::BUTTON_ID_DONE); 267 EXPECT_TRUE(mock_model_->translate_called_); 268 EXPECT_EQ(10, mock_model_->original_language_index_); 269 EXPECT_EQ(20, mock_model_->target_language_index_); 270 } 271 272 TEST_F(TranslateBubbleViewTest, DoneButtonWithoutTranslating) { 273 EXPECT_EQ(TranslateBubbleModel::VIEW_STATE_BEFORE_TRANSLATE, 274 bubble_->GetViewState()); 275 276 // Translate the page once. 277 mock_model_->Translate(); 278 EXPECT_TRUE(mock_model_->translate_called_); 279 280 // Go back to the initial view. 281 EXPECT_EQ(TranslateBubbleModel::VIEW_STATE_BEFORE_TRANSLATE, 282 bubble_->GetViewState()); 283 mock_model_->translate_called_ = false; 284 285 EXPECT_EQ(TranslateBubbleModel::VIEW_STATE_BEFORE_TRANSLATE, 286 bubble_->GetViewState()); 287 bubble_->SwitchView(TranslateBubbleModel::VIEW_STATE_ADVANCED); 288 289 // Click the "Done" button with the current language pair. This time, 290 // translation is not performed and the view state will be back to the 291 // previous view. 292 bubble_->HandleButtonPressed(TranslateBubbleView::BUTTON_ID_DONE); 293 EXPECT_FALSE(mock_model_->translate_called_); 294 295 EXPECT_EQ(TranslateBubbleModel::VIEW_STATE_BEFORE_TRANSLATE, 296 bubble_->GetViewState()); 297 } 298 299 TEST_F(TranslateBubbleViewTest, CancelButtonReturningBeforeTranslate) { 300 bubble_->SwitchView(TranslateBubbleModel::VIEW_STATE_BEFORE_TRANSLATE); 301 bubble_->SwitchView(TranslateBubbleModel::VIEW_STATE_ADVANCED); 302 303 // Click the "Cancel" button to go back. 304 EXPECT_EQ(TranslateBubbleModel::VIEW_STATE_ADVANCED, bubble_->GetViewState()); 305 bubble_->HandleButtonPressed(TranslateBubbleView::BUTTON_ID_CANCEL); 306 EXPECT_EQ(TranslateBubbleModel::VIEW_STATE_BEFORE_TRANSLATE, 307 bubble_->GetViewState()); 308 } 309 310 TEST_F(TranslateBubbleViewTest, CancelButtonReturningAfterTranslate) { 311 bubble_->SwitchView(TranslateBubbleModel::VIEW_STATE_AFTER_TRANSLATE); 312 bubble_->SwitchView(TranslateBubbleModel::VIEW_STATE_ADVANCED); 313 314 // Click the "Cancel" button to go back. 315 EXPECT_EQ(TranslateBubbleModel::VIEW_STATE_ADVANCED, bubble_->GetViewState()); 316 bubble_->HandleButtonPressed(TranslateBubbleView::BUTTON_ID_CANCEL); 317 EXPECT_EQ(TranslateBubbleModel::VIEW_STATE_AFTER_TRANSLATE, 318 bubble_->GetViewState()); 319 } 320 321 TEST_F(TranslateBubbleViewTest, CancelButtonReturningError) { 322 bubble_->SwitchView(TranslateBubbleModel::VIEW_STATE_ERROR); 323 bubble_->SwitchView(TranslateBubbleModel::VIEW_STATE_ADVANCED); 324 325 // Click the "Cancel" button to go back. 326 EXPECT_EQ(TranslateBubbleModel::VIEW_STATE_ADVANCED, bubble_->GetViewState()); 327 bubble_->HandleButtonPressed(TranslateBubbleView::BUTTON_ID_CANCEL); 328 EXPECT_EQ(TranslateBubbleModel::VIEW_STATE_ERROR, bubble_->GetViewState()); 329 } 330