| // Copyright 2014 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 <algorithm> |
| #include <vector> |
| |
| #include "base/command_line.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "components/autofill/content/browser/content_autofill_driver.h" |
| #include "components/autofill/content/common/autofill_messages.h" |
| #include "components/autofill/core/browser/autofill_external_delegate.h" |
| #include "components/autofill/core/browser/autofill_manager.h" |
| #include "components/autofill/core/browser/autofill_test_utils.h" |
| #include "components/autofill/core/browser/test_autofill_client.h" |
| #include "components/autofill/core/common/autofill_switches.h" |
| #include "components/autofill/core/common/form_data_predictions.h" |
| #include "content/public/browser/browser_context.h" |
| #include "content/public/browser/navigation_details.h" |
| #include "content/public/browser/web_contents.h" |
| #include "content/public/common/frame_navigate_params.h" |
| #include "content/public/test/mock_render_process_host.h" |
| #include "content/public/test/test_renderer_host.h" |
| #include "ipc/ipc_test_sink.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace autofill { |
| |
| namespace { |
| |
| const std::string kAppLocale = "en-US"; |
| const AutofillManager::AutofillDownloadManagerState kDownloadState = |
| AutofillManager::DISABLE_AUTOFILL_DOWNLOAD_MANAGER; |
| |
| } // namespace |
| |
| class MockAutofillManager : public AutofillManager { |
| public: |
| MockAutofillManager(AutofillDriver* driver, AutofillClient* client) |
| : AutofillManager(driver, client, kAppLocale, kDownloadState) {} |
| virtual ~MockAutofillManager() {} |
| |
| MOCK_METHOD0(Reset, void()); |
| }; |
| |
| class TestContentAutofillDriver : public ContentAutofillDriver { |
| public: |
| TestContentAutofillDriver(content::WebContents* contents, |
| AutofillClient* client) |
| : ContentAutofillDriver(contents, client, kAppLocale, kDownloadState) { |
| scoped_ptr<AutofillManager> autofill_manager( |
| new MockAutofillManager(this, client)); |
| SetAutofillManager(autofill_manager.Pass()); |
| } |
| virtual ~TestContentAutofillDriver() {} |
| |
| virtual MockAutofillManager* mock_autofill_manager() { |
| return static_cast<MockAutofillManager*>(autofill_manager()); |
| } |
| |
| using ContentAutofillDriver::DidNavigateMainFrame; |
| }; |
| |
| class ContentAutofillDriverTest : public content::RenderViewHostTestHarness { |
| public: |
| virtual void SetUp() override { |
| content::RenderViewHostTestHarness::SetUp(); |
| |
| test_autofill_client_.reset(new TestAutofillClient()); |
| driver_.reset(new TestContentAutofillDriver(web_contents(), |
| test_autofill_client_.get())); |
| } |
| |
| virtual void TearDown() override { |
| // Reset the driver now to cause all pref observers to be removed and avoid |
| // crashes that otherwise occur in the destructor. |
| driver_.reset(); |
| content::RenderViewHostTestHarness::TearDown(); |
| } |
| |
| protected: |
| // Searches for an |AutofillMsg_FillForm| message in the queue of sent IPC |
| // messages. If none is present, returns false. Otherwise, extracts the first |
| // |AutofillMsg_FillForm| message, fills the output parameters with the values |
| // of the message's parameters, and clears the queue of sent messages. |
| bool GetAutofillFillFormMessage(int* page_id, FormData* results) { |
| const uint32 kMsgID = AutofillMsg_FillForm::ID; |
| const IPC::Message* message = |
| process()->sink().GetFirstMessageMatching(kMsgID); |
| if (!message) |
| return false; |
| Tuple2<int, FormData> autofill_param; |
| if (!AutofillMsg_FillForm::Read(message, &autofill_param)) |
| return false; |
| if (page_id) |
| *page_id = autofill_param.a; |
| if (results) |
| *results = autofill_param.b; |
| process()->sink().ClearMessages(); |
| return true; |
| } |
| |
| // Searches for an |AutofillMsg_PreviewForm| message in the queue of sent IPC |
| // messages. If none is present, returns false. Otherwise, extracts the first |
| // |AutofillMsg_PreviewForm| message, fills the output parameters with the |
| // values of the message's parameters, and clears the queue of sent messages. |
| bool GetAutofillPreviewFormMessage(int* page_id, FormData* results) { |
| const uint32 kMsgID = AutofillMsg_PreviewForm::ID; |
| const IPC::Message* message = |
| process()->sink().GetFirstMessageMatching(kMsgID); |
| if (!message) |
| return false; |
| Tuple2<int, FormData> autofill_param; |
| if (!AutofillMsg_PreviewForm::Read(message, &autofill_param)) |
| return false; |
| if (page_id) |
| *page_id = autofill_param.a; |
| if (results) |
| *results = autofill_param.b; |
| process()->sink().ClearMessages(); |
| return true; |
| } |
| |
| // Searches for an |AutofillMsg_FieldTypePredictionsAvailable| message in the |
| // queue of sent IPC messages. If none is present, returns false. Otherwise, |
| // extracts the first |AutofillMsg_FieldTypePredictionsAvailable| message, |
| // fills the output parameter with the values of the message's parameter, and |
| // clears the queue of sent messages. |
| bool GetFieldTypePredictionsAvailable( |
| std::vector<FormDataPredictions>* predictions) { |
| const uint32 kMsgID = AutofillMsg_FieldTypePredictionsAvailable::ID; |
| const IPC::Message* message = |
| process()->sink().GetFirstMessageMatching(kMsgID); |
| if (!message) |
| return false; |
| Tuple1<std::vector<FormDataPredictions> > autofill_param; |
| if (!AutofillMsg_FieldTypePredictionsAvailable::Read(message, |
| &autofill_param)) |
| return false; |
| if (predictions) |
| *predictions = autofill_param.a; |
| |
| process()->sink().ClearMessages(); |
| return true; |
| } |
| |
| // Searches for a message matching |messageID| in the queue of sent IPC |
| // messages. If none is present, returns false. Otherwise, extracts the first |
| // matching message, fills the output parameter with the string16 from the |
| // message's parameter, and clears the queue of sent messages. |
| bool GetString16FromMessageWithID(uint32 messageID, base::string16* value) { |
| const IPC::Message* message = |
| process()->sink().GetFirstMessageMatching(messageID); |
| if (!message) |
| return false; |
| Tuple1<base::string16> autofill_param; |
| switch (messageID) { |
| case AutofillMsg_FillFieldWithValue::ID: |
| if (!AutofillMsg_FillFieldWithValue::Read(message, &autofill_param)) |
| return false; |
| break; |
| case AutofillMsg_PreviewFieldWithValue::ID: |
| if (!AutofillMsg_PreviewFieldWithValue::Read(message, &autofill_param)) |
| return false; |
| break; |
| case AutofillMsg_AcceptDataListSuggestion::ID: |
| if (!AutofillMsg_AcceptDataListSuggestion::Read(message, |
| &autofill_param)) |
| return false; |
| break; |
| default: |
| NOTREACHED(); |
| } |
| if (value) |
| *value = autofill_param.a; |
| process()->sink().ClearMessages(); |
| return true; |
| } |
| |
| // Searches for a message matching |messageID| in the queue of sent IPC |
| // messages. If none is present, returns false. Otherwise, clears the queue |
| // of sent messages and returns true. |
| bool HasMessageMatchingID(uint32 messageID) { |
| const IPC::Message* message = |
| process()->sink().GetFirstMessageMatching(messageID); |
| if (!message) |
| return false; |
| process()->sink().ClearMessages(); |
| return true; |
| } |
| |
| scoped_ptr<TestAutofillClient> test_autofill_client_; |
| scoped_ptr<TestContentAutofillDriver> driver_; |
| }; |
| |
| TEST_F(ContentAutofillDriverTest, GetURLRequestContext) { |
| net::URLRequestContextGetter* request_context = |
| driver_->GetURLRequestContext(); |
| net::URLRequestContextGetter* expected_request_context = |
| web_contents()->GetBrowserContext()->GetRequestContext(); |
| EXPECT_EQ(request_context, expected_request_context); |
| } |
| |
| TEST_F(ContentAutofillDriverTest, NavigatedToDifferentPage) { |
| EXPECT_CALL(*driver_->mock_autofill_manager(), Reset()); |
| content::LoadCommittedDetails details = content::LoadCommittedDetails(); |
| details.is_main_frame = true; |
| details.is_in_page = false; |
| ASSERT_TRUE(details.is_navigation_to_different_page()); |
| content::FrameNavigateParams params = content::FrameNavigateParams(); |
| driver_->DidNavigateMainFrame(details, params); |
| } |
| |
| TEST_F(ContentAutofillDriverTest, NavigatedWithinSamePage) { |
| EXPECT_CALL(*driver_->mock_autofill_manager(), Reset()).Times(0); |
| content::LoadCommittedDetails details = content::LoadCommittedDetails(); |
| details.is_main_frame = false; |
| ASSERT_TRUE(!details.is_navigation_to_different_page()); |
| content::FrameNavigateParams params = content::FrameNavigateParams(); |
| driver_->DidNavigateMainFrame(details, params); |
| } |
| |
| TEST_F(ContentAutofillDriverTest, FormDataSentToRenderer_FillForm) { |
| int input_page_id = 42; |
| FormData input_form_data; |
| test::CreateTestAddressFormData(&input_form_data); |
| driver_->SendFormDataToRenderer( |
| input_page_id, AutofillDriver::FORM_DATA_ACTION_FILL, input_form_data); |
| |
| int output_page_id = 0; |
| FormData output_form_data; |
| EXPECT_FALSE( |
| GetAutofillPreviewFormMessage(&output_page_id, &output_form_data)); |
| EXPECT_TRUE(GetAutofillFillFormMessage(&output_page_id, &output_form_data)); |
| EXPECT_EQ(input_page_id, output_page_id); |
| EXPECT_EQ(input_form_data, output_form_data); |
| } |
| |
| TEST_F(ContentAutofillDriverTest, FormDataSentToRenderer_PreviewForm) { |
| int input_page_id = 42; |
| FormData input_form_data; |
| test::CreateTestAddressFormData(&input_form_data); |
| driver_->SendFormDataToRenderer( |
| input_page_id, AutofillDriver::FORM_DATA_ACTION_PREVIEW, input_form_data); |
| |
| int output_page_id = 0; |
| FormData output_form_data; |
| EXPECT_FALSE(GetAutofillFillFormMessage(&output_page_id, &output_form_data)); |
| EXPECT_TRUE( |
| GetAutofillPreviewFormMessage(&output_page_id, &output_form_data)); |
| EXPECT_EQ(input_page_id, output_page_id); |
| EXPECT_EQ(input_form_data, output_form_data); |
| } |
| |
| TEST_F(ContentAutofillDriverTest, |
| TypePredictionsNotSentToRendererWhenDisabled) { |
| FormData form; |
| test::CreateTestAddressFormData(&form); |
| FormStructure form_structure(form); |
| std::vector<FormStructure*> forms(1, &form_structure); |
| driver_->SendAutofillTypePredictionsToRenderer(forms); |
| EXPECT_FALSE(GetFieldTypePredictionsAvailable(NULL)); |
| } |
| |
| TEST_F(ContentAutofillDriverTest, TypePredictionsSentToRendererWhenEnabled) { |
| CommandLine::ForCurrentProcess()->AppendSwitch( |
| switches::kShowAutofillTypePredictions); |
| |
| FormData form; |
| test::CreateTestAddressFormData(&form); |
| FormStructure form_structure(form); |
| std::vector<FormStructure*> forms(1, &form_structure); |
| std::vector<FormDataPredictions> expected_type_predictions; |
| FormStructure::GetFieldTypePredictions(forms, &expected_type_predictions); |
| driver_->SendAutofillTypePredictionsToRenderer(forms); |
| |
| std::vector<FormDataPredictions> output_type_predictions; |
| EXPECT_TRUE(GetFieldTypePredictionsAvailable(&output_type_predictions)); |
| EXPECT_EQ(expected_type_predictions, output_type_predictions); |
| } |
| |
| TEST_F(ContentAutofillDriverTest, AcceptDataListSuggestion) { |
| base::string16 input_value(base::ASCIIToUTF16("barfoo")); |
| base::string16 output_value; |
| driver_->RendererShouldAcceptDataListSuggestion(input_value); |
| EXPECT_TRUE(GetString16FromMessageWithID( |
| AutofillMsg_AcceptDataListSuggestion::ID, &output_value)); |
| EXPECT_EQ(input_value, output_value); |
| } |
| |
| TEST_F(ContentAutofillDriverTest, ClearFilledFormSentToRenderer) { |
| driver_->RendererShouldClearFilledForm(); |
| EXPECT_TRUE(HasMessageMatchingID(AutofillMsg_ClearForm::ID)); |
| } |
| |
| TEST_F(ContentAutofillDriverTest, ClearPreviewedFormSentToRenderer) { |
| driver_->RendererShouldClearPreviewedForm(); |
| EXPECT_TRUE(HasMessageMatchingID(AutofillMsg_ClearPreviewedForm::ID)); |
| } |
| |
| TEST_F(ContentAutofillDriverTest, FillFieldWithValue) { |
| base::string16 input_value(base::ASCIIToUTF16("barqux")); |
| base::string16 output_value; |
| |
| driver_->RendererShouldFillFieldWithValue(input_value); |
| EXPECT_TRUE(GetString16FromMessageWithID(AutofillMsg_FillFieldWithValue::ID, |
| &output_value)); |
| EXPECT_EQ(input_value, output_value); |
| } |
| |
| TEST_F(ContentAutofillDriverTest, PreviewFieldWithValue) { |
| base::string16 input_value(base::ASCIIToUTF16("barqux")); |
| base::string16 output_value; |
| driver_->RendererShouldPreviewFieldWithValue(input_value); |
| EXPECT_TRUE(GetString16FromMessageWithID( |
| AutofillMsg_PreviewFieldWithValue::ID, |
| &output_value)); |
| EXPECT_EQ(input_value, output_value); |
| } |
| |
| } // namespace autofill |