template_url_unittest.cc revision 72a454cd3513ac24fbdd0e0cb9ad70b86a99b801
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/base_paths.h"
6#include "base/string_util.h"
7#include "base/utf_string_conversions.h"
8#include "chrome/browser/browser_process.h"
9#include "chrome/browser/rlz/rlz.h"
10#include "chrome/browser/search_engines/search_terms_data.h"
11#include "chrome/browser/search_engines/template_url.h"
12#include "testing/gtest/include/gtest/gtest.h"
13
14// Simple implementation of SearchTermsData.
15class TestSearchTermsData : public SearchTermsData {
16 public:
17  explicit TestSearchTermsData(const char* google_base_url)
18      : google_base_url_(google_base_url)  {
19  }
20
21  virtual std::string GoogleBaseURLValue() const {
22    return google_base_url_;
23  }
24
25  virtual std::string GetApplicationLocale() const {
26    return "yy";
27  }
28
29#if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
30  // Returns the value for the Chrome Omnibox rlz.
31  virtual string16 GetRlzParameterValue() const {
32    return string16();
33  }
34#endif
35
36 private:
37  std::string google_base_url_;
38
39  DISALLOW_COPY_AND_ASSIGN(TestSearchTermsData);
40};
41
42class TemplateURLTest : public testing::Test {
43 public:
44  virtual void TearDown() {
45    TemplateURLRef::SetGoogleBaseURL(NULL);
46  }
47
48  void CheckSuggestBaseURL(const char* base_url,
49                           const char* base_suggest_url) const {
50    TestSearchTermsData search_terms_data(base_url);
51    EXPECT_STREQ(base_suggest_url,
52                 search_terms_data.GoogleBaseSuggestURLValue().c_str());
53  }
54};
55
56TEST_F(TemplateURLTest, Defaults) {
57  TemplateURL url;
58  ASSERT_FALSE(url.show_in_default_list());
59  ASSERT_FALSE(url.safe_for_autoreplace());
60  ASSERT_EQ(0, url.prepopulate_id());
61}
62
63TEST_F(TemplateURLTest, TestValidWithComplete) {
64  TemplateURLRef ref("{searchTerms}", 0, 0);
65  ASSERT_TRUE(ref.IsValid());
66}
67
68TEST_F(TemplateURLTest, URLRefTestSearchTerms) {
69  struct SearchTermsCase {
70    const char* url;
71    const string16 terms;
72    const char* output;
73  } search_term_cases[] = {
74    { "http://foo{searchTerms}", ASCIIToUTF16("sea rch/bar"),
75      "http://foosea%20rch/bar" },
76    { "http://foo{searchTerms}?boo=abc", ASCIIToUTF16("sea rch/bar"),
77      "http://foosea%20rch/bar?boo=abc" },
78    { "http://foo/?boo={searchTerms}", ASCIIToUTF16("sea rch/bar"),
79      "http://foo/?boo=sea+rch%2Fbar" },
80    { "http://en.wikipedia.org/{searchTerms}", ASCIIToUTF16("wiki/?"),
81      "http://en.wikipedia.org/wiki/%3F" }
82  };
83  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(search_term_cases); ++i) {
84    const SearchTermsCase& value = search_term_cases[i];
85    TemplateURL t_url;
86    TemplateURLRef ref(value.url, 0, 0);
87    ASSERT_TRUE(ref.IsValid());
88
89    ASSERT_TRUE(ref.SupportsReplacement());
90    GURL result = GURL(ref.ReplaceSearchTerms(t_url, value.terms,
91        TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, string16()));
92    ASSERT_TRUE(result.is_valid());
93    ASSERT_EQ(value.output, result.spec());
94  }
95}
96
97TEST_F(TemplateURLTest, URLRefTestCount) {
98  TemplateURL t_url;
99  TemplateURLRef ref("http://foo{searchTerms}{count?}", 0, 0);
100  ASSERT_TRUE(ref.IsValid());
101  ASSERT_TRUE(ref.SupportsReplacement());
102  GURL result = GURL(ref.ReplaceSearchTerms(t_url, ASCIIToUTF16("X"),
103      TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, string16()));
104  ASSERT_TRUE(result.is_valid());
105  ASSERT_EQ("http://foox/", result.spec());
106}
107
108TEST_F(TemplateURLTest, URLRefTestCount2) {
109  TemplateURL t_url;
110  TemplateURLRef ref("http://foo{searchTerms}{count}", 0, 0);
111  ASSERT_TRUE(ref.IsValid());
112  ASSERT_TRUE(ref.SupportsReplacement());
113  GURL result = GURL(ref.ReplaceSearchTerms(t_url, ASCIIToUTF16("X"),
114      TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, string16()));
115  ASSERT_TRUE(result.is_valid());
116  ASSERT_EQ("http://foox10/", result.spec());
117}
118
119TEST_F(TemplateURLTest, URLRefTestIndices) {
120  TemplateURL t_url;
121  TemplateURLRef ref("http://foo{searchTerms}x{startIndex?}y{startPage?}",
122                     1, 2);
123  ASSERT_TRUE(ref.IsValid());
124  ASSERT_TRUE(ref.SupportsReplacement());
125  GURL result = GURL(ref.ReplaceSearchTerms(t_url, ASCIIToUTF16("X"),
126      TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, string16()));
127  ASSERT_TRUE(result.is_valid());
128  ASSERT_EQ("http://fooxxy/", result.spec());
129}
130
131TEST_F(TemplateURLTest, URLRefTestIndices2) {
132  TemplateURL t_url;
133  TemplateURLRef ref("http://foo{searchTerms}x{startIndex}y{startPage}", 1, 2);
134  ASSERT_TRUE(ref.IsValid());
135  ASSERT_TRUE(ref.SupportsReplacement());
136  GURL result = GURL(ref.ReplaceSearchTerms(t_url, ASCIIToUTF16("X"),
137      TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, string16()));
138  ASSERT_TRUE(result.is_valid());
139  ASSERT_EQ("http://fooxx1y2/", result.spec());
140}
141
142TEST_F(TemplateURLTest, URLRefTestEncoding) {
143  TemplateURL t_url;
144  TemplateURLRef ref(
145      "http://foo{searchTerms}x{inputEncoding?}y{outputEncoding?}a", 1, 2);
146  ASSERT_TRUE(ref.IsValid());
147  ASSERT_TRUE(ref.SupportsReplacement());
148  GURL result = GURL(ref.ReplaceSearchTerms(t_url, ASCIIToUTF16("X"),
149      TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, string16()));
150  ASSERT_TRUE(result.is_valid());
151  ASSERT_EQ("http://fooxxutf-8ya/", result.spec());
152}
153
154TEST_F(TemplateURLTest, InputEncodingBeforeSearchTerm) {
155  TemplateURL t_url;
156  TemplateURLRef ref(
157      "http://foox{inputEncoding?}a{searchTerms}y{outputEncoding?}b", 1, 2);
158  ASSERT_TRUE(ref.IsValid());
159  ASSERT_TRUE(ref.SupportsReplacement());
160  GURL result = GURL(ref.ReplaceSearchTerms(t_url, ASCIIToUTF16("X"),
161      TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, string16()));
162  ASSERT_TRUE(result.is_valid());
163  ASSERT_EQ("http://fooxutf-8axyb/", result.spec());
164}
165
166TEST_F(TemplateURLTest, URLRefTestEncoding2) {
167  TemplateURL t_url;
168  TemplateURLRef ref(
169      "http://foo{searchTerms}x{inputEncoding}y{outputEncoding}a", 1, 2);
170  ASSERT_TRUE(ref.IsValid());
171  ASSERT_TRUE(ref.SupportsReplacement());
172  GURL result = GURL(ref.ReplaceSearchTerms(t_url, ASCIIToUTF16("X"),
173      TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, string16()));
174  ASSERT_TRUE(result.is_valid());
175  ASSERT_EQ("http://fooxxutf-8yutf-8a/", result.spec());
176}
177
178TEST_F(TemplateURLTest, URLRefTestSearchTermsUsingTermsData) {
179  struct SearchTermsCase {
180    const char* url;
181    const string16 terms;
182    const char* output;
183  } search_term_cases[] = {
184    { "{google:baseURL}{language}{searchTerms}", string16(),
185      "http://example.com/e/yy" },
186    { "{google:baseSuggestURL}{searchTerms}", string16(),
187      "http://clients1.example.com/complete/" }
188  };
189
190  TestSearchTermsData search_terms_data("http://example.com/e/");
191  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(search_term_cases); ++i) {
192    const SearchTermsCase& value = search_term_cases[i];
193    TemplateURL t_url;
194    TemplateURLRef ref(value.url, 0, 0);
195    ASSERT_TRUE(ref.IsValid());
196
197    ASSERT_TRUE(ref.SupportsReplacement());
198    GURL result = GURL(ref.ReplaceSearchTermsUsingTermsData(
199        t_url, value.terms,
200        TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, string16(),
201        search_terms_data));
202    ASSERT_TRUE(result.is_valid());
203    ASSERT_EQ(value.output, result.spec());
204  }
205}
206
207TEST_F(TemplateURLTest, URLRefTermToWide) {
208  struct ToWideCase {
209    const char* encoded_search_term;
210    const string16 expected_decoded_term;
211  } to_wide_cases[] = {
212    {"hello+world", ASCIIToUTF16("hello world")},
213    // Test some big-5 input.
214    {"%a7A%A6%6e+to+you", WideToUTF16(L"\x4f60\x597d to you")},
215    // Test some UTF-8 input. We should fall back to this when the encoding
216    // doesn't look like big-5. We have a '5' in the middle, which is an invalid
217    // Big-5 trailing byte.
218    {"%e4%bd%a05%e5%a5%bd+to+you", WideToUTF16(L"\x4f60\x35\x597d to you")},
219    // Undecodable input should stay escaped.
220    {"%91%01+abcd", WideToUTF16(L"%91%01 abcd")},
221    // Make sure we convert %2B to +.
222    {"C%2B%2B", ASCIIToUTF16("C++")},
223    // C%2B is escaped as C%252B, make sure we unescape it properly.
224    {"C%252B", ASCIIToUTF16("C%2B")},
225  };
226
227  TemplateURL t_url;
228
229  // Set one input encoding: big-5. This is so we can test fallback to UTF-8.
230  std::vector<std::string> encodings;
231  encodings.push_back("big-5");
232  t_url.set_input_encodings(encodings);
233
234  TemplateURLRef ref("http://foo?q={searchTerms}", 1, 2);
235  ASSERT_TRUE(ref.IsValid());
236  ASSERT_TRUE(ref.SupportsReplacement());
237
238  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(to_wide_cases); i++) {
239    string16 result = ref.SearchTermToString16(t_url,
240        to_wide_cases[i].encoded_search_term);
241
242    EXPECT_EQ(to_wide_cases[i].expected_decoded_term, result);
243  }
244}
245
246TEST_F(TemplateURLTest, SetFavIcon) {
247  TemplateURL url;
248  GURL favicon_url("http://favicon.url");
249  url.SetFavIconURL(favicon_url);
250  ASSERT_EQ(1U, url.image_refs().size());
251  ASSERT_TRUE(favicon_url == url.GetFavIconURL());
252
253  GURL favicon_url2("http://favicon2.url");
254  url.SetFavIconURL(favicon_url2);
255  ASSERT_EQ(1U, url.image_refs().size());
256  ASSERT_TRUE(favicon_url2 == url.GetFavIconURL());
257}
258
259TEST_F(TemplateURLTest, DisplayURLToURLRef) {
260  struct TestData {
261    const std::string url;
262    const string16 expected_result;
263  } data[] = {
264    { "http://foo{searchTerms}x{inputEncoding}y{outputEncoding}a",
265      ASCIIToUTF16("http://foo%sx{inputEncoding}y{outputEncoding}a") },
266    { "http://X",
267      ASCIIToUTF16("http://X") },
268    { "http://foo{searchTerms",
269      ASCIIToUTF16("http://foo{searchTerms") },
270    { "http://foo{searchTerms}{language}",
271      ASCIIToUTF16("http://foo%s{language}") },
272  };
273  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) {
274    TemplateURLRef ref(data[i].url, 1, 2);
275    EXPECT_EQ(data[i].expected_result, ref.DisplayURL());
276    EXPECT_EQ(data[i].url,
277              TemplateURLRef::DisplayURLToURLRef(ref.DisplayURL()));
278  }
279}
280
281TEST_F(TemplateURLTest, ReplaceSearchTerms) {
282  struct TestData {
283    const std::string url;
284    const std::string expected_result;
285  } data[] = {
286    { "http://foo/{language}{searchTerms}{inputEncoding}",
287      "http://foo/{language}XUTF-8" },
288    { "http://foo/{language}{inputEncoding}{searchTerms}",
289      "http://foo/{language}UTF-8X" },
290    { "http://foo/{searchTerms}{language}{inputEncoding}",
291      "http://foo/X{language}UTF-8" },
292    { "http://foo/{searchTerms}{inputEncoding}{language}",
293      "http://foo/XUTF-8{language}" },
294    { "http://foo/{inputEncoding}{searchTerms}{language}",
295      "http://foo/UTF-8X{language}" },
296    { "http://foo/{inputEncoding}{language}{searchTerms}",
297      "http://foo/UTF-8{language}X" },
298    { "http://foo/{language}a{searchTerms}a{inputEncoding}a",
299      "http://foo/{language}aXaUTF-8a" },
300    { "http://foo/{language}a{inputEncoding}a{searchTerms}a",
301      "http://foo/{language}aUTF-8aXa" },
302    { "http://foo/{searchTerms}a{language}a{inputEncoding}a",
303      "http://foo/Xa{language}aUTF-8a" },
304    { "http://foo/{searchTerms}a{inputEncoding}a{language}a",
305      "http://foo/XaUTF-8a{language}a" },
306    { "http://foo/{inputEncoding}a{searchTerms}a{language}a",
307      "http://foo/UTF-8aXa{language}a" },
308    { "http://foo/{inputEncoding}a{language}a{searchTerms}a",
309      "http://foo/UTF-8a{language}aXa" },
310  };
311  TemplateURL turl;
312  turl.add_input_encoding("UTF-8");
313  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) {
314    TemplateURLRef ref(data[i].url, 1, 2);
315    EXPECT_TRUE(ref.IsValid());
316    EXPECT_TRUE(ref.SupportsReplacement());
317    std::string expected_result = data[i].expected_result;
318    ReplaceSubstringsAfterOffset(&expected_result, 0, "{language}",
319        g_browser_process->GetApplicationLocale());
320    GURL result = GURL(ref.ReplaceSearchTerms(turl, ASCIIToUTF16("X"),
321        TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, string16()));
322    EXPECT_TRUE(result.is_valid());
323    EXPECT_EQ(expected_result, result.spec());
324  }
325}
326
327
328// Tests replacing search terms in various encodings and making sure the
329// generated URL matches the expected value.
330TEST_F(TemplateURLTest, ReplaceArbitrarySearchTerms) {
331  struct TestData {
332    const std::string encoding;
333    const string16 search_term;
334    const std::string url;
335    const std::string expected_result;
336  } data[] = {
337    { "BIG5",  WideToUTF16(L"\x60BD"),
338      "http://foo/?{searchTerms}{inputEncoding}",
339      "http://foo/?%B1~BIG5" },
340    { "UTF-8", ASCIIToUTF16("blah"),
341      "http://foo/?{searchTerms}{inputEncoding}",
342      "http://foo/?blahUTF-8" },
343  };
344  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) {
345    TemplateURL turl;
346    turl.add_input_encoding(data[i].encoding);
347    TemplateURLRef ref(data[i].url, 1, 2);
348    GURL result = GURL(ref.ReplaceSearchTerms(turl,
349        data[i].search_term, TemplateURLRef::NO_SUGGESTIONS_AVAILABLE,
350        string16()));
351    EXPECT_TRUE(result.is_valid());
352    EXPECT_EQ(data[i].expected_result, result.spec());
353  }
354}
355
356TEST_F(TemplateURLTest, Suggestions) {
357  struct TestData {
358    const int accepted_suggestion;
359    const string16 original_query_for_suggestion;
360    const std::string expected_result;
361  } data[] = {
362    { TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, string16(),
363      "http://bar/foo?q=foobar" },
364    { TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, ASCIIToUTF16("foo"),
365      "http://bar/foo?q=foobar" },
366    { TemplateURLRef::NO_SUGGESTION_CHOSEN, string16(),
367      "http://bar/foo?aq=f&q=foobar" },
368    { TemplateURLRef::NO_SUGGESTION_CHOSEN, ASCIIToUTF16("foo"),
369      "http://bar/foo?aq=f&q=foobar" },
370    { 0, string16(), "http://bar/foo?aq=0&oq=&q=foobar" },
371    { 1, ASCIIToUTF16("foo"), "http://bar/foo?aq=1&oq=foo&q=foobar" },
372  };
373  TemplateURL turl;
374  turl.add_input_encoding("UTF-8");
375  TemplateURLRef ref("http://bar/foo?{google:acceptedSuggestion}"
376      "{google:originalQueryForSuggestion}q={searchTerms}", 1, 2);
377  ASSERT_TRUE(ref.IsValid());
378  ASSERT_TRUE(ref.SupportsReplacement());
379  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) {
380    GURL result = GURL(ref.ReplaceSearchTerms(turl, ASCIIToUTF16("foobar"),
381        data[i].accepted_suggestion, data[i].original_query_for_suggestion));
382    EXPECT_TRUE(result.is_valid());
383    EXPECT_EQ(data[i].expected_result, result.spec());
384  }
385}
386
387#if defined(OS_WIN)
388TEST_F(TemplateURLTest, RLZ) {
389  string16 rlz_string;
390#if defined(GOOGLE_CHROME_BUILD)
391  RLZTracker::GetAccessPointRlz(rlz_lib::CHROME_OMNIBOX, &rlz_string);
392#endif
393
394  TemplateURL t_url;
395  TemplateURLRef ref("http://bar/?{google:RLZ}{searchTerms}", 1, 2);
396  ASSERT_TRUE(ref.IsValid());
397  ASSERT_TRUE(ref.SupportsReplacement());
398  GURL result(ref.ReplaceSearchTerms(t_url, L"x",
399      TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, string16()));
400  ASSERT_TRUE(result.is_valid());
401  std::string expected_url = "http://bar/?";
402  if (!rlz_string.empty()) {
403    expected_url += "rlz=" + WideToUTF8(rlz_string) + "&";
404  }
405  expected_url += "x";
406  ASSERT_EQ(expected_url, result.spec());
407}
408#endif
409
410TEST_F(TemplateURLTest, HostAndSearchTermKey) {
411  struct TestData {
412    const std::string url;
413    const std::string host;
414    const std::string path;
415    const std::string search_term_key;
416  } data[] = {
417    { "http://blah/?foo=bar&q={searchTerms}&b=x", "blah", "/", "q"},
418
419    // No query key should result in empty values.
420    { "http://blah/{searchTerms}", "", "", ""},
421
422    // No term should result in empty values.
423    { "http://blah/", "", "", ""},
424
425    // Multiple terms should result in empty values.
426    { "http://blah/?q={searchTerms}&x={searchTerms}", "", "", ""},
427
428    // Term in the host shouldn't match.
429    { "http://{searchTerms}", "", "", ""},
430
431    { "http://blah/?q={searchTerms}", "blah", "/", "q"},
432
433    // Single term with extra chars in value should match.
434    { "http://blah/?q=stock:{searchTerms}", "blah", "/", "q"},
435  };
436
437  TemplateURL t_url;
438  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) {
439    t_url.SetURL(data[i].url, 0, 0);
440    EXPECT_EQ(data[i].host, t_url.url()->GetHost());
441    EXPECT_EQ(data[i].path, t_url.url()->GetPath());
442    EXPECT_EQ(data[i].search_term_key, t_url.url()->GetSearchTermKey());
443  }
444}
445
446TEST_F(TemplateURLTest, GoogleBaseSuggestURL) {
447  static const struct {
448    const char* const base_url;
449    const char* const base_suggest_url;
450  } data[] = {
451    { "http://google.com/", "http://clients1.google.com/complete/", },
452    { "http://www.google.com/", "http://clients1.google.com/complete/", },
453    { "http://www.google.co.uk/", "http://clients1.google.co.uk/complete/", },
454    { "http://www.google.com.by/",
455      "http://clients1.google.com.by/complete/", },
456    { "http://google.com/intl/xx/", "http://clients1.google.com/complete/", },
457  };
458
459  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i)
460    CheckSuggestBaseURL(data[i].base_url, data[i].base_suggest_url);
461}
462
463TEST_F(TemplateURLTest, Keyword) {
464  TemplateURL t_url;
465  t_url.SetURL("http://www.google.com/search", 0, 0);
466  EXPECT_FALSE(t_url.autogenerate_keyword());
467  t_url.set_keyword(ASCIIToUTF16("foo"));
468  EXPECT_EQ(ASCIIToUTF16("foo"), t_url.keyword());
469  t_url.set_autogenerate_keyword(true);
470  EXPECT_TRUE(t_url.autogenerate_keyword());
471  EXPECT_EQ(ASCIIToUTF16("google.com"), t_url.keyword());
472  t_url.set_keyword(ASCIIToUTF16("foo"));
473  EXPECT_FALSE(t_url.autogenerate_keyword());
474  EXPECT_EQ(ASCIIToUTF16("foo"), t_url.keyword());
475}
476
477TEST_F(TemplateURLTest, ParseParameterKnown) {
478  std::string parsed_url("{searchTerms}");
479  TemplateURLRef url_ref(parsed_url, 0, 0);
480  TemplateURLRef::Replacements replacements;
481  EXPECT_TRUE(url_ref.ParseParameter(0, 12, &parsed_url, &replacements));
482  EXPECT_EQ(std::string(), parsed_url);
483  ASSERT_EQ(1U, replacements.size());
484  EXPECT_EQ(static_cast<size_t>(0), replacements[0].index);
485  EXPECT_EQ(TemplateURLRef::SEARCH_TERMS, replacements[0].type);
486}
487
488TEST_F(TemplateURLTest, ParseParameterUnknown) {
489  std::string parsed_url("{}");
490  TemplateURLRef url_ref(parsed_url, 0, 0);
491  TemplateURLRef::Replacements replacements;
492  EXPECT_FALSE(url_ref.ParseParameter(0, 1, &parsed_url, &replacements));
493  EXPECT_EQ("{}", parsed_url);
494  EXPECT_TRUE(replacements.empty());
495}
496
497TEST_F(TemplateURLTest, ParseURLEmpty) {
498  TemplateURLRef url_ref("", 0, 0);
499  TemplateURLRef::Replacements replacements;
500  bool valid = false;
501  EXPECT_EQ(std::string(), url_ref.ParseURL("", &replacements, &valid));
502  EXPECT_TRUE(replacements.empty());
503  EXPECT_TRUE(valid);
504}
505
506TEST_F(TemplateURLTest, ParseURLNoTemplateEnd) {
507  TemplateURLRef url_ref("{", 0, 0);
508  TemplateURLRef::Replacements replacements;
509  bool valid = false;
510  EXPECT_EQ(std::string(), url_ref.ParseURL("{", &replacements, &valid));
511  EXPECT_TRUE(replacements.empty());
512  EXPECT_FALSE(valid);
513}
514
515TEST_F(TemplateURLTest, ParseURLNoKnownParameters) {
516  TemplateURLRef url_ref("{}", 0, 0);
517  TemplateURLRef::Replacements replacements;
518  bool valid = false;
519  EXPECT_EQ("{}", url_ref.ParseURL("{}", &replacements, &valid));
520  EXPECT_TRUE(replacements.empty());
521  EXPECT_TRUE(valid);
522}
523
524TEST_F(TemplateURLTest, ParseURLTwoParameters) {
525  TemplateURLRef url_ref("{}{{%s}}", 0, 0);
526  TemplateURLRef::Replacements replacements;
527  bool valid = false;
528  EXPECT_EQ("{}{}",
529            url_ref.ParseURL("{}{{searchTerms}}", &replacements, &valid));
530  ASSERT_EQ(1U, replacements.size());
531  EXPECT_EQ(static_cast<size_t>(3), replacements[0].index);
532  EXPECT_EQ(TemplateURLRef::SEARCH_TERMS, replacements[0].type);
533  EXPECT_TRUE(valid);
534}
535
536TEST_F(TemplateURLTest, ParseURLNestedParameter) {
537  TemplateURLRef url_ref("{%s", 0, 0);
538  TemplateURLRef::Replacements replacements;
539  bool valid = false;
540  EXPECT_EQ("{", url_ref.ParseURL("{{searchTerms}", &replacements, &valid));
541  ASSERT_EQ(1U, replacements.size());
542  EXPECT_EQ(static_cast<size_t>(1), replacements[0].index);
543  EXPECT_EQ(TemplateURLRef::SEARCH_TERMS, replacements[0].type);
544  EXPECT_TRUE(valid);
545}
546