root/chrome/browser/ui/autofill/autofill_dialog_controller_browsertest.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. MockCallback
  2. LogDialogUiDuration
  3. dialog_dismissal_action
  4. sign_in_user_index_
  5. SignInUrl
  6. ViewClosed
  7. InputValidityMessage
  8. InputsAreValid
  9. ShouldOfferToSaveInChrome
  10. ForceFinishSubmit
  11. CurrentNotifications
  12. set_notifications
  13. GetTestingManager
  14. GetMockValidator
  15. set_use_validation
  16. AsWeakPtr
  17. GetTestingWalletClient
  18. set_sign_in_user_index
  19. GetManager
  20. GetValidator
  21. GetWalletClient
  22. IsSignInContinueUrl
  23. GetMetricLogger
  24. url_
  25. Observe
  26. SetUpCommandLine
  27. SetUpOnMainThread
  28. SectionHasField
  29. CycleRunLoops
  30. InitializeControllerWithoutShowing
  31. InitializeController
  32. GetActiveWebContents
  33. GetRenderViewHost
  34. GetViewTester
  35. metric_logger
  36. controller
  37. RunMessageLoop
  38. SetUpHtmlAndInvoke
  39. RunTestPage
  40. ExpectDomMessage
  41. InitiateDialog
  42. GetValueForHTMLFieldOfType
  43. AddCreditcardToProfile
  44. AddAutofillProfileToProfile
  45. test_generated_bubble_controller
  46. WaitForWebDB
  47. IN_PROC_BROWSER_TEST_F
  48. IN_PROC_BROWSER_TEST_F
  49. IN_PROC_BROWSER_TEST_F
  50. IN_PROC_BROWSER_TEST_F
  51. IN_PROC_BROWSER_TEST_F
  52. IN_PROC_BROWSER_TEST_F
  53. IN_PROC_BROWSER_TEST_F
  54. IN_PROC_BROWSER_TEST_F
  55. IN_PROC_BROWSER_TEST_F
  56. IN_PROC_BROWSER_TEST_F
  57. IN_PROC_BROWSER_TEST_F
  58. IN_PROC_BROWSER_TEST_F
  59. IN_PROC_BROWSER_TEST_F
  60. IN_PROC_BROWSER_TEST_F
  61. IN_PROC_BROWSER_TEST_F
  62. IN_PROC_BROWSER_TEST_F
  63. IN_PROC_BROWSER_TEST_F
  64. IN_PROC_BROWSER_TEST_F
  65. IN_PROC_BROWSER_TEST_F
  66. IN_PROC_BROWSER_TEST_F
  67. IN_PROC_BROWSER_TEST_F
  68. IN_PROC_BROWSER_TEST_F
  69. IN_PROC_BROWSER_TEST_F
  70. IN_PROC_BROWSER_TEST_F
  71. IN_PROC_BROWSER_TEST_F
  72. IN_PROC_BROWSER_TEST_F
  73. IN_PROC_BROWSER_TEST_F
  74. IN_PROC_BROWSER_TEST_F
  75. IN_PROC_BROWSER_TEST_F
  76. SetUpCommandLine
  77. IN_PROC_BROWSER_TEST_F
  78. IN_PROC_BROWSER_TEST_F
  79. IN_PROC_BROWSER_TEST_F
  80. IN_PROC_BROWSER_TEST_F
  81. IN_PROC_BROWSER_TEST_F
  82. IN_PROC_BROWSER_TEST_F
  83. IN_PROC_BROWSER_TEST_F
  84. IN_PROC_BROWSER_TEST_F
  85. IN_PROC_BROWSER_TEST_F

// Copyright (c) 2012 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.

#include "base/bind.h"
#include "base/command_line.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/prefs/pref_service.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "chrome/browser/autofill/personal_data_manager_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/autofill/account_chooser_model.h"
#include "chrome/browser/ui/autofill/autofill_dialog_controller_impl.h"
#include "chrome/browser/ui/autofill/autofill_dialog_i18n_input.h"
#include "chrome/browser/ui/autofill/autofill_dialog_view.h"
#include "chrome/browser/ui/autofill/autofill_dialog_view_tester.h"
#include "chrome/browser/ui/autofill/data_model_wrapper.h"
#include "chrome/browser/ui/autofill/mock_address_validator.h"
#include "chrome/browser/ui/autofill/tab_autofill_manager_delegate.h"
#include "chrome/browser/ui/autofill/test_generated_credit_card_bubble_controller.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_tabstrip.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/autofill/content/browser/risk/proto/fingerprint.pb.h"
#include "components/autofill/content/browser/wallet/gaia_account.h"
#include "components/autofill/content/browser/wallet/mock_wallet_client.h"
#include "components/autofill/content/browser/wallet/wallet_service_url.h"
#include "components/autofill/content/browser/wallet/wallet_test_util.h"
#include "components/autofill/core/browser/autofill_metrics.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill/core/browser/test_personal_data_manager.h"
#include "components/autofill/core/browser/validation.h"
#include "components/autofill/core/common/autofill_switches.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/form_field_data.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/interstitial_page.h"
#include "content/public/browser/navigation_details.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_types.h"
#include "content/public/browser/page_navigator.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/page_transition_types.h"
#include "content/public/common/referrer.h"
#include "content/public/common/url_constants.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_utils.h"
#include "google_apis/gaia/google_service_auth_error.h"
#include "net/test/spawned_test_server/spawned_test_server.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
#include "ui/base/window_open_disposition.h"
#include "url/gurl.h"

#if defined(OS_WIN)
#include "base/win/windows_version.h"
#elif defined(OS_MACOSX)
#include "base/mac/mac_util.h"
#include "base/mac/scoped_nsautorelease_pool.h"
#include "chrome/browser/ui/cocoa/run_loop_testing.h"
#endif

using base::ASCIIToUTF16;

namespace autofill {

namespace {

using testing::Return;
using testing::_;
using ::i18n::addressinput::AddressValidator;

void MockCallback(const FormStructure*) {}

class MockAutofillMetrics : public AutofillMetrics {
 public:
  MockAutofillMetrics()
      : dialog_dismissal_action_(static_cast<DialogDismissalAction>(-1)) {}
  virtual ~MockAutofillMetrics() {}

  virtual void LogDialogUiDuration(
      const base::TimeDelta& duration,
      DialogDismissalAction dismissal_action) const OVERRIDE {
    // Ignore constness for testing.
    MockAutofillMetrics* mutable_this = const_cast<MockAutofillMetrics*>(this);
    mutable_this->dialog_dismissal_action_ = dismissal_action;
  }

  AutofillMetrics::DialogDismissalAction dialog_dismissal_action() const {
    return dialog_dismissal_action_;
  }

  MOCK_CONST_METHOD1(LogDialogDismissalState,
                     void(DialogDismissalState state));

 private:
  DialogDismissalAction dialog_dismissal_action_;

  DISALLOW_COPY_AND_ASSIGN(MockAutofillMetrics);
};

class TestAutofillDialogController : public AutofillDialogControllerImpl {
 public:
  TestAutofillDialogController(
      content::WebContents* contents,
      const FormData& form_data,
      const AutofillMetrics& metric_logger,
      scoped_refptr<content::MessageLoopRunner> runner)
      : AutofillDialogControllerImpl(contents,
                                     form_data,
                                     form_data.origin,
                                     base::Bind(&MockCallback)),
        metric_logger_(metric_logger),
        mock_wallet_client_(
            Profile::FromBrowserContext(contents->GetBrowserContext())->
                GetRequestContext(), this, form_data.origin),
        message_loop_runner_(runner),
        use_validation_(false),
        weak_ptr_factory_(this),
        sign_in_user_index_(0U) {
    test_manager_.Init(
        NULL,
        Profile::FromBrowserContext(contents->GetBrowserContext())->GetPrefs(),
        false);
  }

  virtual ~TestAutofillDialogController() {}

  virtual GURL SignInUrl() const OVERRIDE {
    return GURL(chrome::kChromeUIVersionURL);
  }

  virtual void ViewClosed() OVERRIDE {
    message_loop_runner_->Quit();
    AutofillDialogControllerImpl::ViewClosed();
  }

  virtual base::string16 InputValidityMessage(
      DialogSection section,
      ServerFieldType type,
      const base::string16& value) OVERRIDE {
    if (!use_validation_)
      return base::string16();
    return AutofillDialogControllerImpl::InputValidityMessage(
        section, type, value);
  }

  virtual ValidityMessages InputsAreValid(
      DialogSection section,
      const FieldValueMap& inputs) OVERRIDE {
    if (!use_validation_)
      return ValidityMessages();
    return AutofillDialogControllerImpl::InputsAreValid(section, inputs);
  }

  // Saving to Chrome is tested in AutofillDialogControllerImpl unit tests.
  // TODO(estade): test that the view defaults to saving to Chrome.
  virtual bool ShouldOfferToSaveInChrome() const OVERRIDE {
    return true;
  }

  void ForceFinishSubmit() {
    DoFinishSubmit();
  }

  // Increase visibility for testing.
  using AutofillDialogControllerImpl::view;
  using AutofillDialogControllerImpl::popup_input_type;

  MOCK_METHOD0(LoadRiskFingerprintData, void());

  virtual std::vector<DialogNotification> CurrentNotifications() OVERRIDE {
    return notifications_;
  }

  void set_notifications(const std::vector<DialogNotification>& notifications) {
    notifications_ = notifications;
  }

