diff options
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/browser/autofill/autofill_manager.cc | 32 | ||||
-rw-r--r-- | chrome/browser/autofill/autofill_manager_unittest.cc | 116 | ||||
-rw-r--r-- | chrome/renderer/form_manager.cc | 286 | ||||
-rw-r--r-- | chrome/renderer/form_manager_unittest.cc | 159 |
4 files changed, 467 insertions, 126 deletions
diff --git a/chrome/browser/autofill/autofill_manager.cc b/chrome/browser/autofill/autofill_manager.cc index f0b3988..33d6e6e 100644 --- a/chrome/browser/autofill/autofill_manager.cc +++ b/chrome/browser/autofill/autofill_manager.cc @@ -234,11 +234,29 @@ bool AutoFillManager::FillAutoFillFormData(int query_id, if (*form_structure != form) continue; - DCHECK_EQ(form_structure->field_count(), result.fields.size()); + // The list of fields in |form_structure| and |result.fields| often match + // directly and we can fill these corresponding fields; however, when the + // |form_structure| and |result.fields| do not match directly we search + // ahead in the |form_structure| for the matching field. + // See unit tests: AutoFillManagerTest.FormChangesRemoveField and + // AutoFillManagerTest.FormChangesAddField for usage. + for (size_t i = 0, j = 0; + i < form_structure->field_count() && j < result.fields.size(); + j++) { + size_t k = i; + + // Search forward in the |form_structure| for a corresponding field. + while (k < form_structure->field_count() && + *form_structure->field(k) != result.fields[j]) { + k++; + } - for (size_t i = 0; i < form_structure->field_count(); ++i) { - const AutoFillField* field = form_structure->field(i); + // If we've found a match then fill the |result| field with the found + // field in the |form_structure|. + if (k >= form_structure->field_count()) + continue; + const AutoFillField* field = form_structure->field(k); AutoFillType autofill_type(field->type()); if (credit_card && autofill_type.group() == AutoFillType::CREDIT_CARD) { @@ -246,10 +264,14 @@ bool AutoFillManager::FillAutoFillFormData(int query_id, credit_card->GetFieldText(autofill_type)); } else if (credit_card && autofill_type.group() == AutoFillType::ADDRESS_BILLING) { - FillBillingFormField(credit_card, autofill_type, &result.fields[i]); + FillBillingFormField(credit_card, autofill_type, &result.fields[j]); } else if (profile) { - FillFormField(profile, autofill_type, &result.fields[i]); + FillFormField(profile, autofill_type, &result.fields[j]); } + + // We found a matching field in the |form_structure| so we + // proceed to the next |result| field, and the next |form_structure|. + ++i; } } diff --git a/chrome/browser/autofill/autofill_manager_unittest.cc b/chrome/browser/autofill/autofill_manager_unittest.cc index 9d018d5..a54b04d 100644 --- a/chrome/browser/autofill/autofill_manager_unittest.cc +++ b/chrome/browser/autofill/autofill_manager_unittest.cc @@ -596,4 +596,120 @@ TEST_F(AutoFillManagerTest, FillCreditCardFormWithBilling) { EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[14])); } +TEST_F(AutoFillManagerTest, FormChangesRemoveField) { + FormData form; + form.name = ASCIIToUTF16("MyForm"); + form.method = ASCIIToUTF16("POST"); + form.origin = GURL("http://myform.com/form.html"); + form.action = GURL("http://myform.com/submit.html"); + + webkit_glue::FormField field; + CreateTestFormField("First Name", "firstname", "", "text", &field); + form.fields.push_back(field); + CreateTestFormField("Middle Name", "middlename", "", "text", &field); + form.fields.push_back(field); + CreateTestFormField("Last Name", "lastname", "", "text", &field); + form.fields.push_back(field); + CreateTestFormField("Phone Number", "phonenumber", "", "text", &field); + form.fields.push_back(field); + CreateTestFormField("Email", "email", "", "text", &field); + form.fields.push_back(field); + + // Set up our FormStructures. + std::vector<FormData> forms; + forms.push_back(form); + autofill_manager_->FormsSeen(forms); + + // Now, after the call to |FormsSeen| we remove the phone number field before + // filling. + form.fields.erase(form.fields.begin() + 3); + + // The page ID sent to the AutoFillManager from the RenderView, used to send + // an IPC message back to the renderer. + const int kPageID = 1; + EXPECT_TRUE( + autofill_manager_->FillAutoFillFormData(kPageID, + form, + ASCIIToUTF16("Elvis"), + ASCIIToUTF16("Home"))); + + int page_id = 0; + FormData results; + EXPECT_TRUE(GetAutoFillFormDataFilledMessage(&page_id, &results)); + EXPECT_EQ(ASCIIToUTF16("MyForm"), results.name); + EXPECT_EQ(ASCIIToUTF16("POST"), results.method); + EXPECT_EQ(GURL("http://myform.com/form.html"), results.origin); + EXPECT_EQ(GURL("http://myform.com/submit.html"), results.action); + ASSERT_EQ(4U, results.fields.size()); + + CreateTestFormField("First Name", "firstname", "Elvis", "text", &field); + EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[0])); + CreateTestFormField("Middle Name", "middlename", "Aaron", "text", &field); + EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[1])); + CreateTestFormField("Last Name", "lastname", "Presley", "text", &field); + EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[2])); + CreateTestFormField( + "Email", "email", "theking@gmail.com", "text", &field); + EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[3])); +} + +TEST_F(AutoFillManagerTest, FormChangesAddField) { + FormData form; + form.name = ASCIIToUTF16("MyForm"); + form.method = ASCIIToUTF16("POST"); + form.origin = GURL("http://myform.com/form.html"); + form.action = GURL("http://myform.com/submit.html"); + + webkit_glue::FormField field; + CreateTestFormField("First Name", "firstname", "", "text", &field); + form.fields.push_back(field); + CreateTestFormField("Middle Name", "middlename", "", "text", &field); + form.fields.push_back(field); + CreateTestFormField("Last Name", "lastname", "", "text", &field); + // Note: absent phone number. Adding this below. + form.fields.push_back(field); + CreateTestFormField("Email", "email", "", "text", &field); + form.fields.push_back(field); + + // Set up our FormStructures. + std::vector<FormData> forms; + forms.push_back(form); + autofill_manager_->FormsSeen(forms); + + // Now, after the call to |FormsSeen| we add the phone number field before + // filling. + CreateTestFormField("Phone Number", "phonenumber", "", "text", &field); + form.fields.insert(form.fields.begin() + 3, field); + + // The page ID sent to the AutoFillManager from the RenderView, used to send + // an IPC message back to the renderer. + const int kPageID = 1; + EXPECT_TRUE( + autofill_manager_->FillAutoFillFormData(kPageID, + form, + ASCIIToUTF16("Elvis"), + ASCIIToUTF16("Home"))); + + int page_id = 0; + FormData results; + EXPECT_TRUE(GetAutoFillFormDataFilledMessage(&page_id, &results)); + EXPECT_EQ(ASCIIToUTF16("MyForm"), results.name); + EXPECT_EQ(ASCIIToUTF16("POST"), results.method); + EXPECT_EQ(GURL("http://myform.com/form.html"), results.origin); + EXPECT_EQ(GURL("http://myform.com/submit.html"), results.action); + ASSERT_EQ(5U, results.fields.size()); + + CreateTestFormField("First Name", "firstname", "Elvis", "text", &field); + EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[0])); + CreateTestFormField("Middle Name", "middlename", "Aaron", "text", &field); + EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[1])); + CreateTestFormField("Last Name", "lastname", "Presley", "text", &field); + EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[2])); + CreateTestFormField("Phone Number", "phonenumber", "", "text", &field); + EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[3])); + CreateTestFormField( + "Email", "email", "theking@gmail.com", "text", &field); + EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[4])); +} + } // namespace diff --git a/chrome/renderer/form_manager.cc b/chrome/renderer/form_manager.cc index 12b6353..83f6ed9 100644 --- a/chrome/renderer/form_manager.cc +++ b/chrome/renderer/form_manager.cc @@ -46,30 +46,28 @@ namespace { const size_t kRequiredAutoFillFields = 3; // This is a helper function for the FindChildText() function. -// Returns the node value of the descendant or sibling of |node| that is a -// non-empty text node. This is a faster alternative to |innerText()| for +// Returns the aggregated values of the descendants or siblings of |node| that +// are non-empty text nodes. This is a faster alternative to |innerText()| for // performance critical operations. It does a full depth-first search so -// can be used when the structure is not directly known. It does not aggregate -// the text of multiple nodes, it just returns the value of the first found. -// "Non-empty" in this case means non-empty after the whitespace has been -// stripped. +// can be used when the structure is not directly known. The text is +// accumulated after the whitespace has been stripped. string16 FindChildTextInner(const WebNode& node) { string16 element_text; if (node.isNull()) return element_text; - element_text = node.nodeValue(); - TrimWhitespace(element_text, TRIM_ALL, &element_text); - if (!element_text.empty()) - return element_text; + string16 node_text = node.nodeValue(); + TrimWhitespace(node_text, TRIM_ALL, &node_text); + if (!node_text.empty()) + element_text = node_text; - element_text = FindChildTextInner(node.firstChild()); - if (!element_text.empty()) - return element_text; + string16 child_text = FindChildTextInner(node.firstChild()); + if (!child_text.empty()) + element_text = element_text + child_text; - element_text = FindChildTextInner(node.nextSibling()); - if (!element_text.empty()) - return element_text; + string16 sibling_text = FindChildTextInner(node.nextSibling()); + if (!sibling_text.empty()) + element_text = element_text + sibling_text; return element_text; } @@ -82,6 +80,132 @@ string16 FindChildText(const WebElement& element) { return FindChildTextInner(child); } +// Helper for |InferLabelForElement()| that infers a label, if possible, from +// a previous node of |element|. +string16 InferLabelFromPrevious( + const WebFormControlElement& element) { + string16 inferred_label; + WebNode previous = element.previousSibling(); + if (!previous.isNull()) { + // Eg. Some Text<input ...> + if (previous.isTextNode()) { + inferred_label = previous.nodeValue(); + TrimWhitespace(inferred_label, TRIM_ALL, &inferred_label); + } + + // If we didn't find text, check for previous paragraph. + // Eg. <p>Some Text</p><input ...> + // Note the lack of whitespace between <p> and <input> elements. + if (inferred_label.empty()) { + if (previous.isElementNode()) { + WebElement element = previous.to<WebElement>(); + if (element.hasTagName("p")) { + inferred_label = FindChildText(element); + } + } + } + + // If we didn't find paragraph, check for previous paragraph to this. + // Eg. <p>Some Text</p> <input ...> + // Note the whitespace between <p> and <input> elements. + if (inferred_label.empty()) { + previous = previous.previousSibling(); + if (!previous.isNull() && previous.isElementNode()) { + WebElement element = previous.to<WebElement>(); + if (element.hasTagName("p")) { + inferred_label = FindChildText(element); + } + } + } + + // Look for text node prior to <img> tag. + // Eg. Some Text<img/><input ...> + if (inferred_label.empty()) { + while (inferred_label.empty() && !previous.isNull()) { + if (previous.isTextNode()) { + inferred_label = previous.nodeValue(); + TrimWhitespace(inferred_label, TRIM_ALL, &inferred_label); + } else if (previous.isElementNode()) { + WebElement element = previous.to<WebElement>(); + if (!element.hasTagName("img")) + break; + } else { + break; + } + previous = previous.previousSibling(); + } + } + } + + return inferred_label; +} + +// Helper for |InferLabelForElement()| that infers a label, if possible, from +// surrounding table structure. +// Eg. <tr><td>Some Text</td><td><input ...></td></tr> +// Eg. <tr><td><b>Some Text</b></td><td><b><input ...></b></td></tr> +string16 InferLabelFromTable( + const WebFormControlElement& element) { + string16 inferred_label; + WebNode parent = element.parentNode(); + while (!parent.isNull() && parent.isElementNode() && + !parent.to<WebElement>().hasTagName("td")) + parent = parent.parentNode(); + + if (!parent.isNull() && parent.isElementNode()) { + WebElement element = parent.to<WebElement>(); + if (element.hasTagName("td")) { + WebNode previous = parent.previousSibling(); + + // Skip by any intervening text nodes. + while (!previous.isNull() && previous.isTextNode()) + previous = previous.previousSibling(); + + if (!previous.isNull() && previous.isElementNode()) { + element = previous.to<WebElement>(); + if (element.hasTagName("td")) { + inferred_label = FindChildText(element); + } + } + } + } + + return inferred_label; +} + +// Helper for |InferLabelForElement()| that infers a label, if possible, from +// a surrounding definition list. +// Eg. <dl><dt>Some Text</dt><dd><input ...></dd></dl> +// Eg. <dl><dt><b>Some Text</b></dt><dd><b><input ...></b></dd></dl> +string16 InferLabelFromDefinitionList( + const WebFormControlElement& element) { + string16 inferred_label; + WebNode parent = element.parentNode(); + while (!parent.isNull() && parent.isElementNode() && + !parent.to<WebElement>().hasTagName("dd")) + parent = parent.parentNode(); + + if (!parent.isNull() && parent.isElementNode()) { + WebElement element = parent.to<WebElement>(); + if (element.hasTagName("dd")) { + WebNode previous = parent.previousSibling(); + + // Skip by any intervening text nodes. + while (!previous.isNull() && previous.isTextNode()) + previous = previous.previousSibling(); + + if (!previous.isNull() && previous.isElementNode()) { + element = previous.to<WebElement>(); + if (element.hasTagName("dt")) { + inferred_label = FindChildText(element); + } + } + } + } + + return inferred_label; +} + } // namespace FormManager::FormManager() { @@ -427,62 +551,51 @@ bool FormManager::FillForm(const FormData& form) { for (size_t i = 0, j = 0; i < form_element->control_elements.size() && j < form.fields.size(); - ++i, ++j) { + ++i) { // Once again, empty WebString != empty string16, so we have to explicitly // check for this case. if (form_element->control_elements[i].nameForAutofill().length() == 0 && form.fields[j].name().empty()) continue; - // We assume that the intersection of the fields in - // |form_element->control_elements| and |form.fields| is ordered, but it's - // possible that one or the other sets may have more fields than the other, - // so loop past non-matching fields in the set with more elements. - while (form_element->control_elements[i].nameForAutofill() != - form.fields[j].name()) { - if (form_element->control_elements.size() > form.fields.size()) { - // We're at the end of the elements already. - if (i + 1 == form_element->control_elements.size()) - break; - ++i; - } else if (form.fields.size() > form_element->control_elements.size()) { - // We're at the end of the elements already. - if (j + 1 == form.fields.size()) - break; - ++j; - } else { - NOTREACHED(); - } - - continue; + size_t k = j; + while (k < form.fields.size() && + form_element->control_elements[i].nameForAutofill() != + form.fields[k].name()) { + k++; } + if (k >= form.fields.size()) + continue; WebFormControlElement* element = &form_element->control_elements[i]; - // It's possible that nameForAutofill() is empty if the form control element - // has no name or ID. In that case, iter->nameForAutofill() must also be - // empty. - if (form.fields[j].name().empty()) + // It's possible that nameForAutofill() is empty if the form control + // element has no name or ID. In that case, iter->nameForAutofill() must + // also be empty. + if (form.fields[k].name().empty()) DCHECK(element->nameForAutofill().isEmpty()); else - DCHECK_EQ(form.fields[j].name(), element->nameForAutofill()); + DCHECK_EQ(form.fields[k].name(), element->nameForAutofill()); - if (!form.fields[j].value().empty() && + if (!form.fields[k].value().empty() && element->formControlType() != WebString::fromUTF8("submit")) { if (element->formControlType() == WebString::fromUTF8("text")) { WebInputElement input_element = element->to<WebInputElement>(); // If the maxlength attribute contains a negative value, maxLength() // returns the default maxlength value. input_element.setValue( - form.fields[j].value().substr(0, input_element.maxLength())); + form.fields[k].value().substr(0, input_element.maxLength())); input_element.setAutofilled(true); } else if (element->formControlType() == WebString::fromUTF8("select-one")) { WebSelectElement select_element = element->to<WebSelectElement>(); - select_element.setValue(form.fields[j].value()); + select_element.setValue(form.fields[k].value()); } } + + // We found a matching form field so move on to the next. + ++j; } return true; @@ -559,85 +672,18 @@ bool FormManager::FormElementToFormData(const WebFrame* frame, // static string16 FormManager::InferLabelForElement( const WebFormControlElement& element) { - string16 inferred_label; - WebNode previous = element.previousSibling(); - if (!previous.isNull()) { - if (previous.isTextNode()) { - inferred_label = previous.nodeValue(); - TrimWhitespace(inferred_label, TRIM_ALL, &inferred_label); - } - - // If we didn't find text, check for previous paragraph. - // Eg. <p>Some Text</p><input ...> - // Note the lack of whitespace between <p> and <input> elements. - if (inferred_label.empty()) { - if (previous.isElementNode()) { - WebElement element = previous.to<WebElement>(); - if (element.hasTagName("p")) { - inferred_label = FindChildText(element); - } - } - } + string16 inferred_label = InferLabelFromPrevious(element); - // If we didn't find paragraph, check for previous paragraph to this. - // Eg. <p>Some Text</p> <input ...> - // Note the whitespace between <p> and <input> elements. - if (inferred_label.empty()) { - previous = previous.previousSibling(); - if (!previous.isNull() && previous.isElementNode()) { - WebElement element = previous.to<WebElement>(); - if (element.hasTagName("p")) { - inferred_label = FindChildText(element); - } - } - } - - // Look for text node prior to <img> tag. - // Eg. Some Text<img/><input ...> - if (inferred_label.empty()) { - while (inferred_label.empty() && !previous.isNull()) { - if (previous.isTextNode()) { - inferred_label = previous.nodeValue(); - TrimWhitespace(inferred_label, TRIM_ALL, &inferred_label); - } else if (previous.isElementNode()) { - WebElement element = previous.to<WebElement>(); - if (!element.hasTagName("img")) - break; - } else { - break; - } - previous = previous.previousSibling(); - } - } + // If we didn't find a label, check for table cell case. + if (inferred_label.empty()) { + inferred_label = InferLabelFromTable(element); } - // If we didn't find paragraph, check for table cell case. - // Eg. <tr><td>Some Text</td><td><input ...></td></tr> - // Eg. <tr><td><b>Some Text</b></td><td><b><input ...></b></td></tr> + // If we didn't find a label, check for definition list case. if (inferred_label.empty()) { - WebNode parent = element.parentNode(); - while (!parent.isNull() && parent.isElementNode() && - !parent.to<WebElement>().hasTagName("td")) - parent = parent.parentNode(); - - if (!parent.isNull() && parent.isElementNode()) { - WebElement element = parent.to<WebElement>(); - if (element.hasTagName("td")) { - previous = parent.previousSibling(); - - // Skip by any intervening text nodes. - while (!previous.isNull() && previous.isTextNode()) - previous = previous.previousSibling(); - - if (!previous.isNull() && previous.isElementNode()) { - element = previous.to<WebElement>(); - if (element.hasTagName("td")) { - inferred_label = FindChildText(element); - } - } - } - } + inferred_label = InferLabelFromDefinitionList(element); } return inferred_label; } + diff --git a/chrome/renderer/form_manager_unittest.cc b/chrome/renderer/form_manager_unittest.cc index 01dc52a..d5a8c39 100644 --- a/chrome/renderer/form_manager_unittest.cc +++ b/chrome/renderer/form_manager_unittest.cc @@ -842,7 +842,80 @@ TEST_F(FormManagerTest, LabelsInferredFromTableCellNested) { const std::vector<FormField>& fields = form.fields; ASSERT_EQ(3U, fields.size()); - EXPECT_EQ(FormField(ASCIIToUTF16("First name:"), + EXPECT_EQ(FormField(ASCIIToUTF16("First name:Bogus"), + ASCIIToUTF16("firstname"), + ASCIIToUTF16("John"), + ASCIIToUTF16("text"), + 20), + fields[0]); + EXPECT_EQ(FormField(ASCIIToUTF16("Last name:"), + ASCIIToUTF16("lastname"), + ASCIIToUTF16("Smith"), + ASCIIToUTF16("text"), + 20), + fields[1]); + EXPECT_EQ(FormField(string16(), + ASCIIToUTF16("reply-send"), + ASCIIToUTF16("Send"), + ASCIIToUTF16("submit"), + 0), + fields[2]); +} + +TEST_F(FormManagerTest, LabelsInferredFromDefinitionList) { + LoadHTML("<FORM name=\"TestForm\" action=\"http://cnn.com\" method=\"post\">" + "<DL>" + " <DT>" + " <SPAN>" + " *" + " </SPAN>" + " <SPAN>" + " First name:" + " </SPAN>" + " <SPAN>" + " Bogus" + " </SPAN>" + " </DT>" + " <DD>" + " <FONT>" + " <INPUT type=\"text\" id=\"firstname\" value=\"John\"/>" + " </FONT>" + " </DD>" + " <DT>" + " <SPAN>" + " Last name:" + " </SPAN>" + " </DT>" + " <DD>" + " <FONT>" + " <INPUT type=\"text\" id=\"lastname\" value=\"Smith\"/>" + " </FONT>" + " </DD>" + " <DT></DT>" + " <DD>" + " <INPUT type=\"submit\" name=\"reply-send\" value=\"Send\"/>" + " </DD>" + "</DL>" + "</FORM>"); + + WebFrame* web_frame = GetMainFrame(); + ASSERT_NE(static_cast<WebFrame*>(NULL), web_frame); + + FormManager form_manager; + form_manager.ExtractForms(web_frame); + + std::vector<FormData> forms; + form_manager.GetForms(FormManager::REQUIRE_NONE, &forms); + ASSERT_EQ(1U, forms.size()); + + const FormData& form = forms[0]; + EXPECT_EQ(ASCIIToUTF16("TestForm"), form.name); + EXPECT_EQ(GURL(web_frame->url()), form.origin); + EXPECT_EQ(GURL("http://cnn.com"), form.action); + + const std::vector<FormField>& fields = form.fields; + ASSERT_EQ(3U, fields.size()); + EXPECT_EQ(FormField(ASCIIToUTF16("*First name:Bogus"), ASCIIToUTF16("firstname"), ASCIIToUTF16("John"), ASCIIToUTF16("text"), @@ -1394,6 +1467,90 @@ TEST_F(FormManagerTest, FillFormFewerFormDataFields) { fields[7]); } +// This test sends a FormData object to FillForm with a field changed from +// those in the cached WebFormElement. In this case, we only fill out the +// fields that match between the FormData object and the WebFormElement. +TEST_F(FormManagerTest, FillFormChangedFormDataFields) { + LoadHTML("<FORM name=\"TestForm\" action=\"http://buh.com\" method=\"post\">" + " <INPUT type=\"text\" id=\"firstname\"/>" + " <INPUT type=\"text\" id=\"middlename\"/>" + " <INPUT type=\"text\" id=\"lastname\"/>" + " <INPUT type=\"submit\" name=\"reply-send\" value=\"Send\"/>" + "</FORM>"); + + WebFrame* web_frame = GetMainFrame(); + ASSERT_NE(static_cast<WebFrame*>(NULL), web_frame); + + FormManager form_manager; + form_manager.ExtractForms(web_frame); + + // Verify that we have the form. + std::vector<FormData> forms; + form_manager.GetForms(FormManager::REQUIRE_NONE, &forms); + ASSERT_EQ(1U, forms.size()); + + // After the field modification, the fields in |form| will look like: + // firstname + // middlename + // lastname + FormData* form = &forms[0]; + + // Fill the form. + form->fields[0].set_value(ASCIIToUTF16("Brother")); + form->fields[1].set_value(ASCIIToUTF16("Joseph")); + form->fields[2].set_value(ASCIIToUTF16("Jonathan")); + + // Alter the label and name used for matching. + form->fields[1].set_label(ASCIIToUTF16("bogus")); + form->fields[1].set_name(ASCIIToUTF16("bogus")); + + EXPECT_TRUE(form_manager.FillForm(*form)); + + // Get the input element we want to find. + WebElement element = web_frame->document().getElementById("firstname"); + WebInputElement input_element = element.to<WebInputElement>(); + + // Find the newly-filled form that contains the input element. + FormData form2; + EXPECT_TRUE(form_manager.FindFormWithFormControlElement( + input_element, FormManager::REQUIRE_NONE, &form2)); + EXPECT_EQ(ASCIIToUTF16("TestForm"), form2.name); + EXPECT_EQ(GURL(web_frame->url()), form2.origin); + EXPECT_EQ(GURL("http://buh.com"), form2.action); + + // TODO(jhawkins): We don't actually compare the value of the field in + // FormField::operator==()! + const std::vector<FormField>& fields = form2.fields; + ASSERT_EQ(4U, fields.size()); + EXPECT_EQ(FormField(string16(), + ASCIIToUTF16("firstname"), + ASCIIToUTF16("Brother"), + ASCIIToUTF16("text"), + 20), + fields[0]); + EXPECT_EQ(ASCIIToUTF16("Brother"), fields[0].value()); + EXPECT_EQ(FormField(string16(), + ASCIIToUTF16("middlename"), + ASCIIToUTF16("Joseph"), + ASCIIToUTF16("text"), + 20), + fields[1]); + EXPECT_EQ(string16(), fields[1].value()); + EXPECT_EQ(FormField(string16(), + ASCIIToUTF16("lastname"), + ASCIIToUTF16("Jonathan"), + ASCIIToUTF16("text"), + 20), + fields[2]); + EXPECT_EQ(ASCIIToUTF16("Jonathan"), fields[2].value()); + EXPECT_EQ(FormField(string16(), + ASCIIToUTF16("reply-send"), + ASCIIToUTF16("Send"), + ASCIIToUTF16("submit"), + 0), + fields[3]); +} + // This test sends a FormData object to FillForm with fewer fields than are in // the cached WebFormElement. In this case, we only fill out the fields that // match between the FormData object and the WebFormElement. |