BookmarkManager: Fix 'new folder text field size changes on clicking it' issue.
[chromium-blink-merge.git] / chrome / browser / ui / autofill / autofill_popup_controller_unittest.cc
blob4ecd7bada651fd4f476f304dcaa3baf72cb88479
1 // Copyright (c) 2012 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 #include "base/memory/scoped_ptr.h"
6 #include "base/memory/weak_ptr.h"
7 #include "base/prefs/pref_service.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "chrome/browser/ui/autofill/autofill_popup_controller_impl.h"
10 #include "chrome/browser/ui/autofill/autofill_popup_view.h"
11 #include "chrome/browser/ui/autofill/popup_constants.h"
12 #include "chrome/browser/ui/autofill/test_popup_controller_common.h"
13 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
14 #include "chrome/test/base/testing_profile.h"
15 #include "components/autofill/content/browser/content_autofill_driver.h"
16 #include "components/autofill/content/browser/content_autofill_driver_factory.h"
17 #include "components/autofill/core/browser/autofill_external_delegate.h"
18 #include "components/autofill/core/browser/autofill_manager.h"
19 #include "components/autofill/core/browser/autofill_test_utils.h"
20 #include "components/autofill/core/browser/popup_item_ids.h"
21 #include "components/autofill/core/browser/test_autofill_client.h"
22 #include "components/autofill/core/browser/test_autofill_external_delegate.h"
23 #include "content/public/browser/web_contents.h"
24 #include "grit/components_scaled_resources.h"
25 #include "testing/gmock/include/gmock/gmock.h"
26 #include "testing/gtest/include/gtest/gtest.h"
27 #include "ui/base/resource/resource_bundle.h"
28 #include "ui/gfx/display.h"
29 #include "ui/gfx/geometry/rect.h"
30 #include "ui/gfx/text_utils.h"
32 using ::testing::_;
33 using ::testing::AtLeast;
34 using ::testing::NiceMock;
35 using base::ASCIIToUTF16;
36 using base::WeakPtr;
38 namespace autofill {
39 namespace {
41 class MockAutofillExternalDelegate : public AutofillExternalDelegate {
42 public:
43 MockAutofillExternalDelegate(AutofillManager* autofill_manager,
44 AutofillDriver* autofill_driver)
45 : AutofillExternalDelegate(autofill_manager, autofill_driver) {}
46 ~MockAutofillExternalDelegate() override {}
48 void DidSelectSuggestion(const base::string16& value,
49 int identifier) override {}
50 bool RemoveSuggestion(const base::string16& value, int identifier) override {
51 return true;
53 void ClearPreviewedForm() override {}
54 base::WeakPtr<AutofillExternalDelegate> GetWeakPtr() {
55 return AutofillExternalDelegate::GetWeakPtr();
59 class MockAutofillClient : public autofill::TestAutofillClient {
60 public:
61 MockAutofillClient() : prefs_(autofill::test::PrefServiceForTesting()) {}
62 ~MockAutofillClient() override {}
64 PrefService* GetPrefs() override { return prefs_.get(); }
66 private:
67 scoped_ptr<PrefService> prefs_;
69 DISALLOW_COPY_AND_ASSIGN(MockAutofillClient);
72 class TestAutofillPopupController : public AutofillPopupControllerImpl {
73 public:
74 explicit TestAutofillPopupController(
75 base::WeakPtr<AutofillExternalDelegate> external_delegate,
76 const gfx::RectF& element_bounds)
77 : AutofillPopupControllerImpl(external_delegate,
78 NULL,
79 NULL,
80 element_bounds,
81 base::i18n::UNKNOWN_DIRECTION),
82 test_controller_common_(
83 new TestPopupControllerCommon(element_bounds,
84 base::i18n::LEFT_TO_RIGHT)) {
85 controller_common_.reset(test_controller_common_);
87 ~TestAutofillPopupController() override {}
89 void set_display(const gfx::Display& display) {
90 test_controller_common_->set_display(display);
93 // Making protected functions public for testing
94 using AutofillPopupControllerImpl::SetPopupBounds;
95 using AutofillPopupControllerImpl::GetLineCount;
96 using AutofillPopupControllerImpl::GetSuggestionAt;
97 using AutofillPopupControllerImpl::GetElidedValueAt;
98 using AutofillPopupControllerImpl::GetElidedLabelAt;
99 using AutofillPopupControllerImpl::selected_line;
100 using AutofillPopupControllerImpl::SetSelectedLine;
101 using AutofillPopupControllerImpl::SelectNextLine;
102 using AutofillPopupControllerImpl::SelectPreviousLine;
103 using AutofillPopupControllerImpl::RemoveSelectedLine;
104 using AutofillPopupControllerImpl::popup_bounds;
105 using AutofillPopupControllerImpl::element_bounds;
106 #if !defined(OS_ANDROID)
107 using AutofillPopupControllerImpl::GetValueFontListForRow;
108 using AutofillPopupControllerImpl::GetLabelFontList;
109 using AutofillPopupControllerImpl::RowWidthWithoutText;
110 #endif
111 using AutofillPopupControllerImpl::SetValues;
112 using AutofillPopupControllerImpl::GetDesiredPopupWidth;
113 using AutofillPopupControllerImpl::GetDesiredPopupHeight;
114 using AutofillPopupControllerImpl::GetWeakPtr;
115 MOCK_METHOD1(InvalidateRow, void(size_t));
116 MOCK_METHOD0(UpdateBoundsAndRedrawPopup, void());
117 MOCK_METHOD0(Hide, void());
119 void DoHide() {
120 AutofillPopupControllerImpl::Hide();
123 private:
124 void ShowView() override {}
126 TestPopupControllerCommon* test_controller_common_;
129 } // namespace
131 class AutofillPopupControllerUnitTest : public ChromeRenderViewHostTestHarness {
132 public:
133 AutofillPopupControllerUnitTest()
134 : autofill_client_(new MockAutofillClient()),
135 autofill_popup_controller_(NULL) {}
136 ~AutofillPopupControllerUnitTest() override {}
138 void SetUp() override {
139 ChromeRenderViewHostTestHarness::SetUp();
141 ContentAutofillDriverFactory::CreateForWebContentsAndDelegate(
142 web_contents(), autofill_client_.get(), "en-US",
143 AutofillManager::ENABLE_AUTOFILL_DOWNLOAD_MANAGER);
144 ContentAutofillDriverFactory* factory =
145 ContentAutofillDriverFactory::FromWebContents(web_contents());
146 ContentAutofillDriver* driver =
147 factory->DriverForFrame(web_contents()->GetMainFrame());
148 external_delegate_.reset(
149 new NiceMock<MockAutofillExternalDelegate>(
150 driver->autofill_manager(),
151 driver));
153 autofill_popup_controller_ =
154 new testing::NiceMock<TestAutofillPopupController>(
155 external_delegate_->GetWeakPtr(), gfx::RectF());
158 void TearDown() override {
159 // This will make sure the controller and the view (if any) are both
160 // cleaned up.
161 if (autofill_popup_controller_)
162 autofill_popup_controller_->DoHide();
164 external_delegate_.reset();
165 ChromeRenderViewHostTestHarness::TearDown();
168 TestAutofillPopupController* popup_controller() {
169 return autofill_popup_controller_;
172 MockAutofillExternalDelegate* delegate() {
173 return external_delegate_.get();
176 protected:
177 scoped_ptr<MockAutofillClient> autofill_client_;
178 scoped_ptr<NiceMock<MockAutofillExternalDelegate> > external_delegate_;
179 testing::NiceMock<TestAutofillPopupController>* autofill_popup_controller_;
182 TEST_F(AutofillPopupControllerUnitTest, SetBounds) {
183 // Ensure the popup size can be set and causes a redraw.
184 gfx::Rect popup_bounds(10, 10, 100, 100);
186 EXPECT_CALL(*autofill_popup_controller_,
187 UpdateBoundsAndRedrawPopup());
189 popup_controller()->SetPopupBounds(popup_bounds);
191 EXPECT_EQ(popup_bounds, popup_controller()->popup_bounds());
194 TEST_F(AutofillPopupControllerUnitTest, ChangeSelectedLine) {
195 // Set up the popup.
196 std::vector<Suggestion> suggestions;
197 suggestions.push_back(Suggestion("", "", "", 0));
198 suggestions.push_back(Suggestion("", "", "", 0));
199 autofill_popup_controller_->Show(suggestions);
201 EXPECT_LT(autofill_popup_controller_->selected_line(), 0);
202 // Check that there are at least 2 values so that the first and last selection
203 // are different.
204 EXPECT_GE(2,
205 static_cast<int>(autofill_popup_controller_->GetLineCount()));
207 // Test wrapping before the front.
208 autofill_popup_controller_->SelectPreviousLine();
209 EXPECT_EQ(static_cast<int>(
210 autofill_popup_controller_->GetLineCount() - 1),
211 autofill_popup_controller_->selected_line());
213 // Test wrapping after the end.
214 autofill_popup_controller_->SelectNextLine();
215 EXPECT_EQ(0, autofill_popup_controller_->selected_line());
218 TEST_F(AutofillPopupControllerUnitTest, RedrawSelectedLine) {
219 // Set up the popup.
220 std::vector<Suggestion> suggestions;
221 suggestions.push_back(Suggestion("", "", "", 0));
222 suggestions.push_back(Suggestion("", "", "", 0));
223 autofill_popup_controller_->Show(suggestions);
225 // Make sure that when a new line is selected, it is invalidated so it can
226 // be updated to show it is selected.
227 int selected_line = 0;
228 EXPECT_CALL(*autofill_popup_controller_, InvalidateRow(selected_line));
229 autofill_popup_controller_->SetSelectedLine(selected_line);
231 // Ensure that the row isn't invalidated if it didn't change.
232 EXPECT_CALL(*autofill_popup_controller_,
233 InvalidateRow(selected_line)).Times(0);
234 autofill_popup_controller_->SetSelectedLine(selected_line);
236 // Change back to no selection.
237 EXPECT_CALL(*autofill_popup_controller_, InvalidateRow(selected_line));
238 autofill_popup_controller_->SetSelectedLine(-1);
241 TEST_F(AutofillPopupControllerUnitTest, RemoveLine) {
242 // Set up the popup.
243 std::vector<Suggestion> suggestions;
244 suggestions.push_back(Suggestion("", "", "", 1));
245 suggestions.push_back(Suggestion("", "", "", 1));
246 suggestions.push_back(Suggestion("", "", "", POPUP_ITEM_ID_AUTOFILL_OPTIONS));
247 autofill_popup_controller_->Show(suggestions);
249 // Generate a popup, so it can be hidden later. It doesn't matter what the
250 // external_delegate thinks is being shown in the process, since we are just
251 // testing the popup here.
252 autofill::GenerateTestAutofillPopup(external_delegate_.get());
254 // No line is selected so the removal should fail.
255 EXPECT_FALSE(autofill_popup_controller_->RemoveSelectedLine());
257 // Remove the first entry. The popup should be redrawn since its size has
258 // changed.
259 EXPECT_CALL(*autofill_popup_controller_, UpdateBoundsAndRedrawPopup());
260 autofill_popup_controller_->SetSelectedLine(0);
261 EXPECT_TRUE(autofill_popup_controller_->RemoveSelectedLine());
263 // Remove the last entry. The popup should then be hidden since there are
264 // no Autofill entries left.
265 EXPECT_CALL(*autofill_popup_controller_, Hide());
266 autofill_popup_controller_->SetSelectedLine(0);
267 EXPECT_TRUE(autofill_popup_controller_->RemoveSelectedLine());
270 TEST_F(AutofillPopupControllerUnitTest, RemoveOnlyLine) {
271 // Set up the popup.
272 std::vector<Suggestion> suggestions;
273 suggestions.push_back(Suggestion("", "", "", 1));
274 autofill_popup_controller_->Show(suggestions);
276 // Generate a popup.
277 autofill::GenerateTestAutofillPopup(external_delegate_.get());
279 // Select the only line.
280 autofill_popup_controller_->SetSelectedLine(0);
282 // Remove the only line. There should be no row invalidation and the popup
283 // should then be hidden since there are no Autofill entries left.
284 EXPECT_CALL(*autofill_popup_controller_, Hide());
285 EXPECT_CALL(*autofill_popup_controller_, InvalidateRow(_)).Times(0);
286 EXPECT_TRUE(autofill_popup_controller_->RemoveSelectedLine());
289 TEST_F(AutofillPopupControllerUnitTest, SkipSeparator) {
290 // Set up the popup.
291 std::vector<Suggestion> suggestions;
292 suggestions.push_back(Suggestion("", "", "", 1));
293 suggestions.push_back(Suggestion("", "", "", POPUP_ITEM_ID_SEPARATOR));
294 suggestions.push_back(Suggestion("", "", "", POPUP_ITEM_ID_AUTOFILL_OPTIONS));
295 autofill_popup_controller_->Show(suggestions);
297 autofill_popup_controller_->SetSelectedLine(0);
299 // Make sure next skips the unselectable separator.
300 autofill_popup_controller_->SelectNextLine();
301 EXPECT_EQ(2, autofill_popup_controller_->selected_line());
303 // Make sure previous skips the unselectable separator.
304 autofill_popup_controller_->SelectPreviousLine();
305 EXPECT_EQ(0, autofill_popup_controller_->selected_line());
308 TEST_F(AutofillPopupControllerUnitTest, RowWidthWithoutText) {
309 // Give elements 1 and 3 subtexts and elements 2 and 3 icons, to ensure
310 // all combinations of subtexts and icons.
311 std::vector<Suggestion> suggestions;
312 suggestions.push_back(Suggestion("", "", "", 0));
313 suggestions.push_back(Suggestion("", "x", "", 0));
314 suggestions.push_back(Suggestion("", "", "americanExpressCC", 0));
315 suggestions.push_back(Suggestion("", "x", "genericCC", 0));
317 // Set up some visible display so the text values are kept.
318 gfx::Display display(0, gfx::Rect(0, 0, 100, 100));
319 autofill_popup_controller_->set_display(display);
321 autofill_popup_controller_->Show(suggestions);
323 int base_size =
324 AutofillPopupView::kEndPadding * 2 +
325 kPopupBorderThickness * 2;
326 int subtext_increase = AutofillPopupView::kNamePadding;
328 EXPECT_EQ(base_size, autofill_popup_controller_->RowWidthWithoutText(0));
329 EXPECT_EQ(base_size + subtext_increase,
330 autofill_popup_controller_->RowWidthWithoutText(1));
331 EXPECT_EQ(base_size + AutofillPopupView::kIconPadding +
332 ui::ResourceBundle::GetSharedInstance().GetImageNamed(
333 IDR_AUTOFILL_CC_AMEX).Width(),
334 autofill_popup_controller_->RowWidthWithoutText(2));
335 EXPECT_EQ(base_size + subtext_increase + AutofillPopupView::kIconPadding +
336 ui::ResourceBundle::GetSharedInstance().GetImageNamed(
337 IDR_AUTOFILL_CC_GENERIC).Width(),
338 autofill_popup_controller_->RowWidthWithoutText(3));
341 TEST_F(AutofillPopupControllerUnitTest, UpdateDataListValues) {
342 std::vector<Suggestion> suggestions;
343 suggestions.push_back(Suggestion("", "", "", 1));
344 autofill_popup_controller_->Show(suggestions);
346 // Add one data list entry.
347 base::string16 value1 = ASCIIToUTF16("data list value 1");
348 std::vector<base::string16> data_list_values;
349 data_list_values.push_back(value1);
351 autofill_popup_controller_->UpdateDataListValues(data_list_values,
352 data_list_values);
354 ASSERT_EQ(3u, autofill_popup_controller_->GetLineCount());
356 Suggestion result0 = autofill_popup_controller_->GetSuggestionAt(0);
357 EXPECT_EQ(value1, result0.value);
358 EXPECT_EQ(value1, autofill_popup_controller_->GetElidedValueAt(0));
359 EXPECT_EQ(value1, result0.label);
360 EXPECT_EQ(value1, autofill_popup_controller_->GetElidedLabelAt(0));
361 EXPECT_EQ(POPUP_ITEM_ID_DATALIST_ENTRY, result0.frontend_id);
363 Suggestion result1 = autofill_popup_controller_->GetSuggestionAt(1);
364 EXPECT_EQ(base::string16(), result1.value);
365 EXPECT_EQ(base::string16(), result1.label);
366 EXPECT_EQ(POPUP_ITEM_ID_SEPARATOR, result1.frontend_id);
368 Suggestion result2 = autofill_popup_controller_->GetSuggestionAt(2);
369 EXPECT_EQ(base::string16(), result2.value);
370 EXPECT_EQ(base::string16(), result2.label);
371 EXPECT_EQ(1, result2.frontend_id);
373 // Add two data list entries (which should replace the current one).
374 base::string16 value2 = ASCIIToUTF16("data list value 2");
375 data_list_values.push_back(value2);
377 autofill_popup_controller_->UpdateDataListValues(data_list_values,
378 data_list_values);
379 ASSERT_EQ(4u, autofill_popup_controller_->GetLineCount());
381 // Original one first, followed by new one, then separator.
382 EXPECT_EQ(value1, autofill_popup_controller_->GetSuggestionAt(0).value);
383 EXPECT_EQ(value1, autofill_popup_controller_->GetElidedValueAt(0));
384 EXPECT_EQ(value2, autofill_popup_controller_->GetSuggestionAt(1).value);
385 EXPECT_EQ(value2, autofill_popup_controller_->GetElidedValueAt(1));
386 EXPECT_EQ(POPUP_ITEM_ID_SEPARATOR,
387 autofill_popup_controller_->GetSuggestionAt(2).frontend_id);
389 // Clear all data list values.
390 data_list_values.clear();
391 autofill_popup_controller_->UpdateDataListValues(data_list_values,
392 data_list_values);
394 ASSERT_EQ(1u, autofill_popup_controller_->GetLineCount());
395 EXPECT_EQ(1, autofill_popup_controller_->GetSuggestionAt(0).frontend_id);
398 TEST_F(AutofillPopupControllerUnitTest, PopupsWithOnlyDataLists) {
399 // Create the popup with a single datalist element.
400 std::vector<Suggestion> suggestions;
401 suggestions.push_back(Suggestion("", "", "", POPUP_ITEM_ID_DATALIST_ENTRY));
402 autofill_popup_controller_->Show(suggestions);
404 // Replace the datalist element with a new one.
405 base::string16 value1 = ASCIIToUTF16("data list value 1");
406 std::vector<base::string16> data_list_values;
407 data_list_values.push_back(value1);
409 autofill_popup_controller_->UpdateDataListValues(data_list_values,
410 data_list_values);
412 ASSERT_EQ(1u, autofill_popup_controller_->GetLineCount());
413 EXPECT_EQ(value1, autofill_popup_controller_->GetSuggestionAt(0).value);
414 EXPECT_EQ(POPUP_ITEM_ID_DATALIST_ENTRY,
415 autofill_popup_controller_->GetSuggestionAt(0).frontend_id);
417 // Clear datalist values and check that the popup becomes hidden.
418 EXPECT_CALL(*autofill_popup_controller_, Hide());
419 data_list_values.clear();
420 autofill_popup_controller_->UpdateDataListValues(data_list_values,
421 data_list_values);
424 TEST_F(AutofillPopupControllerUnitTest, GetOrCreate) {
425 ContentAutofillDriverFactory* factory =
426 ContentAutofillDriverFactory::FromWebContents(web_contents());
427 ContentAutofillDriver* driver =
428 factory->DriverForFrame(web_contents()->GetMainFrame());
429 MockAutofillExternalDelegate delegate(driver->autofill_manager(), driver);
431 WeakPtr<AutofillPopupControllerImpl> controller =
432 AutofillPopupControllerImpl::GetOrCreate(
433 WeakPtr<AutofillPopupControllerImpl>(), delegate.GetWeakPtr(), NULL,
434 NULL, gfx::RectF(), base::i18n::UNKNOWN_DIRECTION);
435 EXPECT_TRUE(controller.get());
437 controller->Hide();
439 controller = AutofillPopupControllerImpl::GetOrCreate(
440 WeakPtr<AutofillPopupControllerImpl>(), delegate.GetWeakPtr(), NULL, NULL,
441 gfx::RectF(), base::i18n::UNKNOWN_DIRECTION);
442 EXPECT_TRUE(controller.get());
444 WeakPtr<AutofillPopupControllerImpl> controller2 =
445 AutofillPopupControllerImpl::GetOrCreate(
446 controller, delegate.GetWeakPtr(), NULL, NULL, gfx::RectF(),
447 base::i18n::UNKNOWN_DIRECTION);
448 EXPECT_EQ(controller.get(), controller2.get());
449 controller->Hide();
451 testing::NiceMock<TestAutofillPopupController>* test_controller =
452 new testing::NiceMock<TestAutofillPopupController>(delegate.GetWeakPtr(),
453 gfx::RectF());
454 EXPECT_CALL(*test_controller, Hide());
456 gfx::RectF bounds(0.f, 0.f, 1.f, 2.f);
457 base::WeakPtr<AutofillPopupControllerImpl> controller3 =
458 AutofillPopupControllerImpl::GetOrCreate(
459 test_controller->GetWeakPtr(),
460 delegate.GetWeakPtr(),
461 NULL,
462 NULL,
463 bounds,
464 base::i18n::UNKNOWN_DIRECTION);
465 EXPECT_EQ(
466 bounds,
467 static_cast<AutofillPopupController*>(controller3.get())->
468 element_bounds());
469 controller3->Hide();
471 // Hide the test_controller to delete it.
472 test_controller->DoHide();
475 TEST_F(AutofillPopupControllerUnitTest, ProperlyResetController) {
476 std::vector<Suggestion> suggestions;
477 suggestions.push_back(Suggestion("", "", "", 0));
478 suggestions.push_back(Suggestion("", "", "", 0));
479 popup_controller()->SetValues(suggestions);
480 popup_controller()->SetSelectedLine(0);
482 // Now show a new popup with the same controller, but with fewer items.
483 WeakPtr<AutofillPopupControllerImpl> controller =
484 AutofillPopupControllerImpl::GetOrCreate(
485 popup_controller()->GetWeakPtr(), delegate()->GetWeakPtr(), NULL,
486 NULL, gfx::RectF(), base::i18n::UNKNOWN_DIRECTION);
487 EXPECT_NE(0, controller->selected_line());
488 EXPECT_EQ(0u, controller->GetLineCount());
491 #if !defined(OS_ANDROID)
492 TEST_F(AutofillPopupControllerUnitTest, ElideText) {
493 std::vector<Suggestion> suggestions;
494 suggestions.push_back(
495 Suggestion("Text that will need to be trimmed",
496 "Label that will be trimmed", "genericCC", 0));
497 suggestions.push_back(
498 Suggestion("untrimmed", "Untrimmed", "genericCC", 0));
500 // Show the popup once so we can easily generate the size it needs.
501 autofill_popup_controller_->Show(suggestions);
503 // Ensure the popup will be too small to display all of the first row.
504 int popup_max_width =
505 gfx::GetStringWidth(
506 suggestions[0].value,
507 autofill_popup_controller_->GetValueFontListForRow(0)) +
508 gfx::GetStringWidth(
509 suggestions[0].label,
510 autofill_popup_controller_->GetLabelFontList()) - 25;
511 gfx::Rect popup_bounds = gfx::Rect(0, 0, popup_max_width, 0);
512 autofill_popup_controller_->set_display(gfx::Display(0, popup_bounds));
514 autofill_popup_controller_->Show(suggestions);
516 // The first element was long so it should have been trimmed.
517 EXPECT_NE(autofill_popup_controller_->GetSuggestionAt(0).value,
518 autofill_popup_controller_->GetElidedValueAt(0));
519 EXPECT_NE(autofill_popup_controller_->GetSuggestionAt(0).label,
520 autofill_popup_controller_->GetElidedLabelAt(0));
522 // The second element was shorter so it should be unchanged.
523 EXPECT_EQ(autofill_popup_controller_->GetSuggestionAt(1).value,
524 autofill_popup_controller_->GetElidedValueAt(1));
525 EXPECT_EQ(autofill_popup_controller_->GetSuggestionAt(1).label,
526 autofill_popup_controller_->GetElidedLabelAt(1));
528 #endif
530 } // namespace autofill