Index: chrome/browser/history/top_sites_database_unittest.cc |
diff --git a/chrome/browser/history/top_sites_database_unittest.cc b/chrome/browser/history/top_sites_database_unittest.cc |
index 9ec671964e2d4866b7fc9b387885ea3d60ce911b..608c6dd8d258a861af025eb1bc865d650f18c599 100644 |
--- a/chrome/browser/history/top_sites_database_unittest.cc |
+++ b/chrome/browser/history/top_sites_database_unittest.cc |
@@ -2,14 +2,13 @@ |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
-#include <map> |
+#include "chrome/browser/history/top_sites_database.h" |
#include "base/files/file_path.h" |
#include "base/files/scoped_temp_dir.h" |
#include "base/path_service.h" |
#include "base/strings/utf_string_conversions.h" |
#include "chrome/browser/history/history_types.h" |
-#include "chrome/browser/history/top_sites_database.h" |
#include "chrome/common/chrome_paths.h" |
#include "chrome/tools/profiles/thumbnail-inl.h" |
#include "sql/connection.h" |
@@ -81,6 +80,11 @@ class TopSitesDatabaseTest : public testing::Test { |
file_name_ = temp_dir_.path().AppendASCII("TestTopSites.db"); |
} |
+ // The only difference between v3 and v4 is how redirects URLs are stored, so |
+ // most of the tests should be common. |
+ void DatabaseTest3And4Common(); |
+ void RecoveryTest3And4Common(); |
+ |
base::ScopedTempDir temp_dir_; |
base::FilePath file_name_; |
}; |
@@ -123,33 +127,57 @@ TEST_F(TopSitesDatabaseTest, Version2) { |
ASSERT_EQ(2u, thumbnails.size()); |
} |
-TEST_F(TopSitesDatabaseTest, Version3) { |
- ASSERT_TRUE(CreateDatabaseFromSQL(file_name_, "TopSites.v3.sql")); |
- |
+void TopSitesDatabaseTest::DatabaseTest3And4Common() { |
TopSitesDatabase db; |
ASSERT_TRUE(db.Init(file_name_)); |
- |
VerifyTablesAndColumns(db.db_.get()); |
- // Basic operational check. |
+ // Basic read operational check. |
MostVisitedURLList urls; |
std::map<GURL, Images> thumbnails; |
db.GetPageThumbnails(&urls, &thumbnails); |
ASSERT_EQ(3u, urls.size()); |
ASSERT_EQ(3u, thumbnails.size()); |
EXPECT_EQ(kUrl0, urls[0].url); // [0] because of url_rank. |
+ EXPECT_EQ(kUrl1, urls[1].url); |
+ EXPECT_EQ(kUrl2, urls[2].url); |
+ EXPECT_EQ(2u, urls[0].redirects.size()); |
+ EXPECT_EQ(1u, urls[1].redirects.size()); |
+ EXPECT_EQ(1u, urls[2].redirects.size()); |
+ |
// kGoogleThumbnail includes nul terminator. |
ASSERT_EQ(sizeof(kGoogleThumbnail) - 1, |
thumbnails[urls[0].url].thumbnail->size()); |
EXPECT_TRUE(!memcmp(thumbnails[urls[0].url].thumbnail->front(), |
kGoogleThumbnail, sizeof(kGoogleThumbnail) - 1)); |
+ // Basic write operational check. |
ASSERT_TRUE(db.RemoveURL(urls[1])); |
db.GetPageThumbnails(&urls, &thumbnails); |
ASSERT_EQ(2u, urls.size()); |
ASSERT_EQ(2u, thumbnails.size()); |
} |
+TEST_F(TopSitesDatabaseTest, Version3) { |
+ ASSERT_TRUE(CreateDatabaseFromSQL(file_name_, "TopSites.v3.sql")); |
+ DatabaseTest3And4Common(); |
+} |
+ |
+TEST_F(TopSitesDatabaseTest, Version4) { |
+ ASSERT_TRUE(CreateDatabaseFromSQL(file_name_, "TopSites.v4.sql")); |
+ DatabaseTest3And4Common(); |
+} |
+ |
+// Verify that database is unusable at the SQLite level. |
+void RecoveryTestVerifyDatabaseIsUnusable(const base::FilePath& file_name) { |
+ sql::ScopedErrorIgnorer ignore_errors; |
+ ignore_errors.IgnoreError(SQLITE_CORRUPT); |
+ sql::Connection raw_db; |
+ EXPECT_TRUE(raw_db.Open(file_name)); |
+ EXPECT_FALSE(raw_db.IsSQLValid("PRAGMA integrity_check")); |
+ ASSERT_TRUE(ignore_errors.CheckIgnoredErrors()); |
+} |
+ |
// Version 1 is deprecated, the resulting schema should be current, |
// with no data. |
TEST_F(TopSitesDatabaseTest, Recovery1) { |
@@ -163,15 +191,7 @@ TEST_F(TopSitesDatabaseTest, Recovery1) { |
// Corrupt the database by adjusting the header size. |
EXPECT_TRUE(sql::test::CorruptSizeInHeader(file_name_)); |
- // Database is unusable at the SQLite level. |
- { |
- sql::ScopedErrorIgnorer ignore_errors; |
- ignore_errors.IgnoreError(SQLITE_CORRUPT); |
- sql::Connection raw_db; |
- EXPECT_TRUE(raw_db.Open(file_name_)); |
- EXPECT_FALSE(raw_db.IsSQLValid("PRAGMA integrity_check")); |
- ASSERT_TRUE(ignore_errors.CheckIgnoredErrors()); |
- } |
+ RecoveryTestVerifyDatabaseIsUnusable(file_name_); |
// Corruption should be detected and recovered during Init(). |
{ |
@@ -198,15 +218,7 @@ TEST_F(TopSitesDatabaseTest, Recovery2) { |
// Corrupt the database by adjusting the header. |
EXPECT_TRUE(sql::test::CorruptSizeInHeader(file_name_)); |
- // Database is unusable at the SQLite level. |
- { |
- sql::ScopedErrorIgnorer ignore_errors; |
- ignore_errors.IgnoreError(SQLITE_CORRUPT); |
- sql::Connection raw_db; |
- EXPECT_TRUE(raw_db.Open(file_name_)); |
- EXPECT_FALSE(raw_db.IsSQLValid("PRAGMA integrity_check")); |
- ASSERT_TRUE(ignore_errors.CheckIgnoredErrors()); |
- } |
+ RecoveryTestVerifyDatabaseIsUnusable(file_name_); |
// Corruption should be detected and recovered during Init(). After recovery, |
// the Version2 checks should work. |
@@ -216,7 +228,6 @@ TEST_F(TopSitesDatabaseTest, Recovery2) { |
TopSitesDatabase db; |
ASSERT_TRUE(db.Init(file_name_)); |
- |
VerifyTablesAndColumns(db.db_.get()); |
// Basic operational check. |
@@ -236,26 +247,11 @@ TEST_F(TopSitesDatabaseTest, Recovery2) { |
} |
} |
-TEST_F(TopSitesDatabaseTest, Recovery3) { |
- // Recovery module only supports some platforms at this time. |
- if (!sql::Recovery::FullRecoverySupported()) |
- return; |
- |
- // Create an example database. |
- EXPECT_TRUE(CreateDatabaseFromSQL(file_name_, "TopSites.v3.sql")); |
- |
+void TopSitesDatabaseTest::RecoveryTest3And4Common() { |
// Corrupt the database by adjusting the header. |
EXPECT_TRUE(sql::test::CorruptSizeInHeader(file_name_)); |
- // Database is unusable at the SQLite level. |
- { |
- sql::ScopedErrorIgnorer ignore_errors; |
- ignore_errors.IgnoreError(SQLITE_CORRUPT); |
- sql::Connection raw_db; |
- EXPECT_TRUE(raw_db.Open(file_name_)); |
- EXPECT_FALSE(raw_db.IsSQLValid("PRAGMA integrity_check")); |
- ASSERT_TRUE(ignore_errors.CheckIgnoredErrors()); |
- } |
+ RecoveryTestVerifyDatabaseIsUnusable(file_name_); |
// Corruption should be detected and recovered during Init(). |
{ |
@@ -265,6 +261,7 @@ TEST_F(TopSitesDatabaseTest, Recovery3) { |
TopSitesDatabase db; |
ASSERT_TRUE(db.Init(file_name_)); |
+ // Basic operational check. |
MostVisitedURLList urls; |
std::map<GURL, Images> thumbnails; |
db.GetPageThumbnails(&urls, &thumbnails); |
@@ -352,6 +349,28 @@ TEST_F(TopSitesDatabaseTest, Recovery3) { |
} |
} |
+TEST_F(TopSitesDatabaseTest, Recovery3) { |
+ // Recovery module only supports some platforms at this time. |
+ if (!sql::Recovery::FullRecoverySupported()) |
+ return; |
+ |
+ // Create an example database. |
+ EXPECT_TRUE(CreateDatabaseFromSQL(file_name_, "TopSites.v3.sql")); |
+ |
+ RecoveryTest3And4Common(); |
+} |
+ |
+TEST_F(TopSitesDatabaseTest, Recovery4) { |
+ // Recovery module only supports some platforms at this time. |
+ if (!sql::Recovery::FullRecoverySupported()) |
+ return; |
+ |
+ // Create an example database. |
+ EXPECT_TRUE(CreateDatabaseFromSQL(file_name_, "TopSites.v4.sql")); |
+ |
+ RecoveryTest3And4Common(); |
+} |
+ |
TEST_F(TopSitesDatabaseTest, AddRemoveEditThumbnails) { |
ASSERT_TRUE(CreateDatabaseFromSQL(file_name_, "TopSites.v3.sql")); |
@@ -476,4 +495,205 @@ TEST_F(TopSitesDatabaseTest, AddRemoveEditThumbnails) { |
EXPECT_EQ(kUrl0, urls[1].url); |
} |
+TEST_F(TopSitesDatabaseTest, EncodeCSVString) { |
+ std::vector<std::string> empty_list; |
+ EXPECT_EQ("", TopSitesDatabase::EncodeCSVString(empty_list)); |
+ |
+ std::vector<std::string> empty_string_list; |
+ empty_string_list.push_back(""); |
+ EXPECT_EQ("\"\"", TopSitesDatabase::EncodeCSVString(empty_string_list)); |
+ empty_string_list.push_back(""); |
+ EXPECT_EQ("\"\",\"\"", TopSitesDatabase::EncodeCSVString(empty_string_list)); |
+ |
+ // "\n" is treated like any other character. |
+ std::vector<std::string> single_list; |
+ single_list.push_back("abczABCZ-123 !@#$%^&*(),.'\"\n\r_"); |
+ EXPECT_EQ("\"abczABCZ-123 !@#$%^&*(),.'\"\"\n\r_\"", |
+ TopSitesDatabase::EncodeCSVString(single_list)); |
+ |
+ std::vector<std::string> double_list; |
+ double_list.push_back(" a \"string\", this is "); |
+ double_list.push_back("http://www.test.com:80/path?query#ref"); |
+ EXPECT_EQ("\" a \"\"string\"\", this is \"," |
+ "\"http://www.test.com:80/path?query#ref\"", |
+ TopSitesDatabase::EncodeCSVString(double_list)); |
+ |
+ std::vector<std::string> multi_list; |
+ multi_list.push_back("test"); |
+ multi_list.push_back(""); |
+ multi_list.push_back(","); |
+ multi_list.push_back("http://www.google.com"); |
+ multi_list.push_back(" "); |
+ multi_list.push_back("\r\n"); |
+ multi_list.push_back("\""); |
+ multi_list.push_back("\"quote\""); |
+ multi_list.push_back("data:text/plain,this text has space"); |
+ EXPECT_EQ("\"test\",\"\",\",\",\"http://www.google.com\"," |
+ "\" \",\"\r\n\",\"\"\"\",\"\"\"quote\"\"\"," |
+ "\"data:text/plain,this text has space\"", |
+ TopSitesDatabase::EncodeCSVString(multi_list)); |
+} |
+ |
+TEST_F(TopSitesDatabaseTest, DecodeCSVStringSucceed) { |
+ std::vector<std::string> res; |
+ res.push_back("this gets overwritten"); |
+ |
+ EXPECT_TRUE(TopSitesDatabase::DecodeCSVString("", &res)); |
+ EXPECT_TRUE(res.empty()); |
+ |
+ EXPECT_TRUE(TopSitesDatabase::DecodeCSVString("\"\"", &res)); |
+ EXPECT_EQ(1U, res.size()); |
+ EXPECT_EQ("", res[0]); |
+ |
+ EXPECT_TRUE(TopSitesDatabase::DecodeCSVString("\"\",\"\"", &res)); |
+ EXPECT_EQ(2U, res.size()); |
+ EXPECT_EQ("", res[0]); |
+ EXPECT_EQ("", res[1]); |
+ |
+ // "\n" is treated like any other character. |
+ EXPECT_TRUE(TopSitesDatabase::DecodeCSVString( |
+ "\"abczABCZ-123 !@#$%^&*(),.'\"\"\n\r_\"", &res)); |
+ EXPECT_EQ(1U, res.size()); |
+ EXPECT_EQ("abczABCZ-123 !@#$%^&*(),.'\"\n\r_", res[0]); |
+ |
+ EXPECT_TRUE(TopSitesDatabase::DecodeCSVString( |
+ "\" a \"\"string\"\", this is \"," |
+ "\"http://www.test.com:80/path?query#ref\"", &res)); |
+ EXPECT_EQ(2U, res.size()); |
+ EXPECT_EQ(" a \"string\", this is ", res[0]); |
+ EXPECT_EQ("http://www.test.com:80/path?query#ref", res[1]); |
+ |
+ EXPECT_TRUE(TopSitesDatabase::DecodeCSVString( |
+ "\"test\",\"\",\",\",\"http://www.google.com\"," |
+ "\" \",\"\r\n\",\"\"\"\",\"\"\"quote\"\"\"," |
+ "\"data:text/plain,this text has space\"", &res)); |
+ EXPECT_EQ(9U, res.size()); |
+ EXPECT_EQ("test", res[0]); |
+ EXPECT_EQ("", res[1]); |
+ EXPECT_EQ(",", res[2]); |
+ EXPECT_EQ("http://www.google.com", res[3]); |
+ EXPECT_EQ(" ", res[4]); |
+ EXPECT_EQ("\r\n", res[5]); |
+ EXPECT_EQ("\"", res[6]); |
+ EXPECT_EQ("\"quote\"", res[7]); |
+ EXPECT_EQ("data:text/plain,this text has space", res[8]); |
+} |
+ |
+TEST_F(TopSitesDatabaseTest, DecodeCSVStringFail) { |
+ std::vector<std::string> dummy; |
+ dummy.push_back("Can't touch this"); |
+ // Missing quotes. |
+ EXPECT_FALSE(TopSitesDatabase::DecodeCSVString("test", &dummy)); |
+ EXPECT_FALSE(TopSitesDatabase::DecodeCSVString("test,blah", &dummy)); |
+ EXPECT_FALSE(TopSitesDatabase::DecodeCSVString("\"test\",blah", &dummy)); |
+ EXPECT_FALSE(TopSitesDatabase::DecodeCSVString("\"test", &dummy)); |
+ EXPECT_FALSE(TopSitesDatabase::DecodeCSVString("test\"", &dummy)); |
+ EXPECT_FALSE(TopSitesDatabase::DecodeCSVString("\"\"\"", &dummy)); |
+ EXPECT_FALSE(TopSitesDatabase::DecodeCSVString("\"\",\"\"\"", &dummy)); |
+ // Misplaced comma. |
+ EXPECT_FALSE(TopSitesDatabase::DecodeCSVString(",\"A\"", &dummy)); |
+ EXPECT_FALSE(TopSitesDatabase::DecodeCSVString("\"A\",", &dummy)); |
+ EXPECT_FALSE(TopSitesDatabase::DecodeCSVString("\"A\",,\"B\"", &dummy)); |
+ EXPECT_FALSE(TopSitesDatabase::DecodeCSVString("\"A\",\"B\",\"C\",", &dummy)); |
+ // Garbage after quote. |
+ EXPECT_FALSE(TopSitesDatabase::DecodeCSVString("\"test\"a\"", &dummy)); |
+ EXPECT_FALSE(TopSitesDatabase::DecodeCSVString("\"\"test\"", &dummy)); |
+ // We're strict with trailing white spaces. |
+ EXPECT_FALSE(TopSitesDatabase::DecodeCSVString("\"no\", \"space\"", &dummy)); |
+ EXPECT_FALSE(TopSitesDatabase::DecodeCSVString("\"no\" ,\"space\"", &dummy)); |
+ EXPECT_FALSE(TopSitesDatabase::DecodeCSVString(" \"bad\"", &dummy)); |
+ EXPECT_FALSE(TopSitesDatabase::DecodeCSVString("\"bad\" ", &dummy)); |
+ EXPECT_FALSE(TopSitesDatabase::DecodeCSVString("\"bad\"\n", &dummy)); |
+ // Other. |
+ EXPECT_FALSE(TopSitesDatabase::DecodeCSVString(",", &dummy)); |
+ EXPECT_FALSE(TopSitesDatabase::DecodeCSVString(",,,,,,", &dummy)); |
+ // Verify |dummy| is not touched. |
+ EXPECT_EQ(1U, dummy.size()); |
+ EXPECT_EQ("Can't touch this", dummy[0]); |
+} |
+ |
+TEST_F(TopSitesDatabaseTest, EncodeRedirects) { |
+ RedirectList redirects1; |
+ EXPECT_EQ("", TopSitesDatabase::EncodeRedirects(redirects1)); |
+ redirects1.push_back(GURL("http://www.google.com")); |
+ EXPECT_EQ("\"http://www.google.com/\"", |
+ TopSitesDatabase::EncodeRedirects(redirects1)); |
+ redirects1.push_back(GURL("https://www.youtube.ca/")); |
+ EXPECT_EQ("\"http://www.google.com/\",\"https://www.youtube.ca/\"", |
+ TopSitesDatabase::EncodeRedirects(redirects1)); |
+ redirects1.push_back(GURL("http://www.test.org:137/path?query#ref")); |
+ EXPECT_EQ("\"http://www.google.com/\",\"https://www.youtube.ca/\"," |
+ "\"http://www.test.org:137/path?query#ref\"", |
+ TopSitesDatabase::EncodeRedirects(redirects1)); |
+ |
+ RedirectList redirects2; |
+ redirects2.push_back(GURL("http://www.google.com")); |
+ // Adding invalid URL. |
+ redirects2.push_back(GURL("this is not valid URL")); |
+ // Adding data URL. |
+ redirects2.push_back(GURL("data:text/plain,\"this has space\"")); |
+ // Invalid URL should be ignored. |
+ EXPECT_EQ("\"http://www.google.com/\"," |
+ "\"data:text/plain,\"\"this has space\"\"\"", |
+ TopSitesDatabase::EncodeRedirects(redirects2)); |
+} |
+ |
+TEST_F(TopSitesDatabaseTest, DecodeRedirects) { |
+ RedirectList redirects1; |
+ TopSitesDatabase::DecodeRedirects("", &redirects1); |
+ EXPECT_EQ(0u, redirects1.size()); |
+ |
+ RedirectList redirects2; |
+ TopSitesDatabase::DecodeRedirects( |
+ "\"http://www.google.com/\",\"https://www.youtube.ca/\"," |
+ "\"http://www.test.org:137/path?query#ref\"", &redirects2); |
+ EXPECT_EQ(3U, redirects2.size()); |
+ EXPECT_EQ(GURL("http://www.google.com"), redirects2[0]); |
+ EXPECT_EQ(GURL("https://www.youtube.ca/"), redirects2[1]); |
+ EXPECT_EQ(GURL("http://www.test.org:137/path?query#ref"), redirects2[2]); |
+ |
+ RedirectList redirects3; |
+ TopSitesDatabase::DecodeRedirects( |
+ "\"http://www.google.com\"," |
+ "\"this is not valid URL\",\"\"," |
+ "\"data:text/plain,\"\"this has space\"\"\"", &redirects3); |
+ EXPECT_EQ(2U, redirects3.size()); |
+ EXPECT_EQ(GURL("http://www.google.com"), redirects3[0]); |
+ EXPECT_EQ(GURL("data:text/plain,\"this has space\""), redirects3[1]); |
+} |
+ |
+// Fallback case when redirects are not stored as CSV strings. |
+TEST_F(TopSitesDatabaseTest, DecodeRedirectsFallback) { |
+ RedirectList redirects1; |
+ TopSitesDatabase::DecodeRedirects("http://www.chromium.org", &redirects1); |
+ EXPECT_EQ(1u, redirects1.size()); |
+ EXPECT_EQ(GURL("http://www.chromium.org"), redirects1[0]); |
+ |
+ // Valid case, note multiple spaces. |
+ RedirectList redirects2; |
+ TopSitesDatabase::DecodeRedirects( |
+ " http://www.google.com https://www.youtube.ca" |
+ " http://www.test.org:80/path?query#ref ", |
+ &redirects2); |
+ EXPECT_EQ(3u, redirects2.size()); |
+ EXPECT_EQ(GURL("http://www.google.com"), redirects2[0]); |
+ EXPECT_EQ(GURL("https://www.youtube.ca"), redirects2[1]); |
+ EXPECT_EQ(GURL("http://www.test.org:80/path?query#ref"), redirects2[2]); |
+ |
+ // This might appear in old database, and should be ignored. |
+ RedirectList redirects3; |
+ TopSitesDatabase::DecodeRedirects("data:text/plain,this text has space", |
+ &redirects3); |
+ EXPECT_EQ(1u, redirects3.size()); |
+ EXPECT_EQ(GURL("data:text/plain,this"), redirects3[0]); |
+ |
+ // Unfortunate case that creates dubious results. |
+ RedirectList redirects4; |
+ TopSitesDatabase::DecodeRedirects("Data:text/plain,this http://a has space", |
+ &redirects4); |
+ EXPECT_EQ(2u, redirects4.size()); |
+ EXPECT_EQ(GURL("Data:text/plain,this"), redirects4[0]); |
+ EXPECT_EQ(GURL("http://a"), redirects4[1]); |
+} |
+ |
} // namespace history |