  TestPersonalDataManager* GetTestingManager() {
    return &test_manager_;
  }

  MockAddressValidator* GetMockValidator() {
    return &mock_validator_;
  }

  using AutofillDialogControllerImpl::IsEditingExistingData;
  using AutofillDialogControllerImpl::IsManuallyEditingSection;
  using AutofillDialogControllerImpl::IsPayingWithWallet;
  using AutofillDialogControllerImpl::IsSubmitPausedOn;
  using AutofillDialogControllerImpl::OnDidLoadRiskFingerprintData;
  using AutofillDialogControllerImpl::AccountChooserModelForTesting;
  using AutofillDialogControllerImpl::
      ClearLastWalletItemsFetchTimestampForTesting;

  void set_use_validation(bool use_validation) {
    use_validation_ = use_validation;
  }

  base::WeakPtr<TestAutofillDialogController> AsWeakPtr() {
    return weak_ptr_factory_.GetWeakPtr();
  }

  wallet::MockWalletClient* GetTestingWalletClient() {
    return &mock_wallet_client_;
  }

  void set_sign_in_user_index(size_t sign_in_user_index) {
    sign_in_user_index_ = sign_in_user_index;
  }

 protected:
  virtual PersonalDataManager* GetManager() const OVERRIDE {
    return &const_cast<TestAutofillDialogController*>(this)->test_manager_;
  }

  virtual AddressValidator* GetValidator() OVERRIDE {
    return &mock_validator_;
  }

  virtual wallet::WalletClient* GetWalletClient() OVERRIDE {
    return &mock_wallet_client_;
  }

  virtual bool IsSignInContinueUrl(const GURL& url, size_t* user_index) const
      OVERRIDE {
    *user_index = sign_in_user_index_;
    return url == wallet::GetSignInContinueUrl();
  }

 private:
  // To specify our own metric logger.
  virtual const AutofillMetrics& GetMetricLogger() const OVERRIDE {
    return metric_logger_;
  }

  const AutofillMetrics& metric_logger_;
  TestPersonalDataManager test_manager_;
  testing::NiceMock<MockAddressValidator> mock_validator_;
  testing::NiceMock<wallet::MockWalletClient> mock_wallet_client_;
  scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
  bool use_validation_;

  // A list of notifications to show in the notification area of the dialog.
  // This is used to control what |CurrentNotifications()| returns for testing.
  std::vector<DialogNotification> notifications_;

  // Allows generation of WeakPtrs, so controller liveness can be tested.
  base::WeakPtrFactory<TestAutofillDialogController> weak_ptr_factory_;

  // The user index that is assigned in IsSignInContinueUrl().
  size_t sign_in_user_index_;

  DISALLOW_COPY_AND_ASSIGN(TestAutofillDialogController);
};

// This is a copy of ui_test_utils::UrlLoadObserver, except it observes
// NAV_ENTRY_COMMITTED instead of LOAD_STOP. This is to match the notification
// that AutofillDialogControllerImpl observes. Since NAV_ENTRY_COMMITTED comes
// before LOAD_STOP, and the controller deletes the web contents after receiving
// the former, we will sometimes fail to observe a LOAD_STOP.
// TODO(estade): Should the controller observe LOAD_STOP instead?
class NavEntryCommittedObserver : public content::WindowedNotificationObserver {
 public:
  NavEntryCommittedObserver(const GURL& url,
                            const content::NotificationSource& source)
    : WindowedNotificationObserver(content::NOTIFICATION_NAV_ENTRY_COMMITTED,
                                   source),
      url_(url) {}

  virtual ~NavEntryCommittedObserver() {}

  // content::NotificationObserver:
  virtual void Observe(int type,
                       const content::NotificationSource& source,
                       const content::NotificationDetails& details) OVERRIDE {
    content::LoadCommittedDetails* load_details =
        content::Details<content::LoadCommittedDetails>(details).ptr();
    if (load_details->entry->GetVirtualURL() != url_)
      return;

    WindowedNotificationObserver::Observe(type, source, details);
  }

 private:
  GURL url_;

  DISALLOW_COPY_AND_ASSIGN(NavEntryCommittedObserver);
};

}  // namespace

class AutofillDialogControllerTest : public InProcessBrowserTest {
 public:
  AutofillDialogControllerTest() : controller_(NULL) {}
  virtual ~AutofillDialogControllerTest() {}

  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
    command_line->AppendSwitch(::switches::kReduceSecurityForTesting);
  }

  virtual void SetUpOnMainThread() OVERRIDE {
    autofill::test::DisableSystemServices(browser()->profile()->GetPrefs());
    InitializeController();
  }

 protected:
  bool SectionHasField(DialogSection section, ServerFieldType type) {
    const DetailInputs& fields =
        controller()->RequestedFieldsForSection(section);
    for (size_t i = 0; i < fields.size(); ++i) {
      if (type == fields[i].type)
        return true;
    }
    return false;
  }

  // A helper function that cycles the MessageLoop, and on Mac, the Cocoa run
  // loop. It also drains the NSAutoreleasePool.
  void CycleRunLoops() {
    content::RunAllPendingInMessageLoop();
#if defined(OS_MACOSX)
    chrome::testing::NSRunLoopRunAllPending();
    AutoreleasePool()->Recycle();
#endif
  }

  void InitializeControllerWithoutShowing() {
    if (controller_)
      controller_->Hide();

    FormData form;
    form.name = ASCIIToUTF16("TestForm");
    form.method = ASCIIToUTF16("POST");
    form.user_submitted = true;

    FormFieldData field;
    field.autocomplete_attribute = "shipping tel";
    form.fields.push_back(field);

    test_generated_bubble_controller_ =
        new testing::NiceMock<TestGeneratedCreditCardBubbleController>(
            GetActiveWebContents());
    ASSERT_TRUE(test_generated_bubble_controller_->IsInstalled());

    message_loop_runner_ = new content::MessageLoopRunner;
    controller_ = new TestAutofillDialogController(
        GetActiveWebContents(),
        form,
        metric_logger_,
        message_loop_runner_);
  }

  void InitializeController() {
    InitializeControllerWithoutShowing();
    controller_->Show();
    CycleRunLoops();  // Ensures dialog is fully visible.
  }

  content::WebContents* GetActiveWebContents() {
    return browser()->tab_strip_model()->GetActiveWebContents();
  }

  content::RenderViewHost* GetRenderViewHost() {
    return GetActiveWebContents()->GetRenderViewHost();
  }

  scoped_ptr<AutofillDialogViewTester> GetViewTester() {
    return AutofillDialogViewTester::For(controller()->view()).Pass();
  }

  const MockAutofillMetrics& metric_logger() { return metric_logger_; }
  TestAutofillDialogController* controller() { return controller_; }

  void RunMessageLoop() {
    message_loop_runner_->Run();
  }

  // Loads an HTML page in |GetActiveWebContents()| with markup as follows:
  // <form>|form_inner_html|</form>. After loading, emulates a click event on
  // the page as requestAutocomplete() must be in response to a user gesture.
  // Returns the |AutofillDialogControllerImpl| created by this invocation.
  AutofillDialogControllerImpl* SetUpHtmlAndInvoke(
      const std::string& form_inner_html) {
    content::WebContents* contents = GetActiveWebContents();
    TabAutofillManagerDelegate* delegate =
        TabAutofillManagerDelegate::FromWebContents(contents);
    CHECK(!delegate->GetDialogControllerForTesting());

    ui_test_utils::NavigateToURL(
        browser(), GURL(std::string("data:text/html,") +
        "<!doctype html>"
        "<html>"
          "<body>"
            "<form>" + form_inner_html + "</form>"
            "<script>"
              "function send(msg) {"
                "domAutomationController.setAutomationId(0);"
                "domAutomationController.send(msg);"
              "}"
              "document.forms[0].onautocompleteerror = function(e) {"
                "send('error: ' + e.reason);"
              "};"
              "document.forms[0].onautocomplete = function() {"
                "send('success');"
              "};"
              "window.onclick = function() {"
                "document.forms[0].requestAutocomplete();"
                "send('clicked');"
              "};"
              "function loadIframe() {"
              "  var iframe = document.createElement('iframe');"
              "  iframe.onload = function() {"
              "    send('iframe loaded');"
              "  };"
              "  iframe.src = 'about:blank';"
              "  document.body.appendChild(iframe);"
              "}"
              "function getValueForFieldOfType(type) {"
              "  var fields = document.getElementsByTagName('input');"
              "  for (var i = 0; i < fields.length; i++) {"
              "    if (fields[i].autocomplete == type) {"
              "      send(fields[i].value);"
              "      return;"
              "    }"
              "  }"
              "  send('');"
              "};"
            "</script>"
          "</body>"
        "</html>"));

    InitiateDialog();
    AutofillDialogControllerImpl* controller =
        static_cast<AutofillDialogControllerImpl*>(
            delegate->GetDialogControllerForTesting());
    return controller;
  }

