OLD | NEW |
---|---|
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <algorithm> | 5 #include <algorithm> |
6 #include <vector> | 6 #include <vector> |
7 | 7 |
8 #include "base/basictypes.h" | 8 #include "base/basictypes.h" |
9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
10 #include "base/file_path.h" | 10 #include "base/file_path.h" |
11 #include "base/file_util.h" | 11 #include "base/file_util.h" |
12 #include "base/path_service.h" | 12 #include "base/path_service.h" |
13 #include "base/ref_counted_memory.h" | 13 #include "base/ref_counted_memory.h" |
14 #include "base/scoped_temp_dir.h" | 14 #include "base/scoped_temp_dir.h" |
15 #include "chrome/browser/history/thumbnail_database.h" | 15 #include "chrome/browser/history/thumbnail_database.h" |
16 #include "chrome/common/chrome_paths.h" | 16 #include "chrome/common/chrome_paths.h" |
17 #include "chrome/browser/history/top_sites.h" | 17 #include "chrome/browser/history/top_sites.h" |
sky
2011/01/13 16:55:52
Can this be removed?
satorux1
2011/01/14 07:36:46
Done.
| |
18 #include "chrome/common/thumbnail_score.h" | 18 #include "chrome/common/thumbnail_score.h" |
19 #include "chrome/tools/profiles/thumbnail-inl.h" | 19 #include "chrome/tools/profiles/thumbnail-inl.h" |
20 #include "gfx/codec/jpeg_codec.h" | 20 #include "gfx/codec/jpeg_codec.h" |
21 #include "googleurl/src/gurl.h" | 21 #include "googleurl/src/gurl.h" |
22 #include "testing/gtest/include/gtest/gtest.h" | 22 #include "testing/gtest/include/gtest/gtest.h" |
23 #include "third_party/skia/include/core/SkBitmap.h" | 23 #include "third_party/skia/include/core/SkBitmap.h" |
24 | 24 |
25 using base::Time; | 25 using base::Time; |
26 using base::TimeDelta; | 26 using base::TimeDelta; |
27 | 27 |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
64 gfx::JPEGCodec::Decode(kGoogleThumbnail, sizeof(kGoogleThumbnail))); | 64 gfx::JPEGCodec::Decode(kGoogleThumbnail, sizeof(kGoogleThumbnail))); |
65 } | 65 } |
66 | 66 |
67 scoped_ptr<SkBitmap> google_bitmap_; | 67 scoped_ptr<SkBitmap> google_bitmap_; |
68 | 68 |
69 ScopedTempDir temp_dir_; | 69 ScopedTempDir temp_dir_; |
70 FilePath file_name_; | 70 FilePath file_name_; |
71 FilePath new_file_name_; | 71 FilePath new_file_name_; |
72 }; | 72 }; |
73 | 73 |
74 TEST_F(ThumbnailDatabaseTest, AddDelete) { | |
75 if (history::TopSites::IsEnabled()) | |
76 return; // TopSitesTest replaces this. | |
77 | |
78 ThumbnailDatabase db; | |
79 ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL)); | |
80 | |
81 // Add one page & verify it got added. | |
82 ThumbnailScore boring(kBoringness, true, true); | |
83 Time time; | |
84 GURL gurl; | |
85 db.SetPageThumbnail(gurl, kPage1, *google_bitmap_, boring, time); | |
86 ThumbnailScore score_output; | |
87 ASSERT_TRUE(db.ThumbnailScoreForId(kPage1, &score_output)); | |
88 ASSERT_TRUE(boring.Equals(score_output)); | |
89 | |
90 // Verify a random page is not found. | |
91 int64 page2 = 5678; | |
92 std::vector<unsigned char> jpeg_data; | |
93 EXPECT_FALSE(db.GetPageThumbnail(page2, &jpeg_data)); | |
94 EXPECT_FALSE(db.ThumbnailScoreForId(page2, &score_output)); | |
95 | |
96 // Add another page with a better boringness & verify it got added. | |
97 ThumbnailScore better_boringness(kBetterBoringness, true, true); | |
98 | |
99 db.SetPageThumbnail(gurl, page2, *google_bitmap_, better_boringness, time); | |
100 ASSERT_TRUE(db.ThumbnailScoreForId(page2, &score_output)); | |
101 ASSERT_TRUE(better_boringness.Equals(score_output)); | |
102 | |
103 // Delete the thumbnail for the second page. | |
104 ThumbnailScore worse_boringness(kWorseBoringness, true, true); | |
105 db.SetPageThumbnail(gurl, page2, SkBitmap(), worse_boringness, time); | |
106 ASSERT_FALSE(db.GetPageThumbnail(page2, &jpeg_data)); | |
107 ASSERT_FALSE(db.ThumbnailScoreForId(page2, &score_output)); | |
108 | |
109 // Delete the first thumbnail using the explicit delete API. | |
110 ASSERT_TRUE(db.DeleteThumbnail(kPage1)); | |
111 | |
112 // Make sure it is gone | |
113 ASSERT_FALSE(db.ThumbnailScoreForId(kPage1, &score_output)); | |
114 ASSERT_FALSE(db.GetPageThumbnail(kPage1, &jpeg_data)); | |
115 ASSERT_FALSE(db.ThumbnailScoreForId(page2, &score_output)); | |
116 ASSERT_FALSE(db.GetPageThumbnail(page2, &jpeg_data)); | |
117 } | |
118 | |
119 TEST_F(ThumbnailDatabaseTest, UseLessBoringThumbnails) { | |
120 if (history::TopSites::IsEnabled()) | |
121 return; // TopSitesTest replaces this. | |
122 | |
123 ThumbnailDatabase db; | |
124 Time now = Time::Now(); | |
125 ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL)); | |
126 | |
127 // Add one page & verify it got added. | |
128 ThumbnailScore boring(kBoringness, true, true); | |
129 | |
130 Time time; | |
131 GURL gurl; | |
132 db.SetPageThumbnail(gurl, kPage1, *google_bitmap_, boring, time); | |
133 std::vector<unsigned char> jpeg_data; | |
134 ThumbnailScore score_out; | |
135 ASSERT_TRUE(db.GetPageThumbnail(kPage1, &jpeg_data)); | |
136 ASSERT_TRUE(db.ThumbnailScoreForId(kPage1, &score_out)); | |
137 ASSERT_TRUE(boring.Equals(score_out)); | |
138 | |
139 // Attempt to update the first page entry with a thumbnail that | |
140 // is more boring and verify that it doesn't change. | |
141 ThumbnailScore more_boring(kWorseBoringness, true, true); | |
142 db.SetPageThumbnail(gurl, kPage1, *google_bitmap_, more_boring, time); | |
143 ASSERT_TRUE(db.GetPageThumbnail(kPage1, &jpeg_data)); | |
144 ASSERT_TRUE(db.ThumbnailScoreForId(kPage1, &score_out)); | |
145 ASSERT_TRUE(boring.Equals(score_out)); | |
146 | |
147 // Attempt to update the first page entry with a thumbnail that | |
148 // is less boring and verify that we update it. | |
149 ThumbnailScore less_boring(kBetterBoringness, true, true); | |
150 db.SetPageThumbnail(gurl, kPage1, *google_bitmap_, less_boring, time); | |
151 ASSERT_TRUE(db.GetPageThumbnail(kPage1, &jpeg_data)); | |
152 ASSERT_TRUE(db.ThumbnailScoreForId(kPage1, &score_out)); | |
153 ASSERT_TRUE(less_boring.Equals(score_out)); | |
154 } | |
155 | |
156 TEST_F(ThumbnailDatabaseTest, UseAtTopThumbnails) { | |
157 if (history::TopSites::IsEnabled()) | |
158 return; // TopSitesTest replaces this. | |
159 | |
160 ThumbnailDatabase db; | |
161 Time now = Time::Now(); | |
162 ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL)); | |
163 | |
164 // Add one page & verify it got added. Note that it doesn't have | |
165 // |good_clipping| and isn't |at_top|. | |
166 ThumbnailScore boring_and_bad(kBoringness, false, false); | |
167 | |
168 Time time; | |
169 GURL gurl; | |
170 db.SetPageThumbnail(gurl, kPage1, *google_bitmap_, boring_and_bad, time); | |
171 std::vector<unsigned char> jpeg_data; | |
172 ThumbnailScore score_out; | |
173 ASSERT_TRUE(db.GetPageThumbnail(kPage1, &jpeg_data)); | |
174 ASSERT_TRUE(db.ThumbnailScoreForId(kPage1, &score_out)); | |
175 ASSERT_TRUE(boring_and_bad.Equals(score_out)); | |
176 | |
177 // A thumbnail that's at the top of the page should replace | |
178 // thumbnails that are in the middle, for the same boringness. | |
179 ThumbnailScore boring_but_better(kBoringness, false, true); | |
180 db.SetPageThumbnail(gurl, kPage1, *google_bitmap_, boring_but_better, time); | |
181 ASSERT_TRUE(db.GetPageThumbnail(kPage1, &jpeg_data)); | |
182 ASSERT_TRUE(db.ThumbnailScoreForId(kPage1, &score_out)); | |
183 ASSERT_TRUE(boring_but_better.Equals(score_out)); | |
184 | |
185 // The only case where we should replace a thumbnail at the top with | |
186 // a thumbnail in the middle/bottom is when the current thumbnail is | |
187 // weirdly stretched and the incoming thumbnail isn't. | |
188 ThumbnailScore better_boring_bad_framing(kBetterBoringness, false, false); | |
189 db.SetPageThumbnail(gurl, kPage1, *google_bitmap_, better_boring_bad_framing, | |
190 time); | |
191 ASSERT_TRUE(db.GetPageThumbnail(kPage1, &jpeg_data)); | |
192 ASSERT_TRUE(db.ThumbnailScoreForId(kPage1, &score_out)); | |
193 ASSERT_TRUE(boring_but_better.Equals(score_out)); | |
194 | |
195 ThumbnailScore boring_good_clipping(kBoringness, true, false); | |
196 db.SetPageThumbnail(gurl, kPage1, *google_bitmap_, boring_good_clipping, | |
197 time); | |
198 ASSERT_TRUE(db.GetPageThumbnail(kPage1, &jpeg_data)); | |
199 ASSERT_TRUE(db.ThumbnailScoreForId(kPage1, &score_out)); | |
200 ASSERT_TRUE(boring_good_clipping.Equals(score_out)); | |
201 | |
202 // Now that we have a non-stretched, middle of the page thumbnail, | |
203 // we shouldn't be able to replace it with: | |
204 | |
205 // 1) A stretched thumbnail in the middle of the page | |
206 db.SetPageThumbnail(gurl, kPage1, *google_bitmap_, | |
207 ThumbnailScore(kBetterBoringness, false, false, now), | |
208 time); | |
209 ASSERT_TRUE(db.GetPageThumbnail(kPage1, &jpeg_data)); | |
210 ASSERT_TRUE(db.ThumbnailScoreForId(kPage1, &score_out)); | |
211 ASSERT_TRUE(boring_good_clipping.Equals(score_out)); | |
212 | |
213 // 2) A stretched thumbnail at the top of the page | |
214 db.SetPageThumbnail(gurl, kPage1, *google_bitmap_, | |
215 ThumbnailScore(kBetterBoringness, false, true, now), | |
216 time); | |
217 ASSERT_TRUE(db.GetPageThumbnail(kPage1, &jpeg_data)); | |
218 ASSERT_TRUE(db.ThumbnailScoreForId(kPage1, &score_out)); | |
219 ASSERT_TRUE(boring_good_clipping.Equals(score_out)); | |
220 | |
221 // But it should be replaced by a thumbnail that's clipped properly | |
222 // and is at the top | |
223 ThumbnailScore best_score(kBetterBoringness, true, true); | |
224 db.SetPageThumbnail(gurl, kPage1, *google_bitmap_, best_score, time); | |
225 ASSERT_TRUE(db.GetPageThumbnail(kPage1, &jpeg_data)); | |
226 ASSERT_TRUE(db.ThumbnailScoreForId(kPage1, &score_out)); | |
227 ASSERT_TRUE(best_score.Equals(score_out)); | |
228 } | |
229 | |
230 TEST_F(ThumbnailDatabaseTest, ThumbnailTimeDegradation) { | |
231 if (history::TopSites::IsEnabled()) | |
232 return; // TopSitesTest replaces this. | |
233 | |
234 ThumbnailDatabase db; | |
235 const Time kNow = Time::Now(); | |
236 const Time kThreeHoursAgo = kNow - TimeDelta::FromHours(4); | |
237 const Time kFiveHoursAgo = kNow - TimeDelta::FromHours(6); | |
238 const double kBaseBoringness = 0.305; | |
239 const double kWorseBoringness = 0.345; | |
240 | |
241 ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL)); | |
242 | |
243 // add one page & verify it got added. | |
244 ThumbnailScore base_boringness(kBaseBoringness, true, true, kFiveHoursAgo); | |
245 | |
246 Time time; | |
247 GURL gurl; | |
248 db.SetPageThumbnail(gurl, kPage1, *google_bitmap_, base_boringness, time); | |
249 std::vector<unsigned char> jpeg_data; | |
250 ThumbnailScore score_out; | |
251 ASSERT_TRUE(db.GetPageThumbnail(kPage1, &jpeg_data)); | |
252 ASSERT_TRUE(db.ThumbnailScoreForId(kPage1, &score_out)); | |
253 ASSERT_TRUE(base_boringness.Equals(score_out)); | |
254 | |
255 // Try to add a different thumbnail with a worse score an hour later | |
256 // (but not enough to trip the boringness degradation threshold). | |
257 ThumbnailScore hour_later(kWorseBoringness, true, true, kThreeHoursAgo); | |
258 db.SetPageThumbnail(gurl, kPage1, *google_bitmap_, hour_later, time); | |
259 ASSERT_TRUE(db.GetPageThumbnail(kPage1, &jpeg_data)); | |
260 ASSERT_TRUE(db.ThumbnailScoreForId(kPage1, &score_out)); | |
261 ASSERT_TRUE(base_boringness.Equals(score_out)); | |
262 | |
263 // After a full five hours, things should have degraded enough | |
264 // that we'll allow the same thumbnail with the same (worse) | |
265 // boringness that we previous rejected. | |
266 ThumbnailScore five_hours_later(kWorseBoringness, true, true, kNow); | |
267 db.SetPageThumbnail(gurl, kPage1, *google_bitmap_, five_hours_later, time); | |
268 ASSERT_TRUE(db.GetPageThumbnail(kPage1, &jpeg_data)); | |
269 ASSERT_TRUE(db.ThumbnailScoreForId(kPage1, &score_out)); | |
270 ASSERT_TRUE(five_hours_later.Equals(score_out)); | |
271 } | |
272 | |
273 TEST_F(ThumbnailDatabaseTest, NeverAcceptTotallyBoringThumbnail) { | |
274 // We enforce a maximum boringness score: even in cases where we | |
275 // should replace a thumbnail with another because of reasons other | |
276 // than straight up boringness score, still reject because the | |
277 // thumbnail is totally boring. | |
278 if (history::TopSites::IsEnabled()) | |
279 return; // TopSitesTest replaces this. | |
280 | |
281 ThumbnailDatabase db; | |
282 Time now = Time::Now(); | |
283 ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL)); | |
284 | |
285 std::vector<unsigned char> jpeg_data; | |
286 ThumbnailScore score_out; | |
287 const double kBaseBoringness = 0.50; | |
288 const Time kNow = Time::Now(); | |
289 const int kSizeOfTable = 4; | |
290 struct { | |
291 bool good_scaling; | |
292 bool at_top; | |
293 } const heiarchy_table[] = { | |
294 {false, false}, | |
295 {false, true}, | |
296 {true, false}, | |
297 {true, true} | |
298 }; | |
299 | |
300 Time time; | |
301 GURL gurl; | |
302 | |
303 // Test that for each entry type, all entry types that are better | |
304 // than it still will reject thumbnails which are totally boring. | |
305 for (int i = 0; i < kSizeOfTable; ++i) { | |
306 ThumbnailScore base(kBaseBoringness, | |
307 heiarchy_table[i].good_scaling, | |
308 heiarchy_table[i].at_top, | |
309 kNow); | |
310 | |
311 db.SetPageThumbnail(gurl, kPage1, *google_bitmap_, base, time); | |
312 ASSERT_TRUE(db.GetPageThumbnail(kPage1, &jpeg_data)); | |
313 ASSERT_TRUE(db.ThumbnailScoreForId(kPage1, &score_out)); | |
314 ASSERT_TRUE(base.Equals(score_out)); | |
315 | |
316 for (int j = i; j < kSizeOfTable; ++j) { | |
317 ThumbnailScore shouldnt_replace( | |
318 kTotallyBoring, heiarchy_table[j].good_scaling, | |
319 heiarchy_table[j].at_top, kNow); | |
320 | |
321 db.SetPageThumbnail(gurl, kPage1, *google_bitmap_, shouldnt_replace, | |
322 time); | |
323 ASSERT_TRUE(db.GetPageThumbnail(kPage1, &jpeg_data)); | |
324 ASSERT_TRUE(db.ThumbnailScoreForId(kPage1, &score_out)); | |
325 ASSERT_TRUE(base.Equals(score_out)); | |
326 } | |
327 | |
328 // Clean up for the next iteration | |
329 ASSERT_TRUE(db.DeleteThumbnail(kPage1)); | |
330 ASSERT_FALSE(db.GetPageThumbnail(kPage1, &jpeg_data)); | |
331 ASSERT_FALSE(db.ThumbnailScoreForId(kPage1, &score_out)); | |
332 } | |
333 | |
334 // We should never accept a totally boring thumbnail no matter how | |
335 // much old the current thumbnail is. | |
336 ThumbnailScore base_boring(kBaseBoringness, true, true, kNow); | |
337 db.SetPageThumbnail(gurl, kPage1, *google_bitmap_, base_boring, time); | |
338 ASSERT_TRUE(db.GetPageThumbnail(kPage1, &jpeg_data)); | |
339 ASSERT_TRUE(db.ThumbnailScoreForId(kPage1, &score_out)); | |
340 ASSERT_TRUE(base_boring.Equals(score_out)); | |
341 | |
342 ThumbnailScore totally_boring_in_the_future( | |
343 kTotallyBoring, true, true, kNow + TimeDelta::FromDays(365)); | |
344 db.SetPageThumbnail(gurl, kPage1, *google_bitmap_, | |
345 totally_boring_in_the_future, time); | |
346 ASSERT_TRUE(db.GetPageThumbnail(kPage1, &jpeg_data)); | |
347 ASSERT_TRUE(db.ThumbnailScoreForId(kPage1, &score_out)); | |
348 ASSERT_TRUE(base_boring.Equals(score_out)); | |
349 } | |
350 | |
351 TEST_F(ThumbnailDatabaseTest, NeedsMigrationToTopSites) { | |
352 if (history::TopSites::IsEnabled()) | |
353 return; // TopSitesTest replaces this. | |
354 | |
355 ThumbnailDatabase db; | |
356 ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL)); | |
357 db.BeginTransaction(); | |
358 EXPECT_TRUE(db.NeedsMigrationToTopSites()); | |
359 EXPECT_TRUE(db.RenameAndDropThumbnails(file_name_, new_file_name_)); | |
360 EXPECT_FALSE(db.NeedsMigrationToTopSites()); | |
361 EXPECT_FALSE(file_util::PathExists(file_name_)); | |
362 EXPECT_TRUE(file_util::PathExists(new_file_name_)); | |
363 } | |
364 | |
365 TEST_F(ThumbnailDatabaseTest, GetFaviconAfterMigrationToTopSites) { | 74 TEST_F(ThumbnailDatabaseTest, GetFaviconAfterMigrationToTopSites) { |
366 ThumbnailDatabase db; | 75 ThumbnailDatabase db; |
367 ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL)); | 76 ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL)); |
368 db.BeginTransaction(); | 77 db.BeginTransaction(); |
369 | 78 |
370 std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1)); | 79 std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1)); |
371 scoped_refptr<RefCountedBytes> favicon(new RefCountedBytes(data)); | 80 scoped_refptr<RefCountedBytes> favicon(new RefCountedBytes(data)); |
372 | 81 |
373 GURL url("http://google.com"); | 82 GURL url("http://google.com"); |
374 FavIconID id = db.AddFavIcon(url); | 83 FavIconID id = db.AddFavIcon(url); |
375 base::Time time = base::Time::Now(); | 84 base::Time time = base::Time::Now(); |
376 db.SetFavIcon(id, favicon, time); | 85 db.SetFavIcon(id, favicon, time); |
377 EXPECT_TRUE(db.RenameAndDropThumbnails(file_name_, new_file_name_)); | 86 EXPECT_TRUE(db.RenameAndDropThumbnails(file_name_, new_file_name_)); |
378 | 87 |
379 base::Time time_out; | 88 base::Time time_out; |
380 std::vector<unsigned char> favicon_out; | 89 std::vector<unsigned char> favicon_out; |
381 GURL url_out; | 90 GURL url_out; |
382 EXPECT_TRUE(db.GetFavIcon(id, &time_out, &favicon_out, &url_out)); | 91 EXPECT_TRUE(db.GetFavIcon(id, &time_out, &favicon_out, &url_out)); |
383 EXPECT_EQ(url, url_out); | 92 EXPECT_EQ(url, url_out); |
384 EXPECT_EQ(time.ToTimeT(), time_out.ToTimeT()); | 93 EXPECT_EQ(time.ToTimeT(), time_out.ToTimeT()); |
385 ASSERT_EQ(data.size(), favicon_out.size()); | 94 ASSERT_EQ(data.size(), favicon_out.size()); |
386 EXPECT_TRUE(std::equal(data.begin(), | 95 EXPECT_TRUE(std::equal(data.begin(), |
387 data.end(), | 96 data.end(), |
388 favicon_out.begin())); | 97 favicon_out.begin())); |
389 } | 98 } |
390 | 99 |
391 } // namespace history | 100 } // namespace history |
OLD | NEW |