1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "base/files/file_util.h" 6 #include "base/logging.h" 7 #include "base/path_service.h" 8 #include "base/strings/utf_string_conversions.h" 9 #include "chrome/common/chrome_paths.h" 10 #include "components/search_engines/search_terms_data.h" 11 #include "components/search_engines/template_url.h" 12 #include "components/search_engines/template_url_parser.h" 13 #include "testing/gtest/include/gtest/gtest.h" 14 15 using base::ASCIIToUTF16; 16 17 // ParamFilterImpl ------------------------------------------------------------ 18 19 // Filters any param which as an occurrence of name_str_ in its name or an 20 // occurrence of value_str_ in its value. 21 class ParamFilterImpl : public TemplateURLParser::ParameterFilter { 22 public: 23 ParamFilterImpl(std::string name_str, std::string value_str); 24 virtual ~ParamFilterImpl(); 25 26 virtual bool KeepParameter(const std::string& key, 27 const std::string& value) OVERRIDE; 28 29 private: 30 std::string name_str_; 31 std::string value_str_; 32 33 DISALLOW_COPY_AND_ASSIGN(ParamFilterImpl); 34 }; 35 36 ParamFilterImpl::ParamFilterImpl(std::string name_str, std::string value_str) 37 : name_str_(name_str), 38 value_str_(value_str) { 39 } 40 41 ParamFilterImpl::~ParamFilterImpl() { 42 } 43 44 bool ParamFilterImpl::KeepParameter(const std::string& key, 45 const std::string& value) { 46 return (name_str_.empty() || key.find(name_str_) == std::string::npos) && 47 (value_str_.empty() || value.find(value_str_) == std::string::npos); 48 } 49 50 51 // TemplateURLParserTest ------------------------------------------------------ 52 53 class TemplateURLParserTest : public testing::Test { 54 protected: 55 TemplateURLParserTest(); 56 virtual ~TemplateURLParserTest(); 57 58 virtual void SetUp() OVERRIDE; 59 60 bool is_disabled() const; 61 62 // Parses the OpenSearch description document at file_name (relative to the 63 // data dir). The TemplateURL is placed in |template_url_|. 64 void ParseFile(const std::string& file_name, 65 TemplateURLParser::ParameterFilter* filter); 66 67 // ParseFile parses the results into this template_url. 68 scoped_ptr<TemplateURL> template_url_; 69 70 private: 71 base::FilePath full_path_; 72 }; 73 74 TemplateURLParserTest::TemplateURLParserTest() { 75 } 76 77 TemplateURLParserTest::~TemplateURLParserTest() { 78 } 79 80 void TemplateURLParserTest::SetUp() { 81 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &full_path_)); 82 full_path_ = full_path_.AppendASCII("osdd"); 83 if (!base::PathExists(full_path_)) { 84 LOG(ERROR) << 85 "This test can't be run without some non-redistributable data"; 86 full_path_ = base::FilePath(); 87 } 88 } 89 90 bool TemplateURLParserTest::is_disabled() const { 91 return full_path_.empty(); 92 } 93 94 void TemplateURLParserTest::ParseFile( 95 const std::string& file_name, 96 TemplateURLParser::ParameterFilter* filter) { 97 base::FilePath full_path; 98 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &full_path)); 99 full_path = full_path.AppendASCII("osdd"); 100 full_path = full_path.AppendASCII(file_name); 101 ASSERT_TRUE(base::PathExists(full_path)); 102 103 std::string contents; 104 ASSERT_TRUE(base::ReadFileToString(full_path, &contents)); 105 template_url_.reset(TemplateURLParser::Parse( 106 SearchTermsData(), false, contents.data(), contents.length(), filter)); 107 } 108 109 110 // Actual tests --------------------------------------------------------------- 111 112 TEST_F(TemplateURLParserTest, FailOnBogusURL) { 113 if (is_disabled()) 114 return; 115 ASSERT_NO_FATAL_FAILURE(ParseFile("bogus.xml", NULL)); 116 EXPECT_FALSE(template_url_.get()); 117 } 118 119 TEST_F(TemplateURLParserTest, PassOnHTTPS) { 120 if (is_disabled()) 121 return; 122 ASSERT_NO_FATAL_FAILURE(ParseFile("https.xml", NULL)); 123 EXPECT_TRUE(template_url_.get()); 124 } 125 126 TEST_F(TemplateURLParserTest, FailOnPost) { 127 if (is_disabled()) 128 return; 129 ASSERT_NO_FATAL_FAILURE(ParseFile("post.xml", NULL)); 130 EXPECT_FALSE(template_url_.get()); 131 } 132 133 TEST_F(TemplateURLParserTest, TestDictionary) { 134 if (is_disabled()) 135 return; 136 ASSERT_NO_FATAL_FAILURE(ParseFile("dictionary.xml", NULL)); 137 ASSERT_TRUE(template_url_.get()); 138 EXPECT_EQ(ASCIIToUTF16("Dictionary.com"), template_url_->short_name()); 139 EXPECT_EQ(GURL("http://cache.lexico.com/g/d/favicon.ico"), 140 template_url_->favicon_url()); 141 EXPECT_TRUE(template_url_->url_ref().SupportsReplacement(SearchTermsData())); 142 EXPECT_EQ("http://dictionary.reference.com/browse/{searchTerms}?r=75", 143 template_url_->url()); 144 } 145 146 TEST_F(TemplateURLParserTest, TestMSDN) { 147 if (is_disabled()) 148 return; 149 ASSERT_NO_FATAL_FAILURE(ParseFile("msdn.xml", NULL)); 150 ASSERT_TRUE(template_url_.get()); 151 EXPECT_EQ(ASCIIToUTF16("Search \" MSDN"), template_url_->short_name()); 152 EXPECT_EQ(GURL("http://search.msdn.microsoft.com/search/favicon.ico"), 153 template_url_->favicon_url()); 154 EXPECT_TRUE(template_url_->url_ref().SupportsReplacement(SearchTermsData())); 155 EXPECT_EQ("http://search.msdn.microsoft.com/search/default.aspx?" 156 "Query={searchTerms}&brand=msdn&locale=en-US", 157 template_url_->url()); 158 } 159 160 TEST_F(TemplateURLParserTest, TestWikipedia) { 161 if (is_disabled()) 162 return; 163 ASSERT_NO_FATAL_FAILURE(ParseFile("wikipedia.xml", NULL)); 164 ASSERT_TRUE(template_url_.get()); 165 EXPECT_EQ(ASCIIToUTF16("Wikipedia (English)"), template_url_->short_name()); 166 EXPECT_EQ(GURL("http://en.wikipedia.org/favicon.ico"), 167 template_url_->favicon_url()); 168 EXPECT_TRUE(template_url_->url_ref().SupportsReplacement(SearchTermsData())); 169 EXPECT_EQ("http://en.wikipedia.org/w/index.php?" 170 "title=Special:Search&search={searchTerms}", 171 template_url_->url()); 172 EXPECT_TRUE(template_url_->suggestions_url_ref().SupportsReplacement( 173 SearchTermsData())); 174 EXPECT_EQ("http://en.wikipedia.org/w/api.php?" 175 "action=opensearch&search={searchTerms}", 176 template_url_->suggestions_url()); 177 ASSERT_EQ(2U, template_url_->input_encodings().size()); 178 EXPECT_EQ("UTF-8", template_url_->input_encodings()[0]); 179 EXPECT_EQ("Shift_JIS", template_url_->input_encodings()[1]); 180 } 181 182 TEST_F(TemplateURLParserTest, NoCrashOnEmptyAttributes) { 183 if (is_disabled()) 184 return; 185 ASSERT_NO_FATAL_FAILURE(ParseFile("url_with_no_attributes.xml", NULL)); 186 } 187 188 TEST_F(TemplateURLParserTest, TestFirefoxEbay) { 189 if (is_disabled()) 190 return; 191 // This file uses the Parameter extension 192 // (see http://www.opensearch.org/Specifications/OpenSearch/Extensions/Parameter/1.0) 193 ParamFilterImpl filter("ebay", "ebay"); 194 ASSERT_NO_FATAL_FAILURE(ParseFile("firefox_ebay.xml", &filter)); 195 ASSERT_TRUE(template_url_.get()); 196 EXPECT_EQ(ASCIIToUTF16("eBay"), template_url_->short_name()); 197 EXPECT_TRUE(template_url_->url_ref().SupportsReplacement(SearchTermsData())); 198 EXPECT_EQ("http://search.ebay.com/search/search.dll?query={searchTerms}&" 199 "MfcISAPICommand=GetResult&ht=1&srchdesc=n&maxRecordsReturned=300&" 200 "maxRecordsPerPage=50&SortProperty=MetaEndSort", 201 template_url_->url()); 202 ASSERT_EQ(1U, template_url_->input_encodings().size()); 203 EXPECT_EQ("ISO-8859-1", template_url_->input_encodings()[0]); 204 EXPECT_EQ(GURL("http://search.ebay.com/favicon.ico"), 205 template_url_->favicon_url()); 206 } 207 208 TEST_F(TemplateURLParserTest, TestFirefoxWebster) { 209 if (is_disabled()) 210 return; 211 // This XML file uses a namespace. 212 ParamFilterImpl filter(std::string(), "Mozilla"); 213 ASSERT_NO_FATAL_FAILURE(ParseFile("firefox_webster.xml", &filter)); 214 ASSERT_TRUE(template_url_.get()); 215 EXPECT_EQ(ASCIIToUTF16("Webster"), template_url_->short_name()); 216 EXPECT_TRUE(template_url_->url_ref().SupportsReplacement(SearchTermsData())); 217 EXPECT_EQ("http://www.webster.com/cgi-bin/dictionary?va={searchTerms}", 218 template_url_->url()); 219 ASSERT_EQ(1U, template_url_->input_encodings().size()); 220 EXPECT_EQ("ISO-8859-1", template_url_->input_encodings()[0]); 221 EXPECT_EQ(GURL("http://www.webster.com/favicon.ico"), 222 template_url_->favicon_url()); 223 } 224 225 TEST_F(TemplateURLParserTest, TestFirefoxYahoo) { 226 if (is_disabled()) 227 return; 228 // This XML file uses a namespace. 229 ParamFilterImpl filter(std::string(), "Mozilla"); 230 ASSERT_NO_FATAL_FAILURE(ParseFile("firefox_yahoo.xml", &filter)); 231 ASSERT_TRUE(template_url_.get()); 232 EXPECT_EQ(ASCIIToUTF16("Yahoo"), template_url_->short_name()); 233 EXPECT_TRUE(template_url_->url_ref().SupportsReplacement(SearchTermsData())); 234 EXPECT_EQ("http://ff.search.yahoo.com/gossip?" 235 "output=fxjson&command={searchTerms}", 236 template_url_->suggestions_url()); 237 EXPECT_EQ("http://search.yahoo.com/search?p={searchTerms}&ei=UTF-8", 238 template_url_->url()); 239 ASSERT_EQ(1U, template_url_->input_encodings().size()); 240 EXPECT_EQ("UTF-8", template_url_->input_encodings()[0]); 241 EXPECT_EQ(GURL("http://search.yahoo.com/favicon.ico"), 242 template_url_->favicon_url()); 243 } 244 245 // Make sure we ignore POST suggestions (this is the same XML file as 246 // firefox_yahoo.xml, the suggestion method was just changed to POST). 247 TEST_F(TemplateURLParserTest, TestPostSuggestion) { 248 if (is_disabled()) 249 return; 250 // This XML file uses a namespace. 251 ParamFilterImpl filter(std::string(), "Mozilla"); 252 ASSERT_NO_FATAL_FAILURE(ParseFile("post_suggestion.xml", &filter)); 253 ASSERT_TRUE(template_url_.get()); 254 EXPECT_EQ(ASCIIToUTF16("Yahoo"), template_url_->short_name()); 255 EXPECT_TRUE(template_url_->url_ref().SupportsReplacement(SearchTermsData())); 256 EXPECT_TRUE(template_url_->suggestions_url().empty()); 257 EXPECT_EQ("http://search.yahoo.com/search?p={searchTerms}&ei=UTF-8", 258 template_url_->url()); 259 ASSERT_EQ(1U, template_url_->input_encodings().size()); 260 EXPECT_EQ("UTF-8", template_url_->input_encodings()[0]); 261 EXPECT_EQ(GURL("http://search.yahoo.com/favicon.ico"), 262 template_url_->favicon_url()); 263 } 264