  // Loads an html page on a provided server, the causes it to launch rAc.
  // Returns whether rAc succesfully launched.
  bool RunTestPage(const net::SpawnedTestServer& server) {
    GURL url = server.GetURL(
        "files/request_autocomplete/test_page.html");
    ui_test_utils::NavigateToURL(browser(), url);

    // Pass through the broken SSL interstitial, if any.
    content::WebContents* contents = GetActiveWebContents();
    content::InterstitialPage* interstitial_page =
        contents->GetInterstitialPage();
    if (interstitial_page) {
      ui_test_utils::UrlLoadObserver observer(
          url,
          content::Source<content::NavigationController>(
              &contents->GetController()));
      interstitial_page->Proceed();
      observer.Wait();
    }

    InitiateDialog();

    TabAutofillManagerDelegate* delegate =
        TabAutofillManagerDelegate::FromWebContents(contents);
    AutofillDialogControllerImpl* controller =
        static_cast<AutofillDialogControllerImpl*>(
            delegate->GetDialogControllerForTesting());
    return !!controller;
  }

  // Wait for a message from the DOM automation controller (from JS in the
  // page). Requires |SetUpHtmlAndInvoke()| be called first.
  void ExpectDomMessage(const std::string& expected) {
    std::string message;
    ASSERT_TRUE(dom_message_queue_->WaitForMessage(&message));
    dom_message_queue_->ClearQueue();
    EXPECT_EQ("\"" + expected + "\"", message);
  }

  void InitiateDialog() {
    dom_message_queue_.reset(new content::DOMMessageQueue);

    // Triggers the onclick handler which invokes requestAutocomplete().
    content::WebContents* contents = GetActiveWebContents();
    content::SimulateMouseClick(contents, 0, blink::WebMouseEvent::ButtonLeft);
    ExpectDomMessage("clicked");
  }

  // Returns the value filled into the first field with autocomplete attribute
  // equal to |autocomplete_type|, or an empty string if there is no such field.
  std::string GetValueForHTMLFieldOfType(const std::string& autocomplete_type) {
    std::string script = "getValueForFieldOfType('" + autocomplete_type + "');";
    std::string result;
    EXPECT_TRUE(content::ExecuteScriptAndExtractString(GetRenderViewHost(),
                                                       script,
                                                       &result));
    return result;
  }

  void AddCreditcardToProfile(Profile* profile, const CreditCard& card) {
    PersonalDataManagerFactory::GetForProfile(profile)->AddCreditCard(card);
    WaitForWebDB();
  }

  void AddAutofillProfileToProfile(Profile* profile,
                                   const AutofillProfile& autofill_profile) {
    PersonalDataManagerFactory::GetForProfile(profile)->AddProfile(
        autofill_profile);
    WaitForWebDB();
  }

  TestGeneratedCreditCardBubbleController* test_generated_bubble_controller() {
    return test_generated_bubble_controller_;
  }

 private:
  void WaitForWebDB() {
    content::RunAllPendingInMessageLoop(content::BrowserThread::DB);
  }

  testing::NiceMock<MockAutofillMetrics> metric_logger_;
  TestAutofillDialogController* controller_;  // Weak reference.
  scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
  scoped_ptr<content::DOMMessageQueue> dom_message_queue_;

  // Weak; owned by the active web contents.
  TestGeneratedCreditCardBubbleController* test_generated_bubble_controller_;

  DISALLOW_COPY_AND_ASSIGN(AutofillDialogControllerTest);
};

// Submit the form data.
IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, Submit) {
  GetViewTester()->SubmitForTesting();
  RunMessageLoop();

  EXPECT_EQ(AutofillMetrics::DIALOG_ACCEPTED,
            metric_logger().dialog_dismissal_action());
}

// Cancel out of the dialog.
IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, Cancel) {
  EXPECT_CALL(metric_logger(),
              LogDialogDismissalState(
                  AutofillMetrics::DIALOG_CANCELED_NO_INVALID_FIELDS));

  GetViewTester()->CancelForTesting();
  RunMessageLoop();

  EXPECT_EQ(AutofillMetrics::DIALOG_CANCELED,
            metric_logger().dialog_dismissal_action());
}

// Take some other action that dismisses the dialog.
IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, Hide) {
  EXPECT_CALL(metric_logger(),
              LogDialogDismissalState(
                  AutofillMetrics::DIALOG_CANCELED_NO_INVALID_FIELDS));
  controller()->Hide();

  RunMessageLoop();

  EXPECT_EQ(AutofillMetrics::DIALOG_CANCELED,
            metric_logger().dialog_dismissal_action());
}

IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, CancelWithSuggestions) {
  EXPECT_CALL(metric_logger(),
              LogDialogDismissalState(
                  AutofillMetrics::DIALOG_CANCELED_NO_EDITS));

  CreditCard card(test::GetVerifiedCreditCard());
  controller()->GetTestingManager()->AddTestingCreditCard(&card);
  AutofillProfile profile(test::GetVerifiedProfile());
  controller()->GetTestingManager()->AddTestingProfile(&profile);

  EXPECT_FALSE(controller()->IsManuallyEditingSection(SECTION_CC));
  EXPECT_FALSE(controller()->IsManuallyEditingSection(SECTION_BILLING));
  EXPECT_FALSE(controller()->IsManuallyEditingSection(SECTION_SHIPPING));

  GetViewTester()->CancelForTesting();
  RunMessageLoop();

  EXPECT_EQ(AutofillMetrics::DIALOG_CANCELED,
            metric_logger().dialog_dismissal_action());
}

IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, AcceptWithSuggestions) {
  EXPECT_CALL(metric_logger(),
              LogDialogDismissalState(
                  AutofillMetrics::DIALOG_ACCEPTED_EXISTING_AUTOFILL_DATA));

  CreditCard card(test::GetVerifiedCreditCard());
  controller()->GetTestingManager()->AddTestingCreditCard(&card);
  AutofillProfile profile(test::GetVerifiedProfile());
  controller()->GetTestingManager()->AddTestingProfile(&profile);

  EXPECT_FALSE(controller()->IsManuallyEditingSection(SECTION_CC));
  EXPECT_FALSE(controller()->IsManuallyEditingSection(SECTION_BILLING));
  EXPECT_FALSE(controller()->IsManuallyEditingSection(SECTION_SHIPPING));

  GetViewTester()->SubmitForTesting();
  RunMessageLoop();

  EXPECT_EQ(AutofillMetrics::DIALOG_ACCEPTED,
            metric_logger().dialog_dismissal_action());
}

// Ensure that Hide() will only destroy the controller object after the
// message loop has run. Otherwise, there may be read-after-free issues
// during some tests.
IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, DeferredDestruction) {
  base::WeakPtr<TestAutofillDialogController> weak_ptr =
      controller()->AsWeakPtr();
  EXPECT_TRUE(weak_ptr.get());

  controller()->Hide();
  EXPECT_TRUE(weak_ptr.get());

  RunMessageLoop();
  EXPECT_FALSE(weak_ptr.get());
}

// Ensure that the expected metric is logged when the dialog is closed during
// signin.
IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, CloseDuringSignin) {
  controller()->SignInLinkClicked();

  EXPECT_CALL(metric_logger(),
              LogDialogDismissalState(
                  AutofillMetrics::DIALOG_CANCELED_DURING_SIGNIN));
  GetViewTester()->CancelForTesting();

  RunMessageLoop();

  EXPECT_EQ(AutofillMetrics::DIALOG_CANCELED,
            metric_logger().dialog_dismissal_action());
}

IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, FillInputFromAutofill) {
  AutofillProfile full_profile(test::GetFullProfile());
  controller()->GetTestingManager()->AddTestingProfile(&full_profile);

  // Select "Add new shipping address...".
  ui::MenuModel* model = controller()->MenuModelForSection(SECTION_SHIPPING);
  model->ActivatedAt(model->GetItemCount() - 2);
  ASSERT_TRUE(controller()->IsManuallyEditingSection(SECTION_SHIPPING));

  const DetailInputs& inputs =
      controller()->RequestedFieldsForSection(SECTION_SHIPPING);
  const ServerFieldType triggering_type = inputs[0].type;
  base::string16 value = full_profile.GetRawInfo(triggering_type);
  scoped_ptr<AutofillDialogViewTester> view = GetViewTester();
  view->SetTextContentsOfInput(triggering_type,
                               value.substr(0, value.size() / 2));
  view->ActivateInput(triggering_type);

  ASSERT_EQ(triggering_type, controller()->popup_input_type());
  controller()->DidAcceptSuggestion(base::string16(), 0);

  // All inputs should be filled.
  AutofillProfileWrapper wrapper(&full_profile);
  for (size_t i = 0; i < inputs.size(); ++i) {
    EXPECT_EQ(wrapper.GetInfo(AutofillType(inputs[i].type)),
              view->GetTextContentsOfInput(inputs[i].type));
  }

  // Now simulate some user edits and try again.
  std::vector<base::string16> expectations;
  for (size_t i = 0; i < inputs.size(); ++i) {
    if (controller()->ComboboxModelForAutofillType(inputs[i].type)) {
      expectations.push_back(base::string16());
      continue;
    }
    base::string16 users_input = i % 2 == 0 ? base::string16()
                                            : ASCIIToUTF16("dummy");
    view->SetTextContentsOfInput(inputs[i].type, users_input);
    // Empty inputs should be filled, others should be left alone.
    base::string16 expectation =
        inputs[i].type == triggering_type || users_input.empty() ?
        wrapper.GetInfo(AutofillType(inputs[i].type)) :
        users_input;
    expectations.push_back(expectation);
  }

  view->SetTextContentsOfInput(triggering_type,
                               value.substr(0, value.size() / 2));
  view->ActivateInput(triggering_type);
  ASSERT_EQ(triggering_type, controller()->popup_input_type());
  controller()->DidAcceptSuggestion(base::string16(), 0);

  for (size_t i = 0; i < inputs.size(); ++i) {
    if (controller()->ComboboxModelForAutofillType(inputs[i].type))
      continue;
    EXPECT_EQ(expectations[i], view->GetTextContentsOfInput(inputs[i].type));
  }

  EXPECT_CALL(metric_logger(),
              LogDialogDismissalState(
                  AutofillMetrics::DIALOG_ACCEPTED_SAVE_TO_AUTOFILL));
  view->SubmitForTesting();
}

