| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include <map> | |
| 6 | |
| 7 #include "base/files/file_path.h" | |
| 8 #include "base/files/scoped_temp_dir.h" | |
| 9 #include "base/path_service.h" | |
| 10 #include "base/strings/utf_string_conversions.h" | |
| 11 #include "chrome/browser/history/top_sites_database.h" | |
| 12 #include "chrome/common/chrome_paths.h" | |
| 13 #include "chrome/tools/profiles/thumbnail-inl.h" | |
| 14 #include "components/history/core/browser/history_types.h" | |
| 15 #include "sql/connection.h" | |
| 16 #include "sql/recovery.h" | |
| 17 #include "sql/test/scoped_error_ignorer.h" | |
| 18 #include "sql/test/test_helpers.h" | |
| 19 #include "testing/gtest/include/gtest/gtest.h" | |
| 20 #include "third_party/sqlite/sqlite3.h" | |
| 21 #include "url/gurl.h" | |
| 22 | |
| 23 namespace { | |
| 24 | |
| 25 // URL with url_rank 0 in golden files. | |
| 26 const GURL kUrl0 = GURL("http://www.google.com/"); | |
| 27 | |
| 28 // URL with url_rank 1 in golden files. | |
| 29 const GURL kUrl1 = GURL("http://www.google.com/chrome/intl/en/welcome.html"); | |
| 30 | |
| 31 // URL with url_rank 2 in golden files. | |
| 32 const GURL kUrl2 = GURL("https://chrome.google.com/webstore?hl=en"); | |
| 33 | |
| 34 // Create the test database at |db_path| from the golden file at | |
| 35 // |ascii_path| in the "History/" subdir of the test data dir. | |
| 36 WARN_UNUSED_RESULT bool CreateDatabaseFromSQL(const base::FilePath &db_path, | |
| 37 const char* ascii_path) { | |
| 38 base::FilePath sql_path; | |
| 39 if (!PathService::Get(chrome::DIR_TEST_DATA, &sql_path)) | |
| 40 return false; | |
| 41 sql_path = sql_path.AppendASCII("History").AppendASCII(ascii_path); | |
| 42 return sql::test::CreateDatabaseFromSQL(db_path, sql_path); | |
| 43 } | |
| 44 | |
| 45 // Verify that the up-to-date database has the expected tables and | |
| 46 // columns. Functional tests only check whether the things which | |
| 47 // should be there are, but do not check if extraneous items are | |
| 48 // present. Any extraneous items have the potential to interact | |
| 49 // negatively with future schema changes. | |
| 50 void VerifyTablesAndColumns(sql::Connection* db) { | |
| 51 // [meta] and [thumbnails]. | |
| 52 EXPECT_EQ(2u, sql::test::CountSQLTables(db)); | |
| 53 | |
| 54 // Implicit index on [meta], index on [thumbnails]. | |
| 55 EXPECT_EQ(2u, sql::test::CountSQLIndices(db)); | |
| 56 | |
| 57 // [key] and [value]. | |
| 58 EXPECT_EQ(2u, sql::test::CountTableColumns(db, "meta")); | |
| 59 | |
| 60 // [url], [url_rank], [title], [thumbnail], [redirects], | |
| 61 // [boring_score], [good_clipping], [at_top], [last_updated], and | |
| 62 // [load_completed], [last_forced] | |
| 63 EXPECT_EQ(11u, sql::test::CountTableColumns(db, "thumbnails")); | |
| 64 } | |
| 65 | |
| 66 void VerifyDatabaseEmpty(sql::Connection* db) { | |
| 67 size_t rows = 0; | |
| 68 EXPECT_TRUE(sql::test::CountTableRows(db, "thumbnails", &rows)); | |
| 69 EXPECT_EQ(0u, rows); | |
| 70 } | |
| 71 | |
| 72 } // namespace | |
| 73 | |
| 74 namespace history { | |
| 75 | |
| 76 class TopSitesDatabaseTest : public testing::Test { | |
| 77 protected: | |
| 78 void SetUp() override { | |
| 79 // Get a temporary directory for the test DB files. | |
| 80 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); | |
| 81 file_name_ = temp_dir_.path().AppendASCII("TestTopSites.db"); | |
| 82 } | |
| 83 | |
| 84 base::ScopedTempDir temp_dir_; | |
| 85 base::FilePath file_name_; | |
| 86 }; | |
| 87 | |
| 88 // Version 1 is deprecated, the resulting schema should be current, | |
| 89 // with no data. | |
| 90 TEST_F(TopSitesDatabaseTest, Version1) { | |
| 91 ASSERT_TRUE(CreateDatabaseFromSQL(file_name_, "TopSites.v1.sql")); | |
| 92 | |
| 93 TopSitesDatabase db; | |
| 94 ASSERT_TRUE(db.Init(file_name_)); | |
| 95 VerifyTablesAndColumns(db.db_.get()); | |
| 96 VerifyDatabaseEmpty(db.db_.get()); | |
| 97 } | |
| 98 | |
| 99 TEST_F(TopSitesDatabaseTest, Version2) { | |
| 100 ASSERT_TRUE(CreateDatabaseFromSQL(file_name_, "TopSites.v2.sql")); | |
| 101 | |
| 102 TopSitesDatabase db; | |
| 103 ASSERT_TRUE(db.Init(file_name_)); | |
| 104 | |
| 105 VerifyTablesAndColumns(db.db_.get()); | |
| 106 | |
| 107 // Basic operational check. | |
| 108 MostVisitedURLList urls; | |
| 109 std::map<GURL, Images> thumbnails; | |
| 110 db.GetPageThumbnails(&urls, &thumbnails); | |
| 111 ASSERT_EQ(3u, urls.size()); | |
| 112 ASSERT_EQ(3u, thumbnails.size()); | |
| 113 EXPECT_EQ(kUrl0, urls[0].url); // [0] because of url_rank. | |
| 114 // kGoogleThumbnail includes nul terminator. | |
| 115 ASSERT_EQ(sizeof(kGoogleThumbnail) - 1, | |
| 116 thumbnails[urls[0].url].thumbnail->size()); | |
| 117 EXPECT_TRUE(!memcmp(thumbnails[urls[0].url].thumbnail->front(), | |
| 118 kGoogleThumbnail, sizeof(kGoogleThumbnail) - 1)); | |
| 119 | |
| 120 ASSERT_TRUE(db.RemoveURL(urls[1])); | |
| 121 db.GetPageThumbnails(&urls, &thumbnails); | |
| 122 ASSERT_EQ(2u, urls.size()); | |
| 123 ASSERT_EQ(2u, thumbnails.size()); | |
| 124 } | |
| 125 | |
| 126 TEST_F(TopSitesDatabaseTest, Version3) { | |
| 127 ASSERT_TRUE(CreateDatabaseFromSQL(file_name_, "TopSites.v3.sql")); | |
| 128 | |
| 129 TopSitesDatabase db; | |
| 130 ASSERT_TRUE(db.Init(file_name_)); | |
| 131 | |
| 132 VerifyTablesAndColumns(db.db_.get()); | |
| 133 | |
| 134 // Basic operational check. | |
| 135 MostVisitedURLList urls; | |
| 136 std::map<GURL, Images> thumbnails; | |
| 137 db.GetPageThumbnails(&urls, &thumbnails); | |
| 138 ASSERT_EQ(3u, urls.size()); | |
| 139 ASSERT_EQ(3u, thumbnails.size()); | |
| 140 EXPECT_EQ(kUrl0, urls[0].url); // [0] because of url_rank. | |
| 141 // kGoogleThumbnail includes nul terminator. | |
| 142 ASSERT_EQ(sizeof(kGoogleThumbnail) - 1, | |
| 143 thumbnails[urls[0].url].thumbnail->size()); | |
| 144 EXPECT_TRUE(!memcmp(thumbnails[urls[0].url].thumbnail->front(), | |
| 145 kGoogleThumbnail, sizeof(kGoogleThumbnail) - 1)); | |
| 146 | |
| 147 ASSERT_TRUE(db.RemoveURL(urls[1])); | |
| 148 db.GetPageThumbnails(&urls, &thumbnails); | |
| 149 ASSERT_EQ(2u, urls.size()); | |
| 150 ASSERT_EQ(2u, thumbnails.size()); | |
| 151 } | |
| 152 | |
| 153 // Version 1 is deprecated, the resulting schema should be current, | |
| 154 // with no data. | |
| 155 TEST_F(TopSitesDatabaseTest, Recovery1) { | |
| 156 // Recovery module only supports some platforms at this time. | |
| 157 if (!sql::Recovery::FullRecoverySupported()) | |
| 158 return; | |
| 159 | |
| 160 // Create an example database. | |
| 161 EXPECT_TRUE(CreateDatabaseFromSQL(file_name_, "TopSites.v1.sql")); | |
| 162 | |
| 163 // Corrupt the database by adjusting the header size. | |
| 164 EXPECT_TRUE(sql::test::CorruptSizeInHeader(file_name_)); | |
| 165 | |
| 166 // Database is unusable at the SQLite level. | |
| 167 { | |
| 168 sql::ScopedErrorIgnorer ignore_errors; | |
| 169 ignore_errors.IgnoreError(SQLITE_CORRUPT); | |
| 170 sql::Connection raw_db; | |
| 171 EXPECT_TRUE(raw_db.Open(file_name_)); | |
| 172 EXPECT_FALSE(raw_db.IsSQLValid("PRAGMA integrity_check")); | |
| 173 ASSERT_TRUE(ignore_errors.CheckIgnoredErrors()); | |
| 174 } | |
| 175 | |
| 176 // Corruption should be detected and recovered during Init(). | |
| 177 { | |
| 178 sql::ScopedErrorIgnorer ignore_errors; | |
| 179 ignore_errors.IgnoreError(SQLITE_CORRUPT); | |
| 180 | |
| 181 TopSitesDatabase db; | |
| 182 ASSERT_TRUE(db.Init(file_name_)); | |
| 183 VerifyTablesAndColumns(db.db_.get()); | |
| 184 VerifyDatabaseEmpty(db.db_.get()); | |
| 185 | |
| 186 ASSERT_TRUE(ignore_errors.CheckIgnoredErrors()); | |
| 187 } | |
| 188 } | |
| 189 | |
| 190 TEST_F(TopSitesDatabaseTest, Recovery2) { | |
| 191 // Recovery module only supports some platforms at this time. | |
| 192 if (!sql::Recovery::FullRecoverySupported()) | |
| 193 return; | |
| 194 | |
| 195 // Create an example database. | |
| 196 EXPECT_TRUE(CreateDatabaseFromSQL(file_name_, "TopSites.v2.sql")); | |
| 197 | |
| 198 // Corrupt the database by adjusting the header. | |
| 199 EXPECT_TRUE(sql::test::CorruptSizeInHeader(file_name_)); | |
| 200 | |
| 201 // Database is unusable at the SQLite level. | |
| 202 { | |
| 203 sql::ScopedErrorIgnorer ignore_errors; | |
| 204 ignore_errors.IgnoreError(SQLITE_CORRUPT); | |
| 205 sql::Connection raw_db; | |
| 206 EXPECT_TRUE(raw_db.Open(file_name_)); | |
| 207 EXPECT_FALSE(raw_db.IsSQLValid("PRAGMA integrity_check")); | |
| 208 ASSERT_TRUE(ignore_errors.CheckIgnoredErrors()); | |
| 209 } | |
| 210 | |
| 211 // Corruption should be detected and recovered during Init(). After recovery, | |
| 212 // the Version2 checks should work. | |
| 213 { | |
| 214 sql::ScopedErrorIgnorer ignore_errors; | |
| 215 ignore_errors.IgnoreError(SQLITE_CORRUPT); | |
| 216 | |
| 217 TopSitesDatabase db; | |
| 218 ASSERT_TRUE(db.Init(file_name_)); | |
| 219 | |
| 220 VerifyTablesAndColumns(db.db_.get()); | |
| 221 | |
| 222 // Basic operational check. | |
| 223 MostVisitedURLList urls; | |
| 224 std::map<GURL, Images> thumbnails; | |
| 225 db.GetPageThumbnails(&urls, &thumbnails); | |
| 226 ASSERT_EQ(3u, urls.size()); | |
| 227 ASSERT_EQ(3u, thumbnails.size()); | |
| 228 EXPECT_EQ(kUrl0, urls[0].url); // [0] because of url_rank. | |
| 229 // kGoogleThumbnail includes nul terminator. | |
| 230 ASSERT_EQ(sizeof(kGoogleThumbnail) - 1, | |
| 231 thumbnails[urls[0].url].thumbnail->size()); | |
| 232 EXPECT_TRUE(!memcmp(thumbnails[urls[0].url].thumbnail->front(), | |
| 233 kGoogleThumbnail, sizeof(kGoogleThumbnail) - 1)); | |
| 234 | |
| 235 ASSERT_TRUE(ignore_errors.CheckIgnoredErrors()); | |
| 236 } | |
| 237 } | |
| 238 | |
| 239 TEST_F(TopSitesDatabaseTest, Recovery3) { | |
| 240 // Recovery module only supports some platforms at this time. | |
| 241 if (!sql::Recovery::FullRecoverySupported()) | |
| 242 return; | |
| 243 | |
| 244 // Create an example database. | |
| 245 EXPECT_TRUE(CreateDatabaseFromSQL(file_name_, "TopSites.v3.sql")); | |
| 246 | |
| 247 // Corrupt the database by adjusting the header. | |
| 248 EXPECT_TRUE(sql::test::CorruptSizeInHeader(file_name_)); | |
| 249 | |
| 250 // Database is unusable at the SQLite level. | |
| 251 { | |
| 252 sql::ScopedErrorIgnorer ignore_errors; | |
| 253 ignore_errors.IgnoreError(SQLITE_CORRUPT); | |
| 254 sql::Connection raw_db; | |
| 255 EXPECT_TRUE(raw_db.Open(file_name_)); | |
| 256 EXPECT_FALSE(raw_db.IsSQLValid("PRAGMA integrity_check")); | |
| 257 ASSERT_TRUE(ignore_errors.CheckIgnoredErrors()); | |
| 258 } | |
| 259 | |
| 260 // Corruption should be detected and recovered during Init(). | |
| 261 { | |
| 262 sql::ScopedErrorIgnorer ignore_errors; | |
| 263 ignore_errors.IgnoreError(SQLITE_CORRUPT); | |
| 264 | |
| 265 TopSitesDatabase db; | |
| 266 ASSERT_TRUE(db.Init(file_name_)); | |
| 267 | |
| 268 MostVisitedURLList urls; | |
| 269 std::map<GURL, Images> thumbnails; | |
| 270 db.GetPageThumbnails(&urls, &thumbnails); | |
| 271 ASSERT_EQ(3u, urls.size()); | |
| 272 ASSERT_EQ(3u, thumbnails.size()); | |
| 273 EXPECT_EQ(kUrl0, urls[0].url); // [0] because of url_rank. | |
| 274 // kGoogleThumbnail includes nul terminator. | |
| 275 ASSERT_EQ(sizeof(kGoogleThumbnail) - 1, | |
| 276 thumbnails[urls[0].url].thumbnail->size()); | |
| 277 EXPECT_TRUE(!memcmp(thumbnails[urls[0].url].thumbnail->front(), | |
| 278 kGoogleThumbnail, sizeof(kGoogleThumbnail) - 1)); | |
| 279 | |
| 280 ASSERT_TRUE(ignore_errors.CheckIgnoredErrors()); | |
| 281 } | |
| 282 | |
| 283 // Double-check database integrity. | |
| 284 { | |
| 285 sql::Connection raw_db; | |
| 286 EXPECT_TRUE(raw_db.Open(file_name_)); | |
| 287 ASSERT_EQ("ok", sql::test::IntegrityCheck(&raw_db)); | |
| 288 } | |
| 289 | |
| 290 // Corrupt the thumnails.url auto-index by deleting an element from the table | |
| 291 // but leaving it in the index. | |
| 292 const char kIndexName[] = "sqlite_autoindex_thumbnails_1"; | |
| 293 // TODO(shess): Refactor CorruptTableOrIndex() to make parameterized | |
| 294 // statements easy. | |
| 295 const char kDeleteSql[] = | |
| 296 "DELETE FROM thumbnails WHERE url = " | |
| 297 "'http://www.google.com/chrome/intl/en/welcome.html'"; | |
| 298 EXPECT_TRUE( | |
| 299 sql::test::CorruptTableOrIndex(file_name_, kIndexName, kDeleteSql)); | |
| 300 | |
| 301 // SQLite can operate on the database, but notices the corruption in integrity | |
| 302 // check. | |
| 303 { | |
| 304 sql::Connection raw_db; | |
| 305 EXPECT_TRUE(raw_db.Open(file_name_)); | |
| 306 ASSERT_NE("ok", sql::test::IntegrityCheck(&raw_db)); | |
| 307 } | |
| 308 | |
| 309 // Open the database and access the corrupt index. | |
| 310 { | |
| 311 TopSitesDatabase db; | |
| 312 ASSERT_TRUE(db.Init(file_name_)); | |
| 313 | |
| 314 { | |
| 315 sql::ScopedErrorIgnorer ignore_errors; | |
| 316 ignore_errors.IgnoreError(SQLITE_CORRUPT); | |
| 317 | |
| 318 // Data for kUrl1 was deleted, but the index entry remains, this will | |
| 319 // throw SQLITE_CORRUPT. The corruption handler will recover the database | |
| 320 // and poison the handle, so the outer call fails. | |
| 321 EXPECT_EQ(TopSitesDatabase::kRankOfNonExistingURL, | |
| 322 db.GetURLRank(MostVisitedURL(kUrl1, base::string16()))); | |
| 323 | |
| 324 ASSERT_TRUE(ignore_errors.CheckIgnoredErrors()); | |
| 325 } | |
| 326 } | |
| 327 | |
| 328 // Check that the database is recovered at the SQLite level. | |
| 329 { | |
| 330 sql::Connection raw_db; | |
| 331 EXPECT_TRUE(raw_db.Open(file_name_)); | |
| 332 ASSERT_EQ("ok", sql::test::IntegrityCheck(&raw_db)); | |
| 333 } | |
| 334 | |
| 335 // After recovery, the database accesses won't throw errors. The top-ranked | |
| 336 // item is removed, but the ranking was revised in post-processing. | |
| 337 { | |
| 338 TopSitesDatabase db; | |
| 339 ASSERT_TRUE(db.Init(file_name_)); | |
| 340 VerifyTablesAndColumns(db.db_.get()); | |
| 341 | |
| 342 EXPECT_EQ(TopSitesDatabase::kRankOfNonExistingURL, | |
| 343 db.GetURLRank(MostVisitedURL(kUrl1, base::string16()))); | |
| 344 | |
| 345 MostVisitedURLList urls; | |
| 346 std::map<GURL, Images> thumbnails; | |
| 347 db.GetPageThumbnails(&urls, &thumbnails); | |
| 348 ASSERT_EQ(2u, urls.size()); | |
| 349 ASSERT_EQ(2u, thumbnails.size()); | |
| 350 EXPECT_EQ(kUrl0, urls[0].url); // [0] because of url_rank. | |
| 351 EXPECT_EQ(kUrl2, urls[1].url); // [1] because of url_rank. | |
| 352 } | |
| 353 } | |
| 354 | |
| 355 TEST_F(TopSitesDatabaseTest, AddRemoveEditThumbnails) { | |
| 356 ASSERT_TRUE(CreateDatabaseFromSQL(file_name_, "TopSites.v3.sql")); | |
| 357 | |
| 358 TopSitesDatabase db; | |
| 359 ASSERT_TRUE(db.Init(file_name_)); | |
| 360 | |
| 361 // Add a new URL, not forced, rank = 1. | |
| 362 GURL mapsUrl = GURL("http://maps.google.com/"); | |
| 363 MostVisitedURL url1(mapsUrl, base::ASCIIToUTF16("Google Maps")); | |
| 364 db.SetPageThumbnail(url1, 1, Images()); | |
| 365 | |
| 366 MostVisitedURLList urls; | |
| 367 std::map<GURL, Images> thumbnails; | |
| 368 db.GetPageThumbnails(&urls, &thumbnails); | |
| 369 ASSERT_EQ(4u, urls.size()); | |
| 370 ASSERT_EQ(4u, thumbnails.size()); | |
| 371 EXPECT_EQ(kUrl0, urls[0].url); | |
| 372 EXPECT_EQ(mapsUrl, urls[1].url); | |
| 373 | |
| 374 // Add a new URL, forced. | |
| 375 GURL driveUrl = GURL("http://drive.google.com/"); | |
| 376 MostVisitedURL url2(driveUrl, base::ASCIIToUTF16("Google Drive")); | |
| 377 url2.last_forced_time = base::Time::FromJsTime(789714000000); // 10/1/1995 | |
| 378 db.SetPageThumbnail(url2, TopSitesDatabase::kRankOfForcedURL, Images()); | |
| 379 | |
| 380 db.GetPageThumbnails(&urls, &thumbnails); | |
| 381 ASSERT_EQ(5u, urls.size()); | |
| 382 ASSERT_EQ(5u, thumbnails.size()); | |
| 383 EXPECT_EQ(driveUrl, urls[0].url); // Forced URLs always appear first. | |
| 384 EXPECT_EQ(kUrl0, urls[1].url); | |
| 385 EXPECT_EQ(mapsUrl, urls[2].url); | |
| 386 | |
| 387 // Add a new URL, forced (earlier). | |
| 388 GURL plusUrl = GURL("http://plus.google.com/"); | |
| 389 MostVisitedURL url3(plusUrl, base::ASCIIToUTF16("Google Plus")); | |
| 390 url3.last_forced_time = base::Time::FromJsTime(787035600000); // 10/12/1994 | |
| 391 db.SetPageThumbnail(url3, TopSitesDatabase::kRankOfForcedURL, Images()); | |
| 392 | |
| 393 db.GetPageThumbnails(&urls, &thumbnails); | |
| 394 ASSERT_EQ(6u, urls.size()); | |
| 395 ASSERT_EQ(6u, thumbnails.size()); | |
| 396 EXPECT_EQ(plusUrl, urls[0].url); // New forced URL should appear first. | |
| 397 EXPECT_EQ(driveUrl, urls[1].url); | |
| 398 EXPECT_EQ(kUrl0, urls[2].url); | |
| 399 EXPECT_EQ(mapsUrl, urls[3].url); | |
| 400 | |
| 401 // Change the last_forced_time of a forced URL. | |
| 402 url3.last_forced_time = base::Time::FromJsTime(792392400000); // 10/2/1995 | |
| 403 db.SetPageThumbnail(url3, TopSitesDatabase::kRankOfForcedURL, Images()); | |
| 404 | |
| 405 db.GetPageThumbnails(&urls, &thumbnails); | |
| 406 ASSERT_EQ(6u, urls.size()); | |
| 407 ASSERT_EQ(6u, thumbnails.size()); | |
| 408 EXPECT_EQ(driveUrl, urls[0].url); | |
| 409 EXPECT_EQ(plusUrl, urls[1].url); // Forced URL should have moved second. | |
| 410 EXPECT_EQ(kUrl0, urls[2].url); | |
| 411 EXPECT_EQ(mapsUrl, urls[3].url); | |
| 412 | |
| 413 // Change a non-forced URL to forced using UpdatePageRank. | |
| 414 url1.last_forced_time = base::Time::FromJsTime(792219600000); // 8/2/1995 | |
| 415 db.UpdatePageRank(url1, TopSitesDatabase::kRankOfForcedURL); | |
| 416 | |
| 417 db.GetPageThumbnails(&urls, &thumbnails); | |
| 418 ASSERT_EQ(6u, urls.size()); | |
| 419 ASSERT_EQ(6u, thumbnails.size()); | |
| 420 EXPECT_EQ(driveUrl, urls[0].url); | |
| 421 EXPECT_EQ(mapsUrl, urls[1].url); // Maps moves to second forced URL. | |
| 422 EXPECT_EQ(plusUrl, urls[2].url); | |
| 423 EXPECT_EQ(kUrl0, urls[3].url); | |
| 424 | |
| 425 // Change a forced URL to non-forced using SetPageThumbnail. | |
| 426 url3.last_forced_time = base::Time(); | |
| 427 db.SetPageThumbnail(url3, 1, Images()); | |
| 428 | |
| 429 db.GetPageThumbnails(&urls, &thumbnails); | |
| 430 ASSERT_EQ(6u, urls.size()); | |
| 431 ASSERT_EQ(6u, thumbnails.size()); | |
| 432 EXPECT_EQ(driveUrl, urls[0].url); | |
| 433 EXPECT_EQ(mapsUrl, urls[1].url); | |
| 434 EXPECT_EQ(kUrl0, urls[2].url); | |
| 435 EXPECT_EQ(plusUrl, urls[3].url); // Plus moves to second non-forced URL. | |
| 436 | |
| 437 // Change a non-forced URL to earlier non-forced using UpdatePageRank. | |
| 438 db.UpdatePageRank(url3, 0); | |
| 439 | |
| 440 db.GetPageThumbnails(&urls, &thumbnails); | |
| 441 ASSERT_EQ(6u, urls.size()); | |
| 442 ASSERT_EQ(6u, thumbnails.size()); | |
| 443 EXPECT_EQ(driveUrl, urls[0].url); | |
| 444 EXPECT_EQ(mapsUrl, urls[1].url); | |
| 445 EXPECT_EQ(plusUrl, urls[2].url); // Plus moves to first non-forced URL. | |
| 446 EXPECT_EQ(kUrl0, urls[3].url); | |
| 447 | |
| 448 // Change a non-forced URL to later non-forced using SetPageThumbnail. | |
| 449 db.SetPageThumbnail(url3, 2, Images()); | |
| 450 | |
| 451 db.GetPageThumbnails(&urls, &thumbnails); | |
| 452 ASSERT_EQ(6u, urls.size()); | |
| 453 ASSERT_EQ(6u, thumbnails.size()); | |
| 454 EXPECT_EQ(driveUrl, urls[0].url); | |
| 455 EXPECT_EQ(mapsUrl, urls[1].url); | |
| 456 EXPECT_EQ(kUrl0, urls[2].url); | |
| 457 EXPECT_EQ(plusUrl, urls[4].url); // Plus moves to third non-forced URL. | |
| 458 | |
| 459 // Remove a non-forced URL. | |
| 460 db.RemoveURL(url3); | |
| 461 | |
| 462 db.GetPageThumbnails(&urls, &thumbnails); | |
| 463 ASSERT_EQ(5u, urls.size()); | |
| 464 ASSERT_EQ(5u, thumbnails.size()); | |
| 465 EXPECT_EQ(driveUrl, urls[0].url); | |
| 466 EXPECT_EQ(mapsUrl, urls[1].url); | |
| 467 EXPECT_EQ(kUrl0, urls[2].url); | |
| 468 | |
| 469 // Remove a forced URL. | |
| 470 db.RemoveURL(url2); | |
| 471 | |
| 472 db.GetPageThumbnails(&urls, &thumbnails); | |
| 473 ASSERT_EQ(4u, urls.size()); | |
| 474 ASSERT_EQ(4u, thumbnails.size()); | |
| 475 EXPECT_EQ(mapsUrl, urls[0].url); | |
| 476 EXPECT_EQ(kUrl0, urls[1].url); | |
| 477 } | |
| 478 | |
| 479 } // namespace history | |
| OLD | NEW |