summaryrefslogtreecommitdiffstats
path: root/chrome/browser/webdata/web_database_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/webdata/web_database_unittest.cc')
-rw-r--r--chrome/browser/webdata/web_database_unittest.cc587
1 files changed, 587 insertions, 0 deletions
diff --git a/chrome/browser/webdata/web_database_unittest.cc b/chrome/browser/webdata/web_database_unittest.cc
new file mode 100644
index 0000000..fd68974
--- /dev/null
+++ b/chrome/browser/webdata/web_database_unittest.cc
@@ -0,0 +1,587 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <windows.h>
+
+#include "base/file_util.h"
+#include "base/path_service.h"
+#include "base/string_util.h"
+#include "base/values.h"
+#include "chrome/browser/template_url.h"
+#include "chrome/browser/webdata/web_database.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/stl_util-inl.h"
+#include "skia/include/SkBitmap.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webkit/glue/password_form.h"
+
+class WebDatabaseTest : public testing::Test {
+ protected:
+
+ virtual void SetUp() {
+ wchar_t b[32];
+ _itow_s(static_cast<int>(GetTickCount()), b, arraysize(b), 10);
+
+ PathService::Get(chrome::DIR_TEST_DATA, &file_);
+ file_ += file_util::kPathSeparator;
+ file_ += L"TestWebDatabase";
+ file_ += b;
+ file_ += L".db";
+ DeleteFile(file_.c_str());
+ }
+
+ virtual void TearDown() {
+ DeleteFile(file_.c_str());
+ }
+
+ static int GetKeyCount(const DictionaryValue& d) {
+ DictionaryValue::key_iterator i(d.begin_keys());
+ DictionaryValue::key_iterator e(d.end_keys());
+
+ int r = 0;
+ while (i != e) {
+ ++i;
+ ++r;
+ }
+ return r;
+ }
+
+ static bool StringDictionaryValueEquals(const DictionaryValue& a,
+ const DictionaryValue& b) {
+ int a_count = 0;
+ int b_count = GetKeyCount(b);
+ DictionaryValue::key_iterator i(a.begin_keys());
+ DictionaryValue::key_iterator e(a.end_keys());
+ std::wstring av, bv;
+ while (i != e) {
+ if (!(a.GetString(*i, &av)) ||
+ !(b.GetString(*i, &bv)) ||
+ av != bv)
+ return false;
+
+ a_count++;
+ ++i;
+ }
+
+ return (a_count == b_count);
+ }
+
+ static int64 GetID(const TemplateURL* url) {
+ return url->id();
+ }
+
+ static void SetID(int64 new_id, TemplateURL* url) {
+ url->set_id(new_id);
+ }
+
+ static void set_prepopulate_id(TemplateURL* url, int id) {
+ url->set_prepopulate_id(id);
+ }
+
+ std::wstring file_;
+};
+
+TEST_F(WebDatabaseTest, Keywords) {
+ WebDatabase db;
+
+ EXPECT_TRUE(db.Init(file_));
+
+ TemplateURL template_url;
+ template_url.set_short_name(L"short_name");
+ template_url.set_keyword(L"keyword");
+ GURL favicon_url("http://favicon.url");
+ GURL originating_url("http://google.com");
+ template_url.SetFavIconURL(favicon_url);
+ template_url.SetURL(L"url", 0, 0);
+ template_url.set_safe_for_autoreplace(true);
+ template_url.set_show_in_default_list(true);
+ template_url.set_originating_url(originating_url);
+ template_url.set_usage_count(32);
+ template_url.add_input_encoding("UTF-8");
+ set_prepopulate_id(&template_url, 10);
+ SetID(1, &template_url);
+
+ EXPECT_TRUE(db.AddKeyword(template_url));
+
+ std::vector<TemplateURL*> template_urls;
+ EXPECT_TRUE(db.GetKeywords(&template_urls));
+
+ EXPECT_EQ(1, template_urls.size());
+ const TemplateURL* restored_url = template_urls.front();
+
+ EXPECT_EQ(template_url.short_name(), restored_url->short_name());
+
+ EXPECT_EQ(template_url.keyword(), restored_url->keyword());
+
+ EXPECT_TRUE(favicon_url == restored_url->GetFavIconURL());
+
+ EXPECT_TRUE(restored_url->safe_for_autoreplace());
+
+ EXPECT_TRUE(restored_url->show_in_default_list());
+
+ EXPECT_EQ(GetID(&template_url), GetID(restored_url));
+
+ EXPECT_TRUE(originating_url == restored_url->originating_url());
+
+ EXPECT_EQ(32, restored_url->usage_count());
+
+ ASSERT_EQ(1, restored_url->input_encodings().size());
+ EXPECT_EQ("UTF-8", restored_url->input_encodings()[0]);
+
+ EXPECT_EQ(10, restored_url->prepopulate_id());
+
+ EXPECT_TRUE(db.RemoveKeyword(restored_url->id()));
+
+ template_urls.clear();
+ EXPECT_TRUE(db.GetKeywords(&template_urls));
+
+ EXPECT_EQ(0, template_urls.size());
+
+ delete restored_url;
+}
+
+TEST_F(WebDatabaseTest, KeywordMisc) {
+ WebDatabase db;
+
+ EXPECT_TRUE(db.Init(file_));
+
+ ASSERT_EQ(0, db.GetDefaulSearchProviderID());
+ ASSERT_EQ(0, db.GetBuitinKeywordVersion());
+
+ db.SetDefaultSearchProviderID(10);
+ db.SetBuitinKeywordVersion(11);
+
+ ASSERT_EQ(10, db.GetDefaulSearchProviderID());
+ ASSERT_EQ(11, db.GetBuitinKeywordVersion());
+}
+
+TEST_F(WebDatabaseTest, UpdateKeyword) {
+ WebDatabase db;
+
+ EXPECT_TRUE(db.Init(file_));
+
+ TemplateURL template_url;
+ template_url.set_short_name(L"short_name");
+ template_url.set_keyword(L"keyword");
+ GURL favicon_url("http://favicon.url");
+ GURL originating_url("http://originating.url");
+ template_url.SetFavIconURL(favicon_url);
+ template_url.SetURL(L"url", 0, 0);
+ template_url.set_safe_for_autoreplace(true);
+ template_url.set_show_in_default_list(true);
+ template_url.SetSuggestionsURL(L"url2", 0, 0);
+ SetID(1, &template_url);
+
+ EXPECT_TRUE(db.AddKeyword(template_url));
+
+ GURL originating_url2("http://originating.url");
+ template_url.set_keyword(L"X");
+ template_url.set_originating_url(originating_url2);
+ template_url.add_input_encoding("Shift_JIS");
+ set_prepopulate_id(&template_url, 5);
+ EXPECT_TRUE(db.UpdateKeyword(template_url));
+
+ std::vector<TemplateURL*> template_urls;
+ EXPECT_TRUE(db.GetKeywords(&template_urls));
+
+ EXPECT_EQ(1, template_urls.size());
+ const TemplateURL* restored_url = template_urls.front();
+
+ EXPECT_EQ(template_url.short_name(), restored_url->short_name());
+
+ EXPECT_EQ(template_url.keyword(), restored_url->keyword());
+
+ EXPECT_TRUE(favicon_url == restored_url->GetFavIconURL());
+
+ EXPECT_TRUE(restored_url->safe_for_autoreplace());
+
+ EXPECT_TRUE(restored_url->show_in_default_list());
+
+ EXPECT_EQ(GetID(&template_url), GetID(restored_url));
+
+ EXPECT_TRUE(originating_url2 == restored_url->originating_url());
+
+ ASSERT_EQ(1, restored_url->input_encodings().size());
+ ASSERT_EQ("Shift_JIS", restored_url->input_encodings()[0]);
+
+ EXPECT_EQ(template_url.suggestions_url()->url(),
+ restored_url->suggestions_url()->url());
+
+ EXPECT_EQ(template_url.id(), restored_url->id());
+
+ EXPECT_EQ(template_url.prepopulate_id(), restored_url->prepopulate_id());
+
+ delete restored_url;
+}
+
+TEST_F(WebDatabaseTest, KeywordWithNoFavicon) {
+ WebDatabase db;
+
+ EXPECT_TRUE(db.Init(file_));
+
+ TemplateURL template_url;
+ template_url.set_short_name(L"short_name");
+ template_url.set_keyword(L"keyword");
+ template_url.SetURL(L"url", 0, 0);
+ template_url.set_safe_for_autoreplace(true);
+ SetID(-100, &template_url);
+
+ EXPECT_TRUE(db.AddKeyword(template_url));
+
+ std::vector<TemplateURL*> template_urls;
+ EXPECT_TRUE(db.GetKeywords(&template_urls));
+ EXPECT_EQ(1, template_urls.size());
+ const TemplateURL* restored_url = template_urls.front();
+
+ EXPECT_EQ(template_url.short_name(), restored_url->short_name());
+ EXPECT_EQ(template_url.keyword(), restored_url->keyword());
+ EXPECT_TRUE(!restored_url->GetFavIconURL().is_valid());
+ EXPECT_TRUE(restored_url->safe_for_autoreplace());
+ EXPECT_EQ(GetID(&template_url), GetID(restored_url));
+ delete restored_url;
+}
+
+TEST_F(WebDatabaseTest, Logins) {
+ WebDatabase db;
+
+ EXPECT_TRUE(db.Init(file_));
+
+ std::vector<PasswordForm*> result;
+
+ // Verify the database is empty.
+ EXPECT_TRUE(db.GetAllLogins(&result, true));
+ EXPECT_EQ(0, result.size());
+
+ // Example password form.
+ PasswordForm form;
+ form.origin = GURL(L"http://www.google.com/accounts/LoginAuth");
+ form.action = GURL(L"http://www.google.com/accounts/Login");
+ form.username_element = L"Email";
+ form.username_value = L"test@gmail.com";
+ form.password_element = L"Passwd";
+ form.password_value = L"test";
+ form.submit_element = L"signIn";
+ form.signon_realm = "http://www.google.com";
+ form.ssl_valid = false;
+ form.preferred = false;
+ form.scheme = PasswordForm::SCHEME_HTML;
+
+ // Add it and make sure it is there.
+ EXPECT_TRUE(db.AddLogin(form));
+ EXPECT_TRUE(db.GetAllLogins(&result, true));
+ EXPECT_EQ(1, result.size());
+ delete result[0];
+ result.clear();
+
+ // Match against an exact copy.
+ EXPECT_TRUE(db.GetLogins(form, &result));
+ EXPECT_EQ(1, result.size());
+ delete result[0];
+ result.clear();
+
+ // The example site changes...
+ PasswordForm form2(form);
+ form2.origin = GURL(L"http://www.google.com/new/accounts/LoginAuth");
+ form2.submit_element = L"reallySignIn";
+
+ // Match against an inexact copy
+ EXPECT_TRUE(db.GetLogins(form2, &result));
+ EXPECT_EQ(1, result.size());
+ delete result[0];
+ result.clear();
+
+ // Uh oh, the site changed origin & action URL's all at once!
+ PasswordForm form3(form2);
+ form3.action = GURL(L"http://www.google.com/new/accounts/Login");
+
+ // signon_realm is the same, should match.
+ EXPECT_TRUE(db.GetLogins(form3, &result));
+ EXPECT_EQ(1, result.size());
+ delete result[0];
+ result.clear();
+
+ // Imagine the site moves to a secure server for login.
+ PasswordForm form4(form3);
+ form4.signon_realm = "https://www.google.com";
+ form4.ssl_valid = true;
+
+ // We have only an http record, so no match for this.
+ EXPECT_TRUE(db.GetLogins(form4, &result));
+ EXPECT_EQ(0, result.size());
+
+ // Let's imagine the user logs into the secure site.
+ EXPECT_TRUE(db.AddLogin(form4));
+ EXPECT_TRUE(db.GetAllLogins(&result, true));
+ EXPECT_EQ(2, result.size());
+ delete result[0];
+ delete result[1];
+ result.clear();
+
+ // Now the match works
+ EXPECT_TRUE(db.GetLogins(form4, &result));
+ EXPECT_EQ(1, result.size());
+ delete result[0];
+ result.clear();
+
+ // The user chose to forget the original but not the new.
+ EXPECT_TRUE(db.RemoveLogin(form));
+ EXPECT_TRUE(db.GetAllLogins(&result, true));
+ EXPECT_EQ(1, result.size());
+ delete result[0];
+ result.clear();
+
+ // The old form wont match the new site (http vs https).
+ EXPECT_TRUE(db.GetLogins(form, &result));
+ EXPECT_EQ(0, result.size());
+
+ // The user's request for the HTTPS site is intercepted
+ // by an attacker who presents an invalid SSL cert.
+ PasswordForm form5(form4);
+ form5.ssl_valid = 0;
+
+ // It will match in this case.
+ EXPECT_TRUE(db.GetLogins(form5, &result));
+ EXPECT_EQ(1, result.size());
+ delete result[0];
+ result.clear();
+
+ // User changes his password.
+ PasswordForm form6(form5);
+ form6.password_value = L"test6";
+ form6.preferred = true;
+
+ // We update, and check to make sure it matches the
+ // old form, and there is only one record.
+ EXPECT_TRUE(db.UpdateLogin(form6));
+ // matches
+ EXPECT_TRUE(db.GetLogins(form5, &result));
+ EXPECT_EQ(1, result.size());
+ delete result[0];
+ result.clear();
+ // Only one record.
+ EXPECT_TRUE(db.GetAllLogins(&result, true));
+ EXPECT_EQ(1, result.size());
+ // password element was updated.
+ EXPECT_EQ(form6.password_value, result[0]->password_value);
+ // Preferred login.
+ EXPECT_TRUE(form6.preferred);
+ delete result[0];
+ result.clear();
+
+ // Make sure everything can disappear.
+ EXPECT_TRUE(db.RemoveLogin(form4));
+ EXPECT_TRUE(db.GetAllLogins(&result, true));
+ EXPECT_EQ(0, result.size());
+}
+
+static bool AddTimestampedLogin(WebDatabase* db, std::string url,
+ std::wstring unique_string, const Time& time) {
+ // Example password form.
+ PasswordForm form;
+ form.origin = GURL(url + std::string("/LoginAuth"));
+ form.username_element = unique_string.c_str();
+ form.username_value = unique_string.c_str();
+ form.password_element = unique_string.c_str();
+ form.submit_element = L"signIn";
+ form.signon_realm = url;
+ form.date_created = time;
+ return db->AddLogin(form);
+}
+
+static void ClearResults(std::vector<PasswordForm*>* results) {
+ for (size_t i = 0; i < results->size(); ++i) {
+ delete (*results)[i];
+ }
+ results->clear();
+}
+
+TEST_F(WebDatabaseTest, ClearPrivateData_SavedPasswords) {
+ WebDatabase db;
+
+ EXPECT_TRUE(db.Init(file_));
+
+ std::vector<PasswordForm*> result;
+
+ // Verify the database is empty.
+ EXPECT_TRUE(db.GetAllLogins(&result, true));
+ EXPECT_EQ(0, result.size());
+
+ Time now = Time::Now();
+ TimeDelta one_day = TimeDelta::FromDays(1);
+
+ // Create one with a 0 time.
+ EXPECT_TRUE(AddTimestampedLogin(&db, "1", L"foo1", Time()));
+ // Create one for now and +/- 1 day.
+ EXPECT_TRUE(AddTimestampedLogin(&db, "2", L"foo2", now - one_day));
+ EXPECT_TRUE(AddTimestampedLogin(&db, "3", L"foo3", now));
+ EXPECT_TRUE(AddTimestampedLogin(&db, "4", L"foo4", now + one_day));
+
+ // Verify inserts worked.
+ EXPECT_TRUE(db.GetAllLogins(&result, true));
+ EXPECT_EQ(4, result.size());
+ ClearResults(&result);
+
+ // Delete everything from today's date and on.
+ db.RemoveLoginsCreatedBetween(now, Time());
+
+ // Should have deleted half of what we inserted.
+ EXPECT_TRUE(db.GetAllLogins(&result, true));
+ EXPECT_EQ(2, result.size());
+ ClearResults(&result);
+
+ // Delete with 0 date (should delete all).
+ db.RemoveLoginsCreatedBetween(Time(), Time());
+
+ // Verify nothing is left.
+ EXPECT_TRUE(db.GetAllLogins(&result, true));
+ EXPECT_EQ(0, result.size());
+}
+
+TEST_F(WebDatabaseTest, BlacklistedLogins) {
+ WebDatabase db;
+
+ EXPECT_TRUE(db.Init(file_));
+ std::vector<PasswordForm*> result;
+
+ // Verify the database is empty.
+ EXPECT_TRUE(db.GetAllLogins(&result, true));
+ ASSERT_EQ(0, result.size());
+
+ // Save a form as blacklisted.
+ PasswordForm form;
+ form.origin = GURL(L"http://www.google.com/accounts/LoginAuth");
+ form.action = GURL(L"http://www.google.com/accounts/Login");
+ form.username_element = L"Email";
+ form.password_element = L"Passwd";
+ form.submit_element = L"signIn";
+ form.signon_realm = "http://www.google.com";
+ form.ssl_valid = false;
+ form.preferred = true;
+ form.blacklisted_by_user = true;
+ form.scheme = PasswordForm::SCHEME_HTML;
+ EXPECT_TRUE(db.AddLogin(form));
+
+ // Get all non-blacklisted logins (should be none).
+ EXPECT_TRUE(db.GetAllLogins(&result, false));
+ ASSERT_EQ(0, result.size());
+
+ // GetLogins should give the blacklisted result.
+ EXPECT_TRUE(db.GetLogins(form, &result));
+ EXPECT_EQ(1, result.size());
+ ClearResults(&result);
+
+ // So should GetAll including blacklisted.
+ EXPECT_TRUE(db.GetAllLogins(&result, true));
+ EXPECT_EQ(1, result.size());
+ ClearResults(&result);
+}
+
+TEST_F(WebDatabaseTest, WebAppHasAllImages) {
+ WebDatabase db;
+
+ EXPECT_TRUE(db.Init(file_));
+ GURL url("http://google.com");
+
+ // Initial value for unknown web app should be false.
+ EXPECT_FALSE(db.GetWebAppHasAllImages(url));
+
+ // Set the value and make sure it took.
+ EXPECT_TRUE(db.SetWebAppHasAllImages(url, true));
+ EXPECT_TRUE(db.GetWebAppHasAllImages(url));
+
+ // Remove the app and make sure value reverts to default.
+ EXPECT_TRUE(db.RemoveWebApp(url));
+ EXPECT_FALSE(db.GetWebAppHasAllImages(url));
+}
+
+TEST_F(WebDatabaseTest, WebAppImages) {
+ WebDatabase db;
+
+ ASSERT_TRUE(db.Init(file_));
+ GURL url("http://google.com");
+
+ // Web app should initially have no images.
+ std::vector<SkBitmap> images;
+ ASSERT_TRUE(db.GetWebAppImages(url, &images));
+ ASSERT_EQ(0, images.size());
+
+ // Add an image.
+ SkBitmap image;
+ image.setConfig(SkBitmap::kARGB_8888_Config, 16, 16);
+ image.allocPixels();
+ image.eraseColor(SK_ColorBLACK);
+ ASSERT_TRUE(db.SetWebAppImage(url, image));
+
+ // Make sure we get the image back.
+ ASSERT_TRUE(db.GetWebAppImages(url, &images));
+ ASSERT_EQ(1, images.size());
+ ASSERT_EQ(16, images[0].width());
+ ASSERT_EQ(16, images[0].height());
+
+ // Add another 16x16 image and make sure it replaces the original.
+ image.setConfig(SkBitmap::kARGB_8888_Config, 16, 16);
+ image.allocPixels();
+ image.eraseColor(SK_ColorBLACK);
+ // Some random pixels so that we can identify the image.
+ *(reinterpret_cast<unsigned char*>(image.getPixels())) = 0xAB;
+ ASSERT_TRUE(db.SetWebAppImage(url, image));
+ images.clear();
+ ASSERT_TRUE(db.GetWebAppImages(url, &images));
+ ASSERT_EQ(1, images.size());
+ ASSERT_EQ(16, images[0].width());
+ ASSERT_EQ(16, images[0].height());
+ images[0].lockPixels();
+ unsigned char* pixels =
+ reinterpret_cast<unsigned char*>(images[0].getPixels());
+ ASSERT_TRUE(pixels != NULL);
+ ASSERT_EQ(0xAB, *pixels);
+ images[0].unlockPixels();
+
+ // Add another image at a bigger size.
+ image.setConfig(SkBitmap::kARGB_8888_Config, 32, 32);
+ image.allocPixels();
+ image.eraseColor(SK_ColorBLACK);
+ ASSERT_TRUE(db.SetWebAppImage(url, image));
+
+ // Make sure we get both images back.
+ images.clear();
+ ASSERT_TRUE(db.GetWebAppImages(url, &images));
+ ASSERT_EQ(2, images.size());
+ if (images[0].width() == 16) {
+ ASSERT_EQ(16, images[0].width());
+ ASSERT_EQ(16, images[0].height());
+ ASSERT_EQ(32, images[1].width());
+ ASSERT_EQ(32, images[1].height());
+ } else {
+ ASSERT_EQ(32, images[0].width());
+ ASSERT_EQ(32, images[0].height());
+ ASSERT_EQ(16, images[1].width());
+ ASSERT_EQ(16, images[1].height());
+ }
+}