// This test makes sure that picking a profile variant in the Autofill
// popup works as expected.
IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest,
                       FillInputFromAutofillVariant) {
  AutofillProfile full_profile(test::GetFullProfile());

  // Set up some variant data.
  std::vector<base::string16> names;
  names.push_back(ASCIIToUTF16("John Doe"));
  names.push_back(ASCIIToUTF16("Jane Doe"));
  full_profile.SetRawMultiInfo(NAME_FULL, names);
  std::vector<base::string16> emails;
  emails.push_back(ASCIIToUTF16("user@example.com"));
  emails.push_back(ASCIIToUTF16("admin@example.com"));
  full_profile.SetRawMultiInfo(EMAIL_ADDRESS, emails);
  controller()->GetTestingManager()->AddTestingProfile(&full_profile);

  const DetailInputs& inputs =
      controller()->RequestedFieldsForSection(SECTION_BILLING);
  const ServerFieldType triggering_type = inputs[0].type;
  EXPECT_EQ(NAME_BILLING_FULL, triggering_type);
  scoped_ptr<AutofillDialogViewTester> view = GetViewTester();
  view->ActivateInput(triggering_type);

  ASSERT_EQ(triggering_type, controller()->popup_input_type());

  // Choose the variant suggestion.
  controller()->DidAcceptSuggestion(base::string16(), 1);

  // All inputs should be filled.
  AutofillProfileWrapper wrapper(
      &full_profile, AutofillType(NAME_BILLING_FULL), 1);
  for (size_t i = 0; i < inputs.size(); ++i) {
    EXPECT_EQ(wrapper.GetInfo(AutofillType(inputs[i].type)),
              view->GetTextContentsOfInput(inputs[i].type));
  }

  // Make sure the wrapper applies the variant index to the right group.
  EXPECT_EQ(names[1], wrapper.GetInfo(AutofillType(NAME_BILLING_FULL)));
  // Make sure the wrapper doesn't apply the variant index to the wrong group.
  EXPECT_EQ(emails[0], wrapper.GetInfo(AutofillType(EMAIL_ADDRESS)));
}

// Tests that changing the value of a CC expiration date combobox works as
// expected when Autofill is used to fill text inputs.
//
// Flaky on Win7, WinXP, and Win Aura.  http://crbug.com/270314.
#if defined(OS_WIN)
#define MAYBE_FillComboboxFromAutofill DISABLED_FillComboboxFromAutofill
#else
#define MAYBE_FillComboboxFromAutofill FillComboboxFromAutofill
#endif
IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest,
                       MAYBE_FillComboboxFromAutofill) {
  CreditCard card1;
  test::SetCreditCardInfo(&card1, "JJ Smith", "4111111111111111", "12", "2018");
  controller()->GetTestingManager()->AddTestingCreditCard(&card1);
  CreditCard card2;
  test::SetCreditCardInfo(&card2, "B Bird", "3111111111111111", "11", "2017");
  controller()->GetTestingManager()->AddTestingCreditCard(&card2);
  AutofillProfile full_profile(test::GetFullProfile());
  controller()->GetTestingManager()->AddTestingProfile(&full_profile);

  const DetailInputs& inputs =
      controller()->RequestedFieldsForSection(SECTION_CC);
  const ServerFieldType triggering_type = inputs[0].type;
  base::string16 value = card1.GetRawInfo(triggering_type);
  scoped_ptr<AutofillDialogViewTester> view = GetViewTester();
  view->SetTextContentsOfInput(triggering_type,
                               value.substr(0, value.size() / 2));
  view->ActivateInput(triggering_type);

  ASSERT_EQ(triggering_type, controller()->popup_input_type());
  controller()->DidAcceptSuggestion(base::string16(), 0);

  // All inputs should be filled.
  AutofillCreditCardWrapper wrapper1(&card1);
  for (size_t i = 0; i < inputs.size(); ++i) {
    EXPECT_EQ(wrapper1.GetInfo(AutofillType(inputs[i].type)),
              view->GetTextContentsOfInput(inputs[i].type));
  }

  // Try again with different data. Only expiration date and the triggering
  // input should be overwritten.
  value = card2.GetRawInfo(triggering_type);
  view->SetTextContentsOfInput(triggering_type,
                               value.substr(0, value.size() / 2));
  view->ActivateInput(triggering_type);
  ASSERT_EQ(triggering_type, controller()->popup_input_type());
  controller()->DidAcceptSuggestion(base::string16(), 0);

  AutofillCreditCardWrapper wrapper2(&card2);
  for (size_t i = 0; i < inputs.size(); ++i) {
    const ServerFieldType type = inputs[i].type;
    if (type == triggering_type ||
        type == CREDIT_CARD_EXP_MONTH ||
        type == CREDIT_CARD_EXP_4_DIGIT_YEAR) {
      EXPECT_EQ(wrapper2.GetInfo(AutofillType(type)),
                view->GetTextContentsOfInput(type));
    } else if (type == CREDIT_CARD_VERIFICATION_CODE) {
      EXPECT_TRUE(view->GetTextContentsOfInput(type).empty());
    } else {
      EXPECT_EQ(wrapper1.GetInfo(AutofillType(type)),
                view->GetTextContentsOfInput(type));
    }
  }

  // Now fill from a profile. It should not overwrite any CC info.
  const DetailInputs& billing_inputs =
      controller()->RequestedFieldsForSection(SECTION_BILLING);
  const ServerFieldType billing_triggering_type = billing_inputs[0].type;
  value = full_profile.GetRawInfo(triggering_type);
  view->SetTextContentsOfInput(billing_triggering_type,
                               value.substr(0, value.size() / 2));
  view->ActivateInput(billing_triggering_type);

  ASSERT_EQ(billing_triggering_type, controller()->popup_input_type());
  controller()->DidAcceptSuggestion(base::string16(), 0);

  for (size_t i = 0; i < inputs.size(); ++i) {
    const ServerFieldType type = inputs[i].type;
    if (type == triggering_type ||
        type == CREDIT_CARD_EXP_MONTH ||
        type == CREDIT_CARD_EXP_4_DIGIT_YEAR) {
      EXPECT_EQ(wrapper2.GetInfo(AutofillType(type)),
                view->GetTextContentsOfInput(type));
    } else if (type == CREDIT_CARD_VERIFICATION_CODE) {
      EXPECT_TRUE(view->GetTextContentsOfInput(type).empty());
    } else {
      EXPECT_EQ(wrapper1.GetInfo(AutofillType(type)),
                view->GetTextContentsOfInput(type));
    }
  }
}

IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, ShouldShowErrorBubble) {
  controller()->set_use_validation(true);
  EXPECT_TRUE(controller()->ShouldShowErrorBubble());

  CreditCard card(test::GetCreditCard());
  ASSERT_FALSE(card.IsVerified());
  controller()->GetTestingManager()->AddTestingCreditCard(&card);

  EXPECT_TRUE(controller()->IsManuallyEditingSection(SECTION_CC));
  scoped_ptr<AutofillDialogViewTester> view = GetViewTester();
  view->SetTextContentsOfInput(
      CREDIT_CARD_NUMBER,
      card.GetRawInfo(CREDIT_CARD_NUMBER).substr(0, 1));

  view->ActivateInput(CREDIT_CARD_NUMBER);
  EXPECT_FALSE(controller()->ShouldShowErrorBubble());

  controller()->FocusMoved();
  EXPECT_TRUE(controller()->ShouldShowErrorBubble());

  EXPECT_CALL(metric_logger(),
              LogDialogDismissalState(
                  AutofillMetrics::DIALOG_CANCELED_WITH_INVALID_FIELDS));
  controller()->Hide();
}

// Ensure that expired cards trigger invalid suggestions.
IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, ExpiredCard) {
  CreditCard verified_card(test::GetCreditCard());
  verified_card.set_origin("Chrome settings");
  ASSERT_TRUE(verified_card.IsVerified());
  controller()->GetTestingManager()->AddTestingCreditCard(&verified_card);

  CreditCard expired_card(test::GetCreditCard());
  expired_card.set_origin("Chrome settings");
  expired_card.SetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR, ASCIIToUTF16("2007"));
  ASSERT_TRUE(expired_card.IsVerified());
  ASSERT_FALSE(
      autofill::IsValidCreditCardExpirationDate(
          expired_card.GetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR),
          expired_card.GetRawInfo(CREDIT_CARD_EXP_MONTH),
          base::Time::Now()));
  controller()->GetTestingManager()->AddTestingCreditCard(&expired_card);

  ui::MenuModel* model = controller()->MenuModelForSection(SECTION_CC);
  ASSERT_EQ(4, model->GetItemCount());

  ASSERT_TRUE(model->IsItemCheckedAt(0));
  EXPECT_FALSE(controller()->IsEditingExistingData(SECTION_CC));

  model->ActivatedAt(1);
  ASSERT_TRUE(model->IsItemCheckedAt(1));
  EXPECT_TRUE(controller()->IsEditingExistingData(SECTION_CC));
}

