| // 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 "base/file_util.h" |
| #include "base/path_service.h" |
| #include "base/stl_util-inl.h" |
| #include "base/string_number_conversions.h" |
| #include "base/string16.h" |
| #include "base/time.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/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 "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(); |
| } |
| |
| 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; |
| } |
| |
| class WebDatabaseTest : public testing::Test { |
| 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().ToInternalValue()) + |
| ".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::wstring 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 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_; |
| }; |
| |
| 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); |
| 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(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()); |
| |
| 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(1U, 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(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); |
| 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()); |
| |
| 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("[email protected]"); |
| 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), |
| &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), |
| &changes)); |
| } |
| for (int i = 0; i < 3; i++) { |
| EXPECT_TRUE(db.AddFormFieldValue( |
| FormField(string16(), |
| ASCIIToUTF16("Name"), |
| ASCIIToUTF16("Clark Sutter"), |
| string16(), |
| 0), |
| &changes)); |
| } |
| for (int i = 0; i < 2; i++) { |
| EXPECT_TRUE(db.AddFormFieldValue( |
| FormField(string16(), |
| ASCIIToUTF16("Favorite Color"), |
| ASCIIToUTF16("Green"), |
| string16(), |
| 0), |
| &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), |
| &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), |
| &pair_id, &count)); |
| EXPECT_EQ(0, count); |
| |
| EXPECT_TRUE(db.GetIDAndCountOfFormElement( |
| FormField(string16(), |
| ASCIIToUTF16("Favorite Color"), |
| ASCIIToUTF16("Green"), |
| string16(), |
| 0), |
| &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), |
| &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), |
| &changes)); |
| EXPECT_TRUE(db.AddFormFieldValue(FormField(string16(), |
| ASCIIToUTF16("blank"), |
| ASCIIToUTF16(" "), |
| string16(), |
| 0), |
| &changes)); |
| EXPECT_TRUE(db.AddFormFieldValue(FormField(string16(), |
| ASCIIToUTF16("blank"), |
| ASCIIToUTF16(" "), |
| string16(), |
| 0), |
| &changes)); |
| EXPECT_TRUE(db.AddFormFieldValue(FormField(string16(), |
| ASCIIToUTF16("blank"), |
| kValue, |
| string16(), |
| 0), |
| &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), |
| &changes, |
| t1)); |
| EXPECT_TRUE(db.AddFormFieldValueTime( |
| FormField(string16(), |
| ASCIIToUTF16("Name"), |
| ASCIIToUTF16("Superman"), |
| string16(), |
| 0), |
| &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), |
| &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), |
| &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); |
| 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); |
| 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"), |
| ×tamps)); |
| 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); |
| 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); |
| 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), |
| &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), |
| &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)); |
| } |
| |
| 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, AutoFillProfile) { |
| WebDatabase db; |
| |
| ASSERT_EQ(sql::INIT_OK, db.Init(file_)); |
| |
| // Add a 'Home' profile. |
| AutoFillProfile home_profile(ASCIIToUTF16("Home"), 17); |
| 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("[email protected]")); |
| 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")); |
| |
| EXPECT_TRUE(db.AddAutoFillProfile(home_profile)); |
| |
| // Get the 'Home' profile. |
| AutoFillProfile* db_profile; |
| ASSERT_TRUE(db.GetAutoFillProfileForLabel(ASCIIToUTF16("Home"), &db_profile)); |
| EXPECT_EQ(home_profile, *db_profile); |
| delete db_profile; |
| |
| // Add a 'Billing' profile. |
| AutoFillProfile billing_profile = home_profile; |
| billing_profile.set_label(ASCIIToUTF16("Billing")); |
| billing_profile.set_unique_id(13); |
| billing_profile.SetInfo(AutoFillType(ADDRESS_HOME_LINE1), |
| ASCIIToUTF16("5678 Bottom Street")); |
| billing_profile.SetInfo(AutoFillType(ADDRESS_HOME_LINE2), |
| ASCIIToUTF16("suite 3")); |
| |
| EXPECT_TRUE(db.AddAutoFillProfile(billing_profile)); |
| ASSERT_TRUE(db.GetAutoFillProfileForLabel(ASCIIToUTF16("Billing"), |
| &db_profile)); |
| EXPECT_EQ(billing_profile, *db_profile); |
| delete db_profile; |
| |
| // Update the 'Billing' profile. |
| billing_profile.SetInfo(AutoFillType(NAME_FIRST), ASCIIToUTF16("Jane")); |
| EXPECT_TRUE(db.UpdateAutoFillProfile(billing_profile)); |
| ASSERT_TRUE(db.GetAutoFillProfileForLabel(ASCIIToUTF16("Billing"), |
| &db_profile)); |
| EXPECT_EQ(billing_profile, *db_profile); |
| delete db_profile; |
| |
| // Remove the 'Billing' profile. |
| EXPECT_TRUE(db.RemoveAutoFillProfile(billing_profile.unique_id())); |
| EXPECT_FALSE(db.GetAutoFillProfileForLabel(ASCIIToUTF16("Billing"), |
| &db_profile)); |
| } |
| |
| TEST_F(WebDatabaseTest, CreditCard) { |
| WebDatabase db; |
| |
| ASSERT_EQ(sql::INIT_OK, db.Init(file_)); |
| |
| // Add a 'Work' credit card. |
| CreditCard work_creditcard(ASCIIToUTF16("Work"), 13); |
| work_creditcard.SetInfo(AutoFillType(CREDIT_CARD_NAME), |
| ASCIIToUTF16("Jack Torrance")); |
| work_creditcard.SetInfo(AutoFillType(CREDIT_CARD_TYPE), |
| ASCIIToUTF16("Visa")); |
| 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")); |
| work_creditcard.set_billing_address(ASCIIToUTF16("Overlook Hotel")); |
| |
| EXPECT_TRUE(db.AddCreditCard(work_creditcard)); |
| |
| // Get the 'Work' credit card. |
| CreditCard* db_creditcard; |
| ASSERT_TRUE(db.GetCreditCardForLabel(ASCIIToUTF16("Work"), &db_creditcard)); |
| EXPECT_EQ(work_creditcard, *db_creditcard); |
| delete db_creditcard; |
| |
| // Add a 'Target' profile. |
| CreditCard target_creditcard(ASCIIToUTF16("Target"), 7); |
| target_creditcard.SetInfo(AutoFillType(CREDIT_CARD_NAME), |
| ASCIIToUTF16("Jack Torrance")); |
| target_creditcard.SetInfo(AutoFillType(CREDIT_CARD_TYPE), |
| ASCIIToUTF16("Mastercard")); |
| 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")); |
| target_creditcard.set_billing_address(ASCIIToUTF16("Overlook Hotel")); |
| |
| EXPECT_TRUE(db.AddCreditCard(target_creditcard)); |
| ASSERT_TRUE(db.GetCreditCardForLabel(ASCIIToUTF16("Target"), |
| &db_creditcard)); |
| EXPECT_EQ(target_creditcard, *db_creditcard); |
| delete db_creditcard; |
| |
| // Update the 'Target' profile. |
| target_creditcard.SetInfo(AutoFillType(CREDIT_CARD_NAME), |
| ASCIIToUTF16("Charles Grady")); |
| EXPECT_TRUE(db.UpdateCreditCard(target_creditcard)); |
| ASSERT_TRUE(db.GetCreditCardForLabel(ASCIIToUTF16("Target"), &db_creditcard)); |
| EXPECT_EQ(target_creditcard, *db_creditcard); |
| delete db_creditcard; |
| |
| // Remove the 'Billing' profile. |
| EXPECT_TRUE(db.RemoveCreditCard(target_creditcard.unique_id())); |
| EXPECT_FALSE(db.GetCreditCardForLabel(ASCIIToUTF16("Target"), |
| &db_creditcard)); |
| } |
| |
| 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), |
| &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), |
| &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), |
| &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), |
| &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()); |
| } |