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