// Notifications with long message text should not make the dialog bigger.
IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, LongNotifications) {
  const gfx::Size no_notification_size = GetViewTester()->GetSize();
  ASSERT_GT(no_notification_size.width(), 0);

  std::vector<DialogNotification> notifications;
  notifications.push_back(
      DialogNotification(DialogNotification::DEVELOPER_WARNING, ASCIIToUTF16(
          "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
          "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim "
          "ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut "
          "aliquip ex ea commodo consequat. Duis aute irure dolor in "
          "reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla "
          "pariatur. Excepteur sint occaecat cupidatat non proident, sunt in "
          "culpa qui officia deserunt mollit anim id est laborum.")));
  controller()->set_notifications(notifications);
  controller()->view()->UpdateNotificationArea();

  EXPECT_EQ(no_notification_size.width(),
            GetViewTester()->GetSize().width());
}

IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, AutocompleteEvent) {
  AutofillDialogControllerImpl* controller =
      SetUpHtmlAndInvoke("<input autocomplete='cc-name'>");
  ASSERT_TRUE(controller);

  AddCreditcardToProfile(controller->profile(), test::GetVerifiedCreditCard());
  AddAutofillProfileToProfile(controller->profile(),
                              test::GetVerifiedProfile());

  scoped_ptr<AutofillDialogViewTester> view =
      AutofillDialogViewTester::For(
          static_cast<TestAutofillDialogController*>(controller)->view());
  view->SetTextContentsOfSuggestionInput(SECTION_CC, ASCIIToUTF16("123"));
  view->SubmitForTesting();
  ExpectDomMessage("success");
}

IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest,
                       AutocompleteErrorEventReasonInvalid) {
  AutofillDialogControllerImpl* controller =
      SetUpHtmlAndInvoke("<input autocomplete='cc-name' pattern='.*zebra.*'>");
  ASSERT_TRUE(controller);

  const CreditCard& credit_card = test::GetVerifiedCreditCard();
  ASSERT_TRUE(
    credit_card.GetRawInfo(CREDIT_CARD_NAME).find(ASCIIToUTF16("zebra")) ==
        base::string16::npos);
  AddCreditcardToProfile(controller->profile(), credit_card);
  AddAutofillProfileToProfile(controller->profile(),
                              test::GetVerifiedProfile());

  scoped_ptr<AutofillDialogViewTester> view =
      AutofillDialogViewTester::For(
          static_cast<TestAutofillDialogController*>(controller)->view());
  view->SetTextContentsOfSuggestionInput(SECTION_CC, ASCIIToUTF16("123"));
  view->SubmitForTesting();
  ExpectDomMessage("error: invalid");
}

IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest,
                       AutocompleteErrorEventReasonCancel) {
  AutofillDialogControllerImpl* controller =
      SetUpHtmlAndInvoke("<input autocomplete='cc-name'>");
  ASSERT_TRUE(controller);
  AutofillDialogViewTester::For(
      static_cast<TestAutofillDialogController*>(controller)->view())->
          CancelForTesting();
  ExpectDomMessage("error: cancel");
}

// http://crbug.com/318526
#if defined(OS_MACOSX)
#define MAYBE_ErrorWithFrameNavigation DISABLED_ErrorWithFrameNavigation
#else
#define MAYBE_ErrorWithFrameNavigation ErrorWithFrameNavigation
#endif
IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest,
                       MAYBE_ErrorWithFrameNavigation) {
  AutofillDialogControllerImpl* controller =
      SetUpHtmlAndInvoke("<input autocomplete='cc-name'>");
  ASSERT_TRUE(controller);

  std::string unused;
  ASSERT_TRUE(content::ExecuteScriptAndExtractString(GetRenderViewHost(),
                                                     "loadIframe();",
                                                     &unused));
  ExpectDomMessage("iframe loaded");

  AutofillDialogViewTester::For(
      static_cast<TestAutofillDialogController*>(controller)->view())->
          CancelForTesting();
  ExpectDomMessage("error: cancel");
}

IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, NoCvcSegfault) {
  controller()->set_use_validation(true);

  CreditCard credit_card(test::GetVerifiedCreditCard());
  controller()->GetTestingManager()->AddTestingCreditCard(&credit_card);
  EXPECT_FALSE(controller()->IsEditingExistingData(SECTION_CC));

  ASSERT_NO_FATAL_FAILURE(GetViewTester()->SubmitForTesting());
}

// Flaky on Win7, WinXP, and Win Aura.  http://crbug.com/270314.
#if defined(OS_WIN)
#define MAYBE_PreservedSections DISABLED_PreservedSections
#else
#define MAYBE_PreservedSections PreservedSections
#endif
IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, MAYBE_PreservedSections) {
  controller()->set_use_validation(true);

  scoped_ptr<AutofillDialogViewTester> view = GetViewTester();
  view->SetTextContentsOfInput(CREDIT_CARD_NUMBER,
                               ASCIIToUTF16("4111111111111111"));

  // Create some invalid, manually inputted shipping data.
  view->SetTextContentsOfInput(ADDRESS_HOME_ZIP, ASCIIToUTF16("shipping zip"));

  // Switch to Wallet by simulating a successful server response.
  controller()->OnDidFetchWalletCookieValue(std::string());
  controller()->OnDidGetWalletItems(
      wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED));
  ASSERT_TRUE(controller()->IsPayingWithWallet());

  // The valid data should be preserved.
  EXPECT_EQ(ASCIIToUTF16("4111111111111111"),
            view->GetTextContentsOfInput(CREDIT_CARD_NUMBER));

  // The invalid data should be dropped.
  EXPECT_TRUE(view->GetTextContentsOfInput(ADDRESS_HOME_ZIP).empty());

  // Switch back to Autofill.
  ui::MenuModel* account_chooser = controller()->MenuModelForAccountChooser();
  account_chooser->ActivatedAt(account_chooser->GetItemCount() - 1);
  ASSERT_FALSE(controller()->IsPayingWithWallet());

  // The valid data should still be preserved when switched back.
  EXPECT_EQ(ASCIIToUTF16("4111111111111111"),
            view->GetTextContentsOfInput(CREDIT_CARD_NUMBER));
}

IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest,
                       GeneratedCardLastFourAfterVerifyCvv) {
  controller()->OnDidFetchWalletCookieValue(std::string());

  scoped_ptr<wallet::WalletItems> wallet_items =
      wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED);
  wallet_items->AddInstrument(wallet::GetTestMaskedInstrument());
  wallet_items->AddAddress(wallet::GetTestShippingAddress());

  base::string16 last_four =
      wallet_items->instruments()[0]->TypeAndLastFourDigits();
  controller()->OnDidGetWalletItems(wallet_items.Pass());

  scoped_ptr<AutofillDialogViewTester> test_view = GetViewTester();
  EXPECT_FALSE(test_view->IsShowingOverlay());
  EXPECT_CALL(*controller(), LoadRiskFingerprintData());
  controller()->OnAccept();
  EXPECT_TRUE(test_view->IsShowingOverlay());

  EXPECT_CALL(*controller()->GetTestingWalletClient(), GetFullWallet(_));
  scoped_ptr<risk::Fingerprint> fingerprint(new risk::Fingerprint());
  fingerprint->mutable_machine_characteristics()->mutable_screen_size()->
      set_width(1024);
  controller()->OnDidLoadRiskFingerprintData(fingerprint.Pass());

  controller()->OnDidGetFullWallet(
      wallet::GetTestFullWalletWithRequiredActions(
          std::vector<wallet::RequiredAction>(1, wallet::VERIFY_CVV)));

  ASSERT_TRUE(controller()->IsSubmitPausedOn(wallet::VERIFY_CVV));

  std::string fake_cvc("123");
  test_view->SetTextContentsOfSuggestionInput(SECTION_CC_BILLING,
                                              ASCIIToUTF16(fake_cvc));

  EXPECT_FALSE(test_view->IsShowingOverlay());
  EXPECT_CALL(*controller()->GetTestingWalletClient(),
              AuthenticateInstrument(_, fake_cvc));
  controller()->OnAccept();
  EXPECT_TRUE(test_view->IsShowingOverlay());

  EXPECT_CALL(metric_logger(),
              LogDialogDismissalState(
                  AutofillMetrics::DIALOG_ACCEPTED_EXISTING_WALLET_DATA));

  EXPECT_CALL(*controller()->GetTestingWalletClient(), GetFullWallet(_));
  controller()->OnDidAuthenticateInstrument(true);
  controller()->OnDidGetFullWallet(wallet::GetTestFullWallet());
  controller()->ForceFinishSubmit();

  RunMessageLoop();

  EXPECT_EQ(1, test_generated_bubble_controller()->bubbles_shown());
  EXPECT_EQ(last_four, test_generated_bubble_controller()->backing_card_name());
}

