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