Home | History | Annotate | Download | only in browser
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include <string>
      6 #include <vector>
      7 
      8 #include "base/memory/scoped_ptr.h"
      9 #include "base/strings/string_number_conversions.h"
     10 #include "components/autofill/content/browser/autocheckout_page_meta_data.h"
     11 #include "components/autofill/core/browser/autofill_xml_parser.h"
     12 #include "components/autofill/core/browser/field_types.h"
     13 #include "testing/gtest/include/gtest/gtest.h"
     14 #include "third_party/libjingle/source/talk/xmllite/xmlparser.h"
     15 
     16 namespace autofill {
     17 namespace {
     18 
     19 class AutofillQueryXmlParserTest : public testing::Test {
     20  public:
     21   AutofillQueryXmlParserTest(): upload_required_(USE_UPLOAD_RATES) {};
     22   virtual ~AutofillQueryXmlParserTest() {};
     23 
     24  protected:
     25   void ParseQueryXML(const std::string& xml, bool should_succeed) {
     26     // Create a parser.
     27     AutofillQueryXmlParser parse_handler(&field_infos_,
     28                                          &upload_required_,
     29                                          &experiment_id_,
     30                                          &page_meta_data_);
     31     buzz::XmlParser parser(&parse_handler);
     32     parser.Parse(xml.c_str(), xml.length(), true);
     33     EXPECT_EQ(should_succeed, parse_handler.succeeded());
     34   }
     35 
     36   std::vector<AutofillServerFieldInfo> field_infos_;
     37   UploadRequired upload_required_;
     38   std::string experiment_id_;
     39   autofill::AutocheckoutPageMetaData page_meta_data_;
     40 };
     41 
     42 class AutofillUploadXmlParserTest : public testing::Test {
     43  public:
     44   AutofillUploadXmlParserTest(): positive_(0), negative_(0) {};
     45   virtual ~AutofillUploadXmlParserTest() {};
     46 
     47  protected:
     48   void ParseUploadXML(const std::string& xml, bool should_succeed) {
     49     // Create a parser.
     50     AutofillUploadXmlParser parse_handler(&positive_, &negative_);
     51     buzz::XmlParser parser(&parse_handler);
     52     parser.Parse(xml.c_str(), xml.length(), true);
     53 
     54     EXPECT_EQ(should_succeed, parse_handler.succeeded());
     55   }
     56 
     57   double positive_;
     58   double negative_;
     59 };
     60 
     61 TEST_F(AutofillQueryXmlParserTest, BasicQuery) {
     62   // An XML string representing a basic query response.
     63   std::string xml = "<autofillqueryresponse>"
     64                     "<field autofilltype=\"0\" />"
     65                     "<field autofilltype=\"1\" />"
     66                     "<field autofilltype=\"3\" />"
     67                     "<field autofilltype=\"2\" />"
     68                     "<field autofilltype=\"61\" defaultvalue=\"default\"/>"
     69                     "</autofillqueryresponse>";
     70   ParseQueryXML(xml, true);
     71 
     72   EXPECT_EQ(USE_UPLOAD_RATES, upload_required_);
     73   ASSERT_EQ(5U, field_infos_.size());
     74   EXPECT_EQ(NO_SERVER_DATA, field_infos_[0].field_type);
     75   EXPECT_EQ(UNKNOWN_TYPE, field_infos_[1].field_type);
     76   EXPECT_EQ(NAME_FIRST, field_infos_[2].field_type);
     77   EXPECT_EQ(EMPTY_TYPE, field_infos_[3].field_type);
     78   EXPECT_TRUE(field_infos_[3].default_value.empty());
     79   EXPECT_EQ(FIELD_WITH_DEFAULT_VALUE, field_infos_[4].field_type);
     80   EXPECT_EQ("default", field_infos_[4].default_value);
     81   EXPECT_TRUE(experiment_id_.empty());
     82 }
     83 
     84 // Test parsing the upload required attribute.
     85 TEST_F(AutofillQueryXmlParserTest, TestUploadRequired) {
     86   std::string xml = "<autofillqueryresponse uploadrequired=\"true\">"
     87                     "<field autofilltype=\"0\" />"
     88                     "</autofillqueryresponse>";
     89 
     90   ParseQueryXML(xml, true);
     91 
     92   EXPECT_EQ(upload_required_, upload_required_);
     93   ASSERT_EQ(1U, field_infos_.size());
     94   EXPECT_EQ(NO_SERVER_DATA, field_infos_[0].field_type);
     95   EXPECT_TRUE(experiment_id_.empty());
     96 
     97   field_infos_.clear();
     98   xml = "<autofillqueryresponse uploadrequired=\"false\">"
     99         "<field autofilltype=\"0\" />"
    100         "</autofillqueryresponse>";
    101 
    102   ParseQueryXML(xml, true);
    103 
    104   EXPECT_EQ(UPLOAD_NOT_REQUIRED, upload_required_);
    105   ASSERT_EQ(1U, field_infos_.size());
    106   EXPECT_EQ(NO_SERVER_DATA, field_infos_[0].field_type);
    107   EXPECT_TRUE(experiment_id_.empty());
    108 
    109   field_infos_.clear();
    110   xml = "<autofillqueryresponse uploadrequired=\"bad_value\">"
    111         "<field autofilltype=\"0\" />"
    112         "</autofillqueryresponse>";
    113 
    114   ParseQueryXML(xml, true);
    115 
    116   EXPECT_EQ(USE_UPLOAD_RATES, upload_required_);
    117   ASSERT_EQ(1U, field_infos_.size());
    118   EXPECT_EQ(NO_SERVER_DATA, field_infos_[0].field_type);
    119   EXPECT_TRUE(experiment_id_.empty());
    120 }
    121 
    122 // Test parsing the experiment id attribute
    123 TEST_F(AutofillQueryXmlParserTest, ParseExperimentId) {
    124   // When the attribute is missing, we should get back the default value -- the
    125   // empty string.
    126   std::string xml = "<autofillqueryresponse>"
    127                     "<field autofilltype=\"0\" />"
    128                     "</autofillqueryresponse>";
    129 
    130   ParseQueryXML(xml, true);
    131 
    132   EXPECT_EQ(USE_UPLOAD_RATES, upload_required_);
    133   ASSERT_EQ(1U, field_infos_.size());
    134   EXPECT_EQ(NO_SERVER_DATA, field_infos_[0].field_type);
    135   EXPECT_TRUE(experiment_id_.empty());
    136 
    137   field_infos_.clear();
    138 
    139   // When the attribute is present, make sure we parse it.
    140   xml = "<autofillqueryresponse experimentid=\"FancyNewAlgorithm\">"
    141         "<field autofilltype=\"0\" />"
    142         "</autofillqueryresponse>";
    143 
    144   ParseQueryXML(xml, true);
    145 
    146   EXPECT_EQ(USE_UPLOAD_RATES, upload_required_);
    147   ASSERT_EQ(1U, field_infos_.size());
    148   EXPECT_EQ(NO_SERVER_DATA, field_infos_[0].field_type);
    149   EXPECT_EQ(std::string("FancyNewAlgorithm"), experiment_id_);
    150 
    151   field_infos_.clear();
    152 
    153   // Make sure that we can handle parsing both the upload required and the
    154   // experiment id attribute together.
    155   xml = "<autofillqueryresponse uploadrequired=\"false\""
    156         "                       experimentid=\"ServerSmartyPants\">"
    157         "<field autofilltype=\"0\" />"
    158         "</autofillqueryresponse>";
    159 
    160   ParseQueryXML(xml, true);
    161 
    162   EXPECT_EQ(UPLOAD_NOT_REQUIRED, upload_required_);
    163   ASSERT_EQ(1U, field_infos_.size());
    164   EXPECT_EQ(NO_SERVER_DATA, field_infos_[0].field_type);
    165   EXPECT_EQ("ServerSmartyPants", experiment_id_);
    166 }
    167 
    168 // Fails on ASAN bot. http://crbug.com/253797
    169 #if defined(ADDRESS_SANITIZER)
    170 #define MAYBE_ParseAutofillFlow DISABLED_ParseAutofillFlow
    171 #else
    172 #define MAYBE_ParseAutofillFlow ParseAutofillFlow
    173 #endif
    174 
    175 // Test XML response with autofill_flow information.
    176 TEST_F(AutofillQueryXmlParserTest, MAYBE_ParseAutofillFlow) {
    177   std::string xml = "<autofillqueryresponse>"
    178                     "<field autofilltype=\"55\"/>"
    179                     "<autofill_flow page_no=\"1\" total_pages=\"10\">"
    180                     "<page_advance_button id=\"foo\"/>"
    181                     "<flow_page page_no=\"0\">"
    182                     "<type>1</type>"
    183                     "<type>2</type>"
    184                     "</flow_page>"
    185                     "<flow_page page_no=\"1\">"
    186                     "<type>3</type>"
    187                     "</flow_page>"
    188                     "</autofill_flow>"
    189                     "</autofillqueryresponse>";
    190 
    191   ParseQueryXML(xml, true);
    192 
    193   EXPECT_EQ(1U, field_infos_.size());
    194   EXPECT_EQ(1, page_meta_data_.current_page_number);
    195   EXPECT_EQ(10, page_meta_data_.total_pages);
    196   EXPECT_TRUE(page_meta_data_.ignore_ajax);
    197   EXPECT_EQ("foo", page_meta_data_.proceed_element_descriptor.descriptor);
    198   EXPECT_EQ(autofill::WebElementDescriptor::ID,
    199             page_meta_data_.proceed_element_descriptor.retrieval_method);
    200   EXPECT_EQ(2U, page_meta_data_.page_types.size());
    201   EXPECT_EQ(2U, page_meta_data_.page_types[0].size());
    202   EXPECT_EQ(1U, page_meta_data_.page_types[1].size());
    203   EXPECT_EQ(AUTOCHECKOUT_STEP_SHIPPING, page_meta_data_.page_types[0][0]);
    204   EXPECT_EQ(AUTOCHECKOUT_STEP_DELIVERY, page_meta_data_.page_types[0][1]);
    205   EXPECT_EQ(AUTOCHECKOUT_STEP_BILLING, page_meta_data_.page_types[1][0]);
    206 
    207   // Clear |field_infos_| for the next test;
    208   field_infos_.clear();
    209 
    210   // Test css_selector as page_advance_button.
    211   xml = "<autofillqueryresponse>"
    212         "<field autofilltype=\"55\"/>"
    213         "<autofill_flow page_no=\"1\" total_pages=\"10\">"
    214         "<page_advance_button css_selector=\"[name=&quot;foo&quot;]\"/>"
    215         "</autofill_flow>"
    216         "</autofillqueryresponse>";
    217 
    218   ParseQueryXML(xml, true);
    219 
    220   EXPECT_EQ(1U, field_infos_.size());
    221   EXPECT_EQ(1, page_meta_data_.current_page_number);
    222   EXPECT_EQ(10, page_meta_data_.total_pages);
    223   EXPECT_EQ("[name=\"foo\"]",
    224             page_meta_data_.proceed_element_descriptor.descriptor);
    225   EXPECT_EQ(autofill::WebElementDescriptor::CSS_SELECTOR,
    226             page_meta_data_.proceed_element_descriptor.retrieval_method);
    227 
    228   // Clear |field_infos_| for the next test;
    229   field_infos_.clear();
    230 
    231   // Test first attribute is always the one set.
    232   xml = "<autofillqueryresponse>"
    233         "<field autofilltype=\"55\"/>"
    234         "<autofill_flow page_no=\"1\" total_pages=\"10\">"
    235         "<page_advance_button css_selector=\"[name=&quot;foo&quot;]\""
    236         " id=\"foo\"/>"
    237         "</autofill_flow>"
    238         "</autofillqueryresponse>";
    239 
    240   ParseQueryXML(xml, true);
    241 
    242   EXPECT_EQ(1U, field_infos_.size());
    243   EXPECT_EQ(1, page_meta_data_.current_page_number);
    244   EXPECT_EQ(10, page_meta_data_.total_pages);
    245   EXPECT_EQ("[name=\"foo\"]",
    246             page_meta_data_.proceed_element_descriptor.descriptor);
    247   EXPECT_EQ(autofill::WebElementDescriptor::CSS_SELECTOR,
    248             page_meta_data_.proceed_element_descriptor.retrieval_method);
    249 
    250   // Clear |field_infos_| for the next test;
    251   field_infos_.clear();
    252 
    253   // Test parsing click_elements_before_formfill correctly.
    254   xml = "<autofillqueryresponse>"
    255         "<field autofilltype=\"55\"/>"
    256         "<autofill_flow page_no=\"1\" total_pages=\"10\">"
    257         "<click_elements_before_formfill>"
    258         "<web_element id=\"btn1\" /></click_elements_before_formfill>"
    259         "<click_elements_before_formfill>"
    260         "<web_element css_selector=\"[name=&quot;btn2&quot;]\"/>"
    261         "</click_elements_before_formfill>"
    262         "</autofill_flow>"
    263         "</autofillqueryresponse>";
    264 
    265   ParseQueryXML(xml, true);
    266 
    267   EXPECT_EQ(1U, field_infos_.size());
    268   EXPECT_EQ(1, page_meta_data_.current_page_number);
    269   EXPECT_EQ(10, page_meta_data_.total_pages);
    270   ASSERT_EQ(2U, page_meta_data_.click_elements_before_form_fill.size());
    271   autofill::WebElementDescriptor& click_elment =
    272       page_meta_data_.click_elements_before_form_fill[0];
    273   EXPECT_EQ("btn1", click_elment.descriptor);
    274   EXPECT_EQ(autofill::WebElementDescriptor::ID, click_elment.retrieval_method);
    275   click_elment = page_meta_data_.click_elements_before_form_fill[1];
    276   EXPECT_EQ("[name=\"btn2\"]", click_elment.descriptor);
    277   EXPECT_EQ(autofill::WebElementDescriptor::CSS_SELECTOR,
    278             click_elment.retrieval_method);
    279 
    280   // Clear |field_infos_| for the next test;
    281   field_infos_.clear();
    282 
    283   // Test parsing click_elements_after_formfill correctly.
    284   xml = "<autofillqueryresponse>"
    285         "<field autofilltype=\"55\"/>"
    286         "<autofill_flow page_no=\"1\" total_pages=\"10\">"
    287         "<click_elements_after_formfill>"
    288         "<web_element id=\"btn1\" /></click_elements_after_formfill>"
    289         "</autofill_flow>"
    290         "</autofillqueryresponse>";
    291 
    292   ParseQueryXML(xml, true);
    293 
    294   EXPECT_EQ(1U, field_infos_.size());
    295   EXPECT_EQ(1, page_meta_data_.current_page_number);
    296   EXPECT_EQ(10, page_meta_data_.total_pages);
    297   ASSERT_EQ(1U, page_meta_data_.click_elements_after_form_fill.size());
    298   click_elment = page_meta_data_.click_elements_after_form_fill[0];
    299   EXPECT_EQ("btn1", click_elment.descriptor);
    300   EXPECT_EQ(autofill::WebElementDescriptor::ID, click_elment.retrieval_method);
    301 
    302   // Clear |field_infos_| for the next test.
    303   field_infos_.clear();
    304 
    305   // Test setting of ignore_ajax attribute.
    306   xml = "<autofillqueryresponse>"
    307         "<field autofilltype=\"55\"/>"
    308         "<autofill_flow page_no=\"1\" total_pages=\"10\" ignore_ajax=\"true\">"
    309         "<page_advance_button css_selector=\"[name=&quot;foo&quot;]\""
    310         " id=\"foo\"/>"
    311         "</autofill_flow>"
    312         "</autofillqueryresponse>";
    313 
    314   ParseQueryXML(xml, true);
    315 
    316   EXPECT_EQ(1U, field_infos_.size());
    317   EXPECT_EQ(1, page_meta_data_.current_page_number);
    318   EXPECT_EQ(10, page_meta_data_.total_pages);
    319   EXPECT_TRUE(page_meta_data_.ignore_ajax);
    320   EXPECT_EQ("[name=\"foo\"]",
    321             page_meta_data_.proceed_element_descriptor.descriptor);
    322   EXPECT_EQ(autofill::WebElementDescriptor::CSS_SELECTOR,
    323             page_meta_data_.proceed_element_descriptor.retrieval_method);
    324 
    325  // Clear |field_infos_| for the next test.
    326   field_infos_.clear();
    327 
    328   // Test redundant setting to false of ignore_ajax attribute.
    329   xml = "<autofillqueryresponse>"
    330         "<field autofilltype=\"55\"/>"
    331         "<autofill_flow page_no=\"1\" total_pages=\"10\" ignore_ajax=\"false\">"
    332         "<page_advance_button css_selector=\"[name=&quot;foo&quot;]\""
    333         " id=\"foo\"/>"
    334         "</autofill_flow>"
    335         "</autofillqueryresponse>";
    336 
    337   ParseQueryXML(xml, true);
    338 
    339   EXPECT_EQ(1U, field_infos_.size());
    340   EXPECT_EQ(1, page_meta_data_.current_page_number);
    341   EXPECT_EQ(10, page_meta_data_.total_pages);
    342   EXPECT_FALSE(page_meta_data_.ignore_ajax);
    343   EXPECT_EQ("[name=\"foo\"]",
    344             page_meta_data_.proceed_element_descriptor.descriptor);
    345   EXPECT_EQ(autofill::WebElementDescriptor::CSS_SELECTOR,
    346             page_meta_data_.proceed_element_descriptor.retrieval_method);
    347 }
    348 
    349 // Test badly formed XML queries.
    350 TEST_F(AutofillQueryXmlParserTest, ParseErrors) {
    351   // Test no Autofill type.
    352   std::string xml = "<autofillqueryresponse>"
    353                     "<field/>"
    354                     "</autofillqueryresponse>";
    355 
    356   ParseQueryXML(xml, false);
    357 
    358   EXPECT_EQ(USE_UPLOAD_RATES, upload_required_);
    359   EXPECT_EQ(0U, field_infos_.size());
    360   EXPECT_TRUE(experiment_id_.empty());
    361 
    362   // Test an incorrect Autofill type.
    363   xml = "<autofillqueryresponse>"
    364         "<field autofilltype=\"-1\"/>"
    365         "</autofillqueryresponse>";
    366 
    367   ParseQueryXML(xml, true);
    368 
    369   EXPECT_EQ(USE_UPLOAD_RATES, upload_required_);
    370   ASSERT_EQ(1U, field_infos_.size());
    371   // AutofillType was out of range and should be set to NO_SERVER_DATA.
    372   EXPECT_EQ(NO_SERVER_DATA, field_infos_[0].field_type);
    373   EXPECT_TRUE(experiment_id_.empty());
    374 
    375   // Test upper bound for the field type, MAX_VALID_FIELD_TYPE.
    376   field_infos_.clear();
    377   xml = "<autofillqueryresponse><field autofilltype=\"" +
    378       base::IntToString(MAX_VALID_FIELD_TYPE) + "\"/></autofillqueryresponse>";
    379 
    380   ParseQueryXML(xml, true);
    381 
    382   EXPECT_EQ(USE_UPLOAD_RATES, upload_required_);
    383   ASSERT_EQ(1U, field_infos_.size());
    384   // AutofillType was out of range and should be set to NO_SERVER_DATA.
    385   EXPECT_EQ(NO_SERVER_DATA, field_infos_[0].field_type);
    386   EXPECT_TRUE(experiment_id_.empty());
    387 
    388   // Test an incorrect Autofill type.
    389   field_infos_.clear();
    390   xml = "<autofillqueryresponse>"
    391         "<field autofilltype=\"No Type\"/>"
    392         "</autofillqueryresponse>";
    393 
    394   // Parse fails but an entry is still added to field_infos_.
    395   ParseQueryXML(xml, false);
    396 
    397   EXPECT_EQ(USE_UPLOAD_RATES, upload_required_);
    398   ASSERT_EQ(1U, field_infos_.size());
    399   EXPECT_EQ(NO_SERVER_DATA, field_infos_[0].field_type);
    400   EXPECT_TRUE(experiment_id_.empty());
    401 }
    402 
    403 // Test successfull upload response.
    404 TEST_F(AutofillUploadXmlParserTest, TestSuccessfulResponse) {
    405   ParseUploadXML("<autofilluploadresponse positiveuploadrate=\"0.5\" "
    406                  "negativeuploadrate=\"0.3\"/>",
    407                  true);
    408 
    409   EXPECT_DOUBLE_EQ(0.5, positive_);
    410   EXPECT_DOUBLE_EQ(0.3, negative_);
    411 }
    412 
    413 // Test failed upload response.
    414 TEST_F(AutofillUploadXmlParserTest, TestFailedResponse) {
    415   ParseUploadXML("<autofilluploadresponse positiveuploadrate=\"\" "
    416                  "negativeuploadrate=\"0.3\"/>",
    417                  false);
    418 
    419   EXPECT_DOUBLE_EQ(0, positive_);
    420   EXPECT_DOUBLE_EQ(0.3, negative_);  // Partially parsed.
    421   negative_ = 0;
    422 
    423   ParseUploadXML("<autofilluploadresponse positiveuploadrate=\"0.5\" "
    424                  "negativeuploadrate=\"0.3\"",
    425                  false);
    426 
    427   EXPECT_DOUBLE_EQ(0, positive_);
    428   EXPECT_DOUBLE_EQ(0, negative_);
    429 
    430   ParseUploadXML("bad data", false);
    431 
    432   EXPECT_DOUBLE_EQ(0, positive_);
    433   EXPECT_DOUBLE_EQ(0, negative_);
    434 
    435   ParseUploadXML(std::string(), false);
    436 
    437   EXPECT_DOUBLE_EQ(0, positive_);
    438   EXPECT_DOUBLE_EQ(0, negative_);
    439 }
    440 
    441 }  // namespace
    442 }  // namespace autofill
    443