// Simulates the user signing in to the dialog from the inline web contents.
IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, SimulateSuccessfulSignIn) {
#if defined(OS_WIN)
  // TODO(msw): Fix potential flakiness on Windows XP; http://crbug.com/333641
  if (base::win::GetVersion() <= base::win::VERSION_XP)
    return;
#endif
  browser()->profile()->GetPrefs()->SetBoolean(
      ::prefs::kAutofillDialogPayWithoutWallet,
      true);

  InitializeController();

  controller()->OnDidFetchWalletCookieValue(std::string());
  controller()->OnDidGetWalletItems(
      wallet::GetTestWalletItemsWithRequiredAction(wallet::GAIA_AUTH));

  NavEntryCommittedObserver sign_in_page_observer(
      controller()->SignInUrl(),
      content::NotificationService::AllSources());

  // Simulate a user clicking "Sign In" (which loads dialog's web contents).
  controller()->SignInLinkClicked();
  EXPECT_TRUE(controller()->ShouldShowSignInWebView());

  scoped_ptr<AutofillDialogViewTester> view = GetViewTester();
  content::WebContents* sign_in_contents = view->GetSignInWebContents();
  ASSERT_TRUE(sign_in_contents);

  sign_in_page_observer.Wait();

  NavEntryCommittedObserver continue_page_observer(
      wallet::GetSignInContinueUrl(),
      content::NotificationService::AllSources());

  EXPECT_EQ(sign_in_contents->GetURL(), controller()->SignInUrl());

  AccountChooserModel* account_chooser_model =
      controller()->AccountChooserModelForTesting();
  EXPECT_FALSE(account_chooser_model->WalletIsSelected());

  content::OpenURLParams params(wallet::GetSignInContinueUrl(),
                                content::Referrer(),
                                CURRENT_TAB,
                                content::PAGE_TRANSITION_LINK,
                                true);

  sign_in_contents->GetDelegate()->OpenURLFromTab(sign_in_contents, params);

  EXPECT_CALL(*controller()->GetTestingWalletClient(), GetWalletItems());
  continue_page_observer.Wait();
  content::RunAllPendingInMessageLoop();

  EXPECT_FALSE(controller()->ShouldShowSignInWebView());

  scoped_ptr<wallet::WalletItems> wallet_items =
      wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED);
  wallet_items->AddInstrument(wallet::GetTestMaskedInstrument());
  controller()->OnDidGetWalletItems(wallet_items.Pass());

  // Wallet should now be selected and Chrome shouldn't have crashed (which can
  // happen if the WebContents is deleted while proccessing a nav entry commit).
  EXPECT_TRUE(account_chooser_model->WalletIsSelected());
  EXPECT_FALSE(controller()->IsManuallyEditingSection(SECTION_CC_BILLING));
  EXPECT_FALSE(controller()->IsManuallyEditingSection(SECTION_SHIPPING));

  EXPECT_CALL(metric_logger(),
              LogDialogDismissalState(
                  AutofillMetrics::DIALOG_ACCEPTED_EXISTING_WALLET_DATA));
  view->SubmitForTesting();
  controller()->OnDidGetFullWallet(wallet::GetTestFullWallet());
  controller()->ForceFinishSubmit();
}

IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, AddAccount) {
#if defined(OS_WIN)
  // TODO(msw): Fix potential flakiness on Windows XP; http://crbug.com/333641
  if (base::win::GetVersion() <= base::win::VERSION_XP)
    return;
#endif

  controller()->OnDidFetchWalletCookieValue(std::string());
  std::vector<std::string> usernames;
  usernames.push_back("user_0@example.com");
  controller()->OnDidGetWalletItems(
      wallet::GetTestWalletItemsWithUsers(usernames, 0));

  // Switch to Autofill.
  AccountChooserModel* account_chooser_model =
      controller()->AccountChooserModelForTesting();
  account_chooser_model->ActivatedAt(
      account_chooser_model->GetItemCount() - 1);

  NavEntryCommittedObserver sign_in_page_observer(
      controller()->SignInUrl(),
      content::NotificationService::AllSources());

  // Simulate a user clicking "add account".
  account_chooser_model->ActivatedAt(
      account_chooser_model->GetItemCount() - 2);
  EXPECT_TRUE(controller()->ShouldShowSignInWebView());

  scoped_ptr<AutofillDialogViewTester> view = GetViewTester();
  content::WebContents* sign_in_contents = view->GetSignInWebContents();
  ASSERT_TRUE(sign_in_contents);

  sign_in_page_observer.Wait();

  NavEntryCommittedObserver continue_page_observer(
      wallet::GetSignInContinueUrl(),
      content::NotificationService::AllSources());

  EXPECT_EQ(sign_in_contents->GetURL(), controller()->SignInUrl());

  EXPECT_FALSE(account_chooser_model->WalletIsSelected());

  // User signs into new account, account 3.
  controller()->set_sign_in_user_index(3U);
  content::OpenURLParams params(wallet::GetSignInContinueUrl(),
                                content::Referrer(),
                                CURRENT_TAB,
                                content::PAGE_TRANSITION_LINK,
                                true);
  sign_in_contents->GetDelegate()->OpenURLFromTab(sign_in_contents, params);

  EXPECT_CALL(*controller()->GetTestingWalletClient(), GetWalletItems());
  continue_page_observer.Wait();
  content::RunAllPendingInMessageLoop();

  EXPECT_FALSE(controller()->ShouldShowSignInWebView());
  EXPECT_EQ(3U, controller()->GetTestingWalletClient()->user_index());

  usernames.push_back("user_1@example.com");
  usernames.push_back("user_2@example.com");
  usernames.push_back("user_3@example.com");
  usernames.push_back("user_4@example.com");
  // Curveball: wallet items comes back with user 4 selected.
  controller()->OnDidGetWalletItems(
      wallet::GetTestWalletItemsWithUsers(usernames, 4U));

  EXPECT_TRUE(account_chooser_model->WalletIsSelected());
  EXPECT_EQ(4U, account_chooser_model->GetActiveWalletAccountIndex());
  EXPECT_EQ(4U, controller()->GetTestingWalletClient()->user_index());
}

// Verify that filling a form works correctly, including filling the CVC when
// that is requested separately.
IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest,
                       FillFormIncludesCVC) {
  AutofillDialogControllerImpl* controller =
      SetUpHtmlAndInvoke("<input autocomplete='cc-csc'>");
  ASSERT_TRUE(controller);

  AddCreditcardToProfile(controller->profile(), test::GetVerifiedCreditCard());
  AddAutofillProfileToProfile(controller->profile(),
                              test::GetVerifiedProfile());

  scoped_ptr<AutofillDialogViewTester> view =
      AutofillDialogViewTester::For(
          static_cast<TestAutofillDialogController*>(controller)->view());
  view->SetTextContentsOfSuggestionInput(SECTION_CC, ASCIIToUTF16("123"));
  view->SubmitForTesting();
  ExpectDomMessage("success");
  EXPECT_EQ("123", GetValueForHTMLFieldOfType("cc-csc"));
}

IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, AddNewClearsComboboxes) {
  // Ensure the input under test is a combobox.
  ASSERT_TRUE(
      controller()->ComboboxModelForAutofillType(CREDIT_CARD_EXP_MONTH));

  // Set up an expired card.
  CreditCard card;
  test::SetCreditCardInfo(&card, "Roy Demeo", "4111111111111111", "8", "2013");
  card.set_origin("Chrome settings");
  ASSERT_TRUE(card.IsVerified());

  // Add the card and check that there's a menu for that section.
  controller()->GetTestingManager()->AddTestingCreditCard(&card);
  ASSERT_TRUE(controller()->MenuModelForSection(SECTION_CC));

  // Select the invalid, suggested card from the menu.
  controller()->MenuModelForSection(SECTION_CC)->ActivatedAt(0);
  EXPECT_TRUE(controller()->IsEditingExistingData(SECTION_CC));

  // Get the contents of the combobox of the credit card's expiration month.
  scoped_ptr<AutofillDialogViewTester> view = GetViewTester();
  base::string16 cc_exp_month_text =
      view->GetTextContentsOfInput(CREDIT_CARD_EXP_MONTH);

  // Select "New X..." from the suggestion menu to clear the section's inputs.
  controller()->MenuModelForSection(SECTION_CC)->ActivatedAt(1);
  EXPECT_FALSE(controller()->IsEditingExistingData(SECTION_CC));

  // Ensure that the credit card expiration month has changed.
  EXPECT_NE(cc_exp_month_text,
            view->GetTextContentsOfInput(CREDIT_CARD_EXP_MONTH));
}

IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, TabOpensToJustRight) {
  ASSERT_TRUE(browser()->is_type_tabbed());

  // Tabs should currently be: / rAc() \.
  content::WebContents* dialog_invoker = controller()->GetWebContents();
  EXPECT_EQ(dialog_invoker, GetActiveWebContents());

  TabStripModel* tab_strip = browser()->tab_strip_model();
  ASSERT_EQ(1, tab_strip->count());
  EXPECT_EQ(0, tab_strip->GetIndexOfWebContents(dialog_invoker));

  // Open a tab to about:blank in the background at the end of the tab strip.
  chrome::AddTabAt(browser(), GURL(), -1, false);
  // Tabs should now be: / rAc() \/ blank \.
  EXPECT_EQ(2, tab_strip->count());
  EXPECT_EQ(0, tab_strip->active_index());
  EXPECT_EQ(dialog_invoker, GetActiveWebContents());

  content::WebContents* blank_tab = tab_strip->GetWebContentsAt(1);

  // Simulate clicking "Manage X...".
  controller()->MenuModelForSection(SECTION_SHIPPING)->ActivatedAt(2);
  // Tab should now be: / rAc() \/ manage 1 \/ blank \.
  EXPECT_EQ(3, tab_strip->count());
  int dialog_index = tab_strip->GetIndexOfWebContents(dialog_invoker);
  EXPECT_EQ(0, dialog_index);
  EXPECT_EQ(1, tab_strip->active_index());
  EXPECT_EQ(2, tab_strip->GetIndexOfWebContents(blank_tab));

  content::WebContents* first_manage_tab = tab_strip->GetWebContentsAt(1);

  // Re-activate the dialog's tab (like a user would have to).
  tab_strip->ActivateTabAt(dialog_index, true);
  EXPECT_EQ(dialog_invoker, GetActiveWebContents());

  // Simulate clicking "Manage X...".
  controller()->MenuModelForSection(SECTION_SHIPPING)->ActivatedAt(2);
  // Tabs should now be: / rAc() \/ manage 2 \/ manage 1 \/ blank \.
  EXPECT_EQ(4, tab_strip->count());
  EXPECT_EQ(0, tab_strip->GetIndexOfWebContents(dialog_invoker));
  EXPECT_EQ(1, tab_strip->active_index());
  EXPECT_EQ(2, tab_strip->GetIndexOfWebContents(first_manage_tab));
  EXPECT_EQ(3, tab_strip->GetIndexOfWebContents(blank_tab));
}

IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest,
                       SignInWebViewOpensLinksInNewTab) {
  controller()->OnDidFetchWalletCookieValue(std::string());
  controller()->OnDidGetWalletItems(
      wallet::GetTestWalletItemsWithRequiredAction(wallet::GAIA_AUTH));

  NavEntryCommittedObserver sign_in_page_observer(
      controller()->SignInUrl(),
      content::NotificationService::AllSources());

  controller()->SignInLinkClicked();

  content::WebContents* sign_in_contents =
      GetViewTester()->GetSignInWebContents();
  ASSERT_TRUE(sign_in_contents);

  sign_in_page_observer.Wait();

  content::OpenURLParams params(GURL("http://google.com"),
                                content::Referrer(),
                                CURRENT_TAB,
                                content::PAGE_TRANSITION_LINK,
                                true);
  params.user_gesture = true;

  int num_tabs = browser()->tab_strip_model()->count();
  sign_in_contents->GetDelegate()->OpenURLFromTab(sign_in_contents, params);
  EXPECT_EQ(num_tabs + 1, browser()->tab_strip_model()->count());
}

IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, RefreshOnManageTabClose) {
  ASSERT_TRUE(browser()->is_type_tabbed());

  // GetWalletItems() is called when controller() is created in SetUp().
  EXPECT_CALL(*controller()->GetTestingWalletClient(), GetWalletItems());
  controller()->OnDidFetchWalletCookieValue(std::string());
  controller()->OnDidGetWalletItems(
      wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED));

  content::WebContents* dialog_invoker = controller()->GetWebContents();
  TabAutofillManagerDelegate::FromWebContents(dialog_invoker)->
      SetDialogControllerForTesting(controller()->AsWeakPtr());

  // Open a new tab by selecting "Manage my shipping details..." in Wallet mode.
  EXPECT_EQ(1, browser()->tab_strip_model()->count());
  controller()->MenuModelForSection(SECTION_SHIPPING)->ActivatedAt(2);
  EXPECT_EQ(2, browser()->tab_strip_model()->count());
  ASSERT_NE(dialog_invoker, GetActiveWebContents());

  // Closing the tab opened by "Manage my shipping details..." should refresh
  // the dialog.
  controller()->ClearLastWalletItemsFetchTimestampForTesting();
  EXPECT_CALL(*controller()->GetTestingWalletClient(), GetWalletItems());
  GetActiveWebContents()->Close();
}

// Changes from Wallet to Autofill and verifies that the combined billing/cc
// sections are showing (or not) at the correct times.
IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest,
                       ChangingDataSourceShowsCorrectSections) {
  scoped_ptr<AutofillDialogViewTester> view = GetViewTester();
  EXPECT_TRUE(view->IsShowingSection(SECTION_CC));
  EXPECT_TRUE(view->IsShowingSection(SECTION_BILLING));
  EXPECT_FALSE(view->IsShowingSection(SECTION_CC_BILLING));

  // Switch the dialog to paying with Wallet.
  controller()->OnDidFetchWalletCookieValue(std::string());
  controller()->OnDidGetWalletItems(
      wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED));
  ASSERT_TRUE(controller()->IsPayingWithWallet());

  EXPECT_FALSE(view->IsShowingSection(SECTION_CC));
  EXPECT_FALSE(view->IsShowingSection(SECTION_BILLING));
  EXPECT_TRUE(view->IsShowingSection(SECTION_CC_BILLING));

  // Now switch back to Autofill to ensure this direction works as well.
  ui::MenuModel* account_chooser = controller()->MenuModelForAccountChooser();
  account_chooser->ActivatedAt(account_chooser->GetItemCount() - 1);

  EXPECT_TRUE(view->IsShowingSection(SECTION_CC));
  EXPECT_TRUE(view->IsShowingSection(SECTION_BILLING));
  EXPECT_FALSE(view->IsShowingSection(SECTION_CC_BILLING));
}

IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest,
                       DoesWorkOnHttpWithFlag) {
  net::SpawnedTestServer http_server(
      net::SpawnedTestServer::TYPE_HTTP,
      net::SpawnedTestServer::kLocalhost,
      base::FilePath(FILE_PATH_LITERAL("chrome/test/data")));
  ASSERT_TRUE(http_server.Start());
  EXPECT_TRUE(RunTestPage(http_server));
}

// Like the parent test, but doesn't add the --reduce-security-for-testing flag.
class AutofillDialogControllerSecurityTest :
    public AutofillDialogControllerTest {
 public:
  AutofillDialogControllerSecurityTest() {}
  virtual ~AutofillDialogControllerSecurityTest() {}

  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
    CHECK(!command_line->HasSwitch(::switches::kReduceSecurityForTesting));
  }

  typedef net::BaseTestServer::SSLOptions SSLOptions;

 private:
  DISALLOW_COPY_AND_ASSIGN(AutofillDialogControllerSecurityTest);
};

IN_PROC_BROWSER_TEST_F(AutofillDialogControllerSecurityTest,
                       DoesntWorkOnHttp) {
  net::SpawnedTestServer http_server(
      net::SpawnedTestServer::TYPE_HTTP,
      net::SpawnedTestServer::kLocalhost,
      base::FilePath(FILE_PATH_LITERAL("chrome/test/data")));
  ASSERT_TRUE(http_server.Start());
  EXPECT_FALSE(RunTestPage(http_server));
}

IN_PROC_BROWSER_TEST_F(AutofillDialogControllerSecurityTest,
                       DoesWorkOnHttpWithFlags) {
  net::SpawnedTestServer https_server(
      net::SpawnedTestServer::TYPE_HTTPS,
      SSLOptions(SSLOptions::CERT_OK),
      base::FilePath(FILE_PATH_LITERAL("chrome/test/data")));
  ASSERT_TRUE(https_server.Start());
  EXPECT_TRUE(RunTestPage(https_server));
}

IN_PROC_BROWSER_TEST_F(AutofillDialogControllerSecurityTest,
                       DoesntWorkOnBrokenHttps) {
  net::SpawnedTestServer https_server(
      net::SpawnedTestServer::TYPE_HTTPS,
      SSLOptions(SSLOptions::CERT_EXPIRED),
      base::FilePath(FILE_PATH_LITERAL("chrome/test/data")));
  ASSERT_TRUE(https_server.Start());
  EXPECT_FALSE(RunTestPage(https_server));
}

IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest,
                       CountryChangeRebuildsSection) {
  EXPECT_FALSE(SectionHasField(SECTION_BILLING, ADDRESS_BILLING_SORTING_CODE));
  EXPECT_FALSE(SectionHasField(SECTION_SHIPPING, ADDRESS_HOME_SORTING_CODE));

  // Select "Add new shipping address...".
  controller()->MenuModelForSection(SECTION_SHIPPING)->ActivatedAt(1);

  // Add some valid user input that should be preserved when country changes.
  scoped_ptr<AutofillDialogViewTester> view = GetViewTester();
  view->SetTextContentsOfInput(NAME_FULL, ASCIIToUTF16("B. Loblaw"));

  // Change both sections' countries.
  view->SetTextContentsOfInput(ADDRESS_BILLING_COUNTRY, ASCIIToUTF16("France"));
  view->ActivateInput(ADDRESS_BILLING_COUNTRY);
  view->SetTextContentsOfInput(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("Belarus"));
  view->ActivateInput(ADDRESS_HOME_COUNTRY);

  // Verify the name is still there.
  EXPECT_EQ(ASCIIToUTF16("B. Loblaw"), view->GetTextContentsOfInput(NAME_FULL));

  EXPECT_TRUE(SectionHasField(SECTION_BILLING, ADDRESS_BILLING_SORTING_CODE));
  EXPECT_TRUE(SectionHasField(SECTION_SHIPPING, ADDRESS_HOME_SORTING_CODE));
}

