1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <string>
6 #include <vector>
7 
8 #include "base/files/scoped_temp_dir.h"
9 #include "base/macros.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "base/time/time.h"
13 #include "components/search_engines/keyword_table.h"
14 #include "components/search_engines/template_url_data.h"
15 #include "components/webdata/common/web_database.h"
16 #include "sql/statement.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18 
19 using base::ASCIIToUTF16;
20 using base::Time;
21 using base::TimeDelta;
22 
23 class KeywordTableTest : public testing::Test {
24  public:
KeywordTableTest()25   KeywordTableTest() {}
~KeywordTableTest()26   ~KeywordTableTest() override {}
27 
28  protected:
SetUp()29   void SetUp() override {
30     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
31     file_ = temp_dir_.GetPath().AppendASCII("TestWebDatabase");
32 
33     table_.reset(new KeywordTable);
34     db_.reset(new WebDatabase);
35     db_->AddTable(table_.get());
36     ASSERT_EQ(sql::INIT_OK, db_->Init(file_));
37   }
38 
AddKeyword(const TemplateURLData & keyword) const39   void AddKeyword(const TemplateURLData& keyword) const {
40     EXPECT_TRUE(table_->AddKeyword(keyword));
41   }
42 
CreateAndAddKeyword() const43   TemplateURLData CreateAndAddKeyword() const {
44     TemplateURLData keyword;
45     keyword.SetShortName(ASCIIToUTF16("short_name"));
46     keyword.SetKeyword(ASCIIToUTF16("keyword"));
47     keyword.SetURL("http://url/");
48     keyword.suggestions_url = "url2";
49     keyword.image_url = "http://image-search-url/";
50     keyword.new_tab_url = "http://new-tab-url/";
51     keyword.search_url_post_params = "ie=utf-8,oe=utf-8";
52     keyword.image_url_post_params = "name=1,value=2";
53     keyword.favicon_url = GURL("http://favicon.url/");
54     keyword.originating_url = GURL("http://google.com/");
55     keyword.safe_for_autoreplace = true;
56     keyword.input_encodings.push_back("UTF-8");
57     keyword.input_encodings.push_back("UTF-16");
58     keyword.id = 1;
59     keyword.date_created = base::Time::UnixEpoch();
60     keyword.last_modified = base::Time::UnixEpoch();
61     keyword.last_visited = base::Time::UnixEpoch();
62     keyword.created_by_policy = true;
63     keyword.usage_count = 32;
64     keyword.prepopulate_id = 10;
65     keyword.sync_guid = "1234-5678-90AB-CDEF";
66     keyword.alternate_urls.push_back("a_url1");
67     keyword.alternate_urls.push_back("a_url2");
68     AddKeyword(keyword);
69     return keyword;
70   }
71 
RemoveKeyword(TemplateURLID id) const72   void RemoveKeyword(TemplateURLID id) const {
73     EXPECT_TRUE(table_->RemoveKeyword(id));
74   }
75 
UpdateKeyword(const TemplateURLData & keyword) const76   void UpdateKeyword(const TemplateURLData& keyword) const {
77     EXPECT_TRUE(table_->UpdateKeyword(keyword));
78   }
79 
GetKeywords() const80   KeywordTable::Keywords GetKeywords() const {
81     KeywordTable::Keywords keywords;
82     EXPECT_TRUE(table_->GetKeywords(&keywords));
83     return keywords;
84   }
85 
KeywordMiscTest() const86   void KeywordMiscTest() const {
87     EXPECT_EQ(kInvalidTemplateURLID, table_->GetDefaultSearchProviderID());
88     EXPECT_EQ(0, table_->GetBuiltinKeywordVersion());
89 
90     EXPECT_TRUE(table_->SetDefaultSearchProviderID(10));
91     EXPECT_TRUE(table_->SetBuiltinKeywordVersion(11));
92 
93     EXPECT_EQ(10, table_->GetDefaultSearchProviderID());
94     EXPECT_EQ(11, table_->GetBuiltinKeywordVersion());
95   }
96 
GetStatement(const char * sql,sql::Statement * statement) const97   void GetStatement(const char* sql, sql::Statement* statement) const {
98     statement->Assign(table_->db_->GetUniqueStatement(sql));
99   }
100 
101  private:
102   base::FilePath file_;
103   base::ScopedTempDir temp_dir_;
104   std::unique_ptr<KeywordTable> table_;
105   std::unique_ptr<WebDatabase> db_;
106 
107   DISALLOW_COPY_AND_ASSIGN(KeywordTableTest);
108 };
109 
110 
TEST_F(KeywordTableTest,Keywords)111 TEST_F(KeywordTableTest, Keywords) {
112   TemplateURLData keyword(CreateAndAddKeyword());
113 
114   KeywordTable::Keywords keywords(GetKeywords());
115   EXPECT_EQ(1U, keywords.size());
116   const TemplateURLData& restored_keyword = keywords.front();
117 
118   EXPECT_EQ(keyword.short_name(), restored_keyword.short_name());
119   EXPECT_EQ(keyword.keyword(), restored_keyword.keyword());
120   EXPECT_EQ(keyword.url(), restored_keyword.url());
121   EXPECT_EQ(keyword.suggestions_url, restored_keyword.suggestions_url);
122   EXPECT_EQ(keyword.favicon_url, restored_keyword.favicon_url);
123   EXPECT_EQ(keyword.originating_url, restored_keyword.originating_url);
124   EXPECT_EQ(keyword.safe_for_autoreplace,
125             restored_keyword.safe_for_autoreplace);
126   EXPECT_EQ(keyword.input_encodings, restored_keyword.input_encodings);
127   EXPECT_EQ(keyword.id, restored_keyword.id);
128   // The database stores time only at the resolution of a second.
129   EXPECT_EQ(keyword.date_created.ToTimeT(),
130             restored_keyword.date_created.ToTimeT());
131   EXPECT_EQ(keyword.last_modified.ToTimeT(),
132             restored_keyword.last_modified.ToTimeT());
133   EXPECT_EQ(keyword.last_visited.ToTimeT(),
134             restored_keyword.last_visited.ToTimeT());
135   EXPECT_EQ(keyword.created_by_policy, restored_keyword.created_by_policy);
136   EXPECT_EQ(keyword.created_from_play_api,
137             restored_keyword.created_from_play_api);
138   EXPECT_EQ(keyword.usage_count, restored_keyword.usage_count);
139   EXPECT_EQ(keyword.prepopulate_id, restored_keyword.prepopulate_id);
140 
141   RemoveKeyword(restored_keyword.id);
142 
143   EXPECT_EQ(0U, GetKeywords().size());
144 }
145 
TEST_F(KeywordTableTest,KeywordMisc)146 TEST_F(KeywordTableTest, KeywordMisc) {
147   KeywordMiscTest();
148 }
149 
TEST_F(KeywordTableTest,UpdateKeyword)150 TEST_F(KeywordTableTest, UpdateKeyword) {
151   TemplateURLData keyword(CreateAndAddKeyword());
152 
153   keyword.SetKeyword(ASCIIToUTF16("url"));
154   keyword.originating_url = GURL("http://originating.url/");
155   keyword.input_encodings.push_back("Shift_JIS");
156   keyword.prepopulate_id = 5;
157   keyword.created_from_play_api = true;
158   UpdateKeyword(keyword);
159 
160   KeywordTable::Keywords keywords(GetKeywords());
161   EXPECT_EQ(1U, keywords.size());
162   const TemplateURLData& restored_keyword = keywords.front();
163 
164   EXPECT_EQ(keyword.short_name(), restored_keyword.short_name());
165   EXPECT_EQ(keyword.keyword(), restored_keyword.keyword());
166   EXPECT_EQ(keyword.suggestions_url, restored_keyword.suggestions_url);
167   EXPECT_EQ(keyword.favicon_url, restored_keyword.favicon_url);
168   EXPECT_EQ(keyword.originating_url, restored_keyword.originating_url);
169   EXPECT_EQ(keyword.safe_for_autoreplace,
170             restored_keyword.safe_for_autoreplace);
171   EXPECT_EQ(keyword.input_encodings, restored_keyword.input_encodings);
172   EXPECT_EQ(keyword.id, restored_keyword.id);
173   EXPECT_EQ(keyword.prepopulate_id, restored_keyword.prepopulate_id);
174   EXPECT_EQ(keyword.created_from_play_api,
175             restored_keyword.created_from_play_api);
176 }
177 
TEST_F(KeywordTableTest,KeywordWithNoFavicon)178 TEST_F(KeywordTableTest, KeywordWithNoFavicon) {
179   TemplateURLData keyword;
180   keyword.SetShortName(ASCIIToUTF16("short_name"));
181   keyword.SetKeyword(ASCIIToUTF16("keyword"));
182   keyword.SetURL("http://url/");
183   keyword.safe_for_autoreplace = true;
184   keyword.id = -100;
185   AddKeyword(keyword);
186 
187   KeywordTable::Keywords keywords(GetKeywords());
188   EXPECT_EQ(1U, keywords.size());
189   const TemplateURLData& restored_keyword = keywords.front();
190 
191   EXPECT_EQ(keyword.short_name(), restored_keyword.short_name());
192   EXPECT_EQ(keyword.keyword(), restored_keyword.keyword());
193   EXPECT_EQ(keyword.favicon_url, restored_keyword.favicon_url);
194   EXPECT_EQ(keyword.safe_for_autoreplace,
195             restored_keyword.safe_for_autoreplace);
196   EXPECT_EQ(keyword.id, restored_keyword.id);
197 }
198 
TEST_F(KeywordTableTest,SanitizeURLs)199 TEST_F(KeywordTableTest, SanitizeURLs) {
200   TemplateURLData keyword;
201   keyword.SetShortName(ASCIIToUTF16("legit"));
202   keyword.SetKeyword(ASCIIToUTF16("legit"));
203   keyword.SetURL("http://url/");
204   keyword.id = 1000;
205   AddKeyword(keyword);
206 
207   keyword.SetShortName(ASCIIToUTF16("bogus"));
208   keyword.SetKeyword(ASCIIToUTF16("bogus"));
209   keyword.id = 2000;
210   AddKeyword(keyword);
211 
212   EXPECT_EQ(2U, GetKeywords().size());
213 
214   // Erase the URL field for the second keyword to simulate having bogus data
215   // previously saved into the database.
216   sql::Statement s;
217   GetStatement("UPDATE keywords SET url=? WHERE id=?", &s);
218   s.BindString16(0, base::string16());
219   s.BindInt64(1, 2000);
220   EXPECT_TRUE(s.Run());
221 
222   // GetKeywords() should erase the entry with the empty URL field.
223   EXPECT_EQ(1U, GetKeywords().size());
224 }
225 
TEST_F(KeywordTableTest,SanitizeShortName)226 TEST_F(KeywordTableTest, SanitizeShortName) {
227   TemplateURLData keyword;
228   {
229     keyword.SetShortName(ASCIIToUTF16("legit name"));
230     keyword.SetKeyword(ASCIIToUTF16("legit"));
231     keyword.SetURL("http://url/");
232     keyword.id = 1000;
233     AddKeyword(keyword);
234     KeywordTable::Keywords keywords(GetKeywords());
235     EXPECT_EQ(1U, keywords.size());
236     const TemplateURLData& keyword_from_database = keywords.front();
237     EXPECT_EQ(keyword.id, keyword_from_database.id);
238     EXPECT_EQ(ASCIIToUTF16("legit name"), keyword_from_database.short_name());
239     RemoveKeyword(keyword.id);
240   }
241 
242   {
243     keyword.SetShortName(ASCIIToUTF16("\t\tbogus \tname \n"));
244     keyword.SetKeyword(ASCIIToUTF16("bogus"));
245     keyword.id = 2000;
246     AddKeyword(keyword);
247     KeywordTable::Keywords keywords(GetKeywords());
248     EXPECT_EQ(1U, keywords.size());
249     const TemplateURLData& keyword_from_database = keywords.front();
250     EXPECT_EQ(keyword.id, keyword_from_database.id);
251     EXPECT_EQ(ASCIIToUTF16("bogus name"), keyword_from_database.short_name());
252     RemoveKeyword(keyword.id);
253   }
254 }
255