Upload upstream chromium 114.0.5735.31
[platform/framework/web/chromium-efl.git] / components / search_engines / template_url_unittest.cc
1 // Copyright 2014 The Chromium Authors
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 "components/search_engines/template_url.h"
6
7 #include <stddef.h>
8 #include <string>
9
10 #include "base/base64.h"
11 #include "base/base_paths.h"
12 #include "base/command_line.h"
13 #include "base/feature_list.h"
14 #include "base/i18n/case_conversion.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/strings/string_util.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "base/test/metrics/histogram_tester.h"
19 #include "base/test/scoped_feature_list.h"
20 #include "components/google/core/common/google_util.h"
21 #include "components/omnibox/common/omnibox_features.h"
22 #include "components/search_engines/search_engines_switches.h"
23 #include "components/search_engines/search_terms_data.h"
24 #include "components/search_engines/testing_search_terms_data.h"
25 #include "net/base/url_util.h"
26 #include "testing/gtest/include/gtest/gtest.h"
27 #include "third_party/metrics_proto/omnibox_event.pb.h"
28 #include "third_party/metrics_proto/omnibox_input_type.pb.h"
29 #include "third_party/omnibox_proto/chrome_searchbox_stats.pb.h"
30
31 using base::ASCIIToUTF16;
32 using RequestSource = SearchTermsData::RequestSource;
33
34 namespace {
35 bool IsLowerCase(const std::u16string& str) {
36   return str == base::i18n::ToLower(str);
37 }
38 }
39
40 class TemplateURLTest : public testing::Test {
41  public:
42   TemplateURLTest() : search_terms_data_("http://www.google.com/") {}
43   void CheckSuggestBaseURL(const std::string& base_url,
44                            const std::string& base_suggest_url) const;
45
46   static void ExpectPostParamIs(
47       const TemplateURLRef::PostParam& param,
48       const std::string& name,
49       const std::string& value,
50       const std::string& content_type = std::string());
51
52   static void ExpectContainsPostParam(
53       const TemplateURLRef::PostParams& params,
54       const std::string& name,
55       const std::string& value,
56       const std::string& content_type = std::string());
57
58   TestingSearchTermsData search_terms_data_;
59 };
60
61 void TemplateURLTest::CheckSuggestBaseURL(
62     const std::string& base_url,
63     const std::string& base_suggest_url) const {
64   TestingSearchTermsData search_terms_data(base_url);
65   EXPECT_EQ(base_suggest_url, search_terms_data.GoogleBaseSuggestURLValue());
66 }
67
68 // static
69 void TemplateURLTest::ExpectPostParamIs(const TemplateURLRef::PostParam& param,
70                                         const std::string& name,
71                                         const std::string& value,
72                                         const std::string& content_type) {
73   EXPECT_EQ(name, param.name);
74   EXPECT_EQ(value, param.value);
75   EXPECT_EQ(content_type, param.content_type);
76 }
77
78 // static
79 void TemplateURLTest::ExpectContainsPostParam(
80     const TemplateURLRef::PostParams& params,
81     const std::string& name,
82     const std::string& value,
83     const std::string& content_type) {
84   for (const auto& param : params) {
85     if (param.name == name && param.value == value &&
86         param.content_type == content_type) {
87       return;
88     }
89   }
90   FAIL() << "Expected post param not found.";
91 }
92
93 TEST_F(TemplateURLTest, Defaults) {
94   TemplateURLData data;
95   EXPECT_FALSE(data.safe_for_autoreplace);
96   EXPECT_EQ(0, data.prepopulate_id);
97 }
98
99 TEST_F(TemplateURLTest, TestValidWithComplete) {
100   TemplateURLData data;
101   data.SetURL("{searchTerms}");
102   TemplateURL url(data);
103   EXPECT_TRUE(url.url_ref().IsValid(search_terms_data_));
104 }
105
106 TEST_F(TemplateURLTest, URLRefTestSearchTerms) {
107   struct SearchTermsCase {
108     const char* url;
109     const std::u16string terms;
110     const std::string output;
111   } search_term_cases[] = {
112       {"http://foo{searchTerms}", u"sea rch/bar", "http://foosea%20rch/bar"},
113       {"http://foo{searchTerms}?boo=abc", u"sea rch/bar",
114        "http://foosea%20rch/bar?boo=abc"},
115       {"http://foo/?boo={searchTerms}", u"sea rch/bar",
116        "http://foo/?boo=sea+rch%2Fbar"},
117       {"http://en.wikipedia.org/{searchTerms}", u"wiki/?",
118        "http://en.wikipedia.org/wiki/%3F"}};
119   for (size_t i = 0; i < std::size(search_term_cases); ++i) {
120     const SearchTermsCase& value = search_term_cases[i];
121     TemplateURLData data;
122     data.SetURL(value.url);
123     TemplateURL url(data);
124     EXPECT_TRUE(url.url_ref().IsValid(search_terms_data_));
125     ASSERT_TRUE(url.url_ref().SupportsReplacement(search_terms_data_));
126     GURL result(url.url_ref().ReplaceSearchTerms(
127         TemplateURLRef::SearchTermsArgs(value.terms), search_terms_data_));
128     ASSERT_TRUE(result.is_valid());
129     EXPECT_EQ(value.output, result.spec());
130   }
131 }
132
133 TEST_F(TemplateURLTest, URLRefTestCount) {
134   TemplateURLData data;
135   data.SetURL("http://foo{searchTerms}{count?}");
136   TemplateURL url(data);
137   EXPECT_TRUE(url.url_ref().IsValid(search_terms_data_));
138   ASSERT_TRUE(url.url_ref().SupportsReplacement(search_terms_data_));
139   GURL result(url.url_ref().ReplaceSearchTerms(
140       TemplateURLRef::SearchTermsArgs(u"X"), search_terms_data_));
141   ASSERT_TRUE(result.is_valid());
142   EXPECT_EQ("http://foox/", result.spec());
143 }
144
145 TEST_F(TemplateURLTest, URLRefTestCount2) {
146   TemplateURLData data;
147   data.SetURL("http://foo{searchTerms}{count}");
148   TemplateURL url(data);
149   EXPECT_TRUE(url.url_ref().IsValid(search_terms_data_));
150   ASSERT_TRUE(url.url_ref().SupportsReplacement(search_terms_data_));
151   GURL result(url.url_ref().ReplaceSearchTerms(
152       TemplateURLRef::SearchTermsArgs(u"X"), search_terms_data_));
153   ASSERT_TRUE(result.is_valid());
154   EXPECT_EQ("http://foox10/", result.spec());
155 }
156
157 TEST_F(TemplateURLTest, URLRefTestIndices) {
158   TemplateURLData data;
159   data.SetURL("http://foo{searchTerms}x{startIndex?}y{startPage?}");
160   TemplateURL url(data);
161   EXPECT_TRUE(url.url_ref().IsValid(search_terms_data_));
162   ASSERT_TRUE(url.url_ref().SupportsReplacement(search_terms_data_));
163   GURL result(url.url_ref().ReplaceSearchTerms(
164       TemplateURLRef::SearchTermsArgs(u"X"), search_terms_data_));
165   ASSERT_TRUE(result.is_valid());
166   EXPECT_EQ("http://fooxxy/", result.spec());
167 }
168
169 TEST_F(TemplateURLTest, URLRefTestIndices2) {
170   TemplateURLData data;
171   data.SetURL("http://foo{searchTerms}x{startIndex}y{startPage}");
172   TemplateURL url(data);
173   EXPECT_TRUE(url.url_ref().IsValid(search_terms_data_));
174   ASSERT_TRUE(url.url_ref().SupportsReplacement(search_terms_data_));
175   GURL result(url.url_ref().ReplaceSearchTerms(
176       TemplateURLRef::SearchTermsArgs(u"X"), search_terms_data_));
177   ASSERT_TRUE(result.is_valid());
178   EXPECT_EQ("http://fooxx1y1/", result.spec());
179 }
180
181 TEST_F(TemplateURLTest, URLRefTestEncoding) {
182   TemplateURLData data;
183   data.SetURL("http://foo{searchTerms}x{inputEncoding?}y{outputEncoding?}a");
184   TemplateURL url(data);
185   EXPECT_TRUE(url.url_ref().IsValid(search_terms_data_));
186   ASSERT_TRUE(url.url_ref().SupportsReplacement(search_terms_data_));
187   GURL result(url.url_ref().ReplaceSearchTerms(
188       TemplateURLRef::SearchTermsArgs(u"X"), search_terms_data_));
189   ASSERT_TRUE(result.is_valid());
190   EXPECT_EQ("http://fooxxutf-8ya/", result.spec());
191 }
192
193 TEST_F(TemplateURLTest, URLRefTestImageURLWithPOST) {
194   const char kInvalidPostParamsString[] =
195       "unknown_template={UnknownTemplate},bad_value=bad{value},"
196       "{google:sbiSource}";
197   // List all accpectable parameter format in valid_post_params_string. it is
198   // expected like: "name0=,name1=value1,name2={template1}"
199   const char kValidPostParamsString[] =
200       "image_content={google:imageThumbnail},image_url={google:imageURL},"
201       "sbisrc={google:imageSearchSource},language={language},empty_param=,"
202       "constant_param=constant,width={google:imageOriginalWidth},"
203       "base64_image_content={google:imageThumbnailBase64}";
204   const char KImageSearchURL[] = "http://foo.com/sbi";
205
206   TemplateURLData data;
207   data.image_url = KImageSearchURL;
208
209   // Try to parse invalid post parameters.
210   data.image_url_post_params = kInvalidPostParamsString;
211   TemplateURL url_bad(data);
212   ASSERT_FALSE(url_bad.image_url_ref().IsValid(search_terms_data_));
213   const TemplateURLRef::PostParams& bad_post_params =
214       url_bad.image_url_ref().post_params_;
215   ASSERT_EQ(2U, bad_post_params.size());
216   ExpectPostParamIs(bad_post_params[0], "unknown_template",
217                     "{UnknownTemplate}");
218   ExpectPostParamIs(bad_post_params[1], "bad_value", "bad{value}");
219
220   // Try to parse valid post parameters.
221   data.image_url_post_params = kValidPostParamsString;
222   TemplateURL url(data);
223   ASSERT_TRUE(url.image_url_ref().IsValid(search_terms_data_));
224   ASSERT_FALSE(url.image_url_ref().SupportsReplacement(search_terms_data_));
225
226   // Check term replacement.
227   TemplateURLRef::SearchTermsArgs search_args(u"X");
228   search_args.image_thumbnail_content = "dummy-image-thumbnail";
229   search_args.image_url = GURL("http://dummyimage.com/dummy.jpg");
230   search_args.image_original_size = gfx::Size(10, 10);
231   // Replacement operation with no post_data buffer should still return
232   // the parsed URL.
233   TestingSearchTermsData search_terms_data("http://X");
234   GURL result(url.image_url_ref().ReplaceSearchTerms(
235       search_args, search_terms_data));
236   ASSERT_TRUE(result.is_valid());
237   EXPECT_EQ(KImageSearchURL, result.spec());
238   TemplateURLRef::PostContent post_content;
239   result = GURL(url.image_url_ref().ReplaceSearchTerms(
240       search_args, search_terms_data, &post_content));
241   ASSERT_TRUE(result.is_valid());
242   EXPECT_EQ(KImageSearchURL, result.spec());
243   ASSERT_FALSE(post_content.first.empty());
244   ASSERT_FALSE(post_content.second.empty());
245
246   // Check parsed result of post parameters.
247   const TemplateURLRef::Replacements& replacements =
248       url.image_url_ref().replacements_;
249   const TemplateURLRef::PostParams& post_params =
250       url.image_url_ref().post_params_;
251   EXPECT_EQ(8U, post_params.size());
252   for (auto i = post_params.begin(); i != post_params.end(); ++i) {
253     auto j = replacements.begin();
254     for (; j != replacements.end(); ++j) {
255       if (j->is_post_param && j->index ==
256           static_cast<size_t>(i - post_params.begin())) {
257         switch (j->type) {
258           case TemplateURLRef::GOOGLE_IMAGE_ORIGINAL_WIDTH:
259             ExpectPostParamIs(
260                 *i, "width",
261                 base::NumberToString(search_args.image_original_size.width()));
262             break;
263           case TemplateURLRef::GOOGLE_IMAGE_SEARCH_SOURCE:
264             ExpectPostParamIs(*i, "sbisrc",
265                               search_terms_data.GoogleImageSearchSource());
266             break;
267           case TemplateURLRef::GOOGLE_IMAGE_THUMBNAIL:
268             ExpectPostParamIs(*i, "image_content",
269                               search_args.image_thumbnail_content,
270                               "image/jpeg");
271             break;
272           case TemplateURLRef::GOOGLE_IMAGE_THUMBNAIL_BASE64: {
273             std::string base64_image_content;
274             base::Base64Encode(search_args.image_thumbnail_content,
275                                &base64_image_content);
276             ExpectPostParamIs(*i, "base64_image_content", base64_image_content,
277                               "image/jpeg");
278             break;
279           }
280           case TemplateURLRef::GOOGLE_IMAGE_URL:
281             ExpectPostParamIs(*i, "image_url", search_args.image_url.spec());
282             break;
283           case TemplateURLRef::LANGUAGE:
284             ExpectPostParamIs(*i, "language", "en");
285             break;
286           default:
287             ADD_FAILURE();  // Should never go here.
288         }
289         break;
290       }
291     }
292     if (j != replacements.end())
293       continue;
294     if (i->name == "empty_param")
295       ExpectPostParamIs(*i, "empty_param", std::string());
296     else
297       ExpectPostParamIs(*i, "constant_param", "constant");
298   }
299 }
300
301 TEST_F(TemplateURLTest, ImageThumbnailContentTypePostParams) {
302   TemplateURLData data;
303   data.image_url = "http://foo.com/sbi";
304   data.image_url_post_params =
305       "image_content={google:imageThumbnail},"
306       "base64_image_content={google:imageThumbnailBase64}";
307   TemplateURL url(data);
308   EXPECT_TRUE(url.url_ref().IsValid(search_terms_data_));
309
310   TemplateURLRef::SearchTermsArgs search_args(u"X");
311   search_args.image_thumbnail_content = "dummy-image-thumbnail";
312   search_args.image_thumbnail_content_type = "image/tiff";
313   TestingSearchTermsData search_terms_data("http://X");
314   GURL result(
315       url.image_url_ref().ReplaceSearchTerms(search_args, search_terms_data));
316   ASSERT_TRUE(result.is_valid());
317
318   const TemplateURLRef::PostParams& post_params =
319       url.image_url_ref().post_params_;
320   ExpectContainsPostParam(post_params, "image_content",
321                           search_args.image_thumbnail_content, "image/tiff");
322   std::string base64_image_content;
323   base::Base64Encode(search_args.image_thumbnail_content,
324                      &base64_image_content);
325   ExpectContainsPostParam(post_params, "base64_image_content",
326                           base64_image_content, "image/tiff");
327 }
328
329 TEST_F(TemplateURLTest, ImageURLWithGetShouldNotCrash) {
330   TemplateURLData data;
331   data.SetURL("http://foo/?q={searchTerms}&t={google:imageThumbnail}");
332   TemplateURL url(data);
333   EXPECT_TRUE(url.url_ref().IsValid(search_terms_data_));
334   ASSERT_TRUE(url.url_ref().SupportsReplacement(search_terms_data_));
335
336   TemplateURLRef::SearchTermsArgs search_args(u"X");
337   search_args.image_thumbnail_content = "dummy-image-thumbnail";
338   GURL result(
339       url.url_ref().ReplaceSearchTerms(search_args, search_terms_data_));
340   ASSERT_TRUE(result.is_valid());
341   EXPECT_EQ("http://foo/?q=X&t=dummy-image-thumbnail", result.spec());
342 }
343
344 // Test that setting the prepopulate ID from TemplateURL causes the stored
345 // TemplateURLRef to handle parsing the URL parameters differently.
346 TEST_F(TemplateURLTest, SetPrepopulatedAndParse) {
347   TemplateURLData data;
348   data.SetURL("http://foo{fhqwhgads}bar");
349   TemplateURL url(data);
350   TemplateURLRef::Replacements replacements;
351   bool valid = false;
352   EXPECT_EQ("http://foo{fhqwhgads}bar",
353             url.url_ref().ParseURL("http://foo{fhqwhgads}bar", &replacements,
354                                    nullptr, &valid));
355   EXPECT_TRUE(replacements.empty());
356   EXPECT_TRUE(valid);
357
358   data.prepopulate_id = 123;
359   TemplateURL url2(data);
360   EXPECT_EQ("http://foobar",
361             url2.url_ref().ParseURL("http://foo{fhqwhgads}bar", &replacements,
362                                     nullptr, &valid));
363   EXPECT_TRUE(replacements.empty());
364   EXPECT_TRUE(valid);
365 }
366
367 // Test that setting the prepopulate ID from TemplateURL causes the stored
368 // TemplateURLRef to handle parsing the URL parameters differently.
369 TEST_F(TemplateURLTest, SetPrepopulatedAndReplace) {
370   TemplateURLData data;
371   data.SetURL("http://foo{fhqwhgads}search/?q={searchTerms}");
372   data.suggestions_url = "http://foo{fhqwhgads}suggest/?q={searchTerms}";
373   data.image_url = "http://foo{fhqwhgads}image/";
374   data.image_translate_url = "http://foo{fhqwhgads}image/?translate";
375   data.new_tab_url = "http://foo{fhqwhgads}newtab/";
376   data.contextual_search_url = "http://foo{fhqwhgads}context/";
377   data.alternate_urls.push_back(
378       "http://foo{fhqwhgads}alternate/?q={searchTerms}");
379
380   TemplateURLRef::SearchTermsArgs args(u"X");
381   const SearchTermsData& stdata = search_terms_data_;
382
383   TemplateURL url(data);
384   EXPECT_EQ("http://foo%7Bfhqwhgads%7Dsearch/?q=X",
385             url.url_ref().ReplaceSearchTerms(args, stdata));
386   EXPECT_EQ("http://foo%7Bfhqwhgads%7Dalternate/?q=X",
387             url.url_refs()[0].ReplaceSearchTerms(args, stdata));
388   EXPECT_EQ("http://foo%7Bfhqwhgads%7Dsearch/?q=X",
389             url.url_refs()[1].ReplaceSearchTerms(args, stdata));
390   EXPECT_EQ("http://foo%7Bfhqwhgads%7Dsuggest/?q=X",
391             url.suggestions_url_ref().ReplaceSearchTerms(args, stdata));
392   EXPECT_EQ("http://foo{fhqwhgads}image/",
393             url.image_url_ref().ReplaceSearchTerms(args, stdata));
394   EXPECT_EQ("http://foo%7Bfhqwhgads%7Dimage/?translate",
395             url.image_translate_url_ref().ReplaceSearchTerms(args, stdata));
396   EXPECT_EQ("http://foo{fhqwhgads}newtab/",
397             url.new_tab_url_ref().ReplaceSearchTerms(args, stdata));
398   EXPECT_EQ("http://foo{fhqwhgads}context/",
399             url.contextual_search_url_ref().ReplaceSearchTerms(args, stdata));
400
401   data.prepopulate_id = 123;
402   TemplateURL url2(data);
403   EXPECT_EQ("http://foosearch/?q=X",
404             url2.url_ref().ReplaceSearchTerms(args, stdata));
405   EXPECT_EQ("http://fooalternate/?q=X",
406             url2.url_refs()[0].ReplaceSearchTerms(args, stdata));
407   EXPECT_EQ("http://foosearch/?q=X",
408             url2.url_refs()[1].ReplaceSearchTerms(args, stdata));
409   EXPECT_EQ("http://foosuggest/?q=X",
410             url2.suggestions_url_ref().ReplaceSearchTerms(args, stdata));
411   EXPECT_EQ("http://fooimage/",
412             url2.image_url_ref().ReplaceSearchTerms(args, stdata));
413   EXPECT_EQ("http://fooimage/?translate",
414             url2.image_translate_url_ref().ReplaceSearchTerms(args, stdata));
415   EXPECT_EQ("http://foonewtab/",
416             url2.new_tab_url_ref().ReplaceSearchTerms(args, stdata));
417   EXPECT_EQ("http://foocontext/",
418             url2.contextual_search_url_ref().ReplaceSearchTerms(args, stdata));
419 }
420
421 TEST_F(TemplateURLTest, InputEncodingBeforeSearchTerm) {
422   TemplateURLData data;
423   data.SetURL("http://foox{inputEncoding?}a{searchTerms}y{outputEncoding?}b");
424   TemplateURL url(data);
425   EXPECT_TRUE(url.url_ref().IsValid(search_terms_data_));
426   ASSERT_TRUE(url.url_ref().SupportsReplacement(search_terms_data_));
427   GURL result(url.url_ref().ReplaceSearchTerms(
428       TemplateURLRef::SearchTermsArgs(u"X"), search_terms_data_));
429   ASSERT_TRUE(result.is_valid());
430   EXPECT_EQ("http://fooxutf-8axyb/", result.spec());
431 }
432
433 TEST_F(TemplateURLTest, URLRefTestEncoding2) {
434   TemplateURLData data;
435   data.SetURL("http://foo{searchTerms}x{inputEncoding}y{outputEncoding}a");
436   TemplateURL url(data);
437   EXPECT_TRUE(url.url_ref().IsValid(search_terms_data_));
438   ASSERT_TRUE(url.url_ref().SupportsReplacement(search_terms_data_));
439   GURL result(url.url_ref().ReplaceSearchTerms(
440       TemplateURLRef::SearchTermsArgs(u"X"), search_terms_data_));
441   ASSERT_TRUE(result.is_valid());
442   EXPECT_EQ("http://fooxxutf-8yutf-8a/", result.spec());
443 }
444
445 TEST_F(TemplateURLTest, URLRefTestSearchTermsUsingTermsData) {
446   struct SearchTermsCase {
447     const char* url;
448     const std::u16string terms;
449     const char* output;
450   } search_term_cases[] = {{"{google:baseURL}{language}{searchTerms}",
451                             std::u16string(), "http://example.com/e/en"},
452                            {"{google:baseSuggestURL}{searchTerms}",
453                             std::u16string(), "http://example.com/complete/"}};
454
455   TestingSearchTermsData search_terms_data("http://example.com/e/");
456   TemplateURLData data;
457   for (size_t i = 0; i < std::size(search_term_cases); ++i) {
458     const SearchTermsCase& value = search_term_cases[i];
459     data.SetURL(value.url);
460     TemplateURL url(data);
461     EXPECT_TRUE(url.url_ref().IsValid(search_terms_data));
462     ASSERT_TRUE(url.url_ref().SupportsReplacement(search_terms_data));
463     GURL result(url.url_ref().ReplaceSearchTerms(
464         TemplateURLRef::SearchTermsArgs(value.terms), search_terms_data,
465         nullptr));
466     ASSERT_TRUE(result.is_valid());
467     EXPECT_EQ(value.output, result.spec());
468   }
469 }
470
471 TEST_F(TemplateURLTest, URLRefTermToWide) {
472   struct ToWideCase {
473     const char* encoded_search_term;
474     const std::u16string expected_decoded_term;
475   } to_wide_cases[] = {
476       {"hello+world", u"hello world"},
477       // Test some big-5 input.
478       {"%a7A%A6%6e+to+you", u"\x4f60\x597d to you"},
479       // Test some UTF-8 input. We should fall back to this when the encoding
480       // doesn't look like big-5. We have a '5' in the middle, which is an
481       // invalid Big-5 trailing byte.
482       {"%e4%bd%a05%e5%a5%bd+to+you", u"\x4f60\x35\x597d to you"},
483       // Undecodable input should stay escaped.
484       {"%91%01+abcd", u"%91%01 abcd"},
485       // Make sure we convert %2B to +.
486       {"C%2B%2B", u"C++"},
487       // C%2B is escaped as C%252B, make sure we unescape it properly.
488       {"C%252B", u"C%2B"},
489   };
490
491   // Set one input encoding: big-5. This is so we can test fallback to UTF-8.
492   TemplateURLData data;
493   data.SetURL("http://foo?q={searchTerms}");
494   data.input_encodings.push_back("big-5");
495   TemplateURL url(data);
496   EXPECT_TRUE(url.url_ref().IsValid(search_terms_data_));
497   ASSERT_TRUE(url.url_ref().SupportsReplacement(search_terms_data_));
498   for (size_t i = 0; i < std::size(to_wide_cases); i++) {
499     EXPECT_EQ(to_wide_cases[i].expected_decoded_term,
500               url.url_ref().SearchTermToString16(
501                   to_wide_cases[i].encoded_search_term));
502   }
503 }
504
505 TEST_F(TemplateURLTest, DisplayURLToURLRef) {
506   struct TestData {
507     const std::string url;
508     const std::u16string expected_result;
509   } test_data[] = {
510       {"http://foo{searchTerms}x{inputEncoding}y{outputEncoding}a",
511        u"http://foo%sx{inputEncoding}y{outputEncoding}a"},
512       {"http://X", u"http://X"},
513       {"http://foo{searchTerms", u"http://foo{searchTerms"},
514       {"http://foo{searchTerms}{language}", u"http://foo%s{language}"},
515   };
516   TemplateURLData data;
517   for (const auto& entry : test_data) {
518     data.SetURL(entry.url);
519     TemplateURL url(data);
520     EXPECT_EQ(entry.expected_result,
521               url.url_ref().DisplayURL(search_terms_data_));
522     EXPECT_EQ(entry.url, TemplateURLRef::DisplayURLToURLRef(
523                              url.url_ref().DisplayURL(search_terms_data_)));
524   }
525 }
526
527 TEST_F(TemplateURLTest, ReplaceSearchTerms) {
528   struct TestData {
529     const std::string url;
530     const std::string expected_result;
531   } test_data[] = {
532     { "http://foo/{language}{searchTerms}{inputEncoding}",
533       "http://foo/{language}XUTF-8" },
534     { "http://foo/{language}{inputEncoding}{searchTerms}",
535       "http://foo/{language}UTF-8X" },
536     { "http://foo/{searchTerms}{language}{inputEncoding}",
537       "http://foo/X{language}UTF-8" },
538     { "http://foo/{searchTerms}{inputEncoding}{language}",
539       "http://foo/XUTF-8{language}" },
540     { "http://foo/{inputEncoding}{searchTerms}{language}",
541       "http://foo/UTF-8X{language}" },
542     { "http://foo/{inputEncoding}{language}{searchTerms}",
543       "http://foo/UTF-8{language}X" },
544     { "http://foo/{language}a{searchTerms}a{inputEncoding}a",
545       "http://foo/{language}aXaUTF-8a" },
546     { "http://foo/{language}a{inputEncoding}a{searchTerms}a",
547       "http://foo/{language}aUTF-8aXa" },
548     { "http://foo/{searchTerms}a{language}a{inputEncoding}a",
549       "http://foo/Xa{language}aUTF-8a" },
550     { "http://foo/{searchTerms}a{inputEncoding}a{language}a",
551       "http://foo/XaUTF-8a{language}a" },
552     { "http://foo/{inputEncoding}a{searchTerms}a{language}a",
553       "http://foo/UTF-8aXa{language}a" },
554     { "http://foo/{inputEncoding}a{language}a{searchTerms}a",
555       "http://foo/UTF-8a{language}aXa" },
556   };
557   TemplateURLData data;
558   data.input_encodings.push_back("UTF-8");
559   for (const auto& entry : test_data) {
560     data.SetURL(entry.url);
561     TemplateURL url(data);
562     EXPECT_TRUE(url.url_ref().IsValid(search_terms_data_));
563     ASSERT_TRUE(url.url_ref().SupportsReplacement(search_terms_data_));
564     std::string expected_result = entry.expected_result;
565     base::ReplaceSubstringsAfterOffset(
566         &expected_result, 0, "{language}",
567         search_terms_data_.GetApplicationLocale());
568     GURL result(url.url_ref().ReplaceSearchTerms(
569         TemplateURLRef::SearchTermsArgs(u"X"), search_terms_data_));
570     ASSERT_TRUE(result.is_valid());
571     EXPECT_EQ(expected_result, result.spec());
572   }
573 }
574
575
576 // Tests replacing search terms in various encodings and making sure the
577 // generated URL matches the expected value.
578 TEST_F(TemplateURLTest, ReplaceArbitrarySearchTerms) {
579   struct TestData {
580     const std::string encoding;
581     const std::u16string search_term;
582     const std::string url;
583     const std::string expected_result;
584   } test_data[] = {
585       {"BIG5", u"悽", "http://foo/?{searchTerms}{inputEncoding}",
586        "http://foo/?%B1~BIG5"},
587       {"UTF-8", u"blah", "http://foo/?{searchTerms}{inputEncoding}",
588        "http://foo/?blahUTF-8"},
589       {"Shift_JIS", u"あ", "http://foo/{searchTerms}/bar",
590        "http://foo/%82%A0/bar"},
591       {"Shift_JIS", u"あ い", "http://foo/{searchTerms}/bar",
592        "http://foo/%82%A0%20%82%A2/bar"},
593   };
594   TemplateURLData data;
595   for (const auto& entry : test_data) {
596     data.SetURL(entry.url);
597     data.input_encodings.clear();
598     data.input_encodings.push_back(entry.encoding);
599     TemplateURL url(data);
600     EXPECT_TRUE(url.url_ref().IsValid(search_terms_data_));
601     ASSERT_TRUE(url.url_ref().SupportsReplacement(search_terms_data_));
602     GURL result(url.url_ref().ReplaceSearchTerms(
603         TemplateURLRef::SearchTermsArgs(entry.search_term),
604         search_terms_data_));
605     ASSERT_TRUE(result.is_valid());
606     EXPECT_EQ(entry.expected_result, result.spec());
607   }
608 }
609
610 // Test that encoding with several optional codepages works as intended.
611 // Codepages are tried in order, fallback is UTF-8.
612 TEST_F(TemplateURLTest, ReplaceSearchTermsMultipleEncodings) {
613   struct TestData {
614     const std::vector<std::string> encodings;
615     const std::u16string search_term;
616     const std::string url;
617     const std::string expected_result;
618   } test_data[] = {
619       // First and third encodings are valid. First is used.
620       {{"windows-1251", "cp-866", "UTF-8"},
621        u"я",
622        "http://foo/?{searchTerms}{inputEncoding}",
623        "http://foo/?%FFwindows-1251"},
624       // Second and third encodings are valid, second is used.
625       {{"cp-866", "GB2312", "UTF-8"},
626        u"狗",
627        "http://foo/?{searchTerms}{inputEncoding}",
628        "http://foo/?%B9%B7GB2312"},
629       // Second and third encodings are valid in another order, second is used.
630       {{"cp-866", "UTF-8", "GB2312"},
631        u"狗",
632        "http://foo/?{searchTerms}{inputEncoding}",
633        "http://foo/?%E7%8B%97UTF-8"},
634       // Both encodings are invalid, fallback to UTF-8.
635       {{"cp-866", "windows-1251"},
636        u"狗",
637        "http://foo/?{searchTerms}{inputEncoding}",
638        "http://foo/?%E7%8B%97UTF-8"},
639       // No encodings are given, fallback to UTF-8.
640       {{},
641        u"狗",
642        "http://foo/?{searchTerms}{inputEncoding}",
643        "http://foo/?%E7%8B%97UTF-8"},
644   };
645
646   TemplateURLData data;
647   for (const auto& entry : test_data) {
648     data.SetURL(entry.url);
649     data.input_encodings = entry.encodings;
650     TemplateURL url(data);
651     EXPECT_TRUE(url.url_ref().IsValid(search_terms_data_));
652     ASSERT_TRUE(url.url_ref().SupportsReplacement(search_terms_data_));
653     GURL result(url.url_ref().ReplaceSearchTerms(
654         TemplateURLRef::SearchTermsArgs(entry.search_term),
655         search_terms_data_));
656     ASSERT_TRUE(result.is_valid());
657     EXPECT_EQ(entry.expected_result, result.spec());
658   }
659 }
660
661 // Tests replacing assisted query stats (AQS) in various scenarios.
662 TEST_F(TemplateURLTest, ReplaceAssistedQueryStats) {
663   base::HistogramTester histogram_tester;
664   base::test::ScopedFeatureList feature_list;
665   feature_list.InitWithFeatures({omnibox::kReportAssistedQueryStats},
666                                 {omnibox::kReportSearchboxStats});
667
668   omnibox::metrics::ChromeSearchboxStats searchbox_stats;
669   searchbox_stats.set_client_name("chrome");
670   searchbox_stats.set_zero_prefix_enabled(true);
671
672   struct TestData {
673     const std::u16string search_term;
674     const std::string aqs;
675     const omnibox::metrics::ChromeSearchboxStats searchbox_stats;
676     const std::string base_url;
677     const std::string url;
678     const std::string expected_result;
679   } test_data[] = {
680       // HTTPS and non-empty gs_lcrp and non-empty AQS: Success.
681       {u"foo", "chrome.0.0l6", searchbox_stats, "https://foo/",
682        "{google:baseURL}?q={searchTerms}&{google:assistedQueryStats}",
683        "https://foo/?q=foo&aqs=chrome.0.0l6&"},
684       // Non-Google HTTPS and non-empty gs_lcrp and non-empty AQS: Success.
685       {u"foo", "chrome.0.0l6", searchbox_stats, "https://bar/",
686        "https://foo/?q={searchTerms}&{google:assistedQueryStats}",
687        "https://foo/?q=foo&aqs=chrome.0.0l6&"},
688       // No HTTPS: Failure.
689       {u"foo", "chrome.0.0l6", searchbox_stats, "http://foo/",
690        "{google:baseURL}?q={searchTerms}&{google:assistedQueryStats}",
691        "http://foo/?q=foo&"},
692       // No {google:assistedQueryStats}: Failure.
693       {u"foo", "chrome.0.0l6", searchbox_stats, "https://foo/",
694        "{google:baseURL}?q={searchTerms}", "https://foo/?q=foo"},
695   };
696   TemplateURLData data;
697   data.input_encodings.push_back("UTF-8");
698   for (const auto& entry : test_data) {
699     data.SetURL(entry.url);
700     TemplateURL url(data);
701     EXPECT_TRUE(url.url_ref().IsValid(search_terms_data_));
702     ASSERT_TRUE(url.url_ref().SupportsReplacement(search_terms_data_));
703     TemplateURLRef::SearchTermsArgs search_terms_args(entry.search_term);
704     search_terms_args.assisted_query_stats = entry.aqs;
705     search_terms_args.searchbox_stats.MergeFrom(entry.searchbox_stats);
706     search_terms_data_.set_google_base_url(entry.base_url);
707     GURL result(url.url_ref().ReplaceSearchTerms(search_terms_args,
708                                                  search_terms_data_));
709     ASSERT_TRUE(result.is_valid());
710     EXPECT_EQ(entry.expected_result, result.spec());
711   }
712   // Expect correct histograms to have been logged.
713   histogram_tester.ExpectTotalCount("Omnibox.AssistedQueryStats.Length", 2);
714   histogram_tester.ExpectBucketCount("Omnibox.AssistedQueryStats.Length", 12,
715                                      2);
716
717   histogram_tester.ExpectTotalCount("Omnibox.SearchboxStats.Length", 0);
718 }
719
720 // Tests replacing searchbox stats (gs_lcrp) in various scenarios.
721 TEST_F(TemplateURLTest, ReplaceSearchboxStats) {
722   base::HistogramTester histogram_tester;
723   base::test::ScopedFeatureList feature_list;
724   feature_list.InitWithFeatures({omnibox::kReportSearchboxStats},
725                                 {omnibox::kReportAssistedQueryStats});
726
727   omnibox::metrics::ChromeSearchboxStats searchbox_stats;
728   searchbox_stats.set_client_name("chrome");
729   searchbox_stats.set_zero_prefix_enabled(true);
730
731   struct TestData {
732     const std::u16string search_term;
733     const std::string aqs;
734     const omnibox::metrics::ChromeSearchboxStats searchbox_stats;
735     const std::string base_url;
736     const std::string url;
737     const std::string expected_result;
738   } test_data[] = {
739       // HTTPS and non-empty gs_lcrp and non-empty AQS: Success.
740       {u"foo", "chrome.0.0l6", searchbox_stats, "https://foo/",
741        "{google:baseURL}?q={searchTerms}&{google:assistedQueryStats}",
742        "https://foo/?q=foo&gs_lcrp=EgZjaHJvbWWwAgE&"},
743       // Non-Google HTTPS and non-empty gs_lcrp and non-empty AQS: Success.
744       {u"foo", "chrome.0.0l6", searchbox_stats, "https://bar/",
745        "https://foo/?q={searchTerms}&{google:assistedQueryStats}",
746        "https://foo/?q=foo&gs_lcrp=EgZjaHJvbWWwAgE&"},
747       // No HTTPS: Failure.
748       {u"foo", "chrome.0.0l6", searchbox_stats, "http://foo/",
749        "{google:baseURL}?q={searchTerms}&{google:assistedQueryStats}",
750        "http://foo/?q=foo&"},
751       // No {google:assistedQueryStats}: Failure.
752       {u"foo", "chrome.0.0l6", searchbox_stats, "https://foo/",
753        "{google:baseURL}?q={searchTerms}", "https://foo/?q=foo"},
754   };
755   TemplateURLData data;
756   data.input_encodings.push_back("UTF-8");
757   for (const auto& entry : test_data) {
758     data.SetURL(entry.url);
759     TemplateURL url(data);
760     EXPECT_TRUE(url.url_ref().IsValid(search_terms_data_));
761     ASSERT_TRUE(url.url_ref().SupportsReplacement(search_terms_data_));
762     TemplateURLRef::SearchTermsArgs search_terms_args(entry.search_term);
763     search_terms_args.assisted_query_stats = entry.aqs;
764     search_terms_args.searchbox_stats.MergeFrom(entry.searchbox_stats);
765     search_terms_data_.set_google_base_url(entry.base_url);
766     GURL result(url.url_ref().ReplaceSearchTerms(search_terms_args,
767                                                  search_terms_data_));
768     ASSERT_TRUE(result.is_valid());
769     EXPECT_EQ(entry.expected_result, result.spec());
770   }
771   // Expect correct histograms to have been logged.
772   histogram_tester.ExpectTotalCount("Omnibox.AssistedQueryStats.Length", 0);
773
774   histogram_tester.ExpectTotalCount("Omnibox.SearchboxStats.Length", 2);
775   histogram_tester.ExpectBucketCount("Omnibox.SearchboxStats.Length", 15, 2);
776 }
777
778 // Tests replacing searchbox stats (gs_lcrp) and assisted query stats (AQS).
779 TEST_F(TemplateURLTest, ReplaceSearchboxStatsAndAssistedQueryStats) {
780   base::HistogramTester histogram_tester;
781   base::test::ScopedFeatureList feature_list;
782   feature_list.InitWithFeatures(
783       {omnibox::kReportSearchboxStats, omnibox::kReportAssistedQueryStats}, {});
784
785   omnibox::metrics::ChromeSearchboxStats searchbox_stats;
786   searchbox_stats.set_client_name("chrome");
787   searchbox_stats.set_zero_prefix_enabled(true);
788
789   struct TestData {
790     const std::u16string search_term;
791     const std::string aqs;
792     const omnibox::metrics::ChromeSearchboxStats searchbox_stats;
793     const std::string base_url;
794     const std::string url;
795     const std::string expected_result;
796   } test_data[] = {
797       // HTTPS and non-empty gs_lcrp and non-empty AQS: Success.
798       {u"foo", "chrome.0.0l6", searchbox_stats, "https://foo/",
799        "{google:baseURL}?q={searchTerms}&{google:assistedQueryStats}",
800        "https://foo/?q=foo&gs_lcrp=EgZjaHJvbWWwAgE&aqs=chrome.0.0l6&"},
801       // Non-Google HTTPS and non-empty gs_lcrp and non-empty AQS: Success.
802       {u"foo", "chrome.0.0l6", searchbox_stats, "https://bar/",
803        "https://foo/?q={searchTerms}&{google:assistedQueryStats}",
804        "https://foo/?q=foo&gs_lcrp=EgZjaHJvbWWwAgE&aqs=chrome.0.0l6&"},
805       // No HTTPS: Failure.
806       {u"foo", "chrome.0.0l6", searchbox_stats, "http://foo/",
807        "{google:baseURL}?q={searchTerms}&{google:assistedQueryStats}",
808        "http://foo/?q=foo&"},
809       // No {google:assistedQueryStats}: Failure.
810       {u"foo", "chrome.0.0l6", searchbox_stats, "https://foo/",
811        "{google:baseURL}?q={searchTerms}", "https://foo/?q=foo"},
812   };
813   TemplateURLData data;
814   data.input_encodings.push_back("UTF-8");
815   for (const auto& entry : test_data) {
816     data.SetURL(entry.url);
817     TemplateURL url(data);
818     EXPECT_TRUE(url.url_ref().IsValid(search_terms_data_));
819     ASSERT_TRUE(url.url_ref().SupportsReplacement(search_terms_data_));
820     TemplateURLRef::SearchTermsArgs search_terms_args(entry.search_term);
821     search_terms_args.assisted_query_stats = entry.aqs;
822     search_terms_args.searchbox_stats.MergeFrom(entry.searchbox_stats);
823     search_terms_data_.set_google_base_url(entry.base_url);
824     GURL result(url.url_ref().ReplaceSearchTerms(search_terms_args,
825                                                  search_terms_data_));
826     ASSERT_TRUE(result.is_valid());
827     EXPECT_EQ(entry.expected_result, result.spec());
828   }
829   // Expect correct histograms to have been logged.
830   histogram_tester.ExpectTotalCount("Omnibox.AssistedQueryStats.Length", 2);
831   histogram_tester.ExpectBucketCount("Omnibox.AssistedQueryStats.Length", 12,
832                                      2);
833
834   histogram_tester.ExpectTotalCount("Omnibox.SearchboxStats.Length", 2);
835   histogram_tester.ExpectBucketCount("Omnibox.SearchboxStats.Length", 15, 2);
836 }
837
838 // Tests replacing cursor position.
839 TEST_F(TemplateURLTest, ReplaceCursorPosition) {
840   struct TestData {
841     const std::u16string search_term;
842     size_t cursor_position;
843     const std::string url;
844     const std::string expected_result;
845   } test_data[] = {
846       {u"foo", std::u16string::npos,
847        "{google:baseURL}?{searchTerms}&{google:cursorPosition}",
848        "http://www.google.com/?foo&"},
849       {u"foo", 2, "{google:baseURL}?{searchTerms}&{google:cursorPosition}",
850        "http://www.google.com/?foo&cp=2&"},
851       {u"foo", 15, "{google:baseURL}?{searchTerms}&{google:cursorPosition}",
852        "http://www.google.com/?foo&cp=15&"},
853   };
854   TemplateURLData data;
855   data.input_encodings.push_back("UTF-8");
856   for (const auto& entry : test_data) {
857     data.SetURL(entry.url);
858     TemplateURL url(data);
859     EXPECT_TRUE(url.url_ref().IsValid(search_terms_data_));
860     ASSERT_TRUE(url.url_ref().SupportsReplacement(search_terms_data_));
861     TemplateURLRef::SearchTermsArgs search_terms_args(entry.search_term);
862     search_terms_args.cursor_position = entry.cursor_position;
863     GURL result(url.url_ref().ReplaceSearchTerms(search_terms_args,
864                                                  search_terms_data_));
865     ASSERT_TRUE(result.is_valid());
866     EXPECT_EQ(entry.expected_result, result.spec());
867   }
868 }
869
870 // Tests replacing input type (&oit=).
871 TEST_F(TemplateURLTest, ReplaceInputType) {
872   struct TestData {
873     const std::u16string search_term;
874     metrics::OmniboxInputType input_type;
875     const std::string url;
876     const std::string expected_result;
877   } test_data[] = {
878       {u"foo", metrics::OmniboxInputType::UNKNOWN,
879        "{google:baseURL}?{searchTerms}&{google:inputType}",
880        "http://www.google.com/?foo&oit=1&"},
881       {u"foo", metrics::OmniboxInputType::URL,
882        "{google:baseURL}?{searchTerms}&{google:inputType}",
883        "http://www.google.com/?foo&oit=3&"},
884   };
885   TemplateURLData data;
886   data.input_encodings.push_back("UTF-8");
887   for (const auto& entry : test_data) {
888     data.SetURL(entry.url);
889     TemplateURL url(data);
890     EXPECT_TRUE(url.url_ref().IsValid(search_terms_data_));
891     ASSERT_TRUE(url.url_ref().SupportsReplacement(search_terms_data_));
892     TemplateURLRef::SearchTermsArgs search_terms_args(entry.search_term);
893     search_terms_args.input_type = entry.input_type;
894     GURL result(url.url_ref().ReplaceSearchTerms(search_terms_args,
895                                                  search_terms_data_));
896     ASSERT_TRUE(result.is_valid());
897     EXPECT_EQ(entry.expected_result, result.spec());
898   }
899 }
900
901 // Tests replacing omnibox focus type (&oft=).
902 TEST_F(TemplateURLTest, ReplaceOmniboxFocusType) {
903   struct TestData {
904     const std::u16string search_term;
905     metrics::OmniboxFocusType focus_type;
906     const std::string url;
907     const std::string expected_result;
908   } test_data[] = {
909       {u"foo", metrics::OmniboxFocusType::INTERACTION_DEFAULT,
910        "{google:baseURL}?{searchTerms}&{google:omniboxFocusType}",
911        "http://www.google.com/?foo&"},
912       {u"foo", metrics::OmniboxFocusType::INTERACTION_FOCUS,
913        "{google:baseURL}?{searchTerms}&{google:omniboxFocusType}",
914        "http://www.google.com/?foo&oft=1&"},
915       {u"foo", metrics::OmniboxFocusType::INTERACTION_CLOBBER,
916        "{google:baseURL}?{searchTerms}&{google:omniboxFocusType}",
917        "http://www.google.com/?foo&oft=2&"},
918   };
919   TemplateURLData data;
920   data.input_encodings.push_back("UTF-8");
921   for (const auto& entry : test_data) {
922     data.SetURL(entry.url);
923     TemplateURL url(data);
924     EXPECT_TRUE(url.url_ref().IsValid(search_terms_data_));
925     ASSERT_TRUE(url.url_ref().SupportsReplacement(search_terms_data_));
926     TemplateURLRef::SearchTermsArgs search_terms_args(entry.search_term);
927     search_terms_args.focus_type = entry.focus_type;
928     GURL result(url.url_ref().ReplaceSearchTerms(search_terms_args,
929                                                  search_terms_data_));
930     ASSERT_TRUE(result.is_valid());
931     EXPECT_EQ(entry.expected_result, result.spec());
932   }
933 }
934
935 // Tests replacing prefetch source (&pf=).
936 TEST_F(TemplateURLTest, ReplaceIsPrefetch) {
937   struct TestData {
938     const std::u16string search_term;
939     bool is_prefetch;
940     const std::string url;
941     const std::string expected_result;
942   } test_data[] = {
943       {u"foo", false, "{google:baseURL}?{searchTerms}&{google:prefetchSource}",
944        "http://www.google.com/?foo&"},
945       {u"foo", true, "{google:baseURL}?{searchTerms}&{google:prefetchSource}",
946        "http://www.google.com/?foo&pf=cs&"},
947   };
948   TemplateURLData data;
949   data.input_encodings.push_back("UTF-8");
950   for (const auto& entry : test_data) {
951     data.SetURL(entry.url);
952     TemplateURL url(data);
953     EXPECT_TRUE(url.url_ref().IsValid(search_terms_data_));
954     ASSERT_TRUE(url.url_ref().SupportsReplacement(search_terms_data_));
955     TemplateURLRef::SearchTermsArgs search_terms_args(entry.search_term);
956     search_terms_args.is_prefetch = entry.is_prefetch;
957     GURL result(url.url_ref().ReplaceSearchTerms(search_terms_args,
958                                                  search_terms_data_));
959     ASSERT_TRUE(result.is_valid());
960     EXPECT_EQ(entry.expected_result, result.spec());
961   }
962 }
963
964 // Tests replacing currentPageUrl.
965 TEST_F(TemplateURLTest, ReplaceCurrentPageUrl) {
966   struct TestData {
967     const std::u16string search_term;
968     const std::string current_page_url;
969     const std::string url;
970     const std::string expected_result;
971   } test_data[] = {
972       {u"foo", "http://www.google.com/",
973        "{google:baseURL}?{searchTerms}&{google:currentPageUrl}",
974        "http://www.google.com/?foo&url=http%3A%2F%2Fwww.google.com%2F&"},
975       {u"foo", "", "{google:baseURL}?{searchTerms}&{google:currentPageUrl}",
976        "http://www.google.com/?foo&"},
977       {u"foo", "http://g.com/+-/*&=",
978        "{google:baseURL}?{searchTerms}&{google:currentPageUrl}",
979        "http://www.google.com/?foo&url=http%3A%2F%2Fg.com%2F%2B-%2F*%26%3D&"},
980   };
981   TemplateURLData data;
982   data.input_encodings.push_back("UTF-8");
983   for (const auto& entry : test_data) {
984     data.SetURL(entry.url);
985     TemplateURL url(data);
986     EXPECT_TRUE(url.url_ref().IsValid(search_terms_data_));
987     ASSERT_TRUE(url.url_ref().SupportsReplacement(search_terms_data_));
988     TemplateURLRef::SearchTermsArgs search_terms_args(entry.search_term);
989     search_terms_args.current_page_url = entry.current_page_url;
990     GURL result(url.url_ref().ReplaceSearchTerms(search_terms_args,
991                                                  search_terms_data_));
992     ASSERT_TRUE(result.is_valid());
993     EXPECT_EQ(entry.expected_result, result.spec());
994   }
995 }
996
997 // Tests appending attribution parameter to queries originating from Play API
998 // search engine.
999 TEST_F(TemplateURLTest, PlayAPIAttribution) {
1000   const struct TestData {
1001     const char* url;
1002     std::u16string terms;
1003     bool created_from_play_api;
1004     const char* output;
1005   } test_data[] = {
1006       {"http://foo/?q={searchTerms}", u"bar", false, "http://foo/?q=bar"},
1007       {"http://foo/?q={searchTerms}", u"bar", true,
1008        "http://foo/?q=bar&chrome_dse_attribution=1"}};
1009   TemplateURLData data;
1010   for (const auto& entry : test_data) {
1011     data.SetURL(entry.url);
1012     data.created_from_play_api = entry.created_from_play_api;
1013     TemplateURL url(data);
1014     EXPECT_TRUE(url.url_ref().IsValid(search_terms_data_));
1015     ASSERT_TRUE(url.url_ref().SupportsReplacement(search_terms_data_));
1016     GURL result(url.url_ref().ReplaceSearchTerms(
1017         TemplateURLRef::SearchTermsArgs(entry.terms), search_terms_data_));
1018     ASSERT_TRUE(result.is_valid());
1019     EXPECT_EQ(entry.output, result.spec());
1020   }
1021 }
1022
1023 TEST_F(TemplateURLTest, Suggestions) {
1024   struct TestData {
1025     const int accepted_suggestion;
1026     const std::u16string original_query_for_suggestion;
1027     const std::string expected_result;
1028   } test_data[] = {
1029       {TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, std::u16string(),
1030        "http://bar/foo?q=foobar"},
1031       {TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, u"foo",
1032        "http://bar/foo?q=foobar"},
1033       {TemplateURLRef::NO_SUGGESTION_CHOSEN, std::u16string(),
1034        "http://bar/foo?q=foobar"},
1035       {TemplateURLRef::NO_SUGGESTION_CHOSEN, u"foo", "http://bar/foo?q=foobar"},
1036       {0, std::u16string(), "http://bar/foo?oq=&q=foobar"},
1037       {1, u"foo", "http://bar/foo?oq=foo&q=foobar"},
1038   };
1039   TemplateURLData data;
1040   data.SetURL("http://bar/foo?{google:originalQueryForSuggestion}"
1041               "q={searchTerms}");
1042   data.input_encodings.push_back("UTF-8");
1043   TemplateURL url(data);
1044   EXPECT_TRUE(url.url_ref().IsValid(search_terms_data_));
1045   ASSERT_TRUE(url.url_ref().SupportsReplacement(search_terms_data_));
1046   for (const auto& entry : test_data) {
1047     TemplateURLRef::SearchTermsArgs search_terms_args(u"foobar");
1048     search_terms_args.accepted_suggestion = entry.accepted_suggestion;
1049     search_terms_args.original_query = entry.original_query_for_suggestion;
1050     GURL result(url.url_ref().ReplaceSearchTerms(search_terms_args,
1051                                                  search_terms_data_));
1052     ASSERT_TRUE(result.is_valid());
1053     EXPECT_EQ(entry.expected_result, result.spec());
1054   }
1055 }
1056
1057 TEST_F(TemplateURLTest, RLZ) {
1058   std::u16string rlz_string = search_terms_data_.GetRlzParameterValue(false);
1059
1060   TemplateURLData data;
1061   data.SetURL("http://bar/?{google:RLZ}{searchTerms}");
1062   TemplateURL url(data);
1063   EXPECT_TRUE(url.url_ref().IsValid(search_terms_data_));
1064   ASSERT_TRUE(url.url_ref().SupportsReplacement(search_terms_data_));
1065   GURL result(url.url_ref().ReplaceSearchTerms(
1066       TemplateURLRef::SearchTermsArgs(u"x"), search_terms_data_));
1067   ASSERT_TRUE(result.is_valid());
1068   EXPECT_EQ("http://bar/?rlz=" + base::UTF16ToUTF8(rlz_string) + "&x",
1069             result.spec());
1070 }
1071
1072 TEST_F(TemplateURLTest, RLZFromAppList) {
1073   std::u16string rlz_string = search_terms_data_.GetRlzParameterValue(true);
1074
1075   TemplateURLData data;
1076   data.SetURL("http://bar/?{google:RLZ}{searchTerms}");
1077   TemplateURL url(data);
1078   EXPECT_TRUE(url.url_ref().IsValid(search_terms_data_));
1079   ASSERT_TRUE(url.url_ref().SupportsReplacement(search_terms_data_));
1080   TemplateURLRef::SearchTermsArgs args(u"x");
1081   args.request_source = RequestSource::CROS_APP_LIST;
1082   GURL result(url.url_ref().ReplaceSearchTerms(args, search_terms_data_));
1083   ASSERT_TRUE(result.is_valid());
1084   EXPECT_EQ("http://bar/?rlz=" + base::UTF16ToUTF8(rlz_string) + "&x",
1085             result.spec());
1086 }
1087
1088 TEST_F(TemplateURLTest, HostAndSearchTermKey) {
1089   struct TestData {
1090     const std::string url;
1091     const std::string host;
1092     const std::string path;
1093     const std::string search_term_key;
1094   } test_data[] = {
1095       {"http://blah/?foo=bar&q={searchTerms}&b=x", "blah", "/", "q"},
1096       {"http://blah/{searchTerms}", "blah", "", ""},
1097
1098       // No term should result in empty values.
1099       {"http://blah/", "", "", ""},
1100
1101       // Multiple terms should result in empty values.
1102       {"http://blah/?q={searchTerms}&x={searchTerms}", "", "", ""},
1103
1104       // Term in the host shouldn't match.
1105       {"http://{searchTerms}", "", "", ""},
1106
1107       {"http://blah/?q={searchTerms}", "blah", "/", "q"},
1108       {"https://blah/?q={searchTerms}", "blah", "/", "q"},
1109
1110       // Single term with extra chars in value should match.
1111       {"http://blah/?q=stock:{searchTerms}", "blah", "/", "q"},
1112   };
1113
1114   for (const auto& entry : test_data) {
1115     TemplateURLData data;
1116     data.SetURL(entry.url);
1117     TemplateURL url(data);
1118     EXPECT_EQ(entry.host, url.url_ref().GetHost(search_terms_data_));
1119     EXPECT_EQ(entry.path, url.url_ref().GetPath(search_terms_data_));
1120     EXPECT_EQ(entry.search_term_key,
1121               url.url_ref().GetSearchTermKey(search_terms_data_));
1122   }
1123 }
1124
1125 TEST_F(TemplateURLTest, SearchTermKeyLocation) {
1126   struct TestData {
1127     const std::string url;
1128     const url::Parsed::ComponentType location;
1129     const std::string path;
1130     const std::string key;
1131     const std::string value_prefix;
1132     const std::string value_suffix;
1133   } test_data[] = {
1134       {"http://blah/{searchTerms}/", url::Parsed::PATH, "", "", "/", "/"},
1135       {"http://blah/{searchTerms}", url::Parsed::PATH, "", "", "/", ""},
1136       {"http://blah/begin/{searchTerms}/end", url::Parsed::PATH, "", "",
1137        "/begin/", "/end"},
1138       {"http://blah/?foo=bar&q={searchTerms}&b=x", url::Parsed::QUERY, "/", "q",
1139        "", ""},
1140       {"http://blah/?foo=bar#x={searchTerms}&b=x", url::Parsed::REF, "/", "x",
1141        "", ""},
1142       {"http://www.example.com/?q=chromium-{searchTerms}@chromium.org/info",
1143        url::Parsed::QUERY, "/", "q", "chromium-", "@chromium.org/info"},
1144
1145       // searchTerms is a key, not a value, so this should result in an empty
1146       // value.
1147       {"http://blah/?foo=bar#x=012345678901234&a=b&{searchTerms}=x",
1148        url::Parsed::QUERY, "", "", "", ""},
1149
1150       // Multiple search terms should result in empty values.
1151       {"http://blah/{searchTerms}?q={searchTerms}", url::Parsed::QUERY, "", "",
1152        "", ""},
1153       {"http://blah/{searchTerms}#x={searchTerms}", url::Parsed::QUERY, "", "",
1154        "", ""},
1155       {"http://blah/?q={searchTerms}#x={searchTerms}", url::Parsed::QUERY, "",
1156        "", "", ""},
1157   };
1158
1159   for (const auto& entry : test_data) {
1160     TemplateURLData data;
1161     data.SetURL(entry.url);
1162     TemplateURL url(data);
1163     EXPECT_EQ(entry.location,
1164               url.url_ref().GetSearchTermKeyLocation(search_terms_data_));
1165     EXPECT_EQ(entry.path, url.url_ref().GetPath(search_terms_data_));
1166     EXPECT_EQ(entry.key, url.url_ref().GetSearchTermKey(search_terms_data_));
1167     EXPECT_EQ(entry.value_prefix,
1168               url.url_ref().GetSearchTermValuePrefix(search_terms_data_));
1169     EXPECT_EQ(entry.value_suffix,
1170               url.url_ref().GetSearchTermValueSuffix(search_terms_data_));
1171   }
1172 }
1173
1174 TEST_F(TemplateURLTest, GoogleBaseSuggestURL) {
1175   static const struct {
1176     const char* const base_url;
1177     const char* const base_suggest_url;
1178   } data[] = {
1179     { "http://google.com/", "http://google.com/complete/", },
1180     { "http://www.google.com/", "http://www.google.com/complete/", },
1181     { "http://www.google.co.uk/", "http://www.google.co.uk/complete/", },
1182     { "http://www.google.com.by/", "http://www.google.com.by/complete/", },
1183     { "http://google.com/intl/xx/", "http://google.com/complete/", },
1184   };
1185
1186   for (size_t i = 0; i < std::size(data); ++i)
1187     CheckSuggestBaseURL(data[i].base_url, data[i].base_suggest_url);
1188 }
1189
1190 TEST_F(TemplateURLTest, ParseParameterKnown) {
1191   std::string parsed_url("{searchTerms}");
1192   TemplateURLData data;
1193   data.SetURL(parsed_url);
1194   TemplateURL url(data);
1195   TemplateURLRef::Replacements replacements;
1196   EXPECT_TRUE(url.url_ref().ParseParameter(0, 12, &parsed_url, &replacements));
1197   EXPECT_EQ(std::string(), parsed_url);
1198   ASSERT_EQ(1U, replacements.size());
1199   EXPECT_EQ(0U, replacements[0].index);
1200   EXPECT_EQ(TemplateURLRef::SEARCH_TERMS, replacements[0].type);
1201 }
1202
1203 TEST_F(TemplateURLTest, ParseParameterUnknown) {
1204   std::string parsed_url("{fhqwhgads}abc");
1205   TemplateURLData data;
1206   data.SetURL(parsed_url);
1207   TemplateURL url(data);
1208   TemplateURLRef::Replacements replacements;
1209
1210   // By default, TemplateURLRef should not consider itself prepopulated.
1211   // Therefore we should not replace the unknown parameter.
1212   EXPECT_FALSE(url.url_ref().ParseParameter(0, 10, &parsed_url, &replacements));
1213   EXPECT_EQ("{fhqwhgads}abc", parsed_url);
1214   EXPECT_TRUE(replacements.empty());
1215
1216   // If the TemplateURLRef is prepopulated, we should remove unknown parameters.
1217   parsed_url = "{fhqwhgads}abc";
1218   data.prepopulate_id = 1;
1219   TemplateURL url2(data);
1220   EXPECT_TRUE(url2.url_ref().ParseParameter(0, 10, &parsed_url, &replacements));
1221   EXPECT_EQ("abc", parsed_url);
1222   EXPECT_TRUE(replacements.empty());
1223 }
1224
1225 TEST_F(TemplateURLTest, ParseURLEmpty) {
1226   TemplateURL url((TemplateURLData()));
1227   TemplateURLRef::Replacements replacements;
1228   bool valid = false;
1229   EXPECT_EQ(std::string(), url.url_ref().ParseURL(std::string(), &replacements,
1230                                                   nullptr, &valid));
1231   EXPECT_TRUE(replacements.empty());
1232   EXPECT_TRUE(valid);
1233 }
1234
1235 TEST_F(TemplateURLTest, ParseURLNoTemplateEnd) {
1236   TemplateURLData data;
1237   data.SetURL("{");
1238   TemplateURL url(data);
1239   TemplateURLRef::Replacements replacements;
1240   bool valid = false;
1241   EXPECT_EQ(std::string(),
1242             url.url_ref().ParseURL("{", &replacements, nullptr, &valid));
1243   EXPECT_TRUE(replacements.empty());
1244   EXPECT_FALSE(valid);
1245 }
1246
1247 TEST_F(TemplateURLTest, ParseURLNoKnownParameters) {
1248   TemplateURLData data;
1249   data.SetURL("{}");
1250   TemplateURL url(data);
1251   TemplateURLRef::Replacements replacements;
1252   bool valid = false;
1253   EXPECT_EQ("{}", url.url_ref().ParseURL("{}", &replacements, nullptr, &valid));
1254   EXPECT_TRUE(replacements.empty());
1255   EXPECT_TRUE(valid);
1256 }
1257
1258 TEST_F(TemplateURLTest, ParseURLTwoParameters) {
1259   TemplateURLData data;
1260   data.SetURL("{}{{%s}}");
1261   TemplateURL url(data);
1262   TemplateURLRef::Replacements replacements;
1263   bool valid = false;
1264   EXPECT_EQ("{}{}", url.url_ref().ParseURL("{}{{searchTerms}}", &replacements,
1265                                            nullptr, &valid));
1266   ASSERT_EQ(1U, replacements.size());
1267   EXPECT_EQ(3U, replacements[0].index);
1268   EXPECT_EQ(TemplateURLRef::SEARCH_TERMS, replacements[0].type);
1269   EXPECT_TRUE(valid);
1270 }
1271
1272 TEST_F(TemplateURLTest, ParseURLNestedParameter) {
1273   TemplateURLData data;
1274   data.SetURL("{%s");
1275   TemplateURL url(data);
1276   TemplateURLRef::Replacements replacements;
1277   bool valid = false;
1278   EXPECT_EQ("{", url.url_ref().ParseURL("{{searchTerms}", &replacements,
1279                                         nullptr, &valid));
1280   ASSERT_EQ(1U, replacements.size());
1281   EXPECT_EQ(1U, replacements[0].index);
1282   EXPECT_EQ(TemplateURLRef::SEARCH_TERMS, replacements[0].type);
1283   EXPECT_TRUE(valid);
1284 }
1285
1286 TEST_F(TemplateURLTest, SearchClient) {
1287   const std::string base_url_str("http://google.com/?");
1288   const std::string terms_str("{searchTerms}&{google:searchClient}");
1289   const std::string full_url_str = base_url_str + terms_str;
1290   const std::u16string terms(ASCIIToUTF16(terms_str));
1291   search_terms_data_.set_google_base_url(base_url_str);
1292
1293   TemplateURLData data;
1294   data.SetURL(full_url_str);
1295   TemplateURL url(data);
1296   EXPECT_TRUE(url.url_ref().IsValid(search_terms_data_));
1297   ASSERT_TRUE(url.url_ref().SupportsReplacement(search_terms_data_));
1298   TemplateURLRef::SearchTermsArgs search_terms_args(u"foobar");
1299
1300   // Check that the URL is correct when a client is not present.
1301   GURL result(url.url_ref().ReplaceSearchTerms(search_terms_args,
1302                                                search_terms_data_));
1303   ASSERT_TRUE(result.is_valid());
1304   EXPECT_EQ("http://google.com/?foobar&", result.spec());
1305
1306   // Check that the URL is correct when a client is present.
1307   search_terms_data_.set_search_client("search_client");
1308   GURL result_2(url.url_ref().ReplaceSearchTerms(search_terms_args,
1309                                                  search_terms_data_));
1310   ASSERT_TRUE(result_2.is_valid());
1311   EXPECT_EQ("http://google.com/?foobar&client=search_client&", result_2.spec());
1312 }
1313
1314 TEST_F(TemplateURLTest, SuggestClient) {
1315   const std::string base_url_str("http://google.com/?");
1316   const std::string query_params_str("client={google:suggestClient}");
1317   const std::string full_url_str = base_url_str + query_params_str;
1318   search_terms_data_.set_google_base_url(base_url_str);
1319
1320   TemplateURLData data;
1321   data.SetURL(full_url_str);
1322   TemplateURL url(data);
1323   EXPECT_TRUE(url.url_ref().IsValid(search_terms_data_));
1324   ASSERT_FALSE(url.url_ref().SupportsReplacement(search_terms_data_));
1325   TemplateURLRef::SearchTermsArgs search_terms_args;
1326
1327   // Check that the URL is correct when a client is not present.
1328   GURL result(
1329       url.url_ref().ReplaceSearchTerms(search_terms_args, search_terms_data_));
1330   ASSERT_TRUE(result.is_valid());
1331   EXPECT_EQ("http://google.com/?client=", result.spec());
1332
1333   // Check that the URL is correct when a client is present.
1334   search_terms_data_.set_suggest_client("suggest_client");
1335   GURL result_2(
1336       url.url_ref().ReplaceSearchTerms(search_terms_args, search_terms_data_));
1337   ASSERT_TRUE(result_2.is_valid());
1338   EXPECT_EQ("http://google.com/?client=suggest_client", result_2.spec());
1339 }
1340
1341 TEST_F(TemplateURLTest, ZeroSuggestCacheDuration) {
1342   const std::string base_url_str("http://google.com/?");
1343   const std::string query_params_str("{google:clientCacheTimeToLive}");
1344   const std::string full_url_str = base_url_str + query_params_str;
1345   search_terms_data_.set_google_base_url(base_url_str);
1346   TemplateURLData data;
1347   data.SetURL(full_url_str);
1348   TemplateURL url(data);
1349   EXPECT_TRUE(url.url_ref().IsValid(search_terms_data_));
1350   ASSERT_FALSE(url.url_ref().SupportsReplacement(search_terms_data_));
1351
1352   {
1353     // 'ccttl' query param should not be present if no cache duration is given.
1354     TemplateURLRef::SearchTermsArgs search_terms_args;
1355     GURL result(url.url_ref().ReplaceSearchTerms(search_terms_args,
1356                                                  search_terms_data_));
1357     ASSERT_TRUE(result.is_valid());
1358     EXPECT_EQ("http://google.com/?", result.spec());
1359   }
1360   {
1361     // 'ccttl' query param should be present if a positive cache duration is
1362     // given.
1363     TemplateURLRef::SearchTermsArgs search_terms_args;
1364     search_terms_args.zero_suggest_cache_duration_sec = 300;
1365     GURL result(url.url_ref().ReplaceSearchTerms(search_terms_args,
1366                                                  search_terms_data_));
1367     ASSERT_TRUE(result.is_valid());
1368     EXPECT_EQ("http://google.com/?ccttl=300&", result.spec());
1369   }
1370   {
1371     // 'ccttl' query param shouldn't be present if a zero cache duration is
1372     // given.
1373     TemplateURLRef::SearchTermsArgs search_terms_args;
1374     search_terms_args.zero_suggest_cache_duration_sec = 0;
1375     GURL result(url.url_ref().ReplaceSearchTerms(search_terms_args,
1376                                                  search_terms_data_));
1377     ASSERT_TRUE(result.is_valid());
1378     EXPECT_EQ("http://google.com/?", result.spec());
1379   }
1380   {
1381     // 'ccttl' query param should not be present if the request is not a
1382     // zero-prefix request.
1383     TemplateURLRef::SearchTermsArgs search_terms_args(u"foo");
1384     search_terms_args.zero_suggest_cache_duration_sec = 300;
1385     GURL result(url.url_ref().ReplaceSearchTerms(search_terms_args,
1386                                                  search_terms_data_));
1387     ASSERT_TRUE(result.is_valid());
1388     EXPECT_EQ("http://google.com/?", result.spec());
1389   }
1390 }
1391
1392 TEST_F(TemplateURLTest, GetURLNoSuggestionsURL) {
1393   TemplateURLData data;
1394   data.SetURL("http://google.com/?q={searchTerms}");
1395   data.alternate_urls.push_back("http://google.com/alt?q={searchTerms}");
1396   data.alternate_urls.push_back("{google:baseURL}/alt/#q={searchTerms}");
1397   TemplateURL url(data);
1398   const std::vector<TemplateURLRef>& url_refs = url.url_refs();
1399   ASSERT_EQ(3U, url_refs.size());
1400   EXPECT_EQ("http://google.com/alt?q={searchTerms}", url_refs[0].GetURL());
1401   EXPECT_EQ("{google:baseURL}/alt/#q={searchTerms}", url_refs[1].GetURL());
1402   EXPECT_EQ("http://google.com/?q={searchTerms}", url_refs[2].GetURL());
1403 }
1404
1405 TEST_F(TemplateURLTest, GetURLOnlyOneURL) {
1406   TemplateURLData data;
1407   data.SetURL("http://www.google.co.uk/");
1408   TemplateURL url(data);
1409   const std::vector<TemplateURLRef>& url_refs = url.url_refs();
1410   ASSERT_EQ(1U, url_refs.size());
1411   EXPECT_EQ("http://www.google.co.uk/", url_refs[0].GetURL());
1412 }
1413
1414 TEST_F(TemplateURLTest, ExtractSearchTermsFromURL) {
1415   TemplateURLData data;
1416   data.SetURL("http://google.com/?q={searchTerms}");
1417   data.alternate_urls.push_back("http://google.com/alt/#q={searchTerms}");
1418   data.alternate_urls.push_back(
1419       "http://google.com/alt/?ext=foo&q={searchTerms}#ref=bar");
1420   TemplateURL url(data);
1421   std::u16string result;
1422
1423   EXPECT_TRUE(url.ExtractSearchTermsFromURL(
1424       GURL("http://google.com/?q=something"), search_terms_data_, &result));
1425   EXPECT_EQ(u"something", result);
1426
1427   EXPECT_TRUE(url.ExtractSearchTermsFromURL(
1428       GURL("http://google.com/?q=something"), search_terms_data_, &result));
1429   EXPECT_EQ(u"something", result);
1430
1431   EXPECT_TRUE(url.ExtractSearchTermsFromURL(
1432       GURL("http://google.com/?q=something"), search_terms_data_, &result));
1433   EXPECT_EQ(u"something", result);
1434
1435   EXPECT_TRUE(url.ExtractSearchTermsFromURL(
1436       GURL("http://google.com/?q=something"), search_terms_data_, &result));
1437   EXPECT_EQ(u"something", result);
1438
1439   EXPECT_TRUE(url.ExtractSearchTermsFromURL(
1440       GURL("http://google.com/alt/#q=something"),
1441       search_terms_data_, &result));
1442   EXPECT_EQ(u"something", result);
1443
1444   EXPECT_TRUE(url.ExtractSearchTermsFromURL(
1445       GURL("http://google.com/alt/#q=something"), search_terms_data_, &result));
1446   EXPECT_EQ(u"something", result);
1447
1448   EXPECT_TRUE(url.ExtractSearchTermsFromURL(
1449       GURL("http://google.com/alt/#q=something"), search_terms_data_, &result));
1450   EXPECT_EQ(u"something", result);
1451
1452   EXPECT_TRUE(url.ExtractSearchTermsFromURL(
1453       GURL("http://google.com/alt/#q=something"), search_terms_data_, &result));
1454   EXPECT_EQ(u"something", result);
1455
1456   EXPECT_FALSE(url.ExtractSearchTermsFromURL(
1457       GURL("http://google.ca/?q=something"), search_terms_data_, &result));
1458   EXPECT_EQ(std::u16string(), result);
1459
1460   EXPECT_FALSE(url.ExtractSearchTermsFromURL(
1461       GURL("http://google.ca/?q=something&q=anything"),
1462       search_terms_data_, &result));
1463   EXPECT_EQ(std::u16string(), result);
1464
1465   EXPECT_FALSE(url.ExtractSearchTermsFromURL(
1466       GURL("http://google.com/foo/?q=foo"), search_terms_data_, &result));
1467   EXPECT_EQ(std::u16string(), result);
1468
1469   EXPECT_TRUE(url.ExtractSearchTermsFromURL(
1470       GURL("https://google.com/?q=foo"), search_terms_data_, &result));
1471   EXPECT_EQ(u"foo", result);
1472
1473   EXPECT_FALSE(url.ExtractSearchTermsFromURL(
1474       GURL("http://google.com:8080/?q=foo"), search_terms_data_, &result));
1475   EXPECT_EQ(std::u16string(), result);
1476
1477   EXPECT_TRUE(url.ExtractSearchTermsFromURL(
1478       GURL("http://google.com/?q=1+2+3&b=456"), search_terms_data_, &result));
1479   EXPECT_EQ(u"1 2 3", result);
1480
1481   EXPECT_TRUE(url.ExtractSearchTermsFromURL(
1482       GURL("http://google.com/alt/?q=123#q=456"),
1483       search_terms_data_, &result));
1484   EXPECT_EQ(u"456", result);
1485
1486   EXPECT_TRUE(url.ExtractSearchTermsFromURL(
1487       GURL("http://google.com/alt/?a=012&q=123&b=456#f=789"),
1488       search_terms_data_, &result));
1489   EXPECT_EQ(u"123", result);
1490
1491   EXPECT_TRUE(url.ExtractSearchTermsFromURL(GURL(
1492       "http://google.com/alt/?a=012&q=123&b=456#j=abc&q=789&h=def9"),
1493                                             search_terms_data_, &result));
1494   EXPECT_EQ(u"789", result);
1495
1496   EXPECT_FALSE(url.ExtractSearchTermsFromURL(
1497       GURL("http://google.com/alt/?q="), search_terms_data_, &result));
1498   EXPECT_EQ(std::u16string(), result);
1499
1500   EXPECT_FALSE(url.ExtractSearchTermsFromURL(
1501       GURL("http://google.com/alt/?#q="), search_terms_data_, &result));
1502   EXPECT_EQ(std::u16string(), result);
1503
1504   EXPECT_FALSE(url.ExtractSearchTermsFromURL(
1505       GURL("http://google.com/alt/?q=#q="), search_terms_data_, &result));
1506   EXPECT_EQ(std::u16string(), result);
1507
1508   EXPECT_FALSE(url.ExtractSearchTermsFromURL(
1509       GURL("http://google.com/alt/?q=123#q="), search_terms_data_, &result));
1510   EXPECT_EQ(std::u16string(), result);
1511
1512   EXPECT_TRUE(url.ExtractSearchTermsFromURL(
1513       GURL("http://google.com/alt/?q=#q=123"), search_terms_data_, &result));
1514   EXPECT_EQ(u"123", result);
1515 }
1516
1517 TEST_F(TemplateURLTest, ExtractSearchTermsFromURLPath) {
1518   TemplateURLData data;
1519   data.SetURL("http://term-in-path.com/begin/{searchTerms}/end");
1520   TemplateURL url(data);
1521   std::u16string result;
1522
1523   EXPECT_TRUE(url.ExtractSearchTermsFromURL(
1524       GURL("http://term-in-path.com/begin/something/end"),
1525       search_terms_data_, &result));
1526   EXPECT_EQ(u"something", result);
1527
1528   // "%20" must be converted to space.
1529   EXPECT_TRUE(url.ExtractSearchTermsFromURL(
1530       GURL("http://term-in-path.com/begin/a%20b%20c/end"),
1531       search_terms_data_, &result));
1532   EXPECT_EQ(u"a b c", result);
1533
1534   // Plus must not be converted to space.
1535   EXPECT_TRUE(url.ExtractSearchTermsFromURL(
1536       GURL("http://term-in-path.com/begin/1+2+3/end"),
1537       search_terms_data_, &result));
1538   EXPECT_EQ(u"1+2+3", result);
1539
1540   EXPECT_FALSE(url.ExtractSearchTermsFromURL(
1541       GURL("http://term-in-path.com/about"), search_terms_data_, &result));
1542   EXPECT_EQ(std::u16string(), result);
1543
1544   EXPECT_FALSE(url.ExtractSearchTermsFromURL(
1545       GURL("http://term-in-path.com/begin"), search_terms_data_, &result));
1546   EXPECT_EQ(std::u16string(), result);
1547
1548   EXPECT_FALSE(url.ExtractSearchTermsFromURL(
1549       GURL("http://term-in-path.com/end"), search_terms_data_, &result));
1550   EXPECT_EQ(std::u16string(), result);
1551 }
1552
1553 // Checks that the ExtractSearchTermsFromURL function works correctly
1554 // for urls containing non-latin characters in UTF8 encoding.
1555 TEST_F(TemplateURLTest, ExtractSearchTermsFromUTF8URL) {
1556   TemplateURLData data;
1557   data.SetURL("http://utf-8.ru/?q={searchTerms}");
1558   data.alternate_urls.push_back("http://utf-8.ru/#q={searchTerms}");
1559   data.alternate_urls.push_back("http://utf-8.ru/path/{searchTerms}");
1560   TemplateURL url(data);
1561   std::u16string result;
1562
1563   // Russian text encoded with UTF-8.
1564   EXPECT_TRUE(url.ExtractSearchTermsFromURL(
1565       GURL("http://utf-8.ru/?q=%D0%97%D0%B4%D1%80%D0%B0%D0%B2%D1%81%D1%82"
1566            "%D0%B2%D1%83%D0%B9,+%D0%BC%D0%B8%D1%80!"),
1567       search_terms_data_, &result));
1568   EXPECT_EQ(
1569       u"\x0417\x0434\x0440\x0430\x0432\x0441\x0442\x0432\x0443\x0439, "
1570       u"\x043C\x0438\x0440!",
1571       result);
1572
1573   EXPECT_TRUE(url.ExtractSearchTermsFromURL(
1574       GURL("http://utf-8.ru/#q=%D0%B4%D0%B2%D0%B0+%D1%81%D0%BB%D0%BE%D0%B2"
1575            "%D0%B0"),
1576       search_terms_data_, &result));
1577   EXPECT_EQ(u"\x0434\x0432\x0430 \x0441\x043B\x043E\x0432\x0430", result);
1578
1579   EXPECT_TRUE(url.ExtractSearchTermsFromURL(
1580       GURL("http://utf-8.ru/path/%D0%B1%D1%83%D0%BA%D0%B2%D1%8B%20%D0%90%20"
1581            "%D0%B8%20A"),
1582       search_terms_data_, &result));
1583   EXPECT_EQ(u"\x0431\x0443\x043A\x0432\x044B \x0410 \x0438 A", result);
1584 }
1585
1586 // Checks that the ExtractSearchTermsFromURL function works correctly
1587 // for urls containing non-latin characters in non-UTF8 encoding.
1588 TEST_F(TemplateURLTest, ExtractSearchTermsFromNonUTF8URL) {
1589   TemplateURLData data;
1590   data.SetURL("http://windows-1251.ru/?q={searchTerms}");
1591   data.alternate_urls.push_back("http://windows-1251.ru/#q={searchTerms}");
1592   data.alternate_urls.push_back("http://windows-1251.ru/path/{searchTerms}");
1593   data.input_encodings.push_back("windows-1251");
1594   TemplateURL url(data);
1595   std::u16string result;
1596
1597   // Russian text encoded with Windows-1251.
1598   EXPECT_TRUE(url.ExtractSearchTermsFromURL(
1599       GURL("http://windows-1251.ru/?q=%C7%E4%F0%E0%E2%F1%F2%E2%F3%E9%2C+"
1600            "%EC%E8%F0!"),
1601       search_terms_data_, &result));
1602   EXPECT_EQ(
1603       u"\x0417\x0434\x0440\x0430\x0432\x0441\x0442\x0432\x0443\x0439, "
1604       u"\x043C\x0438\x0440!",
1605       result);
1606
1607   EXPECT_TRUE(url.ExtractSearchTermsFromURL(
1608       GURL("http://windows-1251.ru/#q=%E4%E2%E0+%F1%EB%EE%E2%E0"),
1609       search_terms_data_, &result));
1610   EXPECT_EQ(u"\x0434\x0432\x0430 \x0441\x043B\x043E\x0432\x0430", result);
1611
1612   EXPECT_TRUE(url.ExtractSearchTermsFromURL(
1613       GURL("http://windows-1251.ru/path/%E1%F3%EA%E2%FB%20%C0%20%E8%20A"),
1614       search_terms_data_, &result));
1615   EXPECT_EQ(u"\x0431\x0443\x043A\x0432\x044B \x0410 \x0438 A", result);
1616 }
1617
1618 // Checks that the ExtractSearchTermsFromURL function strips constant
1619 // prefix/suffix strings from the search terms param.
1620 TEST_F(TemplateURLTest, ExtractSearchTermsWithPrefixAndSuffix) {
1621   TemplateURLData data;
1622   data.alternate_urls.push_back(
1623       "http://www.example.com/?q=chromium-{searchTerms}@chromium.org");
1624   data.alternate_urls.push_back(
1625       "http://www.example.com/chromium-{searchTerms}@chromium.org/info");
1626   TemplateURL url(data);
1627   std::u16string result;
1628
1629   EXPECT_TRUE(url.ExtractSearchTermsFromURL(
1630       GURL("http://www.example.com/?q=chromium-dev@chromium.org"),
1631       search_terms_data_, &result));
1632   EXPECT_EQ(u"dev", result);
1633
1634   EXPECT_TRUE(url.ExtractSearchTermsFromURL(
1635       GURL("http://www.example.com/chromium-dev@chromium.org/info"),
1636       search_terms_data_, &result));
1637   EXPECT_EQ(u"dev", result);
1638
1639   // Don't match if the prefix and suffix aren't there.
1640   EXPECT_FALSE(url.ExtractSearchTermsFromURL(
1641       GURL("http://www.example.com/?q=invalid"), search_terms_data_, &result));
1642
1643   // Don't match if the prefix and suffix overlap.
1644   TemplateURLData data_with_overlap;
1645   data.alternate_urls.push_back(
1646       "http://www.example.com/?q=goo{searchTerms}oogle");
1647   TemplateURL url_with_overlap(data);
1648   EXPECT_FALSE(url_with_overlap.ExtractSearchTermsFromURL(
1649       GURL("http://www.example.com/?q=google"), search_terms_data_, &result));
1650 }
1651
1652 TEST_F(TemplateURLTest, ReplaceSearchTermsInURL) {
1653   TemplateURLData data;
1654   data.SetURL("http://google.com/?q={searchTerms}");
1655   data.alternate_urls.push_back("http://google.com/alt/#q={searchTerms}");
1656   data.alternate_urls.push_back(
1657       "http://google.com/alt/?ext=foo&q={searchTerms}#ref=bar");
1658   TemplateURL url(data);
1659   TemplateURLRef::SearchTermsArgs search_terms(u"Bob Morane");
1660   GURL result;
1661
1662   EXPECT_TRUE(url.ReplaceSearchTermsInURL(
1663       GURL("http://google.com/?q=something"), search_terms,
1664       search_terms_data_, &result));
1665   EXPECT_EQ(GURL("http://google.com/?q=Bob+Morane"), result);
1666
1667   result = GURL("http://should.not.change.com");
1668   EXPECT_FALSE(url.ReplaceSearchTermsInURL(
1669       GURL("http://google.ca/?q=something"), search_terms,
1670       search_terms_data_, &result));
1671   EXPECT_EQ(GURL("http://should.not.change.com"), result);
1672
1673   EXPECT_FALSE(url.ReplaceSearchTermsInURL(
1674       GURL("http://google.com/foo/?q=foo"), search_terms,
1675       search_terms_data_, &result));
1676
1677   EXPECT_TRUE(url.ReplaceSearchTermsInURL(
1678       GURL("https://google.com/?q=foo"), search_terms,
1679       search_terms_data_, &result));
1680   EXPECT_EQ(GURL("https://google.com/?q=Bob+Morane"), result);
1681
1682   EXPECT_FALSE(url.ReplaceSearchTermsInURL(
1683       GURL("http://google.com:8080/?q=foo"), search_terms,
1684       search_terms_data_, &result));
1685
1686   EXPECT_TRUE(url.ReplaceSearchTermsInURL(
1687       GURL("http://google.com/?q=1+2+3&b=456"), search_terms,
1688       search_terms_data_, &result));
1689   EXPECT_EQ(GURL("http://google.com/?q=Bob+Morane&b=456"), result);
1690
1691   // Note: Spaces in REF parameters are not escaped. See TryEncoding() in
1692   // template_url.cc for details.
1693   EXPECT_TRUE(url.ReplaceSearchTermsInURL(
1694       GURL("http://google.com/alt/?q=123#q=456"), search_terms,
1695       search_terms_data_, &result));
1696   EXPECT_EQ(GURL("http://google.com/alt/?q=123#q=Bob+Morane"), result);
1697
1698   EXPECT_TRUE(url.ReplaceSearchTermsInURL(
1699       GURL("http://google.com/alt/?a=012&q=123&b=456#f=789"), search_terms,
1700       search_terms_data_, &result));
1701   EXPECT_EQ(GURL("http://google.com/alt/?a=012&q=Bob+Morane&b=456#f=789"),
1702             result);
1703
1704   EXPECT_TRUE(url.ReplaceSearchTermsInURL(
1705       GURL("http://google.com/alt/?a=012&q=123&b=456#j=abc&q=789&h=def9"),
1706       search_terms, search_terms_data_, &result));
1707   EXPECT_EQ(GURL("http://google.com/alt/?a=012&q=123&b=456"
1708                  "#j=abc&q=Bob+Morane&h=def9"), result);
1709
1710   EXPECT_FALSE(url.ReplaceSearchTermsInURL(
1711       GURL("http://google.com/alt/?q="), search_terms,
1712       search_terms_data_, &result));
1713
1714   EXPECT_FALSE(url.ReplaceSearchTermsInURL(
1715       GURL("http://google.com/alt/?#q="), search_terms,
1716       search_terms_data_, &result));
1717
1718   EXPECT_FALSE(url.ReplaceSearchTermsInURL(
1719       GURL("http://google.com/alt/?q=#q="), search_terms,
1720       search_terms_data_, &result));
1721
1722   EXPECT_FALSE(url.ReplaceSearchTermsInURL(
1723       GURL("http://google.com/alt/?q=123#q="), search_terms,
1724       search_terms_data_, &result));
1725
1726   EXPECT_TRUE(url.ReplaceSearchTermsInURL(
1727       GURL("http://google.com/alt/?q=#q=123"), search_terms,
1728       search_terms_data_, &result));
1729   EXPECT_EQ(GURL("http://google.com/alt/?q=#q=Bob+Morane"), result);
1730 }
1731
1732 TEST_F(TemplateURLTest, ReplaceSearchTermsInURLPath) {
1733   TemplateURLData data;
1734   data.SetURL("http://term-in-path.com/begin/{searchTerms}/end");
1735   TemplateURL url(data);
1736   TemplateURLRef::SearchTermsArgs search_terms(u"Bob Morane");
1737   GURL result;
1738
1739   EXPECT_TRUE(url.ReplaceSearchTermsInURL(
1740       GURL("http://term-in-path.com/begin/something/end"), search_terms,
1741       search_terms_data_, &result));
1742   EXPECT_EQ(GURL("http://term-in-path.com/begin/Bob%20Morane/end"), result);
1743
1744   EXPECT_TRUE(url.ReplaceSearchTermsInURL(
1745       GURL("http://term-in-path.com/begin/1%202%203/end"), search_terms,
1746       search_terms_data_, &result));
1747   EXPECT_EQ(GURL("http://term-in-path.com/begin/Bob%20Morane/end"), result);
1748
1749   result = GURL("http://should.not.change.com");
1750   EXPECT_FALSE(url.ReplaceSearchTermsInURL(
1751       GURL("http://term-in-path.com/about"), search_terms,
1752       search_terms_data_, &result));
1753   EXPECT_EQ(GURL("http://should.not.change.com"), result);
1754 }
1755
1756 // Checks that the ReplaceSearchTermsInURL function works correctly
1757 // for search terms containing non-latin characters for a search engine
1758 // using UTF-8 input encoding.
1759 TEST_F(TemplateURLTest, ReplaceSearchTermsInUTF8URL) {
1760   TemplateURLData data;
1761   data.SetURL("http://utf-8.ru/?q={searchTerms}");
1762   data.alternate_urls.push_back("http://utf-8.ru/#q={searchTerms}");
1763   data.alternate_urls.push_back("http://utf-8.ru/path/{searchTerms}");
1764   TemplateURL url(data);
1765
1766   // Russian text which will be encoded with UTF-8.
1767   TemplateURLRef::SearchTermsArgs search_terms(
1768       u"\x0442\x0435\x043A\x0441\x0442");
1769   GURL result;
1770
1771   EXPECT_TRUE(url.ReplaceSearchTermsInURL(
1772       GURL("http://utf-8.ru/?q=a+b"), search_terms, search_terms_data_,
1773       &result));
1774   EXPECT_EQ(GURL("http://utf-8.ru/?q=%D1%82%D0%B5%D0%BA%D1%81%D1%82"),
1775             result);
1776
1777   EXPECT_TRUE(url.ReplaceSearchTermsInURL(
1778       GURL("http://utf-8.ru/#q=a+b"), search_terms, search_terms_data_,
1779       &result));
1780   EXPECT_EQ(GURL("http://utf-8.ru/#q=%D1%82%D0%B5%D0%BA%D1%81%D1%82"),
1781             result);
1782
1783   EXPECT_TRUE(url.ReplaceSearchTermsInURL(
1784       GURL("http://utf-8.ru/path/a%20b"), search_terms, search_terms_data_,
1785       &result));
1786   EXPECT_EQ(GURL("http://utf-8.ru/path/%D1%82%D0%B5%D0%BA%D1%81%D1%82"),
1787             result);
1788 }
1789
1790 // Checks that the ReplaceSearchTermsInURL function works correctly
1791 // for search terms containing non-latin characters for a search engine
1792 // using non UTF-8 input encoding.
1793 TEST_F(TemplateURLTest, ReplaceSearchTermsInNonUTF8URL) {
1794   TemplateURLData data;
1795   data.SetURL("http://windows-1251.ru/?q={searchTerms}");
1796   data.alternate_urls.push_back("http://windows-1251.ru/#q={searchTerms}");
1797   data.alternate_urls.push_back("http://windows-1251.ru/path/{searchTerms}");
1798   data.input_encodings.push_back("windows-1251");
1799   TemplateURL url(data);
1800
1801   // Russian text which will be encoded with Windows-1251.
1802   TemplateURLRef::SearchTermsArgs search_terms(
1803       u"\x0442\x0435\x043A\x0441\x0442");
1804   GURL result;
1805
1806   EXPECT_TRUE(url.ReplaceSearchTermsInURL(
1807       GURL("http://windows-1251.ru/?q=a+b"), search_terms, search_terms_data_,
1808       &result));
1809   EXPECT_EQ(GURL("http://windows-1251.ru/?q=%F2%E5%EA%F1%F2"),
1810             result);
1811
1812   EXPECT_TRUE(url.ReplaceSearchTermsInURL(
1813       GURL("http://windows-1251.ru/#q=a+b"), search_terms, search_terms_data_,
1814       &result));
1815   EXPECT_EQ(GURL("http://windows-1251.ru/#q=%F2%E5%EA%F1%F2"),
1816             result);
1817
1818   EXPECT_TRUE(url.ReplaceSearchTermsInURL(
1819       GURL("http://windows-1251.ru/path/a%20b"), search_terms,
1820       search_terms_data_, &result));
1821   EXPECT_EQ(GURL("http://windows-1251.ru/path/%F2%E5%EA%F1%F2"),
1822             result);
1823 }
1824
1825 // Test the |additional_query_params| field of SearchTermsArgs.
1826 TEST_F(TemplateURLTest, SuggestQueryParams) {
1827   TemplateURLData data;
1828   // Pick a URL with replacements before, during, and after the query, to ensure
1829   // we don't goof up any of them.
1830   data.SetURL("{google:baseURL}search?q={searchTerms}"
1831       "#{google:originalQueryForSuggestion}x");
1832   TemplateURL url(data);
1833
1834   // Baseline: no |additional_query_params| field.
1835   TemplateURLRef::SearchTermsArgs search_terms(u"abc");
1836   search_terms.original_query = u"def";
1837   search_terms.accepted_suggestion = 0;
1838   EXPECT_EQ("http://www.google.com/search?q=abc#oq=def&x",
1839             url.url_ref().ReplaceSearchTerms(search_terms, search_terms_data_));
1840
1841   // Set the |additional_query_params|.
1842   search_terms.additional_query_params = "pq=xyz";
1843   EXPECT_EQ("http://www.google.com/search?pq=xyz&q=abc#oq=def&x",
1844             url.url_ref().ReplaceSearchTerms(search_terms, search_terms_data_));
1845
1846   // Add |append_extra_query_params_from_command_line| into the mix, and ensure
1847   // it works.
1848   search_terms.append_extra_query_params_from_command_line = true;
1849   base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
1850       switches::kExtraSearchQueryParams, "a=b");
1851   EXPECT_EQ("http://www.google.com/search?a=b&pq=xyz&q=abc#oq=def&x",
1852             url.url_ref().ReplaceSearchTerms(search_terms, search_terms_data_));
1853 }
1854
1855 // Test the |search_terms.append_extra_query_params_from_command_line| field of
1856 // SearchTermsArgs.
1857 TEST_F(TemplateURLTest, ExtraQueryParams) {
1858   TemplateURLData data;
1859   // Pick a URL with replacements before, during, and after the query, to ensure
1860   // we don't goof up any of them.
1861   data.SetURL("{google:baseURL}search?q={searchTerms}"
1862       "#{google:originalQueryForSuggestion}x");
1863   TemplateURL url(data);
1864
1865   // Baseline: no command-line args, no
1866   // |search_terms.append_extra_query_params_from_command_line| flag.
1867   TemplateURLRef::SearchTermsArgs search_terms(u"abc");
1868   search_terms.original_query = u"def";
1869   search_terms.accepted_suggestion = 0;
1870   EXPECT_EQ("http://www.google.com/search?q=abc#oq=def&x",
1871             url.url_ref().ReplaceSearchTerms(search_terms, search_terms_data_));
1872
1873   // Set the flag.  Since there are no command-line args, this should have no
1874   // effect.
1875   search_terms.append_extra_query_params_from_command_line = true;
1876   EXPECT_EQ("http://www.google.com/search?q=abc#oq=def&x",
1877             url.url_ref().ReplaceSearchTerms(search_terms, search_terms_data_));
1878
1879   // Now append the command-line arg.  This should be inserted into the query.
1880   base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
1881       switches::kExtraSearchQueryParams, "a=b");
1882   EXPECT_EQ("http://www.google.com/search?a=b&q=abc#oq=def&x",
1883             url.url_ref().ReplaceSearchTerms(search_terms, search_terms_data_));
1884
1885   // Turn off the flag.  Now the command-line arg should be ignored again.
1886   search_terms.append_extra_query_params_from_command_line = false;
1887   EXPECT_EQ("http://www.google.com/search?q=abc#oq=def&x",
1888             url.url_ref().ReplaceSearchTerms(search_terms, search_terms_data_));
1889 }
1890
1891 // Tests replacing pageClassification.
1892 TEST_F(TemplateURLTest, ReplacePageClassification) {
1893   TemplateURLData data;
1894   data.input_encodings.push_back("UTF-8");
1895   data.SetURL("{google:baseURL}?{google:pageClassification}q={searchTerms}");
1896   TemplateURL url(data);
1897   EXPECT_TRUE(url.url_ref().IsValid(search_terms_data_));
1898   ASSERT_TRUE(url.url_ref().SupportsReplacement(search_terms_data_));
1899   TemplateURLRef::SearchTermsArgs search_terms_args(u"foo");
1900
1901   std::string result = url.url_ref().ReplaceSearchTerms(search_terms_args,
1902                                                         search_terms_data_);
1903   EXPECT_EQ("http://www.google.com/?q=foo", result);
1904
1905   search_terms_args.page_classification = metrics::OmniboxEventProto::NTP;
1906   result = url.url_ref().ReplaceSearchTerms(search_terms_args,
1907                                             search_terms_data_);
1908   EXPECT_EQ("http://www.google.com/?pgcl=1&q=foo", result);
1909
1910   search_terms_args.page_classification =
1911       metrics::OmniboxEventProto::HOME_PAGE;
1912   result = url.url_ref().ReplaceSearchTerms(search_terms_args,
1913                                             search_terms_data_);
1914   EXPECT_EQ("http://www.google.com/?pgcl=3&q=foo", result);
1915 }
1916
1917 // Test the IsSearchURL function.
1918 TEST_F(TemplateURLTest, IsSearchURL) {
1919   TemplateURLData data;
1920   data.SetURL("http://bar/search?q={searchTerms}");
1921   data.new_tab_url = "http://bar/newtab";
1922   data.alternate_urls.push_back("http://bar/?q={searchTerms}");
1923   data.alternate_urls.push_back("http://bar/#q={searchTerms}");
1924   data.alternate_urls.push_back("http://bar/search#q{searchTerms}");
1925   data.alternate_urls.push_back("http://bar/webhp#q={searchTerms}");
1926   TemplateURL search_provider(data);
1927
1928   const struct {
1929     const char* const url;
1930     bool result;
1931   } url_data[] = {
1932     { "http://bar/search?q=foo&oq=foo", true, },
1933     { "http://bar/?q=foo&oq=foo", true, },
1934     { "http://bar/#output=search&q=foo&oq=foo", true, },
1935     { "http://bar/webhp#q=foo&oq=foo", true, },
1936     { "http://bar/#q=foo&oq=foo", true, },
1937     { "http://bar/?ext=foo&q=foo#ref=bar", true, },
1938     { "http://bar/url?url=http://www.foo.com/&q=foo#ref=bar", false, },
1939     { "http://bar/", false, },
1940     { "http://foo/", false, },
1941     { "http://bar/newtab", false, },
1942   };
1943
1944   for (size_t i = 0; i < std::size(url_data); ++i) {
1945     EXPECT_EQ(url_data[i].result,
1946               search_provider.IsSearchURL(GURL(url_data[i].url),
1947                                           search_terms_data_));
1948   }
1949 }
1950
1951 TEST_F(TemplateURLTest, SearchboxVersionIncludedForAnswers) {
1952   TemplateURLData data;
1953   search_terms_data_.set_google_base_url("http://bar/");
1954   data.SetURL("http://bar/search?q={searchTerms}&{google:searchVersion}xssi=t");
1955
1956   TemplateURL url(data);
1957   TemplateURLRef::SearchTermsArgs search_terms_args(u"foo");
1958   std::string result = url.url_ref().ReplaceSearchTerms(search_terms_args,
1959                                                         search_terms_data_);
1960   EXPECT_EQ("http://bar/search?q=foo&gs_rn=42&xssi=t", result);
1961 }
1962
1963 TEST_F(TemplateURLTest, SessionToken) {
1964   TemplateURLData data;
1965   search_terms_data_.set_google_base_url("http://bar/");
1966   data.SetURL("http://bar/search?q={searchTerms}&{google:sessionToken}xssi=t");
1967
1968   TemplateURL url(data);
1969   TemplateURLRef::SearchTermsArgs search_terms_args(u"foo");
1970   search_terms_args.session_token = "SESSIONTOKENGOESHERE";
1971   std::string result = url.url_ref().ReplaceSearchTerms(search_terms_args,
1972                                                         search_terms_data_);
1973   EXPECT_EQ("http://bar/search?q=foo&psi=SESSIONTOKENGOESHERE&xssi=t", result);
1974
1975   TemplateURL url2(data);
1976   search_terms_args.session_token = "";
1977   result = url.url_ref().ReplaceSearchTerms(search_terms_args,
1978                                             search_terms_data_);
1979   EXPECT_EQ("http://bar/search?q=foo&xssi=t", result);
1980 }
1981
1982 TEST_F(TemplateURLTest, ContextualSearchParameters) {
1983   TemplateURLData data;
1984   search_terms_data_.set_google_base_url("http://bar/");
1985   data.SetURL("http://bar/_/contextualsearch?"
1986               "{google:contextualSearchVersion}"
1987               "{google:contextualSearchContextData}");
1988
1989   TemplateURL url(data);
1990   TemplateURLRef::SearchTermsArgs search_terms_args(u"foo");
1991   std::string result = url.url_ref().ReplaceSearchTerms(search_terms_args,
1992                                                         search_terms_data_);
1993   EXPECT_EQ("http://bar/_/contextualsearch?", result);
1994
1995   // Test the current common case, which uses no home country or previous
1996   // event.
1997   TemplateURLRef::SearchTermsArgs::ContextualSearchParams params(
1998       2, 1, std::string(), 0, 0, false, std::string(), std::string(),
1999       std::string(), std::string(), false);
2000   search_terms_args.contextual_search_params = params;
2001   result = url.url_ref().ReplaceSearchTerms(search_terms_args,
2002                                             search_terms_data_);
2003   EXPECT_EQ(
2004       "http://bar/_/contextualsearch?"
2005       "ctxs=2&"
2006       "ctxsl_coca=1",
2007       result);
2008
2009   // Test the home country and non-zero event data case.
2010   search_terms_args.contextual_search_params =
2011       TemplateURLRef::SearchTermsArgs::ContextualSearchParams(
2012           2, 2, "CH", 1657713458, 5, false, std::string(), std::string(),
2013           std::string(), std::string(), false);
2014   result =
2015       url.url_ref().ReplaceSearchTerms(search_terms_args, search_terms_data_);
2016
2017   EXPECT_EQ(
2018       "http://bar/_/contextualsearch?"
2019       "ctxs=2&"
2020       "ctxsl_coca=2&"
2021       "ctxs_hc=CH&"
2022       "ctxsl_pid=1657713458&"
2023       "ctxsl_per=5",
2024       result);
2025
2026   // Test exact-search.
2027   search_terms_args.contextual_search_params =
2028       TemplateURLRef::SearchTermsArgs::ContextualSearchParams(
2029           2, 1, std::string(), 0, 0, true, std::string(), std::string(),
2030           std::string(), std::string(), false);
2031   result =
2032       url.url_ref().ReplaceSearchTerms(search_terms_args, search_terms_data_);
2033   // Find our param.
2034   size_t found_pos = result.find("ctxsl_exact=1");
2035   EXPECT_NE(found_pos, std::string::npos);
2036
2037   // Test source and target languages.
2038   search_terms_args.contextual_search_params =
2039       TemplateURLRef::SearchTermsArgs::ContextualSearchParams(
2040           2, 1, std::string(), 0, 0, true, "es", "de", std::string(),
2041           std::string(), false);
2042   result =
2043       url.url_ref().ReplaceSearchTerms(search_terms_args, search_terms_data_);
2044   // Find our params.
2045   size_t source_pos = result.find("tlitesl=es");
2046   EXPECT_NE(source_pos, std::string::npos);
2047   size_t target_pos = result.find("tlitetl=de");
2048   EXPECT_NE(target_pos, std::string::npos);
2049
2050   // Test fluent languages.
2051   search_terms_args.contextual_search_params =
2052       TemplateURLRef::SearchTermsArgs::ContextualSearchParams(
2053           2, 1, std::string(), 0, 0, true, std::string(), std::string(),
2054           "es,de", std::string(), false);
2055   result =
2056       url.url_ref().ReplaceSearchTerms(search_terms_args, search_terms_data_);
2057   // Find our param.  These may actually be URL encoded.
2058   size_t fluent_pos = result.find("&ctxs_fls=es,de");
2059   EXPECT_NE(fluent_pos, std::string::npos);
2060
2061   // Test Related Searches.
2062   search_terms_args.contextual_search_params =
2063       TemplateURLRef::SearchTermsArgs::ContextualSearchParams(
2064           2, 1, std::string(), 0, 0, true, std::string(), std::string(),
2065           std::string(), "1RbCu", false);
2066   result =
2067       url.url_ref().ReplaceSearchTerms(search_terms_args, search_terms_data_);
2068   // Find our param.
2069   size_t ctxsl_rs_pos = result.find("&ctxsl_rs=1RbCu");
2070   EXPECT_NE(ctxsl_rs_pos, std::string::npos);
2071
2072   // Test apply language hint.
2073   search_terms_args.contextual_search_params =
2074       TemplateURLRef::SearchTermsArgs::ContextualSearchParams(
2075           2, 1, std::string(), 0, 0, true, std::string(), std::string(),
2076           std::string(), std::string(), true);
2077   result =
2078       url.url_ref().ReplaceSearchTerms(search_terms_args, search_terms_data_);
2079   // Find our param.
2080   size_t ctxsl_applylh = result.find("&ctxsl_applylh=1");
2081   EXPECT_NE(ctxsl_applylh, std::string::npos);
2082 }
2083
2084 TEST_F(TemplateURLTest, GenerateKeyword) {
2085   ASSERT_EQ(u"foo", TemplateURL::GenerateKeyword(GURL("http://foo")));
2086   ASSERT_EQ(u"foo.", TemplateURL::GenerateKeyword(GURL("http://foo.")));
2087   // www. should be stripped for a public hostname but not a private/intranet
2088   // hostname.
2089   ASSERT_EQ(u"google.com",
2090             TemplateURL::GenerateKeyword(GURL("http://www.google.com")));
2091   ASSERT_EQ(u"www.foo", TemplateURL::GenerateKeyword(GURL("http://www.foo")));
2092   // Make sure we don't get a trailing '/'.
2093   ASSERT_EQ(u"blah", TemplateURL::GenerateKeyword(GURL("http://blah/")));
2094   // Don't generate the empty string.
2095   ASSERT_EQ(u"www.", TemplateURL::GenerateKeyword(GURL("http://www.")));
2096   ASSERT_EQ(u"абв", TemplateURL::GenerateKeyword(GURL("http://xn--80acd")));
2097
2098   // Generated keywords must always be in lowercase, because TemplateURLs always
2099   // converts keywords to lowercase in its constructor and TemplateURLService
2100   // stores TemplateURLs in maps using keyword as key.
2101   EXPECT_TRUE(IsLowerCase(TemplateURL::GenerateKeyword(GURL("http://BLAH/"))));
2102   EXPECT_TRUE(IsLowerCase(
2103       TemplateURL::GenerateKeyword(GURL("http://embeddedhtml.<head>/"))));
2104 }
2105
2106 TEST_F(TemplateURLTest, KeepSearchTermsInURL) {
2107   search_terms_data_.set_google_base_url("http://bar/");
2108
2109   TemplateURLData data;
2110   data.SetURL("http://bar/search?q={searchTerms}&{google:sessionToken}xssi=t");
2111   data.search_intent_params = {"gs_ssp", "si"};
2112   TemplateURL turl(data);
2113
2114   TemplateURLRef::SearchTermsArgs search_terms_args(u"FOO");
2115   search_terms_args.session_token = "SESSIONTOKEN";
2116
2117   {
2118     // Optionally keeps non-empty search intent params.
2119     search_terms_args.additional_query_params = "gs_ssp=GS_SSP";
2120     std::string original_search_url = turl.url_ref().ReplaceSearchTerms(
2121         search_terms_args, search_terms_data_);
2122     EXPECT_EQ("http://bar/search?gs_ssp=GS_SSP&q=FOO&psi=SESSIONTOKEN&xssi=t",
2123               original_search_url);
2124
2125     GURL canonical_search_url;
2126     EXPECT_TRUE(turl.KeepSearchTermsInURL(
2127         GURL(original_search_url), search_terms_data_,
2128         /*keep_search_intent_params=*/true, /*normalize_search_terms=*/true,
2129         &canonical_search_url));
2130     EXPECT_EQ("http://bar/search?gs_ssp=GS_SSP&q=foo&xssi=t",
2131               canonical_search_url);
2132
2133     EXPECT_TRUE(turl.KeepSearchTermsInURL(
2134         GURL(original_search_url), search_terms_data_,
2135         /*keep_search_intent_params=*/false, /*normalize_search_terms=*/true,
2136         &canonical_search_url));
2137     EXPECT_EQ("http://bar/search?q=foo&xssi=t", canonical_search_url);
2138   }
2139   {
2140     // Optionally keeps empty search intent params.
2141     search_terms_args.additional_query_params = "gs_ssp=";
2142     std::string original_search_url = turl.url_ref().ReplaceSearchTerms(
2143         search_terms_args, search_terms_data_);
2144     EXPECT_EQ("http://bar/search?gs_ssp=&q=FOO&psi=SESSIONTOKEN&xssi=t",
2145               original_search_url);
2146
2147     GURL canonical_search_url;
2148     EXPECT_TRUE(turl.KeepSearchTermsInURL(
2149         GURL(original_search_url), search_terms_data_,
2150         /*keep_search_intent_params=*/true, /*normalize_search_terms=*/true,
2151         &canonical_search_url));
2152     EXPECT_EQ("http://bar/search?gs_ssp=&q=foo&xssi=t", canonical_search_url);
2153
2154     EXPECT_TRUE(turl.KeepSearchTermsInURL(
2155         GURL(original_search_url), search_terms_data_,
2156         /*keep_search_intent_params=*/false, /*normalize_search_terms=*/true,
2157         &canonical_search_url));
2158     EXPECT_EQ("http://bar/search?q=foo&xssi=t", canonical_search_url);
2159   }
2160   {
2161     // Discards params besides search terms and optionally search intent params.
2162     search_terms_args.additional_query_params = "wiz=baz&gs_ssp=GS_SSP";
2163     std::string original_search_url = turl.url_ref().ReplaceSearchTerms(
2164         search_terms_args, search_terms_data_);
2165     EXPECT_EQ(
2166         "http://bar/search?wiz=baz&gs_ssp=GS_SSP&q=FOO&psi=SESSIONTOKEN&xssi=t",
2167         original_search_url);
2168
2169     GURL canonical_search_url;
2170     EXPECT_TRUE(turl.KeepSearchTermsInURL(
2171         GURL(original_search_url), search_terms_data_,
2172         /*keep_search_intent_params=*/true, /*normalize_search_terms=*/true,
2173         &canonical_search_url));
2174     EXPECT_EQ("http://bar/search?gs_ssp=GS_SSP&q=foo&xssi=t",
2175               canonical_search_url);
2176
2177     EXPECT_TRUE(turl.KeepSearchTermsInURL(
2178         GURL(original_search_url), search_terms_data_,
2179         /*keep_search_intent_params=*/false, /*normalize_search_terms=*/true,
2180         &canonical_search_url));
2181     EXPECT_EQ("http://bar/search?q=foo&xssi=t", canonical_search_url);
2182   }
2183   {
2184     // Optionally keeps multiple search intent params.
2185     search_terms_args.additional_query_params = "si=SI&gs_ssp=GS_SSP";
2186     std::string original_search_url = turl.url_ref().ReplaceSearchTerms(
2187         search_terms_args, search_terms_data_);
2188     EXPECT_EQ(
2189         "http://bar/search?si=SI&gs_ssp=GS_SSP&q=FOO&psi=SESSIONTOKEN&xssi=t",
2190         original_search_url);
2191
2192     GURL canonical_search_url;
2193     EXPECT_TRUE(turl.KeepSearchTermsInURL(
2194         GURL(original_search_url), search_terms_data_,
2195         /*keep_search_intent_params=*/true, /*normalize_search_terms=*/true,
2196         &canonical_search_url));
2197     EXPECT_EQ("http://bar/search?si=SI&gs_ssp=GS_SSP&q=foo&xssi=t",
2198               canonical_search_url);
2199
2200     EXPECT_TRUE(turl.KeepSearchTermsInURL(
2201         GURL(original_search_url), search_terms_data_,
2202         /*keep_search_intent_params=*/false, /*normalize_search_terms=*/true,
2203         &canonical_search_url));
2204     EXPECT_EQ("http://bar/search?q=foo&xssi=t", canonical_search_url);
2205   }
2206   {
2207     // Search terms extraction, normalized or not.
2208     search_terms_args.additional_query_params = "gs_ssp=GS_SSP";
2209     std::string original_search_url = turl.url_ref().ReplaceSearchTerms(
2210         search_terms_args, search_terms_data_);
2211     EXPECT_EQ("http://bar/search?gs_ssp=GS_SSP&q=FOO&psi=SESSIONTOKEN&xssi=t",
2212               original_search_url);
2213
2214     GURL canonical_search_url;
2215     std::u16string search_terms;
2216     EXPECT_TRUE(turl.KeepSearchTermsInURL(
2217         GURL(original_search_url), search_terms_data_,
2218         /*keep_search_intent_params=*/false, /*normalize_search_terms=*/true,
2219         &canonical_search_url, &search_terms));
2220     EXPECT_EQ("http://bar/search?q=foo&xssi=t", canonical_search_url);
2221     EXPECT_EQ(u"foo", search_terms);
2222
2223     EXPECT_TRUE(turl.KeepSearchTermsInURL(
2224         GURL(original_search_url), search_terms_data_,
2225         /*keep_search_intent_params=*/false, /*normalize_search_terms=*/false,
2226         &canonical_search_url, &search_terms));
2227     EXPECT_EQ("http://bar/search?q=FOO&xssi=t", canonical_search_url);
2228     EXPECT_EQ(u"FOO", search_terms);
2229   }
2230 }
2231
2232 TEST_F(TemplateURLTest, GenerateSearchURL) {
2233   struct GenerateSearchURLCase {
2234     const char* test_name;
2235     const char* url;
2236     const char* expected;
2237   } generate_url_cases[] = {
2238     { "invalid URL", "foo{searchTerms}", "" },
2239     { "URL with no replacements", "http://foo/", "http://foo/" },
2240     { "basic functionality", "http://foo/{searchTerms}",
2241       "http://foo/blah.blah.blah.blah.blah" }
2242   };
2243
2244   for (const auto& generate_url_case : generate_url_cases) {
2245     TemplateURLData data;
2246     data.SetURL(generate_url_case.url);
2247     TemplateURL t_url(data);
2248     EXPECT_EQ(t_url.GenerateSearchURL(search_terms_data_).spec(),
2249               generate_url_case.expected)
2250         << generate_url_case.test_name << " failed.";
2251   }
2252 }
2253
2254 TEST_F(TemplateURLTest, GenerateSuggestionURL) {
2255   struct GenerateSuggestionURLCase {
2256     const char* test_name;
2257     const char* url;
2258     const char* expected;
2259   } generate_url_cases[] = {
2260       {"invalid URL", "foo{searchTerms}", ""},
2261       {"URL with no replacements", "http://foo/", "http://foo/"},
2262       {"basic functionality", "http://foo/{searchTerms}", "http://foo/"}};
2263
2264   for (const auto& generate_url_case : generate_url_cases) {
2265     TemplateURLData data;
2266     data.suggestions_url = generate_url_case.url;
2267     TemplateURL t_url(data);
2268     EXPECT_EQ(t_url.GenerateSuggestionURL(search_terms_data_).spec(),
2269               generate_url_case.expected)
2270         << generate_url_case.test_name << " failed.";
2271   }
2272 }
2273
2274 TEST_F(TemplateURLTest, PrefetchQueryParameters) {
2275   TemplateURLData data;
2276   search_terms_data_.set_google_base_url("http://bar/");
2277   data.SetURL("http://bar/search?q={searchTerms}&{google:prefetchQuery}xssi=t");
2278
2279   TemplateURL url(data);
2280   TemplateURLRef::SearchTermsArgs search_terms_args(u"foo");
2281   search_terms_args.prefetch_query = "full query text";
2282   search_terms_args.prefetch_query_type = "2338";
2283   std::string result =
2284       url.url_ref().ReplaceSearchTerms(search_terms_args, search_terms_data_);
2285   EXPECT_EQ("http://bar/search?q=foo&pfq=full%20query%20text&qha=2338&xssi=t",
2286             result);
2287
2288   TemplateURL url2(data);
2289   search_terms_args.prefetch_query.clear();
2290   search_terms_args.prefetch_query_type.clear();
2291   result =
2292       url2.url_ref().ReplaceSearchTerms(search_terms_args, search_terms_data_);
2293   EXPECT_EQ("http://bar/search?q=foo&xssi=t", result);
2294 }
2295
2296 // Tests that TemplateURL works correctly after changing the Google base URL
2297 // and invalidating cached values.
2298 TEST_F(TemplateURLTest, InvalidateCachedValues) {
2299   TemplateURLData data;
2300   data.SetURL("{google:baseURL}search?q={searchTerms}");
2301   data.suggestions_url = "{google:baseSuggestURL}search?q={searchTerms}";
2302   data.image_url = "{google:baseURL}searchbyimage/upload";
2303   data.image_translate_url = "{google:baseURL}searchbyimage/upload?translate";
2304   data.new_tab_url = "{google:baseURL}_/chrome/newtab";
2305   data.contextual_search_url = "{google:baseURL}_/contextualsearch";
2306   data.alternate_urls.push_back("{google:baseURL}s#q={searchTerms}");
2307   TemplateURL url(data);
2308   TemplateURLRef::SearchTermsArgs search_terms_args(u"X");
2309   std::u16string search_terms;
2310
2311   EXPECT_TRUE(url.HasGoogleBaseURLs(search_terms_data_));
2312   EXPECT_EQ("http://www.google.com/search?q=X",
2313             url.url_ref().ReplaceSearchTerms(search_terms_args,
2314                                              search_terms_data_));
2315   EXPECT_EQ("http://www.google.com/s#q=X",
2316             url.url_refs()[0].ReplaceSearchTerms(search_terms_args,
2317                                                  search_terms_data_));
2318   EXPECT_EQ("http://www.google.com/search?q=X",
2319             url.url_refs()[1].ReplaceSearchTerms(search_terms_args,
2320                                                  search_terms_data_));
2321   EXPECT_EQ("http://www.google.com/complete/search?q=X",
2322             url.suggestions_url_ref().ReplaceSearchTerms(search_terms_args,
2323                                                          search_terms_data_));
2324   EXPECT_EQ("http://www.google.com/searchbyimage/upload",
2325             url.image_url_ref().ReplaceSearchTerms(search_terms_args,
2326                                                    search_terms_data_));
2327   EXPECT_EQ("http://www.google.com/searchbyimage/upload?translate",
2328             url.image_translate_url_ref().ReplaceSearchTerms(
2329                 search_terms_args, search_terms_data_));
2330   EXPECT_EQ("http://www.google.com/_/chrome/newtab",
2331             url.new_tab_url_ref().ReplaceSearchTerms(search_terms_args,
2332                                                      search_terms_data_));
2333   EXPECT_EQ("http://www.google.com/_/contextualsearch",
2334             url.contextual_search_url_ref().ReplaceSearchTerms(
2335                 search_terms_args, search_terms_data_));
2336
2337   EXPECT_TRUE(url.ExtractSearchTermsFromURL(
2338       GURL("http://www.google.com/search?q=Y+Z"),
2339       search_terms_data_, &search_terms));
2340   EXPECT_EQ(u"Y Z", search_terms);
2341   EXPECT_TRUE(url.ExtractSearchTermsFromURL(
2342       GURL("http://www.google.com/s#q=123"),
2343       search_terms_data_, &search_terms));
2344   EXPECT_EQ(u"123", search_terms);
2345
2346   search_terms_data_.set_google_base_url("https://www.foo.org/");
2347   url.InvalidateCachedValues();
2348
2349   EXPECT_TRUE(url.HasGoogleBaseURLs(search_terms_data_));
2350   EXPECT_EQ("https://www.foo.org/search?q=X",
2351             url.url_ref().ReplaceSearchTerms(search_terms_args,
2352                                              search_terms_data_));
2353   EXPECT_EQ("https://www.foo.org/s#q=X",
2354             url.url_refs()[0].ReplaceSearchTerms(search_terms_args,
2355                                                  search_terms_data_));
2356   EXPECT_EQ("https://www.foo.org/search?q=X",
2357             url.url_refs()[1].ReplaceSearchTerms(search_terms_args,
2358                                                  search_terms_data_));
2359   EXPECT_EQ("https://www.foo.org/complete/search?q=X",
2360             url.suggestions_url_ref().ReplaceSearchTerms(search_terms_args,
2361                                                          search_terms_data_));
2362   EXPECT_EQ("https://www.foo.org/searchbyimage/upload",
2363             url.image_url_ref().ReplaceSearchTerms(search_terms_args,
2364                                                    search_terms_data_));
2365   EXPECT_EQ("https://www.foo.org/searchbyimage/upload?translate",
2366             url.image_translate_url_ref().ReplaceSearchTerms(
2367                 search_terms_args, search_terms_data_));
2368   EXPECT_EQ("https://www.foo.org/_/chrome/newtab",
2369             url.new_tab_url_ref().ReplaceSearchTerms(search_terms_args,
2370                                                      search_terms_data_));
2371   EXPECT_EQ("https://www.foo.org/_/contextualsearch",
2372             url.contextual_search_url_ref().ReplaceSearchTerms(
2373                 search_terms_args, search_terms_data_));
2374
2375   EXPECT_TRUE(url.ExtractSearchTermsFromURL(
2376       GURL("https://www.foo.org/search?q=Y+Z"),
2377       search_terms_data_, &search_terms));
2378   EXPECT_EQ(u"Y Z", search_terms);
2379   EXPECT_TRUE(url.ExtractSearchTermsFromURL(
2380       GURL("https://www.foo.org/s#q=123"),
2381       search_terms_data_, &search_terms));
2382   EXPECT_EQ(u"123", search_terms);
2383
2384   search_terms_data_.set_google_base_url("http://www.google.com/");
2385 }
2386
2387 // Tests the use of wildcards in the path to ensure both extracting search terms
2388 // and generating a search URL work correctly.
2389 TEST_F(TemplateURLTest, PathWildcard) {
2390   TemplateURLData data;
2391   data.SetURL(
2392       "https://www.google.com/search{google:pathWildcard}?q={searchTerms}");
2393   TemplateURL url(data);
2394
2395   // Test extracting search terms from a URL.
2396   std::u16string search_terms;
2397   url.ExtractSearchTermsFromURL(GURL("https://www.google.com/search?q=testing"),
2398                                 search_terms_data_, &search_terms);
2399   EXPECT_EQ(u"testing", search_terms);
2400   url.ExtractSearchTermsFromURL(
2401       GURL("https://www.google.com/search;_this_is_a_test;_?q=testing"),
2402       search_terms_data_, &search_terms);
2403   EXPECT_EQ(u"testing", search_terms);
2404
2405   // Tests overlapping prefix/suffix.
2406   data.SetURL(
2407       "https://www.google.com/search{google:pathWildcard}rch?q={searchTerms}");
2408   TemplateURL overlap_url(data);
2409   overlap_url.ExtractSearchTermsFromURL(
2410       GURL("https://www.google.com/search?q=testing"), search_terms_data_,
2411       &search_terms);
2412   EXPECT_TRUE(search_terms.empty());
2413
2414   // Tests wildcard at beginning of path so we only have a suffix.
2415   data.SetURL(
2416       "https://www.google.com/{google:pathWildcard}rch?q={searchTerms}");
2417   TemplateURL suffix_url(data);
2418   suffix_url.ExtractSearchTermsFromURL(
2419       GURL("https://www.google.com/search?q=testing"), search_terms_data_,
2420       &search_terms);
2421   EXPECT_EQ(u"testing", search_terms);
2422
2423   // Tests wildcard between prefix/suffix.
2424   overlap_url.ExtractSearchTermsFromURL(
2425       GURL("https://www.google.com/search_testing_rch?q=testing"),
2426       search_terms_data_, &search_terms);
2427   EXPECT_EQ(u"testing", search_terms);
2428
2429   // Test generating a URL.
2430   TemplateURLRef::SearchTermsArgs search_terms_args(u"foo");
2431   GURL generated_url;
2432   url.ReplaceSearchTermsInURL(url.GenerateSearchURL(search_terms_data_),
2433                               search_terms_args, search_terms_data_,
2434                               &generated_url);
2435   EXPECT_EQ("https://www.google.com/search?q=foo", generated_url.spec());
2436 }
2437
2438 TEST_F(TemplateURLTest, SideImageSearchParams) {
2439   TemplateURLData data;
2440   data.side_image_search_param = "sideimagesearch";
2441   TemplateURL url(data);
2442
2443   // Adds query param with provided version to URL.
2444   GURL result =
2445       url.GenerateSideImageSearchURL(GURL("http://foo.com/?q=123"), "1");
2446   EXPECT_EQ("http://foo.com/?q=123&sideimagesearch=1", result.spec());
2447
2448   // Does not add query param if the provided URL already has that param and
2449   // version.
2450   result = url.GenerateSideImageSearchURL(
2451       GURL("http://foo.com/?q=123&sideimagesearch=1"), "1");
2452   EXPECT_EQ("http://foo.com/?q=123&sideimagesearch=1", result.spec());
2453
2454   // Updates version if the version on the query param does not match.
2455   result = url.GenerateSideImageSearchURL(
2456       GURL("http://foo.com/?q=123&sideimagesearch=2"), "1");
2457   EXPECT_EQ("http://foo.com/?q=123&sideimagesearch=1", result.spec());
2458
2459   // Does nothing if the URL does not have the param.
2460   result = url.RemoveSideImageSearchParamFromURL(GURL("http://foo.com/?q=123"));
2461   EXPECT_EQ("http://foo.com/?q=123", result.spec());
2462
2463   // Removes the param if the provided URL has it.
2464   result = url.RemoveSideImageSearchParamFromURL(
2465       GURL("http://foo.com/?q=123&sideimagesearch=1"));
2466   EXPECT_EQ("http://foo.com/?q=123", result.spec());
2467
2468   // Removes the first instance of the query param that exist in the URL. This
2469   // should not happen but just asserting for expected behavior.
2470   result = url.RemoveSideImageSearchParamFromURL(
2471       GURL("http://foo.com/?q=123&sideimagesearch=1&sideimagesearch=2"));
2472   EXPECT_EQ("http://foo.com/?q=123&sideimagesearch=2", result.spec());
2473 }
2474
2475 TEST_F(TemplateURLTest, ImageTranslate) {
2476   struct TestData {
2477     const std::string image_translate_url;
2478     const std::string image_translate_source_language_param_key;
2479     const std::string image_translate_target_language_param_key;
2480     const std::string image_translate_source_locale;
2481     const std::string image_translate_target_locale;
2482     const std::string expected_result;
2483   } test_data[] = {
2484       {"https://lens.google.com/upload?filtertype=translate"
2485        "&{imageTranslateSourceLocale}{imageTranslateTargetLocale}",
2486        "sourcelang", "targetlang", "zh-CN", "fr",
2487        "https://lens.google.com/"
2488        "upload?filtertype=translate&sourcelang=zh-CN&targetlang=fr&"},
2489       {"https://www.foo.com/images/detail/search"
2490        "?ft=tr&{imageTranslateSourceLocale}{imageTranslateTargetLocale}"
2491        "#fragment",
2492        "sl", "tl", "ja", "es",
2493        "https://www.foo.com/images/detail/search?ft=tr&sl=ja&tl=es&#fragment"},
2494       {"https://bar.com/images/translate/"
2495        "{imageTranslateSourceLocale}/{imageTranslateTargetLocale}/",
2496        "", "", "ko", "de", "https://bar.com/images/translate/ko/de/"},
2497   };
2498   TemplateURLData data;
2499   for (const auto& entry : test_data) {
2500     data.image_translate_url = entry.image_translate_url;
2501     data.image_translate_source_language_param_key =
2502         entry.image_translate_source_language_param_key;
2503     data.image_translate_target_language_param_key =
2504         entry.image_translate_target_language_param_key;
2505     TemplateURL url(data);
2506     TemplateURLRef::SearchTermsArgs search_terms_args(u"");
2507     search_terms_args.image_translate_source_locale =
2508         entry.image_translate_source_locale;
2509     search_terms_args.image_translate_target_locale =
2510         entry.image_translate_target_locale;
2511     GURL result(url.image_translate_url_ref().ReplaceSearchTerms(
2512         search_terms_args, search_terms_data_));
2513     ASSERT_TRUE(result.is_valid());
2514     EXPECT_EQ(entry.expected_result, result.spec());
2515   }
2516 }
2517
2518 TEST_F(TemplateURLTest, ImageSearchBrandingLabel) {
2519   TemplateURLData data;
2520   data.SetShortName(u"foo");
2521   TemplateURL no_image_branding_url(data);
2522
2523   // Without an image_search_branding_label set, should return short_name
2524   EXPECT_EQ(u"foo", no_image_branding_url.image_search_branding_label());
2525
2526   data.image_search_branding_label = u"fooimages";
2527   TemplateURL image_branding_url(data);
2528   EXPECT_EQ(u"fooimages", image_branding_url.image_search_branding_label());
2529 }