// Changing the data source to or from Wallet preserves the shipping country,
// but not the billing country because Wallet only supports US billing
// addresses.
IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest,
                       ChangingDataSourcePreservesCountry) {
  InitializeControllerWithoutShowing();
  controller()->GetTestingManager()->set_default_country_code("CA");
  controller()->Show();
  CycleRunLoops();

  AutofillProfile verified_profile(test::GetVerifiedProfile());
  controller()->GetTestingManager()->AddTestingProfile(&verified_profile);

  CreditCard verified_card(test::GetVerifiedCreditCard());
  controller()->GetTestingManager()->AddTestingCreditCard(&verified_card);
  EXPECT_FALSE(controller()->IsManuallyEditingSection(SECTION_SHIPPING));

  controller()->OnDidFetchWalletCookieValue(std::string());
  scoped_ptr<wallet::WalletItems> items =
      wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED);
  items->AddAccount(wallet::GetTestGaiaAccount());
  items->AddInstrument(wallet::GetTestMaskedInstrument());
  items->AddAddress(wallet::GetTestShippingAddress());
  controller()->OnDidGetWalletItems(items.Pass());

  EXPECT_TRUE(controller()->IsPayingWithWallet());

  // Select "Add new shipping address...".
  controller()->MenuModelForSection(SECTION_SHIPPING)->ActivatedAt(2);
  EXPECT_TRUE(controller()->IsManuallyEditingSection(SECTION_SHIPPING));

  // Default shipping country matches PDM's default, but default billing is
  // always US in Wallet mode.
  scoped_ptr<AutofillDialogViewTester> view = GetViewTester();
  ASSERT_EQ(ASCIIToUTF16("Canada"),
            view->GetTextContentsOfInput(ADDRESS_HOME_COUNTRY));
  ASSERT_EQ(ASCIIToUTF16("United States"),
            view->GetTextContentsOfInput(ADDRESS_BILLING_COUNTRY));

  // Switch the shipping country.
  view->SetTextContentsOfInput(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("Belarus"));
  EXPECT_EQ(ASCIIToUTF16("Belarus"),
            view->GetTextContentsOfInput(ADDRESS_HOME_COUNTRY));
  view->ActivateInput(ADDRESS_HOME_COUNTRY);

  // Switch to using Autofill instead of Wallet.
  ui::MenuModel* account_chooser = controller()->MenuModelForAccountChooser();
  account_chooser->ActivatedAt(account_chooser->GetItemCount() - 1);

  EXPECT_FALSE(controller()->IsPayingWithWallet());

  // Shipping country should have stayed the same.
  EXPECT_EQ(ASCIIToUTF16("Belarus"),
            view->GetTextContentsOfInput(ADDRESS_HOME_COUNTRY));
  ASSERT_TRUE(SectionHasField(SECTION_SHIPPING, ADDRESS_HOME_SORTING_CODE));

  controller()->MenuModelForSection(SECTION_BILLING)->ActivatedAt(1);
  view->SetTextContentsOfInput(ADDRESS_BILLING_COUNTRY,
                               ASCIIToUTF16("Belarus"));
  view->ActivateInput(ADDRESS_BILLING_COUNTRY);
  EXPECT_EQ(ASCIIToUTF16("Belarus"),
            view->GetTextContentsOfInput(ADDRESS_BILLING_COUNTRY));
  ASSERT_TRUE(SectionHasField(SECTION_BILLING, ADDRESS_BILLING_SORTING_CODE));

  // Switch back to Wallet. Country should go back to US.
  account_chooser->ActivatedAt(0);
  EXPECT_EQ(ASCIIToUTF16("United States"),
            view->GetTextContentsOfInput(ADDRESS_BILLING_COUNTRY));
  ASSERT_FALSE(
      SectionHasField(SECTION_CC_BILLING, ADDRESS_BILLING_SORTING_CODE));

  // Make sure shipping is still on Belarus.
  EXPECT_EQ(ASCIIToUTF16("Belarus"),
            view->GetTextContentsOfInput(ADDRESS_HOME_COUNTRY));
  ASSERT_TRUE(SectionHasField(SECTION_SHIPPING, ADDRESS_HOME_SORTING_CODE));
}

IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, AddNewResetsCountry) {
  AutofillProfile verified_profile(test::GetVerifiedProfile());
  controller()->GetTestingManager()->AddTestingProfile(&verified_profile);

  // Select "Add new billing/shipping address...".
  controller()->MenuModelForSection(SECTION_BILLING)->ActivatedAt(1);
  controller()->MenuModelForSection(SECTION_SHIPPING)->ActivatedAt(2);

  scoped_ptr<AutofillDialogViewTester> view = GetViewTester();
  ASSERT_EQ(ASCIIToUTF16("United States"),
            view->GetTextContentsOfInput(ADDRESS_BILLING_COUNTRY));
  ASSERT_EQ(ASCIIToUTF16("United States"),
            view->GetTextContentsOfInput(ADDRESS_HOME_COUNTRY));

  // Switch both billing and shipping countries.
  view->SetTextContentsOfInput(ADDRESS_BILLING_COUNTRY, ASCIIToUTF16("Brazil"));
  view->ActivateInput(ADDRESS_BILLING_COUNTRY);
  view->SetTextContentsOfInput(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("France"));
  view->ActivateInput(ADDRESS_HOME_COUNTRY);

  // Select "Add new billing/shipping address...".
  controller()->MenuModelForSection(SECTION_BILLING)->ActivatedAt(1);
  controller()->MenuModelForSection(SECTION_SHIPPING)->ActivatedAt(2);

  EXPECT_EQ(ASCIIToUTF16("United States"),
            view->GetTextContentsOfInput(ADDRESS_BILLING_COUNTRY));
  EXPECT_EQ(ASCIIToUTF16("United States"),
            view->GetTextContentsOfInput(ADDRESS_HOME_COUNTRY));
}

IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest,
                       FillingFormRebuildsInputs) {
  AutofillProfile full_profile(test::GetFullProfile());
  full_profile.SetRawInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("DE"));
  controller()->GetTestingManager()->AddTestingProfile(&full_profile);

  // Select "Add new shipping address...".
  controller()->MenuModelForSection(SECTION_SHIPPING)->ActivatedAt(1);

  scoped_ptr<AutofillDialogViewTester> view = GetViewTester();
  ASSERT_EQ(ASCIIToUTF16("United States"),
            view->GetTextContentsOfInput(ADDRESS_BILLING_COUNTRY));
  ASSERT_EQ(ASCIIToUTF16("United States"),
            view->GetTextContentsOfInput(ADDRESS_HOME_COUNTRY));

  base::string16 name = full_profile.GetRawInfo(NAME_FULL);
  view->SetTextContentsOfInput(NAME_FULL, name.substr(0, name.size() / 2));
  view->ActivateInput(NAME_FULL);
  ASSERT_EQ(NAME_FULL, controller()->popup_input_type());
  controller()->DidAcceptSuggestion(base::string16(), 0);

  EXPECT_EQ(ASCIIToUTF16("Germany"),
            view->GetTextContentsOfInput(ADDRESS_BILLING_COUNTRY));
  EXPECT_EQ(ASCIIToUTF16("Germany"),
            view->GetTextContentsOfInput(ADDRESS_HOME_COUNTRY));
}

IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest,
                       FillingFormPreservesChangedCountry) {
  AutofillProfile full_profile(test::GetFullProfile());
  full_profile.SetRawInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("DE"));
  controller()->GetTestingManager()->AddTestingProfile(&full_profile);

  // Select "Add new shipping address...".
  controller()->MenuModelForSection(SECTION_SHIPPING)->ActivatedAt(1);

  scoped_ptr<AutofillDialogViewTester> view = GetViewTester();
  view->SetTextContentsOfInput(ADDRESS_BILLING_COUNTRY, ASCIIToUTF16("France"));
  view->ActivateInput(ADDRESS_BILLING_COUNTRY);
  view->SetTextContentsOfInput(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("Belarus"));
  view->ActivateInput(ADDRESS_HOME_COUNTRY);

  base::string16 name = full_profile.GetRawInfo(NAME_FULL);
  view->SetTextContentsOfInput(NAME_FULL, name.substr(0, name.size() / 2));
  view->ActivateInput(NAME_FULL);
  ASSERT_EQ(NAME_FULL, controller()->popup_input_type());
  controller()->DidAcceptSuggestion(base::string16(), 0);

  EXPECT_EQ(ASCIIToUTF16("France"),
            view->GetTextContentsOfInput(ADDRESS_BILLING_COUNTRY));
  EXPECT_EQ(ASCIIToUTF16("Belarus"),
            view->GetTextContentsOfInput(ADDRESS_HOME_COUNTRY));
}

IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, RulesLoaded) {
  // Select "Add new shipping address...".
  controller()->MenuModelForSection(SECTION_SHIPPING)->ActivatedAt(1);
  controller()->set_use_validation(true);

  EXPECT_CALL(*controller()->GetMockValidator(),
              ValidateAddress(CountryCodeMatcher("DE"), _, _)).Times(2).
              WillOnce(Return(AddressValidator::RULES_NOT_READY));

  // Validation should occur on country change and see the rules haven't loaded.
  scoped_ptr<AutofillDialogViewTester> view = GetViewTester();
  view->SetTextContentsOfInput(ADDRESS_HOME_ZIP, ASCIIToUTF16("123"));
  view->SetTextContentsOfInput(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("Germany"));
  view->ActivateInput(ADDRESS_HOME_COUNTRY);

  // Different country loaded, validation should not occur.
  controller()->OnAddressValidationRulesLoaded("FR", true);

  // Relevant country loaded, validation should occur.
  controller()->OnAddressValidationRulesLoaded("DE", true);

  // Relevant country loaded but revalidation already happened, no further
  // validation should occur.
  controller()->OnAddressValidationRulesLoaded("DE", false);

  // Cancelling the dialog causes additional validation to see if the user
  // cancelled with invalid fields, so verify and clear here.
  testing::Mock::VerifyAndClearExpectations(controller()->GetMockValidator());
}

}  // namespace autofill

/* [<][>][^][v][top][bottom][index][help] */