blob: dcae78764fe75648605de56a2f5c9ce19d511c94 [file] [log] [blame]
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <list>
#include <map>
#include <set>
#include <string>
#include <utility>
#include <vector>
#include "app/sql/statement.h"
#include "base/file_util.h"
#include "base/path_service.h"
#include "base/scoped_temp_dir.h"
#include "base/stl_util-inl.h"
#include "base/string_number_conversions.h"
#include "base/string16.h"
#include "base/time.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/autofill/autofill_profile.h"
#include "chrome/browser/autofill/autofill_type.h"
#include "chrome/browser/autofill/credit_card.h"
#include "chrome/browser/guid.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/password_manager/encryptor.h"
#include "chrome/browser/webdata/autofill_change.h"
#include "chrome/browser/webdata/autofill_entry.h"
#include "chrome/browser/webdata/web_database.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/test/ui_test_utils.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "webkit/glue/form_field.h"
#include "webkit/glue/password_form.h"
using base::Time;
using base::TimeDelta;
using webkit_glue::FormField;
using webkit_glue::PasswordForm;
// So we can compare AutofillKeys with EXPECT_EQ().
std::ostream& operator<<(std::ostream& os, const AutofillKey& key) {
return os << UTF16ToASCII(key.name()) << ", " << UTF16ToASCII(key.value());
}
// So we can compare AutofillChanges with EXPECT_EQ().
std::ostream& operator<<(std::ostream& os, const AutofillChange& change) {
switch (change.type()) {
case AutofillChange::ADD: {
os << "ADD";
break;
}
case AutofillChange::UPDATE: {
os << "UPDATE";
break;
}
case AutofillChange::REMOVE: {
os << "REMOVE";
break;
}
}
return os << " " << change.key();
}
namespace {
bool CompareAutofillEntries(const AutofillEntry& a, const AutofillEntry& b) {
std::set<base::Time> timestamps1(a.timestamps().begin(),
a.timestamps().end());
std::set<base::Time> timestamps2(b.timestamps().begin(),
b.timestamps().end());
int compVal = a.key().name().compare(b.key().name());
if (compVal != 0) {
return compVal < 0;
}
compVal = a.key().value().compare(b.key().value());
if (compVal != 0) {
return compVal < 0;
}
if (timestamps1.size() != timestamps2.size()) {
return timestamps1.size() < timestamps2.size();
}
std::set<base::Time>::iterator it;
for (it = timestamps1.begin(); it != timestamps1.end(); it++) {
timestamps2.erase(*it);
}
return timestamps2.size() != 0U;
}
void AutoFillProfile31FromStatement(const sql::Statement& s,
AutoFillProfile* profile,
string16* label,
int* unique_id,
int64* date_modified) {
DCHECK(profile);
DCHECK(label);
DCHECK(unique_id);
DCHECK(date_modified);
*label = s.ColumnString16(0);
*unique_id = s.ColumnInt(1);
profile->SetInfo(AutoFillType(NAME_FIRST), s.ColumnString16(2));
profile->SetInfo(AutoFillType(NAME_MIDDLE), s.ColumnString16(3));
profile->SetInfo(AutoFillType(NAME_LAST),s.ColumnString16(4));
profile->SetInfo(AutoFillType(EMAIL_ADDRESS), s.ColumnString16(5));
profile->SetInfo(AutoFillType(COMPANY_NAME), s.ColumnString16(6));
profile->SetInfo(AutoFillType(ADDRESS_HOME_LINE1), s.ColumnString16(7));
profile->SetInfo(AutoFillType(ADDRESS_HOME_LINE2), s.ColumnString16(8));
profile->SetInfo(AutoFillType(ADDRESS_HOME_CITY), s.ColumnString16(9));
profile->SetInfo(AutoFillType(ADDRESS_HOME_STATE), s.ColumnString16(10));
profile->SetInfo(AutoFillType(ADDRESS_HOME_ZIP), s.ColumnString16(11));
profile->SetInfo(AutoFillType(ADDRESS_HOME_COUNTRY), s.ColumnString16(12));
profile->SetInfo(AutoFillType(PHONE_HOME_WHOLE_NUMBER), s.ColumnString16(13));
profile->SetInfo(AutoFillType(PHONE_FAX_WHOLE_NUMBER), s.ColumnString16(14));
*date_modified = s.ColumnInt64(15);
profile->set_guid(s.ColumnString(16));
EXPECT_TRUE(guid::IsValidGUID(profile->guid()));
}
void AutoFillProfile32FromStatement(const sql::Statement& s,
AutoFillProfile* profile,
string16* label,
int64* date_modified) {
DCHECK(profile);
DCHECK(label);
DCHECK(date_modified);
profile->set_guid(s.ColumnString(0));
EXPECT_TRUE(guid::IsValidGUID(profile->guid()));
*label = s.ColumnString16(1);
profile->SetInfo(AutoFillType(NAME_FIRST), s.ColumnString16(2));
profile->SetInfo(AutoFillType(NAME_MIDDLE), s.ColumnString16(3));
profile->SetInfo(AutoFillType(NAME_LAST),s.ColumnString16(4));
profile->SetInfo(AutoFillType(EMAIL_ADDRESS), s.ColumnString16(5));
profile->SetInfo(AutoFillType(COMPANY_NAME), s.ColumnString16(6));
profile->SetInfo(AutoFillType(ADDRESS_HOME_LINE1), s.ColumnString16(7));
profile->SetInfo(AutoFillType(ADDRESS_HOME_LINE2), s.ColumnString16(8));
profile->SetInfo(AutoFillType(ADDRESS_HOME_CITY), s.ColumnString16(9));
profile->SetInfo(AutoFillType(ADDRESS_HOME_STATE), s.ColumnString16(10));
profile->SetInfo(AutoFillType(ADDRESS_HOME_ZIP), s.ColumnString16(11));
profile->SetInfo(AutoFillType(ADDRESS_HOME_COUNTRY), s.ColumnString16(12));
profile->SetInfo(AutoFillType(PHONE_HOME_WHOLE_NUMBER), s.ColumnString16(13));
profile->SetInfo(AutoFillType(PHONE_FAX_WHOLE_NUMBER), s.ColumnString16(14));
*date_modified = s.ColumnInt64(15);
}
void CreditCard31FromStatement(const sql::Statement& s,
CreditCard* credit_card,
string16* label,
int* unique_id,
std::string* encrypted_number,
int64* date_modified) {
DCHECK(credit_card);
DCHECK(label);
DCHECK(unique_id);
DCHECK(encrypted_number);
DCHECK(date_modified);
*label = s.ColumnString16(0);
*unique_id = s.ColumnInt(1);
credit_card->SetInfo(AutoFillType(CREDIT_CARD_NAME), s.ColumnString16(2));
credit_card->SetInfo(AutoFillType(CREDIT_CARD_TYPE), s.ColumnString16(3));
credit_card->SetInfo(AutoFillType(CREDIT_CARD_EXP_MONTH),
s.ColumnString16(5));
credit_card->SetInfo(AutoFillType(CREDIT_CARD_EXP_4_DIGIT_YEAR),
s.ColumnString16(6));
int encrypted_number_len = s.ColumnByteLength(10);
if (encrypted_number_len) {
encrypted_number->resize(encrypted_number_len);
memcpy(&(*encrypted_number)[0], s.ColumnBlob(10), encrypted_number_len);
}
*date_modified = s.ColumnInt64(12);
credit_card->set_guid(s.ColumnString(13));
EXPECT_TRUE(guid::IsValidGUID(credit_card->guid()));
}
void CreditCard32FromStatement(const sql::Statement& s,
CreditCard* credit_card,
string16* label,
std::string* encrypted_number,
int64* date_modified) {
DCHECK(credit_card);
DCHECK(label);
DCHECK(encrypted_number);
DCHECK(date_modified);
credit_card->set_guid(s.ColumnString(0));
EXPECT_TRUE(guid::IsValidGUID(credit_card->guid()));
*label = s.ColumnString16(1);
credit_card->SetInfo(AutoFillType(CREDIT_CARD_NAME), s.ColumnString16(2));
credit_card->SetInfo(AutoFillType(CREDIT_CARD_EXP_MONTH),
s.ColumnString16(3));
credit_card->SetInfo(AutoFillType(CREDIT_CARD_EXP_4_DIGIT_YEAR),
s.ColumnString16(4));
int encrypted_number_len = s.ColumnByteLength(5);
if (encrypted_number_len) {
encrypted_number->resize(encrypted_number_len);
memcpy(&(*encrypted_number)[0], s.ColumnBlob(5), encrypted_number_len);
}
*date_modified = s.ColumnInt64(6);
}
} // namespace
class WebDatabaseTest : public testing::Test {
public:
WebDatabaseTest() {}
virtual ~WebDatabaseTest() {}
protected:
typedef std::vector<AutofillChange> AutofillChangeList;
typedef std::set<AutofillEntry,
bool (*)(const AutofillEntry&, const AutofillEntry&)> AutofillEntrySet;
typedef std::set<AutofillEntry, bool (*)(const AutofillEntry&,
const AutofillEntry&)>::iterator AutofillEntrySetIterator;
virtual void SetUp() {
#if defined(OS_MACOSX)
Encryptor::UseMockKeychain(true);
#endif
PathService::Get(chrome::DIR_TEST_DATA, &file_);
const std::string test_db = "TestWebDatabase" +
base::Int64ToString(base::Time::Now().ToTimeT()) +
".db";
file_ = file_.AppendASCII(test_db);
file_util::Delete(file_, false);
}
virtual void TearDown() {
file_util::Delete(file_, false);
}
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::string av, bv;
while (i != e) {
if (!(a.GetStringWithoutPathExpansion(*i, &av)) ||
!(b.GetStringWithoutPathExpansion(*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);
}
static void set_logo_id(TemplateURL* url, int id) {
url->set_logo_id(id);
}
static AutofillEntry MakeAutofillEntry(const char* name,
const char* value,
time_t timestamp0,
time_t timestamp1) {
std::vector<base::Time> timestamps;
if (timestamp0 >= 0)
timestamps.push_back(Time::FromTimeT(timestamp0));
if (timestamp1 >= 0)
timestamps.push_back(Time::FromTimeT(timestamp1));
return AutofillEntry(
AutofillKey(ASCIIToUTF16(name), ASCIIToUTF16(value)), timestamps);
}
FilePath file_;
private:
DISALLOW_COPY_AND_ASSIGN(WebDatabaseTest);
};
TEST_F(WebDatabaseTest, Keywords) {
WebDatabase db;
ASSERT_EQ(sql::INIT_OK, 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("http://url/", 0, 0);
template_url.set_safe_for_autoreplace(true);
base::Time created_time = Time::Now();
template_url.set_date_created(created_time);
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");
template_url.add_input_encoding("UTF-16");
set_prepopulate_id(&template_url, 10);
set_logo_id(&template_url, 1000);
template_url.set_created_by_policy(true);
template_url.SetInstantURL("http://instant/", 0, 0);
SetID(1, &template_url);
EXPECT_TRUE(db.AddKeyword(template_url));
std::vector<TemplateURL*> template_urls;
EXPECT_TRUE(db.GetKeywords(&template_urls));
EXPECT_EQ(1U, 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_FALSE(restored_url->autogenerate_keyword());
EXPECT_TRUE(favicon_url == restored_url->GetFavIconURL());
EXPECT_TRUE(restored_url->safe_for_autoreplace());
// The database stores time only at the resolution of a second.
EXPECT_EQ(created_time.ToTimeT(), restored_url->date_created().ToTimeT());
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(2U, restored_url->input_encodings().size());
EXPECT_EQ("UTF-8", restored_url->input_encodings()[0]);
EXPECT_EQ("UTF-16", restored_url->input_encodings()[1]);
EXPECT_EQ(10, restored_url->prepopulate_id());
EXPECT_EQ(1000, restored_url->logo_id());
EXPECT_TRUE(restored_url->created_by_policy());
ASSERT_TRUE(restored_url->instant_url());
EXPECT_EQ("http://instant/", restored_url->instant_url()->url());
EXPECT_TRUE(db.RemoveKeyword(restored_url->id()));
template_urls.clear();
EXPECT_TRUE(db.GetKeywords(&template_urls));
EXPECT_EQ(0U, template_urls.size());
delete restored_url;
}
TEST_F(WebDatabaseTest, KeywordMisc) {
WebDatabase db;
ASSERT_EQ(sql::INIT_OK, 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;
ASSERT_EQ(sql::INIT_OK, 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("http://url/", 0, 0);
template_url.set_safe_for_autoreplace(true);
template_url.set_show_in_default_list(true);
template_url.SetSuggestionsURL("url2", 0, 0);
SetID(1, &template_url);
EXPECT_TRUE(db.AddKeyword(template_url));
GURL originating_url2("http://originating.url/");
template_url.set_originating_url(originating_url2);
template_url.set_autogenerate_keyword(true);
EXPECT_EQ(L"url", template_url.keyword());
template_url.add_input_encoding("Shift_JIS");
set_prepopulate_id(&template_url, 5);
set_logo_id(&template_url, 2000);
template_url.SetInstantURL("http://instant2/", 0, 0);
EXPECT_TRUE(db.UpdateKeyword(template_url));
std::vector<TemplateURL*> template_urls;
EXPECT_TRUE(db.GetKeywords(&template_urls));
EXPECT_EQ(1U, 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->autogenerate_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(1U, 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());
EXPECT_EQ(template_url.logo_id(), restored_url->logo_id());
EXPECT_TRUE(restored_url->instant_url());
EXPECT_EQ(template_url.instant_url()->url(),
restored_url->instant_url()->url());
delete restored_url;
}
TEST_F(WebDatabaseTest, KeywordWithNoFavicon) {
WebDatabase db;
ASSERT_EQ(sql::INIT_OK, db.Init(file_));
TemplateURL template_url;
template_url.set_short_name(L"short_name");
template_url.set_keyword(L"keyword");
template_url.SetURL("http://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(1U, 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;
ASSERT_EQ(sql::INIT_OK, db.Init(file_));
std::vector<PasswordForm*> result;
// Verify the database is empty.
EXPECT_TRUE(db.GetAllLogins(&result, true));
EXPECT_EQ(0U, result.size());
// Example password form.
PasswordForm form;
form.origin = GURL("http://www.google.com/accounts/LoginAuth");
form.action = GURL("http://www.google.com/accounts/Login");
form.username_element = ASCIIToUTF16("Email");
form.username_value = ASCIIToUTF16("test@gmail.com");
form.password_element = ASCIIToUTF16("Passwd");
form.password_value = ASCIIToUTF16("test");
form.submit_element = ASCIIToUTF16("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(1U, result.size());
delete result[0];
result.clear();
// Match against an exact copy.
EXPECT_TRUE(db.GetLogins(form, &result));
EXPECT_EQ(1U, result.size());
delete result[0];
result.clear();
// The example site changes...
PasswordForm form2(form);
form2.origin = GURL("http://www.google.com/new/accounts/LoginAuth");
form2.submit_element = ASCIIToUTF16("reallySignIn");
// Match against an inexact copy
EXPECT_TRUE(db.GetLogins(form2, &result));
EXPECT_EQ(1U, 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("http://www.google.com/new/accounts/Login");
// signon_realm is the same, should match.
EXPECT_TRUE(db.GetLogins(form3, &result));
EXPECT_EQ(1U, 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(0U, 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(2U, result.size());
delete result[0];
delete result[1];
result.clear();
// Now the match works
EXPECT_TRUE(db.GetLogins(form4, &result));
EXPECT_EQ(1U, 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(1U, 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(0U, 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(1U, result.size());
delete result[0];
result.clear();
// User changes his password.
PasswordForm form6(form5);
form6.password_value = ASCIIToUTF16("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(1U, result.size());
delete result[0];
result.clear();
// Only one record.
EXPECT_TRUE(db.GetAllLogins(&result, true));
EXPECT_EQ(1U, 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(0U, result.size());
}
TEST_F(WebDatabaseTest, Autofill) {
WebDatabase db;
ASSERT_EQ(sql::INIT_OK, db.Init(file_));
Time t1 = Time::Now();
// Simulate the submission of a handful of entries in a field called "Name",
// some more often than others.
AutofillChangeList changes;
EXPECT_TRUE(db.AddFormFieldValue(
FormField(string16(),
ASCIIToUTF16("Name"),
ASCIIToUTF16("Superman"),
string16(),
0,
false),
&changes));
std::vector<string16> v;
for (int i = 0; i < 5; i++) {
EXPECT_TRUE(db.AddFormFieldValue(
FormField(string16(),
ASCIIToUTF16("Name"),
ASCIIToUTF16("Clark Kent"),
string16(),
0,
false),
&changes));
}
for (int i = 0; i < 3; i++) {
EXPECT_TRUE(db.AddFormFieldValue(
FormField(string16(),
ASCIIToUTF16("Name"),
ASCIIToUTF16("Clark Sutter"),
string16(),
0,
false),
&changes));
}
for (int i = 0; i < 2; i++) {
EXPECT_TRUE(db.AddFormFieldValue(
FormField(string16(),
ASCIIToUTF16("Favorite Color"),
ASCIIToUTF16("Green"),
string16(),
0,
false),
&changes));
}
int count = 0;
int64 pair_id = 0;
// We have added the name Clark Kent 5 times, so count should be 5 and pair_id
// should be somthing non-zero.
EXPECT_TRUE(db.GetIDAndCountOfFormElement(
FormField(string16(),
ASCIIToUTF16("Name"),
ASCIIToUTF16("Clark Kent"),
string16(),
0,
false),
&pair_id, &count));
EXPECT_EQ(5, count);
EXPECT_NE(0, pair_id);
// Storing in the data base should be case sensitive, so there should be no
// database entry for clark kent lowercase.
EXPECT_TRUE(db.GetIDAndCountOfFormElement(
FormField(string16(),
ASCIIToUTF16("Name"),
ASCIIToUTF16("clark kent"),
string16(),
0,
false),
&pair_id, &count));
EXPECT_EQ(0, count);
EXPECT_TRUE(db.GetIDAndCountOfFormElement(
FormField(string16(),
ASCIIToUTF16("Favorite Color"),
ASCIIToUTF16("Green"),
string16(),
0,
false),
&pair_id, &count));
EXPECT_EQ(2, count);
// This is meant to get a list of suggestions for Name. The empty prefix
// in the second argument means it should return all suggestions for a name
// no matter what they start with. The order that the names occur in the list
// should be decreasing order by count.
EXPECT_TRUE(db.GetFormValuesForElementName(
ASCIIToUTF16("Name"), string16(), &v, 6));
EXPECT_EQ(3U, v.size());
if (v.size() == 3) {
EXPECT_EQ(ASCIIToUTF16("Clark Kent"), v[0]);
EXPECT_EQ(ASCIIToUTF16("Clark Sutter"), v[1]);
EXPECT_EQ(ASCIIToUTF16("Superman"), v[2]);
}
// If we query again limiting the list size to 1, we should only get the most
// frequent entry.
EXPECT_TRUE(db.GetFormValuesForElementName(
ASCIIToUTF16("Name"), string16(), &v, 1));
EXPECT_EQ(1U, v.size());
if (v.size() == 1) {
EXPECT_EQ(ASCIIToUTF16("Clark Kent"), v[0]);
}
// Querying for suggestions given a prefix is case-insensitive, so the prefix
// "cLa" shoud get suggestions for both Clarks.
EXPECT_TRUE(db.GetFormValuesForElementName(
ASCIIToUTF16("Name"), ASCIIToUTF16("cLa"), &v, 6));
EXPECT_EQ(2U, v.size());
if (v.size() == 2) {
EXPECT_EQ(ASCIIToUTF16("Clark Kent"), v[0]);
EXPECT_EQ(ASCIIToUTF16("Clark Sutter"), v[1]);
}
// Removing all elements since the beginning of this function should remove
// everything from the database.
changes.clear();
EXPECT_TRUE(db.RemoveFormElementsAddedBetween(t1, Time(), &changes));
const AutofillChange expected_changes[] = {
AutofillChange(AutofillChange::REMOVE,
AutofillKey(ASCIIToUTF16("Name"),
ASCIIToUTF16("Superman"))),
AutofillChange(AutofillChange::REMOVE,
AutofillKey(ASCIIToUTF16("Name"),
ASCIIToUTF16("Clark Kent"))),
AutofillChange(AutofillChange::REMOVE,
AutofillKey(ASCIIToUTF16("Name"),
ASCIIToUTF16("Clark Sutter"))),
AutofillChange(AutofillChange::REMOVE,
AutofillKey(ASCIIToUTF16("Favorite Color"),
ASCIIToUTF16("Green"))),
};
EXPECT_EQ(arraysize(expected_changes), changes.size());
for (size_t i = 0; i < arraysize(expected_changes); i++) {
EXPECT_EQ(expected_changes[i], changes[i]);
}
EXPECT_TRUE(db.GetIDAndCountOfFormElement(
FormField(string16(),
ASCIIToUTF16("Name"),
ASCIIToUTF16("Clark Kent"),
string16(),
0,
false),
&pair_id, &count));
EXPECT_EQ(0, count);
EXPECT_TRUE(
db.GetFormValuesForElementName(ASCIIToUTF16("Name"), string16(), &v, 6));
EXPECT_EQ(0U, v.size());
// Now add some values with empty strings.
const string16 kValue = ASCIIToUTF16(" toto ");
EXPECT_TRUE(db.AddFormFieldValue(FormField(string16(),
ASCIIToUTF16("blank"),
string16(),
string16(),
0,
false),
&changes));
EXPECT_TRUE(db.AddFormFieldValue(FormField(string16(),
ASCIIToUTF16("blank"),
ASCIIToUTF16(" "),
string16(),
0,
false),
&changes));
EXPECT_TRUE(db.AddFormFieldValue(FormField(string16(),
ASCIIToUTF16("blank"),
ASCIIToUTF16(" "),
string16(),
0,
false),
&changes));
EXPECT_TRUE(db.AddFormFieldValue(FormField(string16(),
ASCIIToUTF16("blank"),
kValue,
string16(),
0,
false),
&changes));
// They should be stored normally as the DB layer does not check for empty
// values.
v.clear();
EXPECT_TRUE(db.GetFormValuesForElementName(
ASCIIToUTF16("blank"), string16(), &v, 10));
EXPECT_EQ(4U, v.size());
// Now we'll check that ClearAutofillEmptyValueElements() works as expected.
db.ClearAutofillEmptyValueElements();
v.clear();
EXPECT_TRUE(db.GetFormValuesForElementName(ASCIIToUTF16("blank"),
string16(), &v, 10));
ASSERT_EQ(1U, v.size());
EXPECT_EQ(kValue, v[0]);
}
TEST_F(WebDatabaseTest, Autofill_RemoveBetweenChanges) {
WebDatabase db;
ASSERT_EQ(sql::INIT_OK, db.Init(file_));
TimeDelta one_day(TimeDelta::FromDays(1));
Time t1 = Time::Now();
Time t2 = t1 + one_day;
AutofillChangeList changes;
EXPECT_TRUE(db.AddFormFieldValueTime(
FormField(string16(),
ASCIIToUTF16("Name"),
ASCIIToUTF16("Superman"),
string16(),
0,
false),
&changes,
t1));
EXPECT_TRUE(db.AddFormFieldValueTime(
FormField(string16(),
ASCIIToUTF16("Name"),
ASCIIToUTF16("Superman"),
string16(),
0,
false),
&changes,
t2));
changes.clear();
EXPECT_TRUE(db.RemoveFormElementsAddedBetween(t1, t2, &changes));
ASSERT_EQ(1U, changes.size());
EXPECT_EQ(AutofillChange(AutofillChange::UPDATE,
AutofillKey(ASCIIToUTF16("Name"),
ASCIIToUTF16("Superman"))),
changes[0]);
changes.clear();
EXPECT_TRUE(db.RemoveFormElementsAddedBetween(t2, t2 + one_day, &changes));
ASSERT_EQ(1U, changes.size());
EXPECT_EQ(AutofillChange(AutofillChange::REMOVE,
AutofillKey(ASCIIToUTF16("Name"),
ASCIIToUTF16("Superman"))),
changes[0]);
}
TEST_F(WebDatabaseTest, Autofill_AddChanges) {
WebDatabase db;
ASSERT_EQ(sql::INIT_OK, db.Init(file_));
TimeDelta one_day(TimeDelta::FromDays(1));
Time t1 = Time::Now();
Time t2 = t1 + one_day;
AutofillChangeList changes;
EXPECT_TRUE(db.AddFormFieldValueTime(
FormField(string16(),
ASCIIToUTF16("Name"),
ASCIIToUTF16("Superman"),
string16(),
0,
false),
&changes,
t1));
ASSERT_EQ(1U, changes.size());
EXPECT_EQ(AutofillChange(AutofillChange::ADD,
AutofillKey(ASCIIToUTF16("Name"),
ASCIIToUTF16("Superman"))),
changes[0]);
changes.clear();
EXPECT_TRUE(db.AddFormFieldValueTime(
FormField(string16(),
ASCIIToUTF16("Name"),
ASCIIToUTF16("Superman"),
string16(),
0,
false),
&changes,
t2));
ASSERT_EQ(1U, changes.size());
EXPECT_EQ(AutofillChange(AutofillChange::UPDATE,
AutofillKey(ASCIIToUTF16("Name"),
ASCIIToUTF16("Superman"))),
changes[0]);
}
TEST_F(WebDatabaseTest, Autofill_UpdateOneWithOneTimestamp) {
WebDatabase db;
ASSERT_EQ(sql::INIT_OK, db.Init(file_));
AutofillEntry entry(MakeAutofillEntry("foo", "bar", 1, -1));
std::vector<AutofillEntry> entries;
entries.push_back(entry);
ASSERT_TRUE(db.UpdateAutofillEntries(entries));
FormField field(string16(),
ASCIIToUTF16("foo"),
ASCIIToUTF16("bar"),
string16(),
0,
false);
int64 pair_id;
int count;
ASSERT_TRUE(db.GetIDAndCountOfFormElement(field, &pair_id, &count));
EXPECT_LE(0, pair_id);
EXPECT_EQ(1, count);
std::vector<AutofillEntry> all_entries;
ASSERT_TRUE(db.GetAllAutofillEntries(&all_entries));
ASSERT_EQ(1U, all_entries.size());
EXPECT_TRUE(entry == all_entries[0]);
}
TEST_F(WebDatabaseTest, Autofill_UpdateOneWithTwoTimestamps) {
WebDatabase db;
ASSERT_EQ(sql::INIT_OK, db.Init(file_));
AutofillEntry entry(MakeAutofillEntry("foo", "bar", 1, 2));
std::vector<AutofillEntry> entries;
entries.push_back(entry);
ASSERT_TRUE(db.UpdateAutofillEntries(entries));
FormField field(string16(),
ASCIIToUTF16("foo"),
ASCIIToUTF16("bar"),
string16(),
0,
false);
int64 pair_id;
int count;
ASSERT_TRUE(db.GetIDAndCountOfFormElement(field, &pair_id, &count));
EXPECT_LE(0, pair_id);
EXPECT_EQ(2, count);
std::vector<AutofillEntry> all_entries;
ASSERT_TRUE(db.GetAllAutofillEntries(&all_entries));
ASSERT_EQ(1U, all_entries.size());
EXPECT_TRUE(entry == all_entries[0]);
}
TEST_F(WebDatabaseTest, Autofill_GetAutofillTimestamps) {
WebDatabase db;
ASSERT_EQ(sql::INIT_OK, db.Init(file_));
AutofillEntry entry(MakeAutofillEntry("foo", "bar", 1, 2));
std::vector<AutofillEntry> entries;
entries.push_back(entry);
ASSERT_TRUE(db.UpdateAutofillEntries(entries));
std::vector<base::Time> timestamps;
ASSERT_TRUE(db.GetAutofillTimestamps(ASCIIToUTF16("foo"),
ASCIIToUTF16("bar"),
&timestamps));
ASSERT_EQ(2U, timestamps.size());
EXPECT_TRUE(Time::FromTimeT(1) == timestamps[0]);
EXPECT_TRUE(Time::FromTimeT(2) == timestamps[1]);
}
TEST_F(WebDatabaseTest, Autofill_UpdateTwo) {
WebDatabase db;
ASSERT_EQ(sql::INIT_OK, db.Init(file_));
AutofillEntry entry0(MakeAutofillEntry("foo", "bar0", 1, -1));
AutofillEntry entry1(MakeAutofillEntry("foo", "bar1", 2, 3));
std::vector<AutofillEntry> entries;
entries.push_back(entry0);
entries.push_back(entry1);
ASSERT_TRUE(db.UpdateAutofillEntries(entries));
FormField field0(string16(),
ASCIIToUTF16("foo"),
ASCIIToUTF16("bar0"),
string16(),
0,
false);
int64 pair_id;
int count;
ASSERT_TRUE(db.GetIDAndCountOfFormElement(field0, &pair_id, &count));
EXPECT_LE(0, pair_id);
EXPECT_EQ(1, count);
FormField field1(string16(),
ASCIIToUTF16("foo"),
ASCIIToUTF16("bar1"),
string16(),
0,
false);
ASSERT_TRUE(db.GetIDAndCountOfFormElement(field1, &pair_id, &count));
EXPECT_LE(0, pair_id);
EXPECT_EQ(2, count);
}
TEST_F(WebDatabaseTest, Autofill_UpdateReplace) {
WebDatabase db;
ASSERT_EQ(sql::INIT_OK, db.Init(file_));
AutofillChangeList changes;
// Add a form field. This will be replaced.
EXPECT_TRUE(db.AddFormFieldValue(
FormField(string16(),
ASCIIToUTF16("Name"),
ASCIIToUTF16("Superman"),
string16(),
0,
false),
&changes));
AutofillEntry entry(MakeAutofillEntry("Name", "Superman", 1, 2));
std::vector<AutofillEntry> entries;
entries.push_back(entry);
ASSERT_TRUE(db.UpdateAutofillEntries(entries));
std::vector<AutofillEntry> all_entries;
ASSERT_TRUE(db.GetAllAutofillEntries(&all_entries));
ASSERT_EQ(1U, all_entries.size());
EXPECT_TRUE(entry == all_entries[0]);
}
TEST_F(WebDatabaseTest, Autofill_UpdateDontReplace) {
WebDatabase db;
ASSERT_EQ(sql::INIT_OK, db.Init(file_));
Time t = Time::Now();
AutofillEntry existing(
MakeAutofillEntry("Name", "Superman", t.ToTimeT(), -1));
AutofillChangeList changes;
// Add a form field. This will NOT be replaced.
EXPECT_TRUE(db.AddFormFieldValueTime(
FormField(string16(),
existing.key().name(),
existing.key().value(),
string16(),
0,
false),
&changes,
t));
AutofillEntry entry(MakeAutofillEntry("Name", "Clark Kent", 1, 2));
std::vector<AutofillEntry> entries;
entries.push_back(entry);
ASSERT_TRUE(db.UpdateAutofillEntries(entries));
std::vector<AutofillEntry> all_entries;
ASSERT_TRUE(db.GetAllAutofillEntries(&all_entries));
ASSERT_EQ(2U, all_entries.size());
AutofillEntrySet expected_entries(all_entries.begin(),
all_entries.end(),
CompareAutofillEntries);
EXPECT_EQ(1U, expected_entries.count(existing));
EXPECT_EQ(1U, expected_entries.count(entry));
}
TEST_F(WebDatabaseTest, Autofill_AddFormFieldValues) {
WebDatabase db;
ASSERT_EQ(sql::INIT_OK, db.Init(file_));
Time t = Time::Now();
// Add multiple values for "firstname" and "lastname" names. Test that only
// first value of each gets added. Related to security issue:
// http://crbug.com/51727.
std::vector<FormField> elements;
elements.push_back(FormField(string16(),
ASCIIToUTF16("firstname"),
ASCIIToUTF16("Joe"),
string16(),
0,
false));
elements.push_back(FormField(string16(),
ASCIIToUTF16("firstname"),
ASCIIToUTF16("Jane"),
string16(),
0,
false));
elements.push_back(FormField(string16(),
ASCIIToUTF16("lastname"),
ASCIIToUTF16("Smith"),
string16(),
0,
false));
elements.push_back(FormField(string16(),
ASCIIToUTF16("lastname"),
ASCIIToUTF16("Jones"),
string16(),
0,
false));
std::vector<AutofillChange> changes;
db.AddFormFieldValuesTime(elements, &changes, t);
ASSERT_EQ(2U, changes.size());
EXPECT_EQ(changes[0], AutofillChange(AutofillChange::ADD,
AutofillKey(ASCIIToUTF16("firstname"),
ASCIIToUTF16("Joe"))));
EXPECT_EQ(changes[1], AutofillChange(AutofillChange::ADD,
AutofillKey(ASCIIToUTF16("lastname"),
ASCIIToUTF16("Smith"))));
std::vector<AutofillEntry> all_entries;
ASSERT_TRUE(db.GetAllAutofillEntries(&all_entries));
ASSERT_EQ(2U, all_entries.size());
}
static bool AddTimestampedLogin(WebDatabase* db, std::string url,
const std::string& unique_string,
const Time& time) {
// Example password form.
PasswordForm form;
form.origin = GURL(url + std::string("/LoginAuth"));
form.username_element = ASCIIToUTF16(unique_string);
form.username_value = ASCIIToUTF16(unique_string);
form.password_element = ASCIIToUTF16(unique_string);
form.submit_element = ASCIIToUTF16("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;
ASSERT_EQ(sql::INIT_OK, db.Init(file_));
std::vector<PasswordForm*> result;
// Verify the database is empty.
EXPECT_TRUE(db.GetAllLogins(&result, true));
EXPECT_EQ(0U, result.size());
Time now = Time::Now();
TimeDelta one_day = TimeDelta::FromDays(1);
// Create one with a 0 time.
EXPECT_TRUE(AddTimestampedLogin(&db, "1", "foo1", Time()));
// Create one for now and +/- 1 day.
EXPECT_TRUE(AddTimestampedLogin(&db, "2", "foo2", now - one_day));
EXPECT_TRUE(AddTimestampedLogin(&db, "3", "foo3", now));
EXPECT_TRUE(AddTimestampedLogin(&db, "4", "foo4", now + one_day));
// Verify inserts worked.
EXPECT_TRUE(db.GetAllLogins(&result, true));
EXPECT_EQ(4U, 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(2U, 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(0U, result.size());
}
TEST_F(WebDatabaseTest, BlacklistedLogins) {
WebDatabase db;
ASSERT_EQ(sql::INIT_OK, db.Init(file_));
std::vector<PasswordForm*> result;
// Verify the database is empty.
EXPECT_TRUE(db.GetAllLogins(&result, true));
ASSERT_EQ(0U, result.size());
// Save a form as blacklisted.
PasswordForm form;
form.origin = GURL("http://www.google.com/accounts/LoginAuth");
form.action = GURL("http://www.google.com/accounts/Login");
form.username_element = ASCIIToUTF16("Email");
form.password_element = ASCIIToUTF16("Passwd");
form.submit_element = ASCIIToUTF16("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(0U, result.size());
// GetLogins should give the blacklisted result.
EXPECT_TRUE(db.GetLogins(form, &result));
EXPECT_EQ(1U, result.size());
ClearResults(&result);
// So should GetAll including blacklisted.
EXPECT_TRUE(db.GetAllLogins(&result, true));
EXPECT_EQ(1U, result.size());
ClearResults(&result);
}
TEST_F(WebDatabaseTest, WebAppHasAllImages) {
WebDatabase db;
ASSERT_EQ(sql::INIT_OK, 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_EQ(sql::INIT_OK, 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(0U, 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(1U, 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);
// Set some random pixels so that we can identify the image. We don't use
// transparent images because of pre-multiplication rounding errors.
SkColor test_pixel_1 = 0xffccbbaa;
SkColor test_pixel_2 = 0xffaabbaa;
SkColor test_pixel_3 = 0xff339966;
image.getAddr32(0, 1)[0] = test_pixel_1;
image.getAddr32(0, 1)[1] = test_pixel_2;
image.getAddr32(0, 1)[2] = test_pixel_3;
ASSERT_TRUE(db.SetWebAppImage(url, image));
images.clear();
ASSERT_TRUE(db.GetWebAppImages(url, &images));
ASSERT_EQ(1U, images.size());
ASSERT_EQ(16, images[0].width());
ASSERT_EQ(16, images[0].height());
images[0].lockPixels();
ASSERT_TRUE(images[0].getPixels() != NULL);
ASSERT_EQ(test_pixel_1, images[0].getAddr32(0, 1)[0]);
ASSERT_EQ(test_pixel_2, images[0].getAddr32(0, 1)[1]);
ASSERT_EQ(test_pixel_3, images[0].getAddr32(0, 1)[2]);
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(2U, 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());
}
}
TEST_F(WebDatabaseTest, TokenServiceGetAllRemoveAll) {
WebDatabase db;
ASSERT_EQ(sql::INIT_OK, db.Init(file_));
std::map<std::string, std::string> out_map;
std::string service;
std::string service2;
service = "testservice";
service2 = "othertestservice";
EXPECT_TRUE(db.GetAllTokens(&out_map));
EXPECT_TRUE(out_map.empty());
// Check that get all tokens works
EXPECT_TRUE(db.SetTokenForService(service, "pepperoni"));
EXPECT_TRUE(db.SetTokenForService(service2, "steak"));
EXPECT_TRUE(db.GetAllTokens(&out_map));
EXPECT_EQ(out_map.find(service)->second, "pepperoni");
EXPECT_EQ(out_map.find(service2)->second, "steak");
out_map.clear();
// Purge
EXPECT_TRUE(db.RemoveAllTokens());
EXPECT_TRUE(db.GetAllTokens(&out_map));
EXPECT_TRUE(out_map.empty());
// Check that you can still add it back in
EXPECT_TRUE(db.SetTokenForService(service, "cheese"));
EXPECT_TRUE(db.GetAllTokens(&out_map));
EXPECT_EQ(out_map.find(service)->second, "cheese");
}
TEST_F(WebDatabaseTest, TokenServiceGetSet) {
WebDatabase db;
ASSERT_EQ(sql::INIT_OK, db.Init(file_));
std::map<std::string, std::string> out_map;
std::string service;
service = "testservice";
EXPECT_TRUE(db.GetAllTokens(&out_map));
EXPECT_TRUE(out_map.empty());
EXPECT_TRUE(db.SetTokenForService(service, "pepperoni"));
EXPECT_TRUE(db.GetAllTokens(&out_map));
EXPECT_EQ(out_map.find(service)->second, "pepperoni");
out_map.clear();
// try blanking it - won't remove it from the db though!
EXPECT_TRUE(db.SetTokenForService(service, ""));
EXPECT_TRUE(db.GetAllTokens(&out_map));
EXPECT_EQ(out_map.find(service)->second, "");
out_map.clear();
// try mutating it
EXPECT_TRUE(db.SetTokenForService(service, "ham"));
EXPECT_TRUE(db.GetAllTokens(&out_map));
EXPECT_EQ(out_map.find(service)->second, "ham");
}
TEST_F(WebDatabaseTest, AutoFillProfile) {
WebDatabase db;
ASSERT_EQ(sql::INIT_OK, db.Init(file_));
// Add a 'Home' profile.
AutoFillProfile home_profile;
home_profile.set_label(ASCIIToUTF16("Home"));
home_profile.SetInfo(AutoFillType(NAME_FIRST), ASCIIToUTF16("John"));
home_profile.SetInfo(AutoFillType(NAME_MIDDLE), ASCIIToUTF16("Q."));
home_profile.SetInfo(AutoFillType(NAME_LAST), ASCIIToUTF16("Smith"));
home_profile.SetInfo(AutoFillType(EMAIL_ADDRESS),
ASCIIToUTF16("js@smith.xyz"));
home_profile.SetInfo(AutoFillType(COMPANY_NAME), ASCIIToUTF16("Google"));
home_profile.SetInfo(AutoFillType(ADDRESS_HOME_LINE1),
ASCIIToUTF16("1234 Apple Way"));
home_profile.SetInfo(AutoFillType(ADDRESS_HOME_LINE2),
ASCIIToUTF16("unit 5"));
home_profile.SetInfo(AutoFillType(ADDRESS_HOME_CITY),
ASCIIToUTF16("Los Angeles"));
home_profile.SetInfo(AutoFillType(ADDRESS_HOME_STATE), ASCIIToUTF16("CA"));
home_profile.SetInfo(AutoFillType(ADDRESS_HOME_ZIP), ASCIIToUTF16("90025"));
home_profile.SetInfo(AutoFillType(ADDRESS_HOME_COUNTRY), ASCIIToUTF16("US"));
home_profile.SetInfo(AutoFillType(PHONE_HOME_WHOLE_NUMBER),
ASCIIToUTF16("18181234567"));
home_profile.SetInfo(AutoFillType(PHONE_FAX_WHOLE_NUMBER),
ASCIIToUTF16("1915243678"));
Time pre_creation_time = Time::Now();
EXPECT_TRUE(db.AddAutoFillProfile(home_profile));
Time post_creation_time = Time::Now();
// Get the 'Home' profile.
AutoFillProfile* db_profile;
ASSERT_TRUE(db.GetAutoFillProfileForLabel(ASCIIToUTF16("Home"), &db_profile));
EXPECT_EQ(home_profile, *db_profile);
sql::Statement s_home(db.db_.GetUniqueStatement(
"SELECT date_modified "
"FROM autofill_profiles WHERE label='Home'"));
ASSERT_TRUE(s_home);
ASSERT_TRUE(s_home.Step());
EXPECT_GE(s_home.ColumnInt64(0), pre_creation_time.ToTimeT());
EXPECT_LE(s_home.ColumnInt64(0), post_creation_time.ToTimeT());
EXPECT_FALSE(s_home.Step());
delete db_profile;
// Add a 'Billing' profile.
AutoFillProfile billing_profile = home_profile;
billing_profile.set_label(ASCIIToUTF16("Billing"));
billing_profile.SetInfo(AutoFillType(ADDRESS_HOME_LINE1),
ASCIIToUTF16("5678 Bottom Street"));
billing_profile.SetInfo(AutoFillType(ADDRESS_HOME_LINE2),
ASCIIToUTF16("suite 3"));
billing_profile.set_guid(guid::GenerateGUID());
pre_creation_time = Time::Now();
EXPECT_TRUE(db.AddAutoFillProfile(billing_profile));
post_creation_time = Time::Now();
// Get the 'Billing' profile.
ASSERT_TRUE(db.GetAutoFillProfileForLabel(ASCIIToUTF16("Billing"),
&db_profile));
EXPECT_EQ(billing_profile, *db_profile);
sql::Statement s_billing(db.db_.GetUniqueStatement(
"SELECT date_modified FROM autofill_profiles WHERE label='Billing'"));
ASSERT_TRUE(s_billing);
ASSERT_TRUE(s_billing.Step());
EXPECT_GE(s_billing.ColumnInt64(0), pre_creation_time.ToTimeT());
EXPECT_LE(s_billing.ColumnInt64(0), post_creation_time.ToTimeT());
EXPECT_FALSE(s_billing.Step());
delete db_profile;
// Update the 'Billing' profile.
billing_profile.SetInfo(AutoFillType(NAME_FIRST), ASCIIToUTF16("Jane"));
Time pre_modification_time = Time::Now();
EXPECT_TRUE(db.UpdateAutoFillProfile(billing_profile));
Time post_modification_time = Time::Now();
ASSERT_TRUE(db.GetAutoFillProfileForLabel(ASCIIToUTF16("Billing"),
&db_profile));
EXPECT_EQ(billing_profile, *db_profile);
sql::Statement s_billing_updated(db.db_.GetUniqueStatement(
"SELECT date_modified FROM autofill_profiles WHERE label='Billing'"));
ASSERT_TRUE(s_billing_updated);
ASSERT_TRUE(s_billing_updated.Step());
EXPECT_GE(s_billing_updated.ColumnInt64(0),
pre_modification_time.ToTimeT());
EXPECT_LE(s_billing_updated.ColumnInt64(0),
post_modification_time.ToTimeT());
EXPECT_FALSE(s_billing_updated.Step());
delete db_profile;
// Remove the 'Billing' profile.
EXPECT_TRUE(db.RemoveAutoFillProfile(billing_profile.guid()));
EXPECT_FALSE(db.GetAutoFillProfileForLabel(ASCIIToUTF16("Billing"),
&db_profile));
// Add a 'GUID' profile.
AutoFillProfile guid_profile = home_profile;
guid_profile.set_label(ASCIIToUTF16("GUID"));
guid_profile.SetInfo(AutoFillType(ADDRESS_HOME_LINE1),
ASCIIToUTF16("5678 Top Street"));
guid_profile.SetInfo(AutoFillType(ADDRESS_HOME_LINE2),
ASCIIToUTF16("suite 4"));
guid_profile.set_guid(guid::GenerateGUID());
EXPECT_TRUE(db.AddAutoFillProfile(guid_profile));
ASSERT_TRUE(db.GetAutoFillProfileForGUID(guid_profile.guid(),
&db_profile));
EXPECT_EQ(guid_profile, *db_profile);
delete db_profile;
// Update the 'GUID' profile.
guid_profile.SetInfo(AutoFillType(NAME_FIRST), ASCIIToUTF16("Jimmy"));
EXPECT_TRUE(db.UpdateAutoFillProfile(guid_profile));
ASSERT_TRUE(db.GetAutoFillProfileForGUID(guid_profile.guid(),
&db_profile));
EXPECT_EQ(guid_profile, *db_profile);
delete db_profile;
// Remove the 'GUID' profile.
EXPECT_TRUE(db.RemoveAutoFillProfile(guid_profile.guid()));
EXPECT_FALSE(db.GetAutoFillProfileForGUID(guid_profile.guid(),
&db_profile));
}
TEST_F(WebDatabaseTest, CreditCard) {
WebDatabase db;
ASSERT_EQ(sql::INIT_OK, db.Init(file_));
// Add a 'Work' credit card.
CreditCard work_creditcard;
work_creditcard.set_label(ASCIIToUTF16("Work"));
work_creditcard.SetInfo(AutoFillType(CREDIT_CARD_NAME),
ASCIIToUTF16("Jack Torrance"));
work_creditcard.SetInfo(AutoFillType(CREDIT_CARD_NUMBER),
ASCIIToUTF16("1234567890123456"));
work_creditcard.SetInfo(AutoFillType(CREDIT_CARD_EXP_MONTH),
ASCIIToUTF16("04"));
work_creditcard.SetInfo(AutoFillType(CREDIT_CARD_EXP_4_DIGIT_YEAR),
ASCIIToUTF16("2013"));
Time pre_creation_time = Time::Now();
EXPECT_TRUE(db.AddCreditCard(work_creditcard));
Time post_creation_time = Time::Now();
// Get the 'Work' credit card.
CreditCard* db_creditcard;
ASSERT_TRUE(db.GetCreditCardForLabel(ASCIIToUTF16("Work"), &db_creditcard));
EXPECT_EQ(work_creditcard, *db_creditcard);
sql::Statement s_work(db.db_.GetUniqueStatement(
"SELECT guid, label, name_on_card, expiration_month, expiration_year, "
"card_number_encrypted, date_modified "
"FROM credit_cards WHERE label='Work'"));
ASSERT_TRUE(s_work);
ASSERT_TRUE(s_work.Step());
EXPECT_GE(s_work.ColumnInt64(6), pre_creation_time.ToTimeT());
EXPECT_LE(s_work.ColumnInt64(6), post_creation_time.ToTimeT());
EXPECT_FALSE(s_work.Step());
delete db_creditcard;
// Add a 'Target' credit card.
CreditCard target_creditcard;
target_creditcard.set_label(ASCIIToUTF16("Target"));
target_creditcard.SetInfo(AutoFillType(CREDIT_CARD_NAME),
ASCIIToUTF16("Jack Torrance"));
target_creditcard.SetInfo(AutoFillType(CREDIT_CARD_NUMBER),
ASCIIToUTF16("1111222233334444"));
target_creditcard.SetInfo(AutoFillType(CREDIT_CARD_EXP_MONTH),
ASCIIToUTF16("06"));
target_creditcard.SetInfo(AutoFillType(CREDIT_CARD_EXP_4_DIGIT_YEAR),
ASCIIToUTF16("2012"));
pre_creation_time = Time::Now();
EXPECT_TRUE(db.AddCreditCard(target_creditcard));
post_creation_time = Time::Now();
ASSERT_TRUE(db.GetCreditCardForLabel(ASCIIToUTF16("Target"),
&db_creditcard));
EXPECT_EQ(target_creditcard, *db_creditcard);
sql::Statement s_target(db.db_.GetUniqueStatement(
"SELECT guid, label, name_on_card, expiration_month, expiration_year, "
"card_number_encrypted, date_modified "
"FROM credit_cards WHERE label='Target'"));
ASSERT_TRUE(s_target);
ASSERT_TRUE(s_target.Step());
EXPECT_GE(s_target.ColumnInt64(6), pre_creation_time.ToTimeT());
EXPECT_LE(s_target.ColumnInt64(6), post_creation_time.ToTimeT());
EXPECT_FALSE(s_target.Step());
delete db_creditcard;
// Update the 'Target' credit card.
target_creditcard.SetInfo(AutoFillType(CREDIT_CARD_NAME),
ASCIIToUTF16("Charles Grady"));
Time pre_modification_time = Time::Now();
EXPECT_TRUE(db.UpdateCreditCard(target_creditcard));
Time post_modification_time = Time::Now();
ASSERT_TRUE(db.GetCreditCardForLabel(ASCIIToUTF16("Target"), &db_creditcard));
EXPECT_EQ(target_creditcard, *db_creditcard);
sql::Statement s_target_updated(db.db_.GetUniqueStatement(
"SELECT guid, label, name_on_card, expiration_month, expiration_year, "
"card_number_encrypted, date_modified "
"FROM credit_cards WHERE label='Target'"));
ASSERT_TRUE(s_target_updated);
ASSERT_TRUE(s_target_updated.Step());
EXPECT_GE(s_target_updated.ColumnInt64(6),
pre_modification_time.ToTimeT());
EXPECT_LE(s_target_updated.ColumnInt64(6),
post_modification_time.ToTimeT());
EXPECT_FALSE(s_target_updated.Step());
delete db_creditcard;
// Remove the 'Target' credit card.
EXPECT_TRUE(db.RemoveCreditCard(target_creditcard.guid()));
EXPECT_FALSE(db.GetCreditCardForLabel(ASCIIToUTF16("Target"),
&db_creditcard));
// Add a 'GUID' profile.
CreditCard guid_creditcard;
guid_creditcard.set_label(ASCIIToUTF16("GUID"));
guid_creditcard.SetInfo(AutoFillType(CREDIT_CARD_NAME),
ASCIIToUTF16("Jimmy Jones"));
guid_creditcard.SetInfo(AutoFillType(CREDIT_CARD_NUMBER),
ASCIIToUTF16("9999222233334444"));
guid_creditcard.SetInfo(AutoFillType(CREDIT_CARD_EXP_MONTH),
ASCIIToUTF16("07"));
guid_creditcard.SetInfo(AutoFillType(CREDIT_CARD_EXP_4_DIGIT_YEAR),
ASCIIToUTF16("2013"));
EXPECT_TRUE(db.AddCreditCard(guid_creditcard));
ASSERT_TRUE(db.GetCreditCardForGUID(guid_creditcard.guid(),
&db_creditcard));
EXPECT_EQ(guid_creditcard, *db_creditcard);
delete db_creditcard;
// Update the 'GUID' profile.
guid_creditcard.SetInfo(AutoFillType(CREDIT_CARD_NAME),
ASCIIToUTF16("Jimmy Grady"));
EXPECT_TRUE(db.UpdateCreditCard(guid_creditcard));
ASSERT_TRUE(db.GetCreditCardForGUID(guid_creditcard.guid(), &db_creditcard));
EXPECT_EQ(guid_creditcard, *db_creditcard);
delete db_creditcard;
// Remove the 'GUID' profile.
EXPECT_TRUE(db.RemoveCreditCard(guid_creditcard.guid()));
EXPECT_FALSE(db.GetCreditCardForGUID(guid_creditcard.guid(),
&db_creditcard));
}
TEST_F(WebDatabaseTest, UpdateAutoFillProfile) {
WebDatabase db;
ASSERT_EQ(sql::INIT_OK, db.Init(file_));
// Add a profile to the db.
AutoFillProfile profile;
profile.set_label(ASCIIToUTF16("Test Profile"));
profile.SetInfo(AutoFillType(NAME_FIRST), ASCIIToUTF16("John"));
profile.SetInfo(AutoFillType(NAME_MIDDLE), ASCIIToUTF16("Q."));
profile.SetInfo(AutoFillType(NAME_LAST), ASCIIToUTF16("Smith"));
profile.SetInfo(AutoFillType(EMAIL_ADDRESS), ASCIIToUTF16("js@example.com"));
profile.SetInfo(AutoFillType(COMPANY_NAME), ASCIIToUTF16("Google"));
profile.SetInfo(AutoFillType(ADDRESS_HOME_LINE1),
ASCIIToUTF16("1234 Apple Way"));
profile.SetInfo(AutoFillType(ADDRESS_HOME_LINE2), ASCIIToUTF16("unit 5"));
profile.SetInfo(AutoFillType(ADDRESS_HOME_CITY), ASCIIToUTF16("Los Angeles"));
profile.SetInfo(AutoFillType(ADDRESS_HOME_STATE), ASCIIToUTF16("CA"));
profile.SetInfo(AutoFillType(ADDRESS_HOME_ZIP), ASCIIToUTF16("90025"));
profile.SetInfo(AutoFillType(ADDRESS_HOME_COUNTRY), ASCIIToUTF16("US"));
profile.SetInfo(AutoFillType(PHONE_HOME_WHOLE_NUMBER),
ASCIIToUTF16("18181234567"));
profile.SetInfo(AutoFillType(PHONE_FAX_WHOLE_NUMBER),
ASCIIToUTF16("1915243678"));
db.AddAutoFillProfile(profile);
// Set a mocked value for the profile's creation time.
const time_t mock_creation_date = Time::Now().ToTimeT() - 13;
sql::Statement s_mock_creation_date(db.db_.GetUniqueStatement(
"UPDATE autofill_profiles SET date_modified = ?"));
ASSERT_TRUE(s_mock_creation_date);
s_mock_creation_date.BindInt64(0, mock_creation_date);
ASSERT_TRUE(s_mock_creation_date.Run());
// Get the profile.
AutoFillProfile* tmp_profile;
ASSERT_TRUE(db.GetAutoFillProfileForGUID(profile.guid(), &tmp_profile));
scoped_ptr<AutoFillProfile> db_profile(tmp_profile);
EXPECT_EQ(profile, *db_profile);
sql::Statement s_original(db.db_.GetUniqueStatement(
"SELECT date_modified FROM autofill_profiles"));
ASSERT_TRUE(s_original);
ASSERT_TRUE(s_original.Step());
EXPECT_EQ(mock_creation_date, s_original.ColumnInt64(0));
EXPECT_FALSE(s_original.Step());
// Now, update the profile and save the update to the database.
// The modification date should change to reflect the update.
profile.SetInfo(AutoFillType(EMAIL_ADDRESS), ASCIIToUTF16("js@smith.xyz"));
db.UpdateAutoFillProfile(profile);
// Get the profile.
ASSERT_TRUE(db.GetAutoFillProfileForGUID(profile.guid(), &tmp_profile));
db_profile.reset(tmp_profile);
EXPECT_EQ(profile, *db_profile);
sql::Statement s_updated(db.db_.GetUniqueStatement(
"SELECT date_modified FROM autofill_profiles"));
ASSERT_TRUE(s_updated);
ASSERT_TRUE(s_updated.Step());
EXPECT_LT(mock_creation_date, s_updated.ColumnInt64(0));
EXPECT_FALSE(s_updated.Step());
// Set a mocked value for the profile's modification time.
const time_t mock_modification_date = Time::Now().ToTimeT() - 7;
sql::Statement s_mock_modification_date(db.db_.GetUniqueStatement(
"UPDATE autofill_profiles SET date_modified = ?"));
ASSERT_TRUE(s_mock_modification_date);
s_mock_modification_date.BindInt64(0, mock_modification_date);
ASSERT_TRUE(s_mock_modification_date.Run());
// Finally, call into |UpdateAutoFillProfile()| without changing the profile.
// The modification date should not change.
db.UpdateAutoFillProfile(profile);
// Get the profile.
ASSERT_TRUE(db.GetAutoFillProfileForGUID(profile.guid(), &tmp_profile));
db_profile.reset(tmp_profile);
EXPECT_EQ(profile, *db_profile);
sql::Statement s_unchanged(db.db_.GetUniqueStatement(
"SELECT date_modified FROM autofill_profiles"));
ASSERT_TRUE(s_unchanged);
ASSERT_TRUE(s_unchanged.Step());
EXPECT_EQ(mock_modification_date, s_unchanged.ColumnInt64(0));
EXPECT_FALSE(s_unchanged.Step());
}
TEST_F(WebDatabaseTest, UpdateCreditCard) {
WebDatabase db;
ASSERT_EQ(sql::INIT_OK, db.Init(file_));
// Add a credit card to the db.
CreditCard credit_card;
credit_card.set_label(ASCIIToUTF16("Test Credit Card"));
credit_card.SetInfo(AutoFillType(CREDIT_CARD_NAME),
ASCIIToUTF16("Jack Torrance"));
credit_card.SetInfo(AutoFillType(CREDIT_CARD_NUMBER),
ASCIIToUTF16("1234567890123456"));
credit_card.SetInfo(AutoFillType(CREDIT_CARD_EXP_MONTH),
ASCIIToUTF16("04"));
credit_card.SetInfo(AutoFillType(CREDIT_CARD_EXP_4_DIGIT_YEAR),
ASCIIToUTF16("2013"));
db.AddCreditCard(credit_card);
// Set a mocked value for the credit card's creation time.
const time_t mock_creation_date = Time::Now().ToTimeT() - 13;
sql::Statement s_mock_creation_date(db.db_.GetUniqueStatement(
"UPDATE credit_cards SET date_modified = ?"));
ASSERT_TRUE(s_mock_creation_date);
s_mock_creation_date.BindInt64(0, mock_creation_date);
ASSERT_TRUE(s_mock_creation_date.Run());
// Get the credit card.
CreditCard* tmp_credit_card;
ASSERT_TRUE(db.GetCreditCardForGUID(credit_card.guid(), &tmp_credit_card));
scoped_ptr<CreditCard> db_credit_card(tmp_credit_card);
EXPECT_EQ(credit_card, *db_credit_card);
sql::Statement s_original(db.db_.GetUniqueStatement(
"SELECT date_modified FROM credit_cards"));
ASSERT_TRUE(s_original);
ASSERT_TRUE(s_original.Step());
EXPECT_EQ(mock_creation_date, s_original.ColumnInt64(0));
EXPECT_FALSE(s_original.Step());
// Now, update the credit card and save the update to the database.
// The modification date should change to reflect the update.
credit_card.SetInfo(AutoFillType(CREDIT_CARD_EXP_MONTH), ASCIIToUTF16("01"));
db.UpdateCreditCard(credit_card);
// Get the credit card.
ASSERT_TRUE(db.GetCreditCardForGUID(credit_card.guid(), &tmp_credit_card));
db_credit_card.reset(tmp_credit_card);
EXPECT_EQ(credit_card, *db_credit_card);
sql::Statement s_updated(db.db_.GetUniqueStatement(
"SELECT date_modified FROM credit_cards"));
ASSERT_TRUE(s_updated);
ASSERT_TRUE(s_updated.Step());
EXPECT_LT(mock_creation_date, s_updated.ColumnInt64(0));
EXPECT_FALSE(s_updated.Step());
// Set a mocked value for the credit card's modification time.
const time_t mock_modification_date = Time::Now().ToTimeT() - 7;
sql::Statement s_mock_modification_date(db.db_.GetUniqueStatement(
"UPDATE credit_cards SET date_modified = ?"));
ASSERT_TRUE(s_mock_modification_date);
s_mock_modification_date.BindInt64(0, mock_modification_date);
ASSERT_TRUE(s_mock_modification_date.Run());
// Finally, call into |UpdateCreditCard()| without changing the credit card.
// The modification date should not change.
db.UpdateCreditCard(credit_card);
// Get the profile.
ASSERT_TRUE(db.GetCreditCardForGUID(credit_card.guid(), &tmp_credit_card));
db_credit_card.reset(tmp_credit_card);
EXPECT_EQ(credit_card, *db_credit_card);
sql::Statement s_unchanged(db.db_.GetUniqueStatement(
"SELECT date_modified FROM credit_cards"));
ASSERT_TRUE(s_unchanged);
ASSERT_TRUE(s_unchanged.Step());
EXPECT_EQ(mock_modification_date, s_unchanged.ColumnInt64(0));
EXPECT_FALSE(s_unchanged.Step());
}
TEST_F(WebDatabaseTest, RemoveAutoFillProfilesAndCreditCardsModifiedBetween) {
WebDatabase db;
ASSERT_EQ(sql::INIT_OK, db.Init(file_));
// Populate the autofill_profiles and credit_cards tables.
ASSERT_TRUE(db.db_.Execute(
"INSERT INTO autofill_profiles (guid, date_modified) "
"VALUES('00000000-0000-0000-0000-000000000000', 11);"
"INSERT INTO autofill_profiles (guid, date_modified) "
"VALUES('00000000-0000-0000-0000-000000000001', 21);"
"INSERT INTO autofill_profiles (guid, date_modified) "
"VALUES('00000000-0000-0000-0000-000000000002', 31);"
"INSERT INTO autofill_profiles (guid, date_modified) "
"VALUES('00000000-0000-0000-0000-000000000003', 41);"
"INSERT INTO autofill_profiles (guid, date_modified) "
"VALUES('00000000-0000-0000-0000-000000000004', 51);"
"INSERT INTO autofill_profiles (guid, date_modified) "
"VALUES('00000000-0000-0000-0000-000000000005', 61);"
"INSERT INTO credit_cards (guid, date_modified) "
"VALUES('00000000-0000-0000-0000-000000000006', 17);"
"INSERT INTO credit_cards (guid, date_modified) "
"VALUES('00000000-0000-0000-0000-000000000007', 27);"
"INSERT INTO credit_cards (guid, date_modified) "
"VALUES('00000000-0000-0000-0000-000000000008', 37);"
"INSERT INTO credit_cards (guid, date_modified) "
"VALUES('00000000-0000-0000-0000-000000000009', 47);"
"INSERT INTO credit_cards (guid, date_modified) "
"VALUES('00000000-0000-0000-0000-000000000010', 57);"
"INSERT INTO credit_cards (guid, date_modified) "
"VALUES('00000000-0000-0000-0000-000000000011', 67);"));
// Remove all entries modified in the bounded time range [17,41).
db.RemoveAutoFillProfilesAndCreditCardsModifiedBetween(
base::Time::FromTimeT(17), base::Time::FromTimeT(41));
sql::Statement s_autofill_profiles_bounded(db.db_.GetUniqueStatement(
"SELECT date_modified FROM autofill_profiles"));
ASSERT_TRUE(s_autofill_profiles_bounded);
ASSERT_TRUE(s_autofill_profiles_bounded.Step());
EXPECT_EQ(11, s_autofill_profiles_bounded.ColumnInt64(0));
ASSERT_TRUE(s_autofill_profiles_bounded.Step());
EXPECT_EQ(41, s_autofill_profiles_bounded.ColumnInt64(0));
ASSERT_TRUE(s_autofill_profiles_bounded.Step());
EXPECT_EQ(51, s_autofill_profiles_bounded.ColumnInt64(0));
ASSERT_TRUE(s_autofill_profiles_bounded.Step());
EXPECT_EQ(61, s_autofill_profiles_bounded.ColumnInt64(0));
EXPECT_FALSE(s_autofill_profiles_bounded.Step());
sql::Statement s_credit_cards_bounded(db.db_.GetUniqueStatement(
"SELECT date_modified FROM credit_cards"));
ASSERT_TRUE(s_credit_cards_bounded);
ASSERT_TRUE(s_credit_cards_bounded.Step());
EXPECT_EQ(47, s_credit_cards_bounded.ColumnInt64(0));
ASSERT_TRUE(s_credit_cards_bounded.Step());
EXPECT_EQ(57, s_credit_cards_bounded.ColumnInt64(0));
ASSERT_TRUE(s_credit_cards_bounded.Step());
EXPECT_EQ(67, s_credit_cards_bounded.ColumnInt64(0));
EXPECT_FALSE(s_credit_cards_bounded.Step());
// Remove all entries modified on or after time 51 (unbounded range).
db.RemoveAutoFillProfilesAndCreditCardsModifiedBetween(
base::Time::FromTimeT(51), base::Time());
sql::Statement s_autofill_profiles_unbounded(db.db_.GetUniqueStatement(
"SELECT date_modified FROM autofill_profiles"));
ASSERT_TRUE(s_autofill_profiles_unbounded);
ASSERT_TRUE(s_autofill_profiles_unbounded.Step());
EXPECT_EQ(11, s_autofill_profiles_unbounded.ColumnInt64(0));
ASSERT_TRUE(s_autofill_profiles_unbounded.Step());
EXPECT_EQ(41, s_autofill_profiles_unbounded.ColumnInt64(0));
EXPECT_FALSE(s_autofill_profiles_unbounded.Step());
sql::Statement s_credit_cards_unbounded(db.db_.GetUniqueStatement(
"SELECT date_modified FROM credit_cards"));
ASSERT_TRUE(s_credit_cards_unbounded);
ASSERT_TRUE(s_credit_cards_unbounded.Step());
EXPECT_EQ(47, s_credit_cards_unbounded.ColumnInt64(0));
EXPECT_FALSE(s_credit_cards_unbounded.Step());
// Remove all remaining entries.
db.RemoveAutoFillProfilesAndCreditCardsModifiedBetween(base::Time(),
base::Time());
sql::Statement s_autofill_profiles_empty(db.db_.GetUniqueStatement(
"SELECT date_modified FROM autofill_profiles"));
ASSERT_TRUE(s_autofill_profiles_empty);
EXPECT_FALSE(s_autofill_profiles_empty.Step());
sql::Statement s_credit_cards_empty(db.db_.GetUniqueStatement(
"SELECT date_modified FROM credit_cards"));
ASSERT_TRUE(s_credit_cards_empty);
EXPECT_FALSE(s_credit_cards_empty.Step());
}
TEST_F(WebDatabaseTest, Autofill_GetAllAutofillEntries_NoResults) {
WebDatabase db;
ASSERT_EQ(sql::INIT_OK, db.Init(file_));
std::vector<AutofillEntry> entries;
ASSERT_TRUE(db.GetAllAutofillEntries(&entries));
EXPECT_EQ(0U, entries.size());
}
TEST_F(WebDatabaseTest, Autofill_GetAllAutofillEntries_OneResult) {
WebDatabase db;
ASSERT_EQ(sql::INIT_OK, db.Init(file_));
AutofillChangeList changes;
std::map<std::string, std::vector<base::Time> > name_value_times_map;
time_t start = 0;
std::vector<base::Time> timestamps1;
EXPECT_TRUE(db.AddFormFieldValueTime(
FormField(string16(),
ASCIIToUTF16("Name"),
ASCIIToUTF16("Superman"),
string16(),
0,
false),
&changes,
Time::FromTimeT(start)));
timestamps1.push_back(Time::FromTimeT(start));
std::string key1("NameSuperman");
name_value_times_map.insert(std::pair<std::string,
std::vector<base::Time> > (key1, timestamps1));
AutofillEntrySet expected_entries(CompareAutofillEntries);
AutofillKey ak1(ASCIIToUTF16("Name"), ASCIIToUTF16("Superman"));
AutofillEntry ae1(ak1, timestamps1);
expected_entries.insert(ae1);
std::vector<AutofillEntry> entries;
ASSERT_TRUE(db.GetAllAutofillEntries(&entries));
AutofillEntrySet entry_set(entries.begin(), entries.end(),
CompareAutofillEntries);
// make sure the lists of entries match
ASSERT_EQ(expected_entries.size(), entry_set.size());
AutofillEntrySetIterator it;
for (it = entry_set.begin(); it != entry_set.end(); it++) {
expected_entries.erase(*it);
}
EXPECT_EQ(0U, expected_entries.size());
}
TEST_F(WebDatabaseTest, Autofill_GetAllAutofillEntries_TwoDistinct) {
WebDatabase db;
ASSERT_EQ(sql::INIT_OK, db.Init(file_));
AutofillChangeList changes;
std::map<std::string, std::vector<base::Time> > name_value_times_map;
time_t start = 0;
std::vector<base::Time> timestamps1;
EXPECT_TRUE(db.AddFormFieldValueTime(
FormField(string16(),
ASCIIToUTF16("Name"),
ASCIIToUTF16("Superman"),
string16(),
0,
false),
&changes,
Time::FromTimeT(start)));
timestamps1.push_back(Time::FromTimeT(start));
std::string key1("NameSuperman");
name_value_times_map.insert(std::pair<std::string,
std::vector<base::Time> > (key1, timestamps1));
start++;
std::vector<base::Time> timestamps2;
EXPECT_TRUE(db.AddFormFieldValueTime(
FormField(string16(),
ASCIIToUTF16("Name"),
ASCIIToUTF16("Clark Kent"),
string16(),
0,
false),
&changes,
Time::FromTimeT(start)));
timestamps2.push_back(Time::FromTimeT(start));
std::string key2("NameClark Kent");
name_value_times_map.insert(std::pair<std::string,
std::vector<base::Time> > (key2, timestamps2));
AutofillEntrySet expected_entries(CompareAutofillEntries);
AutofillKey ak1(ASCIIToUTF16("Name"), ASCIIToUTF16("Superman"));
AutofillKey ak2(ASCIIToUTF16("Name"), ASCIIToUTF16("Clark Kent"));
AutofillEntry ae1(ak1, timestamps1);
AutofillEntry ae2(ak2, timestamps2);
expected_entries.insert(ae1);
expected_entries.insert(ae2);
std::vector<AutofillEntry> entries;
ASSERT_TRUE(db.GetAllAutofillEntries(&entries));
AutofillEntrySet entry_set(entries.begin(), entries.end(),
CompareAutofillEntries);
// make sure the lists of entries match
ASSERT_EQ(expected_entries.size(), entry_set.size());
AutofillEntrySetIterator it;
for (it = entry_set.begin(); it != entry_set.end(); it++) {
expected_entries.erase(*it);
}
EXPECT_EQ(0U, expected_entries.size());
}
TEST_F(WebDatabaseTest, Autofill_GetAllAutofillEntries_TwoSame) {
WebDatabase db;
ASSERT_EQ(sql::INIT_OK, db.Init(file_));
AutofillChangeList changes;
std::map<std::string, std::vector<base::Time> > name_value_times_map;
time_t start = 0;
std::vector<base::Time> timestamps;
for (int i = 0; i < 2; i++) {
EXPECT_TRUE(db.AddFormFieldValueTime(
FormField(string16(),
ASCIIToUTF16("Name"),
ASCIIToUTF16("Superman"),
string16(),
0,
false),
&changes,
Time::FromTimeT(start)));
timestamps.push_back(Time::FromTimeT(start));
start++;
}
std::string key("NameSuperman");
name_value_times_map.insert(std::pair<std::string,
std::vector<base::Time> > (key, timestamps));
AutofillEntrySet expected_entries(CompareAutofillEntries);
AutofillKey ak1(ASCIIToUTF16("Name"), ASCIIToUTF16("Superman"));
AutofillEntry ae1(ak1, timestamps);
expected_entries.insert(ae1);
std::vector<AutofillEntry> entries;
ASSERT_TRUE(db.GetAllAutofillEntries(&entries));
AutofillEntrySet entry_set(entries.begin(), entries.end(),
CompareAutofillEntries);
// make sure the lists of entries match
ASSERT_EQ(expected_entries.size(), entry_set.size());
AutofillEntrySetIterator it;
for (it = entry_set.begin(); it != entry_set.end(); it++) {
expected_entries.erase(*it);
}
EXPECT_EQ(0U, expected_entries.size());
}
// The WebDatabaseMigrationTest encapsulates testing of database migrations.
// Specifically, these tests are intended to exercise any schema changes in
// the WebDatabase and data migrations that occur in
// |WebDatabase::MigrateOldVersionsAsNeeded()|.
class WebDatabaseMigrationTest : public testing::Test {
public:
WebDatabaseMigrationTest() {}
virtual ~WebDatabaseMigrationTest() {}
virtual void SetUp() {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
}
protected:
// Current tested version number. When adding a migration in
// |WebDatabase::MigrateOldVersionsAsNeeded()| and changing the version number
// |kCurrentVersionNumber| this value should change to reflect the new version
// number and a new migration test added below.
static const int kCurrentTestedVersionNumber;
FilePath GetDatabasePath() {
const FilePath::CharType kWebDatabaseFilename[] =
FILE_PATH_LITERAL("TestWebDatabase.sqlite3");
return temp_dir_.path().Append(FilePath(kWebDatabaseFilename));
}
// The textual contents of |file| are read from
// "chrome/test/data/web_database" and returned in the string |contents|.
// Returns true if the file exists and is read successfully, false otherwise.
bool GetWebDatabaseData(const FilePath& file, std::string* contents) {
FilePath path = ui_test_utils::GetTestFilePath(
FilePath(FILE_PATH_LITERAL("web_database")), file);
return file_util::PathExists(path) &&
file_util::ReadFileToString(path, contents);
}
static int VersionFromConnection(sql::Connection* connection) {
// Get version.
sql::Statement s(connection->GetUniqueStatement(
"SELECT value FROM meta WHERE key='version'"));
if (!s.Step())
return 0;
return s.ColumnInt(0);
}
// The sql files located in "chrome/test/data/web_database" were generated by
// launching the Chromium application prior to schema change, then using the
// sqlite3 command-line application to dump the contents of the "Web Data"
// database.
// Like this:
// > .output version_nn.sql
// > .dump
void LoadDatabase(const FilePath& path);
// Assertion testing for migrating from version 27 and 28.
void MigrateVersion28Assertions();
private:
ScopedTempDir temp_dir_;
DISALLOW_COPY_AND_ASSIGN(WebDatabaseMigrationTest);
};
const int WebDatabaseMigrationTest::kCurrentTestedVersionNumber = 32;
void WebDatabaseMigrationTest::LoadDatabase(const FilePath& file) {
std::string contents;
ASSERT_TRUE(GetWebDatabaseData(file, &contents));
sql::Connection connection;
ASSERT_TRUE(connection.Open(GetDatabasePath()));
ASSERT_TRUE(connection.Execute(contents.data()));
}
void WebDatabaseMigrationTest::MigrateVersion28Assertions() {
// Load the database via the WebDatabase class and migrate the database to
// the current version.
{
WebDatabase db;
ASSERT_EQ(sql::INIT_OK, db.Init(GetDatabasePath()));
}
// Verify post-conditions. These are expectations for current version of the
// database.
{
sql::Connection connection;
ASSERT_TRUE(connection.Open(GetDatabasePath()));
// Check version.
EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
// Make sure supports_instant was dropped and instant_url was added.
EXPECT_FALSE(connection.DoesColumnExist("keywords", "supports_instant"));
EXPECT_TRUE(connection.DoesColumnExist("keywords", "instant_url"));
// Check that instant_url is empty.
std::string stmt = "SELECT instant_url FROM keywords";
sql::Statement s(connection.GetUniqueStatement(stmt.c_str()));
ASSERT_TRUE(s.Step());
EXPECT_EQ(std::string(), s.ColumnString(0));
// Verify the data made it over.
stmt = "SELECT id, short_name, keyword, favicon_url, url, "
"show_in_default_list, safe_for_autoreplace, originating_url, "
"date_created, usage_count, input_encodings, suggest_url, "
"prepopulate_id, autogenerate_keyword, logo_id, created_by_policy, "
"instant_url FROM keywords";
sql::Statement s2(connection.GetUniqueStatement(stmt.c_str()));
ASSERT_TRUE(s2.Step());
EXPECT_EQ(2, s2.ColumnInt(0));
EXPECT_EQ("Google", s2.ColumnString(1));
EXPECT_EQ("google.com", s2.ColumnString(2));
EXPECT_EQ("http://www.google.com/favicon.ico", s2.ColumnString(3));
EXPECT_EQ("{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}"\
"{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}"\
"&q={searchTerms}",
s2.ColumnString(4));
EXPECT_EQ(1, s2.ColumnInt(5));
EXPECT_EQ(1, s2.ColumnInt(6));
EXPECT_EQ(std::string(), s2.ColumnString(7));
EXPECT_EQ(0, s2.ColumnInt(8));
EXPECT_EQ(0, s2.ColumnInt(9));
EXPECT_EQ(std::string("UTF-8"), s2.ColumnString(10));
EXPECT_EQ(std::string("{google:baseSuggestURL}search?client=chrome&hl="
"{language}&q={searchTerms}"), s2.ColumnString(11));
EXPECT_EQ(1, s2.ColumnInt(12));
EXPECT_EQ(1, s2.ColumnInt(13));
EXPECT_EQ(6245, s2.ColumnInt(14));
EXPECT_EQ(0, s2.ColumnInt(15));
EXPECT_EQ(0, s2.ColumnInt(16));
EXPECT_EQ(std::string(), s2.ColumnString(17));
}
}
// Tests that the all migrations from an empty database succeed.
TEST_F(WebDatabaseMigrationTest, MigrateEmptyToCurrent) {
// Load the database via the WebDatabase class and migrate the database to
// the current version.
{
WebDatabase db;
ASSERT_EQ(sql::INIT_OK, db.Init(GetDatabasePath()));
}
// Verify post-conditions. These are expectations for current version of the
// database.
{
sql::Connection connection;
ASSERT_TRUE(connection.Open(GetDatabasePath()));
// Check version.
EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
// Check that expected tables are present.
EXPECT_TRUE(connection.DoesTableExist("meta"));
EXPECT_TRUE(connection.DoesTableExist("keywords"));
EXPECT_TRUE(connection.DoesTableExist("logins"));
EXPECT_TRUE(connection.DoesTableExist("web_app_icons"));
EXPECT_TRUE(connection.DoesTableExist("web_apps"));
EXPECT_TRUE(connection.DoesTableExist("autofill"));
EXPECT_TRUE(connection.DoesTableExist("autofill_dates"));
EXPECT_TRUE(connection.DoesTableExist("autofill_profiles"));
EXPECT_TRUE(connection.DoesTableExist("credit_cards"));
EXPECT_TRUE(connection.DoesTableExist("token_service"));
}
}
// Tests that the |credit_card| table gets added to the schema for a version 22
// database.
TEST_F(WebDatabaseMigrationTest, MigrateVersion22ToCurrent) {
// This schema is taken from a build prior to the addition of the
// |credit_card| table. Version 22 of the schema. Contrast this with the
// corrupt version below.
ASSERT_NO_FATAL_FAILURE(
LoadDatabase(FilePath(FILE_PATH_LITERAL("version_22.sql"))));
// Verify pre-conditions.
{
sql::Connection connection;
ASSERT_TRUE(connection.Open(GetDatabasePath()));
// No |credit_card| table prior to version 23.
ASSERT_FALSE(connection.DoesColumnExist("credit_cards", "guid"));
ASSERT_FALSE(
connection.DoesColumnExist("credit_cards", "card_number_encrypted"));
}
// Load the database via the WebDatabase class and migrate the database to
// the current version.
{
WebDatabase db;
ASSERT_EQ(sql::INIT_OK, db.Init(GetDatabasePath()));
}
// Verify post-conditions. These are expectations for current version of the
// database.
{
sql::Connection connection;
ASSERT_TRUE(connection.Open(GetDatabasePath()));
// Check version.
EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
// |credit_card| table now exists.
EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "guid"));
EXPECT_TRUE(
connection.DoesColumnExist("credit_cards", "card_number_encrypted"));
}
}
// Tests that the |credit_card| table gets added to the schema for a corrupt
// version 22 database. The corruption is that the |credit_cards| table exists
// but the schema version number was not set correctly to 23 or later. This
// test exercises code introduced to fix bug http://crbug.com/50699 that
// resulted from the corruption.
TEST_F(WebDatabaseMigrationTest, MigrateVersion22CorruptedToCurrent) {
// This schema is taken from a build after the addition of the |credit_card|
// table. Due to a bug in the migration logic the version is set incorrectly
// to 22 (it should have been updated to 23 at least).
ASSERT_NO_FATAL_FAILURE(
LoadDatabase(FilePath(FILE_PATH_LITERAL("version_22_corrupt.sql"))));
// Verify pre-conditions. These are expectations for corrupt version 22 of
// the database.
{
sql::Connection connection;
ASSERT_TRUE(connection.Open(GetDatabasePath()));
// Columns existing and not existing before current version.
ASSERT_TRUE(connection.DoesColumnExist("credit_cards", "unique_id"));
ASSERT_TRUE(
connection.DoesColumnExist("credit_cards", "card_number_encrypted"));
ASSERT_TRUE(connection.DoesColumnExist("keywords", "id"));
ASSERT_FALSE(connection.DoesColumnExist("keywords", "logo_id"));
}
// Load the database via the WebDatabase class and migrate the database to
// the current version.
{
WebDatabase db;
ASSERT_EQ(sql::INIT_OK, db.Init(GetDatabasePath()));
}
// Verify post-conditions. These are expectations for current version of the
// database.
{
sql::Connection connection;
ASSERT_TRUE(connection.Open(GetDatabasePath()));
// Check version.
EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
// Columns existing and not existing before version 25.
EXPECT_FALSE(connection.DoesColumnExist("credit_cards", "unique_id"));
EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "guid"));
EXPECT_TRUE(
connection.DoesColumnExist("credit_cards", "card_number_encrypted"));
EXPECT_TRUE(connection.DoesColumnExist("keywords", "id"));
EXPECT_TRUE(connection.DoesColumnExist("keywords", "logo_id"));
}
}
// Tests that the |keywords| |logo_id| column gets added to the schema for a
// version 24 database.
TEST_F(WebDatabaseMigrationTest, MigrateVersion24ToCurrent) {
// This schema is taken from a build prior to the addition of the |keywords|
// |logo_id| column.
ASSERT_NO_FATAL_FAILURE(
LoadDatabase(FilePath(FILE_PATH_LITERAL("version_24.sql"))));
// Verify pre-conditions. These are expectations for version 24 of the
// database.
{
sql::Connection connection;
ASSERT_TRUE(connection.Open(GetDatabasePath()));
// Columns existing and not existing before current version.
ASSERT_TRUE(connection.DoesColumnExist("keywords", "id"));
ASSERT_FALSE(connection.DoesColumnExist("keywords", "logo_id"));
}
// Load the database via the WebDatabase class and migrate the database to
// the current version.
{
WebDatabase db;
ASSERT_EQ(sql::INIT_OK, db.Init(GetDatabasePath()));
}
// Verify post-conditions. These are expectations for current version of the
// database.
{
sql::Connection connection;
ASSERT_TRUE(connection.Open(GetDatabasePath()));
// Check version.
EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
// |keywords| |logo_id| column should have been added.
EXPECT_TRUE(connection.DoesColumnExist("keywords", "id"));
EXPECT_TRUE(connection.DoesColumnExist("keywords", "logo_id"));
}
}
// Tests that the |keywords| |created_by_policy| column gets added to the schema
// for a version 25 database.
TEST_F(WebDatabaseMigrationTest, MigrateVersion25ToCurrent) {
// This schema is taken from a build prior to the addition of the |keywords|
// |created_by_policy| column.
ASSERT_NO_FATAL_FAILURE(
LoadDatabase(FilePath(FILE_PATH_LITERAL("version_25.sql"))));
// Verify pre-conditions. These are expectations for version 25 of the
// database.
{
sql::Connection connection;
ASSERT_TRUE(connection.Open(GetDatabasePath()));
}
// Load the database via the WebDatabase class and migrate the database to
// the current version.
{
WebDatabase db;
ASSERT_EQ(sql::INIT_OK, db.Init(GetDatabasePath()));
}
// Verify post-conditions. These are expectations for current version of the
// database.
{
sql::Connection connection;
ASSERT_TRUE(connection.Open(GetDatabasePath()));
// Check version.
EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
// |keywords| |logo_id| column should have been added.
EXPECT_TRUE(connection.DoesColumnExist("keywords", "id"));
EXPECT_TRUE(connection.DoesColumnExist("keywords", "created_by_policy"));
}
}
// Tests that the credit_cards.billing_address column is changed from a string
// to an int whilst preserving the associated billing address. This version of
// the test makes sure a stored label is converted to an ID.
TEST_F(WebDatabaseMigrationTest, MigrateVersion26ToCurrentStringLabels) {
// This schema is taken from a build prior to the change of column type for
// credit_cards.billing_address from string to int.
ASSERT_NO_FATAL_FAILURE(
LoadDatabase(FilePath(FILE_PATH_LITERAL("version_26.sql"))));
// Verify pre-conditions. These are expectations for version 26 of the
// database.
{
sql::Connection connection;
ASSERT_TRUE(connection.Open(GetDatabasePath()));
// Columns existing and not existing before current version.
EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "billing_address"));
std::string stmt = "INSERT INTO autofill_profiles"
"(label, unique_id, first_name, middle_name, last_name, email,"
" company_name, address_line_1, address_line_2, city, state, zipcode,"
" country, phone, fax)"
"VALUES ('Home',1,'','','','','','','','','','','','','')";
sql::Statement s(connection.GetUniqueStatement(stmt.c_str()));
ASSERT_TRUE(s.Run());
// Insert a CC linked to an existing address.
std::string stmt2 = "INSERT INTO credit_cards"
"(label, unique_id, name_on_card, type, card_number,"
" expiration_month, expiration_year, verification_code, billing_address,"
" shipping_address, card_number_encrypted, verification_code_encrypted)"
"VALUES ('label',2,'Jack','Visa','1234',2,2012,'','Home','','','')";
sql::Statement s2(connection.GetUniqueStatement(stmt2.c_str()));
ASSERT_TRUE(s2.Run());
// |billing_address| is a string.
std::string stmt3 = "SELECT billing_address FROM credit_cards";
sql::Statement s3(connection.GetUniqueStatement(stmt3.c_str()));
ASSERT_TRUE(s3.Step());
EXPECT_EQ(s3.ColumnType(0), sql::COLUMN_TYPE_TEXT);
}
// Load the database via the WebDatabase class and migrate the database to
// the current version.
{
WebDatabase db;
ASSERT_EQ(sql::INIT_OK, db.Init(GetDatabasePath()));
}
// Verify post-conditions. These are expectations for current version of the
// database.
{
sql::Connection connection;
ASSERT_TRUE(connection.Open(GetDatabasePath()));
// Check version.
EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
EXPECT_FALSE(connection.DoesColumnExist("credit_cards", "billing_address"));
// Verify the credit card data is converted.
sql::Statement s(connection.GetUniqueStatement(
"SELECT guid, label, name_on_card, expiration_month, expiration_year, "
"card_number_encrypted, date_modified "
"FROM credit_cards"));
ASSERT_TRUE(s.Step());
EXPECT_EQ("label", s.ColumnString(1));
EXPECT_EQ("Jack", s.ColumnString(2));
EXPECT_EQ(2, s.ColumnInt(3));
EXPECT_EQ(2012, s.ColumnInt(4));
// Column 5 is encrypted number blob.
// Column 6 is date_modified.
}
}
// Tests that the credit_cards.billing_address column is changed from a string
// to an int whilst preserving the associated billing address. This version of
// the test makes sure a stored string ID is converted to an integer ID.
TEST_F(WebDatabaseMigrationTest, MigrateVersion26ToCurrentStringIDs) {
// This schema is taken from a build prior to the change of column type for
// credit_cards.billing_address from string to int.
ASSERT_NO_FATAL_FAILURE(
LoadDatabase(FilePath(FILE_PATH_LITERAL("version_26.sql"))));
// Verify pre-conditions. These are expectations for version 26 of the
// database.
{
sql::Connection connection;
ASSERT_TRUE(connection.Open(GetDatabasePath()));
EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "billing_address"));
std::string stmt = "INSERT INTO autofill_profiles"
"(label, unique_id, first_name, middle_name, last_name, email,"
" company_name, address_line_1, address_line_2, city, state, zipcode,"
" country, phone, fax)"
"VALUES ('Home',1,'','','','','','','','','','','','','')";
sql::Statement s(connection.GetUniqueStatement(stmt.c_str()));
ASSERT_TRUE(s.Run());
// Insert a CC linked to an existing address.
std::string stmt2 = "INSERT INTO credit_cards"
"(label, unique_id, name_on_card, type, card_number,"
" expiration_month, expiration_year, verification_code, billing_address,"
" shipping_address, card_number_encrypted, verification_code_encrypted)"
"VALUES ('label',2,'Jack','Visa','1234',2,2012,'','1','','','')";
sql::Statement s2(connection.GetUniqueStatement(stmt2.c_str()));
ASSERT_TRUE(s2.Run());
// |billing_address| is a string.
std::string stmt3 = "SELECT billing_address FROM credit_cards";
sql::Statement s3(connection.GetUniqueStatement(stmt3.c_str()));
ASSERT_TRUE(s3.Step());
EXPECT_EQ(s3.ColumnType(0), sql::COLUMN_TYPE_TEXT);
}
// Load the database via the WebDatabase class and migrate the database to
// the current version.
{
WebDatabase db;
ASSERT_EQ(sql::INIT_OK, db.Init(GetDatabasePath()));
}
// Verify post-conditions. These are expectations for current version of the
// database.
{
sql::Connection connection;
ASSERT_TRUE(connection.Open(GetDatabasePath()));
// Check version.
EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
// |keywords| |logo_id| column should have been added.
EXPECT_TRUE(connection.DoesColumnExist("keywords", "id"));
EXPECT_TRUE(connection.DoesColumnExist("keywords", "created_by_policy"));
EXPECT_FALSE(connection.DoesColumnExist("credit_cards", "billing_address"));
// Verify the credit card data is converted.
sql::Statement s(connection.GetUniqueStatement(
"SELECT guid, label, name_on_card, expiration_month, expiration_year, "
"card_number_encrypted, date_modified "
"FROM credit_cards"));
ASSERT_TRUE(s.Step());
EXPECT_EQ("label", s.ColumnString(1));
EXPECT_EQ("Jack", s.ColumnString(2));
EXPECT_EQ(2, s.ColumnInt(3));
EXPECT_EQ(2012, s.ColumnInt(4));
// Column 5 is encrypted credit card number blob.
// Column 6 is date_modified.
}
}
// Tests migration from 27->current. This test is now the same as 28->current
// as the column added in 28 was nuked in 29.
TEST_F(WebDatabaseMigrationTest, MigrateVersion27ToCurrent) {
// Initialize the database.
ASSERT_NO_FATAL_FAILURE(
LoadDatabase(FilePath(FILE_PATH_LITERAL("version_27.sql"))));
// Verify pre-conditions. These are expectations for version 28 of the
// database.
{
sql::Connection connection;
ASSERT_TRUE(connection.Open(GetDatabasePath()));
ASSERT_FALSE(connection.DoesColumnExist("keywords", "supports_instant"));
ASSERT_FALSE(connection.DoesColumnExist("keywords", "instant_url"));
}
MigrateVersion28Assertions();
}
// Makes sure instant_url is added correctly to keywords.
TEST_F(WebDatabaseMigrationTest, MigrateVersion28ToCurrent) {
// Initialize the database.
ASSERT_NO_FATAL_FAILURE(
LoadDatabase(FilePath(FILE_PATH_LITERAL("version_28.sql"))));
// Verify pre-conditions. These are expectations for version 28 of the
// database.
{
sql::Connection connection;
ASSERT_TRUE(connection.Open(GetDatabasePath()));
ASSERT_TRUE(connection.DoesColumnExist("keywords", "supports_instant"));
ASSERT_FALSE(connection.DoesColumnExist("keywords", "instant_url"));
}
MigrateVersion28Assertions();
}
// Makes sure date_modified is added correctly to autofill_profiles and
// credit_cards.
TEST_F(WebDatabaseMigrationTest, MigrateVersion29ToCurrent) {
// Initialize the database.
ASSERT_NO_FATAL_FAILURE(
LoadDatabase(FilePath(FILE_PATH_LITERAL("version_29.sql"))));
// Verify pre-conditions. These are expectations for version 29 of the
// database.
{
sql::Connection connection;
ASSERT_TRUE(connection.Open(GetDatabasePath()));
EXPECT_FALSE(connection.DoesColumnExist("autofill_profiles",
"date_modified"));
EXPECT_FALSE(connection.DoesColumnExist("credit_cards",
"date_modified"));
}
// Load the database via the WebDatabase class and migrate the database to
// the current version.
Time pre_creation_time = Time::Now();
{
WebDatabase db;
ASSERT_EQ(sql::INIT_OK, db.Init(GetDatabasePath()));
}
Time post_creation_time = Time::Now();
// Verify post-conditions. These are expectations for current version of the
// database.
{
sql::Connection connection;
ASSERT_TRUE(connection.Open(GetDatabasePath()));
// Check version.
EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
// Check that the columns were created.
EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles",
"date_modified"));
EXPECT_TRUE(connection.DoesColumnExist("credit_cards",
"date_modified"));
sql::Statement s_profiles(connection.GetUniqueStatement(
"SELECT date_modified FROM autofill_profiles "));
ASSERT_TRUE(s_profiles);
while (s_profiles.Step()) {
EXPECT_GE(s_profiles.ColumnInt64(0),
pre_creation_time.ToTimeT());
EXPECT_LE(s_profiles.ColumnInt64(0),
post_creation_time.ToTimeT());
}
EXPECT_TRUE(s_profiles.Succeeded());
sql::Statement s_credit_cards(connection.GetUniqueStatement(
"SELECT date_modified FROM credit_cards "));
ASSERT_TRUE(s_credit_cards);
while (s_credit_cards.Step()) {
EXPECT_GE(s_credit_cards.ColumnInt64(0),
pre_creation_time.ToTimeT());
EXPECT_LE(s_credit_cards.ColumnInt64(0),
post_creation_time.ToTimeT());
}
EXPECT_TRUE(s_credit_cards.Succeeded());
}
}
// Makes sure guids are added to autofill_profiles and credit_cards tables.
TEST_F(WebDatabaseMigrationTest, MigrateVersion30ToCurrent) {
// Initialize the database.
ASSERT_NO_FATAL_FAILURE(
LoadDatabase(FilePath(FILE_PATH_LITERAL("version_30.sql"))));
// Verify pre-conditions. These are expectations for version 29 of the
// database.
{
sql::Connection connection;
ASSERT_TRUE(connection.Open(GetDatabasePath()));
EXPECT_FALSE(connection.DoesColumnExist("autofill_profiles", "guid"));
EXPECT_FALSE(connection.DoesColumnExist("credit_cards", "guid"));
}
// Load the database via the WebDatabase class and migrate the database to
// the current version.
{
WebDatabase db;
ASSERT_EQ(sql::INIT_OK, db.Init(GetDatabasePath()));
}
// Verify post-conditions. These are expectations for current version of the
// database.
{
sql::Connection connection;
ASSERT_TRUE(connection.Open(GetDatabasePath()));
// Check version.
EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
ASSERT_TRUE(connection.DoesColumnExist("autofill_profiles", "guid"));
ASSERT_TRUE(connection.DoesColumnExist("credit_cards", "guid"));
// Check that guids are non-null, non-empty, conforms to guid format, and
// are different.
sql::Statement s(
connection.GetUniqueStatement("SELECT guid FROM autofill_profiles"));
ASSERT_TRUE(s.Step());
std::string guid1 = s.ColumnString(0);
EXPECT_TRUE(guid::IsValidGUID(guid1));
ASSERT_TRUE(s.Step());
std::string guid2 = s.ColumnString(0);
EXPECT_TRUE(guid::IsValidGUID(guid2));
EXPECT_NE(guid1, guid2);
}
}
// Removes unique IDs and make GUIDs the primary key. Also removes unused
// columns.
TEST_F(WebDatabaseMigrationTest, MigrateVersion31ToCurrent) {
// Initialize the database.
ASSERT_NO_FATAL_FAILURE(
LoadDatabase(FilePath(FILE_PATH_LITERAL("version_31.sql"))));
// Verify pre-conditions. These are expectations for version 30 of the
// database.
AutoFillProfile profile;
string16 profile_label;
int profile_unique_id = 0;
int64 profile_date_modified = 0;
CreditCard credit_card;
string16 cc_label;
int cc_unique_id = 0;
std::string cc_number_encrypted;
int64 cc_date_modified = 0;
{
sql::Connection connection;
ASSERT_TRUE(connection.Open(GetDatabasePath()));
// Verify existence of columns we'll be changing.
EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "guid"));
EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "unique_id"));
EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "guid"));
EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "unique_id"));
EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "type"));
EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "card_number"));
EXPECT_TRUE(connection.DoesColumnExist("credit_cards",
"verification_code"));
EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "billing_address"));
EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "shipping_address"));
EXPECT_TRUE(connection.DoesColumnExist("credit_cards",
"verification_code_encrypted"));
// Fetch data in the database prior to migration.
sql::Statement s1(
connection.GetUniqueStatement(
"SELECT label, unique_id, first_name, middle_name, last_name, "
"email, company_name, address_line_1, address_line_2, city, state, "
"zipcode, country, phone, fax, date_modified, guid "
"FROM autofill_profiles"));
ASSERT_TRUE(s1.Step());
EXPECT_NO_FATAL_FAILURE(AutoFillProfile31FromStatement(
s1, &profile, &profile_label, &profile_unique_id,
&profile_date_modified));
sql::Statement s2(
connection.GetUniqueStatement(
"SELECT label, unique_id, name_on_card, type, card_number, "
"expiration_month, expiration_year, verification_code, "
"billing_address, shipping_address, card_number_encrypted, "
"verification_code_encrypted, date_modified, guid "
"FROM credit_cards"));
ASSERT_TRUE(s2.Step());
EXPECT_NO_FATAL_FAILURE(CreditCard31FromStatement(s2,
&credit_card,
&cc_label,
&cc_unique_id,
&cc_number_encrypted,
&cc_date_modified));
EXPECT_NE(profile_unique_id, cc_unique_id);
EXPECT_NE(profile.guid(), credit_card.guid());
}
// Load the database via the WebDatabase class and migrate the database to
// the current version.
{
WebDatabase db;
ASSERT_EQ(sql::INIT_OK, db.Init(GetDatabasePath()));
}
// Verify post-conditions. These are expectations for current version of the
// database.
{
sql::Connection connection;
ASSERT_TRUE(connection.Open(GetDatabasePath()));
// Check version.
EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
// Verify existence of columns we'll be changing.
EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "guid"));
EXPECT_FALSE(connection.DoesColumnExist("autofill_profiles", "unique_id"));
EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "guid"));
EXPECT_FALSE(connection.DoesColumnExist("credit_cards", "unique_id"));
EXPECT_FALSE(connection.DoesColumnExist("credit_cards", "type"));
EXPECT_FALSE(connection.DoesColumnExist("credit_cards", "card_number"));
EXPECT_FALSE(connection.DoesColumnExist("credit_cards",
"verification_code"));
EXPECT_FALSE(connection.DoesColumnExist("credit_cards", "billing_address"));
EXPECT_FALSE(connection.DoesColumnExist("credit_cards",
"shipping_address"));
EXPECT_FALSE(connection.DoesColumnExist("credit_cards",
"verification_code_encrypted"));
// Verify data in the database after the migration.
sql::Statement s1(
connection.GetUniqueStatement(
"SELECT guid, label, first_name, middle_name, last_name, "
"email, company_name, address_line_1, address_line_2, city, state, "
"zipcode, country, phone, fax, date_modified "
"FROM autofill_profiles"));
ASSERT_TRUE(s1.Step());
AutoFillProfile profile_a;
string16 profile_label_a;
int64 profile_date_modified_a = 0;
EXPECT_NO_FATAL_FAILURE(AutoFillProfile32FromStatement(
s1, &profile_a, &profile_label_a, &profile_date_modified_a));
EXPECT_EQ(profile, profile_a);
EXPECT_EQ(profile_label, profile_label_a);
EXPECT_EQ(profile_date_modified, profile_date_modified_a);
sql::Statement s2(
connection.GetUniqueStatement(
"SELECT guid, label, name_on_card, expiration_month, "
"expiration_year, card_number_encrypted, date_modified "
"FROM credit_cards"));
ASSERT_TRUE(s2.Step());
CreditCard credit_card_a;
string16 cc_label_a;
std::string cc_number_encrypted_a;
int64 cc_date_modified_a = 0;
EXPECT_NO_FATAL_FAILURE(CreditCard32FromStatement(s2,
&credit_card_a,
&cc_label_a,
&cc_number_encrypted_a,
&cc_date_modified_a));
EXPECT_EQ(credit_card, credit_card_a);
EXPECT_EQ(cc_label, cc_label_a);
EXPECT_EQ(cc_number_encrypted, cc_number_encrypted_a);
EXPECT_EQ(cc_date_modified, cc_date_modified_a);
}
}