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
15using 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.
21class 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
36ParamFilterImpl::ParamFilterImpl(std::string name_str, std::string value_str)
37   : name_str_(name_str),
38     value_str_(value_str) {
39}
40
41ParamFilterImpl::~ParamFilterImpl() {
42}
43
44bool 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
53class 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
74TemplateURLParserTest::TemplateURLParserTest() {
75}
76
77TemplateURLParserTest::~TemplateURLParserTest() {
78}
79
80void 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
90bool TemplateURLParserTest::is_disabled() const {
91  return full_path_.empty();
92}
93
94void 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
112TEST_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
119TEST_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
126TEST_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
133TEST_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
146TEST_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
160TEST_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
182TEST_F(TemplateURLParserTest, NoCrashOnEmptyAttributes) {
183  if (is_disabled())
184    return;
185  ASSERT_NO_FATAL_FAILURE(ParseFile("url_with_no_attributes.xml", NULL));
186}
187
188TEST_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
208TEST_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
225TEST_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).
247TEST_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