summaryrefslogtreecommitdiffstats
path: root/components
diff options
context:
space:
mode:
authorcaitkp@chromium.org <caitkp@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-04-05 18:41:22 +0000
committercaitkp@chromium.org <caitkp@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-04-05 18:41:22 +0000
commitc8e56bd49ed2a92cc51164aa2f06c5d7e1ed0a60 (patch)
treec6d621de3b1164c0752d76e7cc4f8b1c39c55bd4 /components
parentb1babd99ec7a05a76f0b93f6fa17519b661a07b5 (diff)
downloadchromium_src-c8e56bd49ed2a92cc51164aa2f06c5d7e1ed0a60.zip
chromium_src-c8e56bd49ed2a92cc51164aa2f06c5d7e1ed0a60.tar.gz
chromium_src-c8e56bd49ed2a92cc51164aa2f06c5d7e1ed0a60.tar.bz2
Move WebData component unittests to //components/webdata.
TBR=ben@chromium.org BUG=181277 Review URL: https://chromiumcodereview.appspot.com/13650007 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@192608 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'components')
-rw-r--r--components/autofill/browser/autocomplete_history_manager_unittest.cc2
-rw-r--r--components/webdata/DEPS22
-rw-r--r--components/webdata/autofill/autofill_entry_unittest.cc78
-rw-r--r--components/webdata/autofill/autofill_table_unittest.cc1328
-rw-r--r--components/webdata/autofill/web_data_service_unittest.cc532
-rw-r--r--components/webdata/autofill/web_database_migration_unittest.cc1992
-rw-r--r--components/webdata/common/web_data_service_test_util.cc38
-rw-r--r--components/webdata/common/web_data_service_test_util.h76
8 files changed, 4063 insertions, 5 deletions
diff --git a/components/autofill/browser/autocomplete_history_manager_unittest.cc b/components/autofill/browser/autocomplete_history_manager_unittest.cc
index 5d1e2a2..fcee54d 100644
--- a/components/autofill/browser/autocomplete_history_manager_unittest.cc
+++ b/components/autofill/browser/autocomplete_history_manager_unittest.cc
@@ -9,7 +9,6 @@
#include "base/string16.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/webdata/web_data_service_factory.h"
-#include "chrome/browser/webdata/web_data_service_test_util.h"
#include "chrome/test/base/chrome_render_view_host_test_harness.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_profile.h"
@@ -19,6 +18,7 @@
#include "components/autofill/browser/test_autofill_manager_delegate.h"
#include "components/autofill/common/form_data.h"
#include "components/webdata/autofill/autofill_webdata_service.h"
+#include "components/webdata/common/web_data_service_test_util.h"
#include "content/public/test/test_browser_thread.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/components/webdata/DEPS b/components/webdata/DEPS
index c9730aa..6ccecd5 100644
--- a/components/webdata/DEPS
+++ b/components/webdata/DEPS
@@ -1,10 +1,24 @@
include_rules = [
- # Webdata is being made into a component (it will end up at
- # //components/webdata and not depend on //chrome), so we have these basic
- # rules followed by temporary exceptions. Please don't add to the list of
- # exceptions!
"+components/encryptor",
"+content/public/browser",
"+sql",
"+ui",
]
+
+specific_include_rules = {
+ # TODO(caitkp): Extract unit tests from //chrome, at lower priority
+ # than production code.
+ r'(.*_unittest|.*_test_util)\.(cc|h)': [
+ "+chrome/browser/webdata/keyword_table.h",
+ "+chrome/browser/webdata/logins_table.h",
+ "+chrome/browser/webdata/token_service_table.h",
+ "+chrome/browser/webdata/web_apps_table.h",
+ "+chrome/browser/webdata/web_data_service.h",
+ "+chrome/browser/webdata/web_data_service_factory.h",
+ "+chrome/browser/webdata/web_intents_table.h",
+ "+chrome/test/base/ui_test_utils.h",
+ "+content/public/test",
+ "+testing/gmock/include/gmock/gmock.h",
+ "+testing/gtest/include/gtest/gtest.h",
+ ],
+}
diff --git a/components/webdata/autofill/autofill_entry_unittest.cc b/components/webdata/autofill/autofill_entry_unittest.cc
new file mode 100644
index 0000000..481877b
--- /dev/null
+++ b/components/webdata/autofill/autofill_entry_unittest.cc
@@ -0,0 +1,78 @@
+// Copyright (c) 2012 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 <algorithm>
+
+#include "base/time.h"
+#include "base/utf_string_conversions.h"
+#include "components/webdata/autofill/autofill_entry.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+const unsigned int kMaxAutofillTimeStamps = 2;
+
+TEST(AutofillEntryTest, NoCulling) {
+ std::vector<base::Time> source, result;
+ base::Time current = base::Time::Now();
+ for (size_t i = 0; i < kMaxAutofillTimeStamps; ++i)
+ source.push_back(current);
+
+ EXPECT_FALSE(AutofillEntry::CullTimeStamps(source, &result));
+ EXPECT_EQ(result.size(), kMaxAutofillTimeStamps);
+ for (std::vector<base::Time>::const_iterator it = result.begin();
+ it != result.end(); ++it) {
+ EXPECT_EQ(*it, current);
+ }
+}
+
+TEST(AutofillEntryTest, Culling) {
+ std::vector<base::Time> source, result;
+ base::Time current = base::Time::Now();
+ const int offset = 10000;
+
+ int64 internal_value = current.ToInternalValue();
+ for (size_t i = 0; i < kMaxAutofillTimeStamps * 2 ; ++i) {
+ source.push_back(base::Time::FromInternalValue(
+ internal_value + i * offset));
+ }
+ std::sort(source.begin(), source.end());
+ EXPECT_TRUE(AutofillEntry::CullTimeStamps(source, &result));
+
+ EXPECT_EQ(result.size(), kMaxAutofillTimeStamps);
+ EXPECT_EQ(result.front(), base::Time::FromInternalValue(internal_value));
+ int last_offset = (kMaxAutofillTimeStamps * 2 - 1) * offset;
+ EXPECT_EQ(result.back(),
+ base::Time::FromInternalValue(last_offset + internal_value));
+}
+
+TEST(AutofillEntryTest, CullByTime) {
+ base::TimeDelta one_hour = base::TimeDelta::FromHours(1);
+
+ std::vector<base::Time> timestamps;
+ base::Time cutoff_time = AutofillEntry::ExpirationTime();
+
+ // Within the time limit.
+ timestamps.push_back(cutoff_time + one_hour);
+
+ AutofillKey key(UTF8ToUTF16("test_key"), UTF8ToUTF16("test_value"));
+
+ AutofillEntry entry_within_the_limits(key, timestamps);
+ EXPECT_FALSE(entry_within_the_limits.IsExpired());
+
+ // One within the time limit, one outside.
+ timestamps.push_back(cutoff_time - one_hour);
+
+ AutofillEntry entry_partially_within_the_limits(key, timestamps);
+ EXPECT_TRUE(
+ entry_partially_within_the_limits.IsExpired());
+
+ // All outside the time limit.
+ timestamps.clear();
+ timestamps.push_back(cutoff_time - one_hour);
+ timestamps.push_back(cutoff_time - one_hour * 2);
+ timestamps.push_back(cutoff_time - one_hour * 3);
+
+ AutofillEntry entry_outside_the_limits(key, timestamps);
+ EXPECT_TRUE(entry_outside_the_limits.IsExpired());
+ EXPECT_TRUE(entry_outside_the_limits.timestamps_culled());
+}
diff --git a/components/webdata/autofill/autofill_table_unittest.cc b/components/webdata/autofill/autofill_table_unittest.cc
new file mode 100644
index 0000000..6ce6d57
--- /dev/null
+++ b/components/webdata/autofill/autofill_table_unittest.cc
@@ -0,0 +1,1328 @@
+// Copyright (c) 2012 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 <vector>
+
+#include "base/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/guid.h"
+#include "base/path_service.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/time.h"
+#include "base/utf_string_conversions.h"
+#include "components/autofill/browser/autofill_profile.h"
+#include "components/autofill/browser/autofill_type.h"
+#include "components/autofill/browser/credit_card.h"
+#include "components/autofill/common/form_field_data.h"
+#include "components/webdata/autofill/autofill_change.h"
+#include "components/webdata/autofill/autofill_entry.h"
+#include "components/webdata/autofill/autofill_table.h"
+#include "components/webdata/common/web_database.h"
+#include "components/webdata/encryptor/encryptor.h"
+#include "sql/statement.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::Time;
+using base::TimeDelta;
+
+// 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<Time> timestamps1(a.timestamps().begin(), a.timestamps().end());
+ std::set<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<Time>::iterator it;
+ for (it = timestamps1.begin(); it != timestamps1.end(); it++) {
+ timestamps2.erase(*it);
+ }
+
+ return !timestamps2.empty();
+}
+
+} // anonymous namespace
+
+class AutofillTableTest : public testing::Test {
+ public:
+ AutofillTableTest() {}
+ virtual ~AutofillTableTest() {}
+
+ protected:
+ 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
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ file_ = temp_dir_.path().AppendASCII("TestWebDatabase");
+
+ table_.reset(new AutofillTable);
+ db_.reset(new WebDatabase);
+ db_->AddTable(table_.get());
+ ASSERT_EQ(sql::INIT_OK, db_->Init(file_));
+ }
+
+ static AutofillEntry MakeAutofillEntry(const char* name,
+ const char* value,
+ time_t timestamp0,
+ time_t timestamp1) {
+ std::vector<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);
+ }
+
+ base::FilePath file_;
+ base::ScopedTempDir temp_dir_;
+ scoped_ptr<AutofillTable> table_;
+ scoped_ptr<WebDatabase> db_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AutofillTableTest);
+};
+
+TEST_F(AutofillTableTest, Autofill) {
+ Time t1 = Time::Now();
+
+ // Simulate the submission of a handful of entries in a field called "Name",
+ // some more often than others.
+ AutofillChangeList changes;
+ FormFieldData field;
+ field.name = ASCIIToUTF16("Name");
+ field.value = ASCIIToUTF16("Superman");
+ base::Time now = base::Time::Now();
+ base::TimeDelta two_seconds = base::TimeDelta::FromSeconds(2);
+ EXPECT_TRUE(table_->AddFormFieldValue(field, &changes));
+ std::vector<string16> v;
+ for (int i = 0; i < 5; i++) {
+ field.value = ASCIIToUTF16("Clark Kent");
+ EXPECT_TRUE(table_->AddFormFieldValueTime(field, &changes,
+ now + i * two_seconds));
+ }
+ for (int i = 0; i < 3; i++) {
+ field.value = ASCIIToUTF16("Clark Sutter");
+ EXPECT_TRUE(table_->AddFormFieldValueTime(field, &changes,
+ now + i * two_seconds));
+ }
+ for (int i = 0; i < 2; i++) {
+ field.name = ASCIIToUTF16("Favorite Color");
+ field.value = ASCIIToUTF16("Green");
+ EXPECT_TRUE(table_->AddFormFieldValueTime(field, &changes,
+ now + i * two_seconds));
+ }
+
+ 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.
+ field.name = ASCIIToUTF16("Name");
+ field.value = ASCIIToUTF16("Clark Kent");
+ EXPECT_TRUE(table_->GetIDAndCountOfFormElement(field, &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.
+ field.value = ASCIIToUTF16("clark kent");
+ EXPECT_TRUE(table_->GetIDAndCountOfFormElement(field, &pair_id, &count));
+ EXPECT_EQ(0, count);
+
+ field.name = ASCIIToUTF16("Favorite Color");
+ field.value = ASCIIToUTF16("Green");
+ EXPECT_TRUE(table_->GetIDAndCountOfFormElement(field, &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(table_->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(table_->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(table_->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(table_->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]);
+ }
+
+ field.name = ASCIIToUTF16("Name");
+ field.value = ASCIIToUTF16("Clark Kent");
+ EXPECT_TRUE(table_->GetIDAndCountOfFormElement(field, &pair_id, &count));
+ EXPECT_EQ(0, count);
+
+ EXPECT_TRUE(table_->GetFormValuesForElementName(
+ ASCIIToUTF16("Name"), string16(), &v, 6));
+ EXPECT_EQ(0U, v.size());
+
+ // Now add some values with empty strings.
+ const string16 kValue = ASCIIToUTF16(" toto ");
+ field.name = ASCIIToUTF16("blank");
+ field.value = string16();
+ EXPECT_TRUE(table_->AddFormFieldValue(field, &changes));
+ field.name = ASCIIToUTF16("blank");
+ field.value = ASCIIToUTF16(" ");
+ EXPECT_TRUE(table_->AddFormFieldValue(field, &changes));
+ field.name = ASCIIToUTF16("blank");
+ field.value = ASCIIToUTF16(" ");
+ EXPECT_TRUE(table_->AddFormFieldValue(field, &changes));
+ field.name = ASCIIToUTF16("blank");
+ field.value = kValue;
+ EXPECT_TRUE(table_->AddFormFieldValue(field, &changes));
+
+ // They should be stored normally as the DB layer does not check for empty
+ // values.
+ v.clear();
+ EXPECT_TRUE(table_->GetFormValuesForElementName(
+ ASCIIToUTF16("blank"), string16(), &v, 10));
+ EXPECT_EQ(4U, v.size());
+
+ // Now we'll check that ClearAutofillEmptyValueElements() works as expected.
+ table_->ClearAutofillEmptyValueElements();
+
+ v.clear();
+ EXPECT_TRUE(table_->GetFormValuesForElementName(
+ ASCIIToUTF16("blank"), string16(), &v, 10));
+ ASSERT_EQ(1U, v.size());
+
+ EXPECT_EQ(kValue, v[0]);
+}
+
+TEST_F(AutofillTableTest, Autofill_RemoveBetweenChanges) {
+ TimeDelta one_day(TimeDelta::FromDays(1));
+ Time t1 = Time::Now();
+ Time t2 = t1 + one_day;
+
+ AutofillChangeList changes;
+ FormFieldData field;
+ field.name = ASCIIToUTF16("Name");
+ field.value = ASCIIToUTF16("Superman");
+ EXPECT_TRUE(table_->AddFormFieldValueTime(field, &changes, t1));
+ EXPECT_TRUE(table_->AddFormFieldValueTime(field, &changes, t2));
+
+ changes.clear();
+ EXPECT_TRUE(table_->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(
+ table_->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(AutofillTableTest, Autofill_AddChanges) {
+ TimeDelta one_day(TimeDelta::FromDays(1));
+ Time t1 = Time::Now();
+ Time t2 = t1 + one_day;
+
+ AutofillChangeList changes;
+ FormFieldData field;
+ field.name = ASCIIToUTF16("Name");
+ field.value = ASCIIToUTF16("Superman");
+ EXPECT_TRUE(table_->AddFormFieldValueTime(field, &changes, t1));
+ ASSERT_EQ(1U, changes.size());
+ EXPECT_EQ(AutofillChange(AutofillChange::ADD,
+ AutofillKey(ASCIIToUTF16("Name"),
+ ASCIIToUTF16("Superman"))),
+ changes[0]);
+
+ changes.clear();
+ EXPECT_TRUE(
+ table_->AddFormFieldValueTime(field, &changes, t2));
+ ASSERT_EQ(1U, changes.size());
+ EXPECT_EQ(AutofillChange(AutofillChange::UPDATE,
+ AutofillKey(ASCIIToUTF16("Name"),
+ ASCIIToUTF16("Superman"))),
+ changes[0]);
+}
+
+TEST_F(AutofillTableTest, Autofill_UpdateOneWithOneTimestamp) {
+ AutofillEntry entry(MakeAutofillEntry("foo", "bar", 1, -1));
+ std::vector<AutofillEntry> entries;
+ entries.push_back(entry);
+ ASSERT_TRUE(table_->UpdateAutofillEntries(entries));
+
+ FormFieldData field;
+ field.name = ASCIIToUTF16("foo");
+ field.value = ASCIIToUTF16("bar");
+ int64 pair_id;
+ int count;
+ ASSERT_TRUE(table_->GetIDAndCountOfFormElement(field, &pair_id, &count));
+ EXPECT_LE(0, pair_id);
+ EXPECT_EQ(1, count);
+
+ std::vector<AutofillEntry> all_entries;
+ ASSERT_TRUE(table_->GetAllAutofillEntries(&all_entries));
+ ASSERT_EQ(1U, all_entries.size());
+ EXPECT_TRUE(entry == all_entries[0]);
+}
+
+TEST_F(AutofillTableTest, Autofill_UpdateOneWithTwoTimestamps) {
+ AutofillEntry entry(MakeAutofillEntry("foo", "bar", 1, 2));
+ std::vector<AutofillEntry> entries;
+ entries.push_back(entry);
+ ASSERT_TRUE(table_->UpdateAutofillEntries(entries));
+
+ FormFieldData field;
+ field.name = ASCIIToUTF16("foo");
+ field.value = ASCIIToUTF16("bar");
+ int64 pair_id;
+ int count;
+ ASSERT_TRUE(table_->GetIDAndCountOfFormElement(field, &pair_id, &count));
+ EXPECT_LE(0, pair_id);
+ EXPECT_EQ(2, count);
+
+ std::vector<AutofillEntry> all_entries;
+ ASSERT_TRUE(table_->GetAllAutofillEntries(&all_entries));
+ ASSERT_EQ(1U, all_entries.size());
+ EXPECT_TRUE(entry == all_entries[0]);
+}
+
+TEST_F(AutofillTableTest, Autofill_GetAutofillTimestamps) {
+ AutofillEntry entry(MakeAutofillEntry("foo", "bar", 1, 2));
+ std::vector<AutofillEntry> entries;
+ entries.push_back(entry);
+ ASSERT_TRUE(table_->UpdateAutofillEntries(entries));
+
+ std::vector<Time> timestamps;
+ ASSERT_TRUE(table_->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(AutofillTableTest, Autofill_UpdateTwo) {
+ 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(table_->UpdateAutofillEntries(entries));
+
+ FormFieldData field0;
+ field0.name = ASCIIToUTF16("foo");
+ field0.value = ASCIIToUTF16("bar0");
+ int64 pair_id;
+ int count;
+ ASSERT_TRUE(table_->GetIDAndCountOfFormElement(field0, &pair_id, &count));
+ EXPECT_LE(0, pair_id);
+ EXPECT_EQ(1, count);
+
+ FormFieldData field1;
+ field1.name = ASCIIToUTF16("foo");
+ field1.value = ASCIIToUTF16("bar1");
+ ASSERT_TRUE(table_->GetIDAndCountOfFormElement(field1, &pair_id, &count));
+ EXPECT_LE(0, pair_id);
+ EXPECT_EQ(2, count);
+}
+
+TEST_F(AutofillTableTest, Autofill_UpdateReplace) {
+ AutofillChangeList changes;
+ // Add a form field. This will be replaced.
+ FormFieldData field;
+ field.name = ASCIIToUTF16("Name");
+ field.value = ASCIIToUTF16("Superman");
+ EXPECT_TRUE(table_->AddFormFieldValue(field, &changes));
+
+ AutofillEntry entry(MakeAutofillEntry("Name", "Superman", 1, 2));
+ std::vector<AutofillEntry> entries;
+ entries.push_back(entry);
+ ASSERT_TRUE(table_->UpdateAutofillEntries(entries));
+
+ std::vector<AutofillEntry> all_entries;
+ ASSERT_TRUE(table_->GetAllAutofillEntries(&all_entries));
+ ASSERT_EQ(1U, all_entries.size());
+ EXPECT_TRUE(entry == all_entries[0]);
+}
+
+TEST_F(AutofillTableTest, Autofill_UpdateDontReplace) {
+ Time t = Time::Now();
+ AutofillEntry existing(
+ MakeAutofillEntry("Name", "Superman", t.ToTimeT(), -1));
+
+ AutofillChangeList changes;
+ // Add a form field. This will NOT be replaced.
+ FormFieldData field;
+ field.name = existing.key().name();
+ field.value = existing.key().value();
+ EXPECT_TRUE(table_->AddFormFieldValueTime(field, &changes, t));
+ AutofillEntry entry(MakeAutofillEntry("Name", "Clark Kent", 1, 2));
+ std::vector<AutofillEntry> entries;
+ entries.push_back(entry);
+ ASSERT_TRUE(table_->UpdateAutofillEntries(entries));
+
+ std::vector<AutofillEntry> all_entries;
+ ASSERT_TRUE(table_->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(AutofillTableTest, Autofill_AddFormFieldValues) {
+ 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<FormFieldData> elements;
+ FormFieldData field;
+ field.name = ASCIIToUTF16("firstname");
+ field.value = ASCIIToUTF16("Joe");
+ elements.push_back(field);
+
+ field.name = ASCIIToUTF16("firstname");
+ field.value = ASCIIToUTF16("Jane");
+ elements.push_back(field);
+
+ field.name = ASCIIToUTF16("lastname");
+ field.value = ASCIIToUTF16("Smith");
+ elements.push_back(field);
+
+ field.name = ASCIIToUTF16("lastname");
+ field.value = ASCIIToUTF16("Jones");
+ elements.push_back(field);
+
+ std::vector<AutofillChange> changes;
+ table_->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(table_->GetAllAutofillEntries(&all_entries));
+ ASSERT_EQ(2U, all_entries.size());
+}
+
+TEST_F(AutofillTableTest, AutofillProfile) {
+ // Add a 'Home' profile.
+ AutofillProfile home_profile;
+ home_profile.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
+ home_profile.SetRawInfo(NAME_MIDDLE, ASCIIToUTF16("Q."));
+ home_profile.SetRawInfo(NAME_LAST, ASCIIToUTF16("Smith"));
+ home_profile.SetRawInfo(EMAIL_ADDRESS, ASCIIToUTF16("js@smith.xyz"));
+ home_profile.SetRawInfo(COMPANY_NAME, ASCIIToUTF16("Google"));
+ home_profile.SetRawInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("1234 Apple Way"));
+ home_profile.SetRawInfo(ADDRESS_HOME_LINE2, ASCIIToUTF16("unit 5"));
+ home_profile.SetRawInfo(ADDRESS_HOME_CITY, ASCIIToUTF16("Los Angeles"));
+ home_profile.SetRawInfo(ADDRESS_HOME_STATE, ASCIIToUTF16("CA"));
+ home_profile.SetRawInfo(ADDRESS_HOME_ZIP, ASCIIToUTF16("90025"));
+ home_profile.SetRawInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("US"));
+ home_profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("18181234567"));
+
+ Time pre_creation_time = Time::Now();
+ EXPECT_TRUE(table_->AddAutofillProfile(home_profile));
+ Time post_creation_time = Time::Now();
+
+ // Get the 'Home' profile.
+ AutofillProfile* db_profile;
+ ASSERT_TRUE(table_->GetAutofillProfile(home_profile.guid(), &db_profile));
+ EXPECT_EQ(home_profile, *db_profile);
+ sql::Statement s_home(db_->GetSQLConnection()->GetUniqueStatement(
+ "SELECT date_modified "
+ "FROM autofill_profiles WHERE guid=?"));
+ s_home.BindString(0, home_profile.guid());
+ ASSERT_TRUE(s_home.is_valid());
+ 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_guid(base::GenerateGUID());
+ billing_profile.SetRawInfo(ADDRESS_HOME_LINE1,
+ ASCIIToUTF16("5678 Bottom Street"));
+ billing_profile.SetRawInfo(ADDRESS_HOME_LINE2, ASCIIToUTF16("suite 3"));
+
+ pre_creation_time = Time::Now();
+ EXPECT_TRUE(table_->AddAutofillProfile(billing_profile));
+ post_creation_time = Time::Now();
+
+ // Get the 'Billing' profile.
+ ASSERT_TRUE(table_->GetAutofillProfile(billing_profile.guid(), &db_profile));
+ EXPECT_EQ(billing_profile, *db_profile);
+ sql::Statement s_billing(db_->GetSQLConnection()->GetUniqueStatement(
+ "SELECT date_modified FROM autofill_profiles WHERE guid=?"));
+ s_billing.BindString(0, billing_profile.guid());
+ ASSERT_TRUE(s_billing.is_valid());
+ 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, name only.
+ billing_profile.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Jane"));
+ Time pre_modification_time = Time::Now();
+ EXPECT_TRUE(table_->UpdateAutofillProfileMulti(billing_profile));
+ Time post_modification_time = Time::Now();
+ ASSERT_TRUE(table_->GetAutofillProfile(billing_profile.guid(), &db_profile));
+ EXPECT_EQ(billing_profile, *db_profile);
+ sql::Statement s_billing_updated(db_->GetSQLConnection()->GetUniqueStatement(
+ "SELECT date_modified FROM autofill_profiles WHERE guid=?"));
+ s_billing_updated.BindString(0, billing_profile.guid());
+ ASSERT_TRUE(s_billing_updated.is_valid());
+ 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;
+
+ // Update the 'Billing' profile.
+ billing_profile.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Janice"));
+ billing_profile.SetRawInfo(NAME_MIDDLE, ASCIIToUTF16("C."));
+ billing_profile.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Joplin"));
+ billing_profile.SetRawInfo(EMAIL_ADDRESS, ASCIIToUTF16("jane@singer.com"));
+ billing_profile.SetRawInfo(COMPANY_NAME, ASCIIToUTF16("Indy"));
+ billing_profile.SetRawInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("Open Road"));
+ billing_profile.SetRawInfo(ADDRESS_HOME_LINE2, ASCIIToUTF16("Route 66"));
+ billing_profile.SetRawInfo(ADDRESS_HOME_CITY, ASCIIToUTF16("NFA"));
+ billing_profile.SetRawInfo(ADDRESS_HOME_STATE, ASCIIToUTF16("NY"));
+ billing_profile.SetRawInfo(ADDRESS_HOME_ZIP, ASCIIToUTF16("10011"));
+ billing_profile.SetRawInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("US"));
+ billing_profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER,
+ ASCIIToUTF16("18181230000"));
+ Time pre_modification_time_2 = Time::Now();
+ EXPECT_TRUE(table_->UpdateAutofillProfileMulti(billing_profile));
+ Time post_modification_time_2 = Time::Now();
+ ASSERT_TRUE(table_->GetAutofillProfile(billing_profile.guid(), &db_profile));
+ EXPECT_EQ(billing_profile, *db_profile);
+ sql::Statement s_billing_updated_2(
+ db_->GetSQLConnection()->GetUniqueStatement(
+ "SELECT date_modified FROM autofill_profiles WHERE guid=?"));
+ s_billing_updated_2.BindString(0, billing_profile.guid());
+ ASSERT_TRUE(s_billing_updated_2.is_valid());
+ ASSERT_TRUE(s_billing_updated_2.Step());
+ EXPECT_GE(s_billing_updated_2.ColumnInt64(0),
+ pre_modification_time_2.ToTimeT());
+ EXPECT_LE(s_billing_updated_2.ColumnInt64(0),
+ post_modification_time_2.ToTimeT());
+ EXPECT_FALSE(s_billing_updated_2.Step());
+ delete db_profile;
+
+ // Remove the 'Billing' profile.
+ EXPECT_TRUE(table_->RemoveAutofillProfile(billing_profile.guid()));
+ EXPECT_FALSE(table_->GetAutofillProfile(billing_profile.guid(), &db_profile));
+}
+
+TEST_F(AutofillTableTest, AutofillProfileMultiValueNames) {
+ AutofillProfile p;
+ const string16 kJohnDoe(ASCIIToUTF16("John Doe"));
+ const string16 kJohnPDoe(ASCIIToUTF16("John P. Doe"));
+ std::vector<string16> set_values;
+ set_values.push_back(kJohnDoe);
+ set_values.push_back(kJohnPDoe);
+ p.SetRawMultiInfo(NAME_FULL, set_values);
+
+ EXPECT_TRUE(table_->AddAutofillProfile(p));
+
+ AutofillProfile* db_profile;
+ ASSERT_TRUE(table_->GetAutofillProfile(p.guid(), &db_profile));
+ EXPECT_EQ(p, *db_profile);
+ EXPECT_EQ(0, p.Compare(*db_profile));
+ delete db_profile;
+
+ // Update the values.
+ const string16 kNoOne(ASCIIToUTF16("No One"));
+ set_values[1] = kNoOne;
+ p.SetRawMultiInfo(NAME_FULL, set_values);
+ EXPECT_TRUE(table_->UpdateAutofillProfileMulti(p));
+ ASSERT_TRUE(table_->GetAutofillProfile(p.guid(), &db_profile));
+ EXPECT_EQ(p, *db_profile);
+ EXPECT_EQ(0, p.Compare(*db_profile));
+ delete db_profile;
+
+ // Delete values.
+ set_values.clear();
+ p.SetRawMultiInfo(NAME_FULL, set_values);
+ EXPECT_TRUE(table_->UpdateAutofillProfileMulti(p));
+ ASSERT_TRUE(table_->GetAutofillProfile(p.guid(), &db_profile));
+ EXPECT_EQ(p, *db_profile);
+ EXPECT_EQ(0, p.Compare(*db_profile));
+ EXPECT_EQ(string16(), db_profile->GetRawInfo(NAME_FULL));
+ delete db_profile;
+}
+
+TEST_F(AutofillTableTest, AutofillProfileSingleValue) {
+ AutofillProfile p;
+ const string16 kJohnDoe(ASCIIToUTF16("John Doe"));
+ const string16 kJohnPDoe(ASCIIToUTF16("John P. Doe"));
+ std::vector<string16> set_values;
+ set_values.push_back(kJohnDoe);
+ set_values.push_back(kJohnPDoe);
+ p.SetRawMultiInfo(NAME_FULL, set_values);
+
+ EXPECT_TRUE(table_->AddAutofillProfile(p));
+
+ AutofillProfile* db_profile;
+ ASSERT_TRUE(table_->GetAutofillProfile(p.guid(), &db_profile));
+ EXPECT_EQ(p, *db_profile);
+ EXPECT_EQ(0, p.Compare(*db_profile));
+ delete db_profile;
+
+ const string16 kNoOne(ASCIIToUTF16("No One"));
+ set_values.resize(1);
+ set_values[0] = kNoOne;
+ p.SetRawMultiInfo(NAME_FULL, set_values);
+ EXPECT_TRUE(table_->UpdateAutofillProfile(p));
+ ASSERT_TRUE(table_->GetAutofillProfile(p.guid(), &db_profile));
+ EXPECT_EQ(p.PrimaryValue(), db_profile->PrimaryValue());
+ EXPECT_EQ(p.guid(), db_profile->guid());
+ EXPECT_NE(0, p.Compare(*db_profile));
+ db_profile->GetRawMultiInfo(NAME_FULL, &set_values);
+ ASSERT_EQ(2UL, set_values.size());
+ EXPECT_EQ(kNoOne, set_values[0]);
+ EXPECT_EQ(kJohnPDoe, set_values[1]);
+ delete db_profile;
+}
+
+TEST_F(AutofillTableTest, AutofillProfileMultiValueEmails) {
+ AutofillProfile p;
+ const string16 kJohnDoe(ASCIIToUTF16("john@doe.com"));
+ const string16 kJohnPDoe(ASCIIToUTF16("john_p@doe.com"));
+ std::vector<string16> set_values;
+ set_values.push_back(kJohnDoe);
+ set_values.push_back(kJohnPDoe);
+ p.SetRawMultiInfo(EMAIL_ADDRESS, set_values);
+
+ EXPECT_TRUE(table_->AddAutofillProfile(p));
+
+ AutofillProfile* db_profile;
+ ASSERT_TRUE(table_->GetAutofillProfile(p.guid(), &db_profile));
+ EXPECT_EQ(p, *db_profile);
+ EXPECT_EQ(0, p.Compare(*db_profile));
+ delete db_profile;
+
+ // Update the values.
+ const string16 kNoOne(ASCIIToUTF16("no@one.com"));
+ set_values[1] = kNoOne;
+ p.SetRawMultiInfo(EMAIL_ADDRESS, set_values);
+ EXPECT_TRUE(table_->UpdateAutofillProfileMulti(p));
+ ASSERT_TRUE(table_->GetAutofillProfile(p.guid(), &db_profile));
+ EXPECT_EQ(p, *db_profile);
+ EXPECT_EQ(0, p.Compare(*db_profile));
+ delete db_profile;
+
+ // Delete values.
+ set_values.clear();
+ p.SetRawMultiInfo(EMAIL_ADDRESS, set_values);
+ EXPECT_TRUE(table_->UpdateAutofillProfileMulti(p));
+ ASSERT_TRUE(table_->GetAutofillProfile(p.guid(), &db_profile));
+ EXPECT_EQ(p, *db_profile);
+ EXPECT_EQ(0, p.Compare(*db_profile));
+ EXPECT_EQ(string16(), db_profile->GetRawInfo(EMAIL_ADDRESS));
+ delete db_profile;
+}
+
+TEST_F(AutofillTableTest, AutofillProfileMultiValuePhone) {
+ AutofillProfile p;
+ const string16 kJohnDoe(ASCIIToUTF16("4151112222"));
+ const string16 kJohnPDoe(ASCIIToUTF16("4151113333"));
+ std::vector<string16> set_values;
+ set_values.push_back(kJohnDoe);
+ set_values.push_back(kJohnPDoe);
+ p.SetRawMultiInfo(PHONE_HOME_WHOLE_NUMBER, set_values);
+
+ EXPECT_TRUE(table_->AddAutofillProfile(p));
+
+ AutofillProfile* db_profile;
+ ASSERT_TRUE(table_->GetAutofillProfile(p.guid(), &db_profile));
+ EXPECT_EQ(p, *db_profile);
+ EXPECT_EQ(0, p.Compare(*db_profile));
+ delete db_profile;
+
+ // Update the values.
+ const string16 kNoOne(ASCIIToUTF16("4151110000"));
+ set_values[1] = kNoOne;
+ p.SetRawMultiInfo(PHONE_HOME_WHOLE_NUMBER, set_values);
+ EXPECT_TRUE(table_->UpdateAutofillProfileMulti(p));
+ ASSERT_TRUE(table_->GetAutofillProfile(p.guid(), &db_profile));
+ EXPECT_EQ(p, *db_profile);
+ EXPECT_EQ(0, p.Compare(*db_profile));
+ delete db_profile;
+
+ // Delete values.
+ set_values.clear();
+ p.SetRawMultiInfo(PHONE_HOME_WHOLE_NUMBER, set_values);
+ EXPECT_TRUE(table_->UpdateAutofillProfileMulti(p));
+ ASSERT_TRUE(table_->GetAutofillProfile(p.guid(), &db_profile));
+ EXPECT_EQ(p, *db_profile);
+ EXPECT_EQ(0, p.Compare(*db_profile));
+ EXPECT_EQ(string16(), db_profile->GetRawInfo(EMAIL_ADDRESS));
+ delete db_profile;
+}
+
+TEST_F(AutofillTableTest, AutofillProfileTrash) {
+ std::vector<std::string> guids;
+ table_->GetAutofillProfilesInTrash(&guids);
+ EXPECT_TRUE(guids.empty());
+
+ ASSERT_TRUE(table_->AddAutofillGUIDToTrash(
+ "00000000-0000-0000-0000-000000000000"));
+ ASSERT_TRUE(table_->AddAutofillGUIDToTrash(
+ "00000000-0000-0000-0000-000000000001"));
+ ASSERT_TRUE(table_->GetAutofillProfilesInTrash(&guids));
+ EXPECT_EQ(2UL, guids.size());
+ EXPECT_EQ("00000000-0000-0000-0000-000000000000", guids[0]);
+ EXPECT_EQ("00000000-0000-0000-0000-000000000001", guids[1]);
+
+ ASSERT_TRUE(table_->EmptyAutofillProfilesTrash());
+ ASSERT_TRUE(table_->GetAutofillProfilesInTrash(&guids));
+ EXPECT_TRUE(guids.empty());
+}
+
+TEST_F(AutofillTableTest, AutofillProfileTrashInteraction) {
+ std::vector<std::string> guids;
+ table_->GetAutofillProfilesInTrash(&guids);
+ EXPECT_TRUE(guids.empty());
+
+ AutofillProfile profile;
+ profile.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
+ profile.SetRawInfo(NAME_MIDDLE, ASCIIToUTF16("Q."));
+ profile.SetRawInfo(NAME_LAST, ASCIIToUTF16("Smith"));
+ profile.SetRawInfo(EMAIL_ADDRESS,ASCIIToUTF16("js@smith.xyz"));
+ profile.SetRawInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("1 Main St"));
+ profile.SetRawInfo(ADDRESS_HOME_CITY, ASCIIToUTF16("Los Angeles"));
+ profile.SetRawInfo(ADDRESS_HOME_STATE, ASCIIToUTF16("CA"));
+ profile.SetRawInfo(ADDRESS_HOME_ZIP, ASCIIToUTF16("90025"));
+ profile.SetRawInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("US"));
+
+ // Mark this profile as in the trash. This stops |AddAutofillProfile| from
+ // adding it.
+ EXPECT_TRUE(table_->AddAutofillGUIDToTrash(profile.guid()));
+ EXPECT_TRUE(table_->AddAutofillProfile(profile));
+ AutofillProfile* added_profile = NULL;
+ EXPECT_FALSE(table_->GetAutofillProfile(profile.guid(), &added_profile));
+ EXPECT_EQ(static_cast<AutofillProfile*>(NULL), added_profile);
+
+ // Add the profile for real this time.
+ EXPECT_TRUE(table_->EmptyAutofillProfilesTrash());
+ EXPECT_TRUE(table_->GetAutofillProfilesInTrash(&guids));
+ EXPECT_TRUE(guids.empty());
+ EXPECT_TRUE(table_->AddAutofillProfile(profile));
+ EXPECT_TRUE(table_->GetAutofillProfile(profile.guid(),
+ &added_profile));
+ ASSERT_NE(static_cast<AutofillProfile*>(NULL), added_profile);
+ delete added_profile;
+
+ // Mark this profile as in the trash. This stops |UpdateAutofillProfileMulti|
+ // from updating it. In normal operation a profile should not be both in the
+ // trash and in the profiles table simultaneously.
+ EXPECT_TRUE(table_->AddAutofillGUIDToTrash(profile.guid()));
+ profile.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Jane"));
+ EXPECT_TRUE(table_->UpdateAutofillProfileMulti(profile));
+ AutofillProfile* updated_profile = NULL;
+ EXPECT_TRUE(table_->GetAutofillProfile(profile.guid(), &updated_profile));
+ ASSERT_NE(static_cast<AutofillProfile*>(NULL), added_profile);
+ EXPECT_EQ(ASCIIToUTF16("John"), updated_profile->GetRawInfo(NAME_FIRST));
+ delete updated_profile;
+
+ // Try to delete the trashed profile. This stops |RemoveAutofillProfile| from
+ // deleting it. In normal operation deletion is done by migration step, and
+ // removal from trash is done by |WebDataService|. |RemoveAutofillProfile|
+ // does remove the item from the trash if it is found however, so that if
+ // other clients remove it (via Sync say) then it is gone and doesn't need to
+ // be processed further by |WebDataService|.
+ EXPECT_TRUE(table_->RemoveAutofillProfile(profile.guid()));
+ AutofillProfile* removed_profile = NULL;
+ EXPECT_TRUE(table_->GetAutofillProfile(profile.guid(), &removed_profile));
+ EXPECT_FALSE(table_->IsAutofillGUIDInTrash(profile.guid()));
+ ASSERT_NE(static_cast<AutofillProfile*>(NULL), removed_profile);
+ delete removed_profile;
+
+ // Check that emptying the trash now allows removal to occur.
+ EXPECT_TRUE(table_->EmptyAutofillProfilesTrash());
+ EXPECT_TRUE(table_->RemoveAutofillProfile(profile.guid()));
+ removed_profile = NULL;
+ EXPECT_FALSE(table_->GetAutofillProfile(profile.guid(), &removed_profile));
+ EXPECT_EQ(static_cast<AutofillProfile*>(NULL), removed_profile);
+}
+
+TEST_F(AutofillTableTest, CreditCard) {
+ // Add a 'Work' credit card.
+ CreditCard work_creditcard;
+ work_creditcard.SetRawInfo(CREDIT_CARD_NAME, ASCIIToUTF16("Jack Torrance"));
+ work_creditcard.SetRawInfo(CREDIT_CARD_NUMBER,
+ ASCIIToUTF16("1234567890123456"));
+ work_creditcard.SetRawInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("04"));
+ work_creditcard.SetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR,
+ ASCIIToUTF16("2013"));
+
+ Time pre_creation_time = Time::Now();
+ EXPECT_TRUE(table_->AddCreditCard(work_creditcard));
+ Time post_creation_time = Time::Now();
+
+ // Get the 'Work' credit card.
+ CreditCard* db_creditcard;
+ ASSERT_TRUE(table_->GetCreditCard(work_creditcard.guid(), &db_creditcard));
+ EXPECT_EQ(work_creditcard, *db_creditcard);
+ sql::Statement s_work(db_->GetSQLConnection()->GetUniqueStatement(
+ "SELECT guid, name_on_card, expiration_month, expiration_year, "
+ "card_number_encrypted, date_modified "
+ "FROM credit_cards WHERE guid=?"));
+ s_work.BindString(0, work_creditcard.guid());
+ ASSERT_TRUE(s_work.is_valid());
+ ASSERT_TRUE(s_work.Step());
+ EXPECT_GE(s_work.ColumnInt64(5), pre_creation_time.ToTimeT());
+ EXPECT_LE(s_work.ColumnInt64(5), post_creation_time.ToTimeT());
+ EXPECT_FALSE(s_work.Step());
+ delete db_creditcard;
+
+ // Add a 'Target' credit card.
+ CreditCard target_creditcard;
+ target_creditcard.SetRawInfo(CREDIT_CARD_NAME, ASCIIToUTF16("Jack Torrance"));
+ target_creditcard.SetRawInfo(CREDIT_CARD_NUMBER,
+ ASCIIToUTF16("1111222233334444"));
+ target_creditcard.SetRawInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("06"));
+ target_creditcard.SetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR,
+ ASCIIToUTF16("2012"));
+
+ pre_creation_time = Time::Now();
+ EXPECT_TRUE(table_->AddCreditCard(target_creditcard));
+ post_creation_time = Time::Now();
+ ASSERT_TRUE(table_->GetCreditCard(target_creditcard.guid(), &db_creditcard));
+ EXPECT_EQ(target_creditcard, *db_creditcard);
+ sql::Statement s_target(db_->GetSQLConnection()->GetUniqueStatement(
+ "SELECT guid, name_on_card, expiration_month, expiration_year, "
+ "card_number_encrypted, date_modified "
+ "FROM credit_cards WHERE guid=?"));
+ s_target.BindString(0, target_creditcard.guid());
+ ASSERT_TRUE(s_target.is_valid());
+ ASSERT_TRUE(s_target.Step());
+ EXPECT_GE(s_target.ColumnInt64(5), pre_creation_time.ToTimeT());
+ EXPECT_LE(s_target.ColumnInt64(5), post_creation_time.ToTimeT());
+ EXPECT_FALSE(s_target.Step());
+ delete db_creditcard;
+
+ // Update the 'Target' credit card.
+ target_creditcard.SetRawInfo(CREDIT_CARD_NAME, ASCIIToUTF16("Charles Grady"));
+ Time pre_modification_time = Time::Now();
+ EXPECT_TRUE(table_->UpdateCreditCard(target_creditcard));
+ Time post_modification_time = Time::Now();
+ ASSERT_TRUE(table_->GetCreditCard(target_creditcard.guid(), &db_creditcard));
+ EXPECT_EQ(target_creditcard, *db_creditcard);
+ sql::Statement s_target_updated(db_->GetSQLConnection()->GetUniqueStatement(
+ "SELECT guid, name_on_card, expiration_month, expiration_year, "
+ "card_number_encrypted, date_modified "
+ "FROM credit_cards WHERE guid=?"));
+ s_target_updated.BindString(0, target_creditcard.guid());
+ ASSERT_TRUE(s_target_updated.is_valid());
+ ASSERT_TRUE(s_target_updated.Step());
+ EXPECT_GE(s_target_updated.ColumnInt64(5), pre_modification_time.ToTimeT());
+ EXPECT_LE(s_target_updated.ColumnInt64(5), post_modification_time.ToTimeT());
+ EXPECT_FALSE(s_target_updated.Step());
+ delete db_creditcard;
+
+ // Remove the 'Target' credit card.
+ EXPECT_TRUE(table_->RemoveCreditCard(target_creditcard.guid()));
+ EXPECT_FALSE(table_->GetCreditCard(target_creditcard.guid(), &db_creditcard));
+}
+
+TEST_F(AutofillTableTest, UpdateAutofillProfile) {
+ // Add a profile to the db.
+ AutofillProfile profile;
+ profile.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
+ profile.SetRawInfo(NAME_MIDDLE, ASCIIToUTF16("Q."));
+ profile.SetRawInfo(NAME_LAST, ASCIIToUTF16("Smith"));
+ profile.SetRawInfo(EMAIL_ADDRESS, ASCIIToUTF16("js@example.com"));
+ profile.SetRawInfo(COMPANY_NAME, ASCIIToUTF16("Google"));
+ profile.SetRawInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("1234 Apple Way"));
+ profile.SetRawInfo(ADDRESS_HOME_LINE2, ASCIIToUTF16("unit 5"));
+ profile.SetRawInfo(ADDRESS_HOME_CITY, ASCIIToUTF16("Los Angeles"));
+ profile.SetRawInfo(ADDRESS_HOME_STATE, ASCIIToUTF16("CA"));
+ profile.SetRawInfo(ADDRESS_HOME_ZIP, ASCIIToUTF16("90025"));
+ profile.SetRawInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("US"));
+ profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("18181234567"));
+ table_->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_->GetSQLConnection()->GetUniqueStatement(
+ "UPDATE autofill_profiles SET date_modified = ?"));
+ ASSERT_TRUE(s_mock_creation_date.is_valid());
+ s_mock_creation_date.BindInt64(0, mock_creation_date);
+ ASSERT_TRUE(s_mock_creation_date.Run());
+
+ // Get the profile.
+ AutofillProfile* tmp_profile;
+ ASSERT_TRUE(table_->GetAutofillProfile(profile.guid(), &tmp_profile));
+ scoped_ptr<AutofillProfile> db_profile(tmp_profile);
+ EXPECT_EQ(profile, *db_profile);
+ sql::Statement s_original(db_->GetSQLConnection()->GetUniqueStatement(
+ "SELECT date_modified FROM autofill_profiles"));
+ ASSERT_TRUE(s_original.is_valid());
+ 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.SetRawInfo(EMAIL_ADDRESS, ASCIIToUTF16("js@smith.xyz"));
+ table_->UpdateAutofillProfileMulti(profile);
+
+ // Get the profile.
+ ASSERT_TRUE(table_->GetAutofillProfile(profile.guid(), &tmp_profile));
+ db_profile.reset(tmp_profile);
+ EXPECT_EQ(profile, *db_profile);
+ sql::Statement s_updated(db_->GetSQLConnection()->GetUniqueStatement(
+ "SELECT date_modified FROM autofill_profiles"));
+ ASSERT_TRUE(s_updated.is_valid());
+ 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_->GetSQLConnection()->GetUniqueStatement(
+ "UPDATE autofill_profiles SET date_modified = ?"));
+ ASSERT_TRUE(s_mock_modification_date.is_valid());
+ s_mock_modification_date.BindInt64(0, mock_modification_date);
+ ASSERT_TRUE(s_mock_modification_date.Run());
+
+ // Finally, call into |UpdateAutofillProfileMulti()| without changing the
+ // profile. The modification date should not change.
+ table_->UpdateAutofillProfileMulti(profile);
+
+ // Get the profile.
+ ASSERT_TRUE(table_->GetAutofillProfile(profile.guid(), &tmp_profile));
+ db_profile.reset(tmp_profile);
+ EXPECT_EQ(profile, *db_profile);
+ sql::Statement s_unchanged(db_->GetSQLConnection()->GetUniqueStatement(
+ "SELECT date_modified FROM autofill_profiles"));
+ ASSERT_TRUE(s_unchanged.is_valid());
+ ASSERT_TRUE(s_unchanged.Step());
+ EXPECT_EQ(mock_modification_date, s_unchanged.ColumnInt64(0));
+ EXPECT_FALSE(s_unchanged.Step());
+}
+
+TEST_F(AutofillTableTest, UpdateCreditCard) {
+ // Add a credit card to the db.
+ CreditCard credit_card;
+ credit_card.SetRawInfo(CREDIT_CARD_NAME, ASCIIToUTF16("Jack Torrance"));
+ credit_card.SetRawInfo(CREDIT_CARD_NUMBER, ASCIIToUTF16("1234567890123456"));
+ credit_card.SetRawInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("04"));
+ credit_card.SetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR, ASCIIToUTF16("2013"));
+ table_->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_->GetSQLConnection()->GetUniqueStatement(
+ "UPDATE credit_cards SET date_modified = ?"));
+ ASSERT_TRUE(s_mock_creation_date.is_valid());
+ 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(table_->GetCreditCard(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_->GetSQLConnection()->GetUniqueStatement(
+ "SELECT date_modified FROM credit_cards"));
+ ASSERT_TRUE(s_original.is_valid());
+ 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.SetRawInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("01"));
+ table_->UpdateCreditCard(credit_card);
+
+ // Get the credit card.
+ ASSERT_TRUE(table_->GetCreditCard(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_->GetSQLConnection()->GetUniqueStatement(
+ "SELECT date_modified FROM credit_cards"));
+ ASSERT_TRUE(s_updated.is_valid());
+ 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_->GetSQLConnection()->GetUniqueStatement(
+ "UPDATE credit_cards SET date_modified = ?"));
+ ASSERT_TRUE(s_mock_modification_date.is_valid());
+ 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.
+ table_->UpdateCreditCard(credit_card);
+
+ // Get the profile.
+ ASSERT_TRUE(table_->GetCreditCard(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_->GetSQLConnection()->GetUniqueStatement(
+ "SELECT date_modified FROM credit_cards"));
+ ASSERT_TRUE(s_unchanged.is_valid());
+ ASSERT_TRUE(s_unchanged.Step());
+ EXPECT_EQ(mock_modification_date, s_unchanged.ColumnInt64(0));
+ EXPECT_FALSE(s_unchanged.Step());
+}
+
+TEST_F(AutofillTableTest, RemoveAutofillDataModifiedBetween) {
+ // Populate the autofill_profiles and credit_cards tables.
+ ASSERT_TRUE(db_->GetSQLConnection()->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).
+ std::vector<std::string> profile_guids;
+ std::vector<std::string> credit_card_guids;
+ table_->RemoveAutofillDataModifiedBetween(
+ Time::FromTimeT(17), Time::FromTimeT(41),
+ &profile_guids, &credit_card_guids);
+ ASSERT_EQ(2UL, profile_guids.size());
+ EXPECT_EQ("00000000-0000-0000-0000-000000000001", profile_guids[0]);
+ EXPECT_EQ("00000000-0000-0000-0000-000000000002", profile_guids[1]);
+ sql::Statement s_autofill_profiles_bounded(
+ db_->GetSQLConnection()->GetUniqueStatement(
+ "SELECT date_modified FROM autofill_profiles"));
+ ASSERT_TRUE(s_autofill_profiles_bounded.is_valid());
+ 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());
+ ASSERT_EQ(3UL, credit_card_guids.size());
+ EXPECT_EQ("00000000-0000-0000-0000-000000000006", credit_card_guids[0]);
+ EXPECT_EQ("00000000-0000-0000-0000-000000000007", credit_card_guids[1]);
+ EXPECT_EQ("00000000-0000-0000-0000-000000000008", credit_card_guids[2]);
+ sql::Statement s_credit_cards_bounded(
+ db_->GetSQLConnection()->GetUniqueStatement(
+ "SELECT date_modified FROM credit_cards"));
+ ASSERT_TRUE(s_credit_cards_bounded.is_valid());
+ 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).
+ table_->RemoveAutofillDataModifiedBetween(
+ Time::FromTimeT(51), Time(),
+ &profile_guids, &credit_card_guids);
+ ASSERT_EQ(2UL, profile_guids.size());
+ EXPECT_EQ("00000000-0000-0000-0000-000000000004", profile_guids[0]);
+ EXPECT_EQ("00000000-0000-0000-0000-000000000005", profile_guids[1]);
+ sql::Statement s_autofill_profiles_unbounded(
+ db_->GetSQLConnection()->GetUniqueStatement(
+ "SELECT date_modified FROM autofill_profiles"));
+ ASSERT_TRUE(s_autofill_profiles_unbounded.is_valid());
+ 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());
+ ASSERT_EQ(2UL, credit_card_guids.size());
+ EXPECT_EQ("00000000-0000-0000-0000-000000000010", credit_card_guids[0]);
+ EXPECT_EQ("00000000-0000-0000-0000-000000000011", credit_card_guids[1]);
+ sql::Statement s_credit_cards_unbounded(
+ db_->GetSQLConnection()->GetUniqueStatement(
+ "SELECT date_modified FROM credit_cards"));
+ ASSERT_TRUE(s_credit_cards_unbounded.is_valid());
+ 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.
+ table_->RemoveAutofillDataModifiedBetween(
+ Time(), Time(),
+ &profile_guids, &credit_card_guids);
+ ASSERT_EQ(2UL, profile_guids.size());
+ EXPECT_EQ("00000000-0000-0000-0000-000000000000", profile_guids[0]);
+ EXPECT_EQ("00000000-0000-0000-0000-000000000003", profile_guids[1]);
+ sql::Statement s_autofill_profiles_empty(
+ db_->GetSQLConnection()->GetUniqueStatement(
+ "SELECT date_modified FROM autofill_profiles"));
+ ASSERT_TRUE(s_autofill_profiles_empty.is_valid());
+ EXPECT_FALSE(s_autofill_profiles_empty.Step());
+ ASSERT_EQ(1UL, credit_card_guids.size());
+ EXPECT_EQ("00000000-0000-0000-0000-000000000009", credit_card_guids[0]);
+ sql::Statement s_credit_cards_empty(
+ db_->GetSQLConnection()->GetUniqueStatement(
+ "SELECT date_modified FROM credit_cards"));
+ ASSERT_TRUE(s_credit_cards_empty.is_valid());
+ EXPECT_FALSE(s_credit_cards_empty.Step());
+}
+
+TEST_F(AutofillTableTest, Autofill_GetAllAutofillEntries_NoResults) {
+ std::vector<AutofillEntry> entries;
+ ASSERT_TRUE(table_->GetAllAutofillEntries(&entries));
+
+ EXPECT_EQ(0U, entries.size());
+}
+
+TEST_F(AutofillTableTest, Autofill_GetAllAutofillEntries_OneResult) {
+ AutofillChangeList changes;
+ std::map<std::string, std::vector<Time> > name_value_times_map;
+
+ time_t start = 0;
+ std::vector<Time> timestamps1;
+ FormFieldData field;
+ field.name = ASCIIToUTF16("Name");
+ field.value = ASCIIToUTF16("Superman");
+ EXPECT_TRUE(table_->AddFormFieldValueTime(field, &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<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(table_->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(AutofillTableTest, Autofill_GetAllAutofillEntries_TwoDistinct) {
+ AutofillChangeList changes;
+ std::map<std::string, std::vector<Time> > name_value_times_map;
+ time_t start = 0;
+
+ std::vector<Time> timestamps1;
+ FormFieldData field;
+ field.name = ASCIIToUTF16("Name");
+ field.value = ASCIIToUTF16("Superman");
+ EXPECT_TRUE(table_->AddFormFieldValueTime(field, &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<Time> > (key1, timestamps1));
+
+ start++;
+ std::vector<Time> timestamps2;
+ field.name = ASCIIToUTF16("Name");
+ field.value = ASCIIToUTF16("Clark Kent");
+ EXPECT_TRUE(table_->AddFormFieldValueTime(field, &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<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(table_->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(AutofillTableTest, Autofill_GetAllAutofillEntries_TwoSame) {
+ AutofillChangeList changes;
+ std::map<std::string, std::vector<Time> > name_value_times_map;
+
+ time_t start = 0;
+ std::vector<Time> timestamps;
+ for (int i = 0; i < 2; i++) {
+ FormFieldData field;
+ field.name = ASCIIToUTF16("Name");
+ field.value = ASCIIToUTF16("Superman");
+ EXPECT_TRUE(table_->AddFormFieldValueTime(field, &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<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(table_->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());
+}
diff --git a/components/webdata/autofill/web_data_service_unittest.cc b/components/webdata/autofill/web_data_service_unittest.cc
new file mode 100644
index 0000000..b7124ac
--- /dev/null
+++ b/components/webdata/autofill/web_data_service_unittest.cc
@@ -0,0 +1,532 @@
+// Copyright (c) 2012 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 <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "base/message_loop.h"
+#include "base/stl_util.h"
+#include "base/string16.h"
+#include "base/string_util.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/time.h"
+#include "base/utf_string_conversions.h"
+#include "components/autofill/browser/autofill_country.h"
+#include "components/autofill/browser/autofill_profile.h"
+#include "components/autofill/browser/credit_card.h"
+#include "components/autofill/common/form_field_data.h"
+#include "components/webdata/autofill/autofill_change.h"
+#include "components/webdata/autofill/autofill_entry.h"
+#include "components/webdata/autofill/autofill_table.h"
+#include "components/webdata/autofill/autofill_webdata_service.h"
+#include "components/webdata/autofill/autofill_webdata_service_observer.h"
+#include "components/webdata/common/web_data_service_test_util.h"
+#include "components/webdata/common/web_database_service.h"
+#include "content/public/test/test_browser_thread.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::Time;
+using base::TimeDelta;
+using base::WaitableEvent;
+using content::BrowserThread;
+using testing::_;
+using testing::DoDefault;
+using testing::ElementsAreArray;
+using testing::Pointee;
+using testing::Property;
+
+static const int kWebDataServiceTimeoutSeconds = 8;
+
+ACTION_P(SignalEvent, event) {
+ event->Signal();
+}
+
+class MockAutofillWebDataServiceObserver
+ : public AutofillWebDataServiceObserverOnDBThread {
+ public:
+ MOCK_METHOD1(AutofillEntriesChanged,
+ void(const AutofillChangeList& changes));
+ MOCK_METHOD1(AutofillProfileChanged,
+ void(const AutofillProfileChange& change));
+};
+
+class WebDataServiceTest : public testing::Test {
+ public:
+ WebDataServiceTest()
+ : ui_thread_(BrowserThread::UI, &message_loop_),
+ db_thread_(BrowserThread::DB) {}
+
+ protected:
+ virtual void SetUp() {
+ db_thread_.Start();
+
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ base::FilePath path = temp_dir_.path().AppendASCII("TestWebDB");
+
+ wdbs_ = new WebDatabaseService(path);
+ wdbs_->AddTable(scoped_ptr<WebDatabaseTable>(new AutofillTable()));
+ wdbs_->LoadDatabase(WebDatabaseService::InitCallback());
+
+ wds_ = new AutofillWebDataService(
+ wdbs_, WebDataServiceBase::ProfileErrorCallback());
+ wds_->Init();
+ }
+
+ virtual void TearDown() {
+ wds_->ShutdownOnUIThread();
+ wdbs_->ShutdownDatabase();
+ wds_ = NULL;
+ wdbs_ = NULL;
+ WaitForDatabaseThread();
+
+ MessageLoop::current()->PostTask(FROM_HERE, MessageLoop::QuitClosure());
+ MessageLoop::current()->Run();
+ db_thread_.Stop();
+ }
+
+ void WaitForDatabaseThread() {
+ base::WaitableEvent done(false, false);
+ BrowserThread::PostTask(
+ BrowserThread::DB,
+ FROM_HERE,
+ base::Bind(&base::WaitableEvent::Signal, base::Unretained(&done)));
+ done.Wait();
+ }
+
+ MessageLoopForUI message_loop_;
+ content::TestBrowserThread ui_thread_;
+ content::TestBrowserThread db_thread_;
+ base::FilePath profile_dir_;
+ scoped_refptr<AutofillWebDataService> wds_;
+ scoped_refptr<WebDatabaseService> wdbs_;
+ base::ScopedTempDir temp_dir_;
+};
+
+class WebDataServiceAutofillTest : public WebDataServiceTest {
+ public:
+ WebDataServiceAutofillTest()
+ : WebDataServiceTest(),
+ unique_id1_(1),
+ unique_id2_(2),
+ test_timeout_(TimeDelta::FromSeconds(kWebDataServiceTimeoutSeconds)),
+ done_event_(false, false) {}
+
+ protected:
+ virtual void SetUp() {
+ WebDataServiceTest::SetUp();
+ name1_ = ASCIIToUTF16("name1");
+ name2_ = ASCIIToUTF16("name2");
+ value1_ = ASCIIToUTF16("value1");
+ value2_ = ASCIIToUTF16("value2");
+
+ void(AutofillWebDataService::*add_observer_func)(
+ AutofillWebDataServiceObserverOnDBThread*) =
+ &AutofillWebDataService::AddObserver;
+ BrowserThread::PostTask(
+ BrowserThread::DB,
+ FROM_HERE,
+ base::Bind(add_observer_func, wds_, &observer_));
+ WaitForDatabaseThread();
+ }
+
+ virtual void TearDown() {
+ void(AutofillWebDataService::*remove_observer_func)(
+ AutofillWebDataServiceObserverOnDBThread*) =
+ &AutofillWebDataService::RemoveObserver;
+ BrowserThread::PostTask(
+ BrowserThread::DB,
+ FROM_HERE,
+ base::Bind(remove_observer_func, wds_, &observer_));
+ WaitForDatabaseThread();
+
+ WebDataServiceTest::TearDown();
+ }
+
+ void AppendFormField(const string16& name,
+ const string16& value,
+ std::vector<FormFieldData>* form_fields) {
+ FormFieldData field;
+ field.name = name;
+ field.value = value;
+ form_fields->push_back(field);
+ }
+
+ string16 name1_;
+ string16 name2_;
+ string16 value1_;
+ string16 value2_;
+ int unique_id1_, unique_id2_;
+ const TimeDelta test_timeout_;
+ testing::NiceMock<MockAutofillWebDataServiceObserver> observer_;
+ WaitableEvent done_event_;
+};
+
+// Simple consumer for Keywords data. Stores the result data and quits UI
+// message loop when callback is invoked.
+class KeywordsConsumer : public WebDataServiceConsumer {
+ public:
+ KeywordsConsumer() : load_succeeded(false) {}
+
+ virtual void OnWebDataServiceRequestDone(
+ WebDataService::Handle h,
+ const WDTypedResult* result) OVERRIDE {
+ if (result) {
+ load_succeeded = true;
+ DCHECK(result->GetType() == KEYWORDS_RESULT);
+ keywords_result =
+ reinterpret_cast<const WDResult<WDKeywordsResult>*>(
+ result)->GetValue();
+ }
+
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ MessageLoop::current()->Quit();
+ }
+
+ // True if keywords data was loaded successfully.
+ bool load_succeeded;
+ // Result data from completion callback.
+ WDKeywordsResult keywords_result;
+};
+
+TEST_F(WebDataServiceAutofillTest, FormFillAdd) {
+ const AutofillChange expected_changes[] = {
+ AutofillChange(AutofillChange::ADD, AutofillKey(name1_, value1_)),
+ AutofillChange(AutofillChange::ADD, AutofillKey(name2_, value2_))
+ };
+
+ // This will verify that the correct notification is triggered,
+ // passing the correct list of autofill keys in the details.
+ EXPECT_CALL(observer_,
+ AutofillEntriesChanged(ElementsAreArray(expected_changes)))
+ .WillOnce(SignalEvent(&done_event_));
+
+ std::vector<FormFieldData> form_fields;
+ AppendFormField(name1_, value1_, &form_fields);
+ AppendFormField(name2_, value2_, &form_fields);
+ wds_->AddFormFields(form_fields);
+
+ // The event will be signaled when the mock observer is notified.
+ done_event_.TimedWait(test_timeout_);
+
+ AutofillWebDataServiceConsumer<std::vector<string16> > consumer;
+ WebDataService::Handle handle;
+ static const int limit = 10;
+ handle = wds_->GetFormValuesForElementName(
+ name1_, string16(), limit, &consumer);
+
+ // The message loop will exit when the consumer is called.
+ MessageLoop::current()->Run();
+
+ EXPECT_EQ(handle, consumer.handle());
+ ASSERT_EQ(1U, consumer.result().size());
+ EXPECT_EQ(value1_, consumer.result()[0]);
+}
+
+TEST_F(WebDataServiceAutofillTest, FormFillRemoveOne) {
+ // First add some values to autofill.
+ EXPECT_CALL(observer_, AutofillEntriesChanged(_))
+ .WillOnce(SignalEvent(&done_event_));
+ std::vector<FormFieldData> form_fields;
+ AppendFormField(name1_, value1_, &form_fields);
+ wds_->AddFormFields(form_fields);
+
+ // The event will be signaled when the mock observer is notified.
+ done_event_.TimedWait(test_timeout_);
+
+ // This will verify that the correct notification is triggered,
+ // passing the correct list of autofill keys in the details.
+ const AutofillChange expected_changes[] = {
+ AutofillChange(AutofillChange::REMOVE, AutofillKey(name1_, value1_))
+ };
+ EXPECT_CALL(observer_,
+ AutofillEntriesChanged(ElementsAreArray(expected_changes)))
+ .WillOnce(SignalEvent(&done_event_));
+ wds_->RemoveFormValueForElementName(name1_, value1_);
+
+ // The event will be signaled when the mock observer is notified.
+ done_event_.TimedWait(test_timeout_);
+}
+
+TEST_F(WebDataServiceAutofillTest, FormFillRemoveMany) {
+ TimeDelta one_day(TimeDelta::FromDays(1));
+ Time t = Time::Now();
+
+ EXPECT_CALL(observer_, AutofillEntriesChanged(_))
+ .WillOnce(SignalEvent(&done_event_));
+
+ std::vector<FormFieldData> form_fields;
+ AppendFormField(name1_, value1_, &form_fields);
+ AppendFormField(name2_, value2_, &form_fields);
+ wds_->AddFormFields(form_fields);
+
+ // The event will be signaled when the mock observer is notified.
+ done_event_.TimedWait(test_timeout_);
+
+ // This will verify that the correct notification is triggered,
+ // passing the correct list of autofill keys in the details.
+ const AutofillChange expected_changes[] = {
+ AutofillChange(AutofillChange::REMOVE, AutofillKey(name1_, value1_)),
+ AutofillChange(AutofillChange::REMOVE, AutofillKey(name2_, value2_))
+ };
+ EXPECT_CALL(observer_,
+ AutofillEntriesChanged(ElementsAreArray(expected_changes)))
+ .WillOnce(SignalEvent(&done_event_));
+ wds_->RemoveFormElementsAddedBetween(t, t + one_day);
+
+ // The event will be signaled when the mock observer is notified.
+ done_event_.TimedWait(test_timeout_);
+}
+
+TEST_F(WebDataServiceAutofillTest, ProfileAdd) {
+ AutofillProfile profile;
+
+ // Check that GUID-based notification was sent.
+ const AutofillProfileChange expected_change(
+ AutofillProfileChange::ADD, profile.guid(), &profile);
+ EXPECT_CALL(observer_, AutofillProfileChanged(expected_change))
+ .WillOnce(SignalEvent(&done_event_));
+
+ wds_->AddAutofillProfile(profile);
+ done_event_.TimedWait(test_timeout_);
+
+ // Check that it was added.
+ AutofillWebDataServiceConsumer<std::vector<AutofillProfile*> > consumer;
+ WebDataService::Handle handle = wds_->GetAutofillProfiles(&consumer);
+ MessageLoop::current()->Run();
+ EXPECT_EQ(handle, consumer.handle());
+ ASSERT_EQ(1U, consumer.result().size());
+ EXPECT_EQ(profile, *consumer.result()[0]);
+ STLDeleteElements(&consumer.result());
+}
+
+TEST_F(WebDataServiceAutofillTest, ProfileRemove) {
+ AutofillProfile profile;
+
+ // Add a profile.
+ EXPECT_CALL(observer_, AutofillProfileChanged(_))
+ .WillOnce(SignalEvent(&done_event_));
+ wds_->AddAutofillProfile(profile);
+ done_event_.TimedWait(test_timeout_);
+
+ // Check that it was added.
+ AutofillWebDataServiceConsumer<std::vector<AutofillProfile*> > consumer;
+ WebDataService::Handle handle = wds_->GetAutofillProfiles(&consumer);
+ MessageLoop::current()->Run();
+ EXPECT_EQ(handle, consumer.handle());
+ ASSERT_EQ(1U, consumer.result().size());
+ EXPECT_EQ(profile, *consumer.result()[0]);
+ STLDeleteElements(&consumer.result());
+
+ // Check that GUID-based notification was sent.
+ const AutofillProfileChange expected_change(
+ AutofillProfileChange::REMOVE, profile.guid(), NULL);
+ EXPECT_CALL(observer_, AutofillProfileChanged(expected_change))
+ .WillOnce(SignalEvent(&done_event_));
+
+ // Remove the profile.
+ wds_->RemoveAutofillProfile(profile.guid());
+ done_event_.TimedWait(test_timeout_);
+
+ // Check that it was removed.
+ AutofillWebDataServiceConsumer<std::vector<AutofillProfile*> > consumer2;
+ WebDataService::Handle handle2 = wds_->GetAutofillProfiles(&consumer2);
+ MessageLoop::current()->Run();
+ EXPECT_EQ(handle2, consumer2.handle());
+ ASSERT_EQ(0U, consumer2.result().size());
+}
+
+TEST_F(WebDataServiceAutofillTest, ProfileUpdate) {
+ AutofillProfile profile1;
+ profile1.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Abe"));
+ AutofillProfile profile2;
+ profile2.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Alice"));
+
+ EXPECT_CALL(observer_, AutofillProfileChanged(_))
+ .WillOnce(DoDefault())
+ .WillOnce(SignalEvent(&done_event_));
+
+ wds_->AddAutofillProfile(profile1);
+ wds_->AddAutofillProfile(profile2);
+ done_event_.TimedWait(test_timeout_);
+
+ // Check that they were added.
+ AutofillWebDataServiceConsumer<std::vector<AutofillProfile*> > consumer;
+ WebDataService::Handle handle = wds_->GetAutofillProfiles(&consumer);
+ MessageLoop::current()->Run();
+ EXPECT_EQ(handle, consumer.handle());
+ ASSERT_EQ(2U, consumer.result().size());
+ EXPECT_EQ(profile1, *consumer.result()[0]);
+ EXPECT_EQ(profile2, *consumer.result()[1]);
+ STLDeleteElements(&consumer.result());
+
+ AutofillProfile profile1_changed(profile1);
+ profile1_changed.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Bill"));
+ const AutofillProfileChange expected_change(
+ AutofillProfileChange::UPDATE, profile1.guid(), &profile1_changed);
+
+ EXPECT_CALL(observer_, AutofillProfileChanged(expected_change))
+ .WillOnce(SignalEvent(&done_event_));
+
+ // Update the profile.
+ wds_->UpdateAutofillProfile(profile1_changed);
+ done_event_.TimedWait(test_timeout_);
+
+ // Check that the updates were made.
+ AutofillWebDataServiceConsumer<std::vector<AutofillProfile*> > consumer2;
+ WebDataService::Handle handle2 = wds_->GetAutofillProfiles(&consumer2);
+ MessageLoop::current()->Run();
+ EXPECT_EQ(handle2, consumer2.handle());
+ ASSERT_EQ(2U, consumer2.result().size());
+ EXPECT_NE(profile1, *consumer2.result()[0]);
+ EXPECT_EQ(profile1_changed, *consumer2.result()[0]);
+ EXPECT_EQ(profile2, *consumer2.result()[1]);
+ STLDeleteElements(&consumer2.result());
+}
+
+TEST_F(WebDataServiceAutofillTest, CreditAdd) {
+ CreditCard card;
+ wds_->AddCreditCard(card);
+ WaitForDatabaseThread();
+
+ // Check that it was added.
+ AutofillWebDataServiceConsumer<std::vector<CreditCard*> > consumer;
+ WebDataService::Handle handle = wds_->GetCreditCards(&consumer);
+ MessageLoop::current()->Run();
+ EXPECT_EQ(handle, consumer.handle());
+ ASSERT_EQ(1U, consumer.result().size());
+ EXPECT_EQ(card, *consumer.result()[0]);
+ STLDeleteElements(&consumer.result());
+}
+
+TEST_F(WebDataServiceAutofillTest, CreditCardRemove) {
+ CreditCard credit_card;
+
+ // Add a credit card.
+ wds_->AddCreditCard(credit_card);
+ WaitForDatabaseThread();
+
+ // Check that it was added.
+ AutofillWebDataServiceConsumer<std::vector<CreditCard*> > consumer;
+ WebDataService::Handle handle = wds_->GetCreditCards(&consumer);
+ MessageLoop::current()->Run();
+ EXPECT_EQ(handle, consumer.handle());
+ ASSERT_EQ(1U, consumer.result().size());
+ EXPECT_EQ(credit_card, *consumer.result()[0]);
+ STLDeleteElements(&consumer.result());
+
+ // Remove the credit card.
+ wds_->RemoveCreditCard(credit_card.guid());
+ WaitForDatabaseThread();
+
+ // Check that it was removed.
+ AutofillWebDataServiceConsumer<std::vector<CreditCard*> > consumer2;
+ WebDataService::Handle handle2 = wds_->GetCreditCards(&consumer2);
+ MessageLoop::current()->Run();
+ EXPECT_EQ(handle2, consumer2.handle());
+ ASSERT_EQ(0U, consumer2.result().size());
+}
+
+TEST_F(WebDataServiceAutofillTest, CreditUpdate) {
+ CreditCard card1;
+ card1.SetRawInfo(CREDIT_CARD_NAME, ASCIIToUTF16("Abe"));
+ CreditCard card2;
+ card2.SetRawInfo(CREDIT_CARD_NAME, ASCIIToUTF16("Alice"));
+
+ wds_->AddCreditCard(card1);
+ wds_->AddCreditCard(card2);
+ WaitForDatabaseThread();
+
+ // Check that they got added.
+ AutofillWebDataServiceConsumer<std::vector<CreditCard*> > consumer;
+ WebDataService::Handle handle = wds_->GetCreditCards(&consumer);
+ MessageLoop::current()->Run();
+ EXPECT_EQ(handle, consumer.handle());
+ ASSERT_EQ(2U, consumer.result().size());
+ EXPECT_EQ(card1, *consumer.result()[0]);
+ EXPECT_EQ(card2, *consumer.result()[1]);
+ STLDeleteElements(&consumer.result());
+
+ CreditCard card1_changed(card1);
+ card1_changed.SetRawInfo(CREDIT_CARD_NAME, ASCIIToUTF16("Bill"));
+
+ wds_->UpdateCreditCard(card1_changed);
+ WaitForDatabaseThread();
+
+ // Check that the updates were made.
+ AutofillWebDataServiceConsumer<std::vector<CreditCard*> > consumer2;
+ WebDataService::Handle handle2 = wds_->GetCreditCards(&consumer2);
+ MessageLoop::current()->Run();
+ EXPECT_EQ(handle2, consumer2.handle());
+ ASSERT_EQ(2U, consumer2.result().size());
+ EXPECT_NE(card1, *consumer2.result()[0]);
+ EXPECT_EQ(card1_changed, *consumer2.result()[0]);
+ EXPECT_EQ(card2, *consumer2.result()[1]);
+ STLDeleteElements(&consumer2.result());
+}
+
+TEST_F(WebDataServiceAutofillTest, AutofillRemoveModifiedBetween) {
+ // Add a profile.
+ EXPECT_CALL(observer_, AutofillProfileChanged(_))
+ .WillOnce(SignalEvent(&done_event_));
+ AutofillProfile profile;
+ wds_->AddAutofillProfile(profile);
+ done_event_.TimedWait(test_timeout_);
+
+ // Check that it was added.
+ AutofillWebDataServiceConsumer<std::vector<AutofillProfile*> >
+ profile_consumer;
+ WebDataService::Handle handle = wds_->GetAutofillProfiles(&profile_consumer);
+ MessageLoop::current()->Run();
+ EXPECT_EQ(handle, profile_consumer.handle());
+ ASSERT_EQ(1U, profile_consumer.result().size());
+ EXPECT_EQ(profile, *profile_consumer.result()[0]);
+ STLDeleteElements(&profile_consumer.result());
+
+ // Add a credit card.
+ CreditCard credit_card;
+ wds_->AddCreditCard(credit_card);
+ WaitForDatabaseThread();
+
+ // Check that it was added.
+ AutofillWebDataServiceConsumer<std::vector<CreditCard*> > card_consumer;
+ handle = wds_->GetCreditCards(&card_consumer);
+ MessageLoop::current()->Run();
+ EXPECT_EQ(handle, card_consumer.handle());
+ ASSERT_EQ(1U, card_consumer.result().size());
+ EXPECT_EQ(credit_card, *card_consumer.result()[0]);
+ STLDeleteElements(&card_consumer.result());
+
+ // Check that GUID-based notification was sent for the profile.
+ const AutofillProfileChange expected_profile_change(
+ AutofillProfileChange::REMOVE, profile.guid(), NULL);
+ EXPECT_CALL(observer_, AutofillProfileChanged(expected_profile_change))
+ .WillOnce(SignalEvent(&done_event_));
+
+ // Remove the profile using time range of "all time".
+ wds_->RemoveAutofillDataModifiedBetween(Time(), Time());
+ done_event_.TimedWait(test_timeout_);
+ WaitForDatabaseThread();
+
+ // Check that the profile was removed.
+ AutofillWebDataServiceConsumer<std::vector<AutofillProfile*> >
+ profile_consumer2;
+ WebDataService::Handle handle2 =
+ wds_->GetAutofillProfiles(&profile_consumer2);
+ MessageLoop::current()->Run();
+ EXPECT_EQ(handle2, profile_consumer2.handle());
+ ASSERT_EQ(0U, profile_consumer2.result().size());
+
+ // Check that the credit card was removed.
+ AutofillWebDataServiceConsumer<std::vector<CreditCard*> > card_consumer2;
+ handle2 = wds_->GetCreditCards(&card_consumer2);
+ MessageLoop::current()->Run();
+ EXPECT_EQ(handle2, card_consumer2.handle());
+ ASSERT_EQ(0U, card_consumer2.result().size());
+}
diff --git a/components/webdata/autofill/web_database_migration_unittest.cc b/components/webdata/autofill/web_database_migration_unittest.cc
new file mode 100644
index 0000000..8a715a5
--- /dev/null
+++ b/components/webdata/autofill/web_database_migration_unittest.cc
@@ -0,0 +1,1992 @@
+// Copyright (c) 2012 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 <string>
+
+#include "base/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/guid.h"
+#include "base/message_loop.h"
+#include "base/stl_util.h"
+#include "base/string16.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/time.h"
+#include "base/utf_string_conversions.h"
+#include "base/values.h"
+#include "chrome/browser/webdata/keyword_table.h"
+#include "chrome/browser/webdata/logins_table.h"
+#include "chrome/browser/webdata/token_service_table.h"
+#include "chrome/browser/webdata/web_apps_table.h"
+#include "chrome/browser/webdata/web_intents_table.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "components/autofill/browser/autofill_country.h"
+#include "components/autofill/browser/autofill_profile.h"
+#include "components/autofill/browser/autofill_type.h"
+#include "components/autofill/browser/credit_card.h"
+#include "components/webdata/autofill/autofill_change.h"
+#include "components/webdata/autofill/autofill_entry.h"
+#include "components/webdata/autofill/autofill_table.h"
+#include "components/webdata/common/web_database.h"
+#include "content/public/test/test_browser_thread.h"
+#include "sql/statement.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::Time;
+using content::BrowserThread;
+
+namespace {
+
+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->SetRawInfo(NAME_FIRST, s.ColumnString16(2));
+ profile->SetRawInfo(NAME_MIDDLE, s.ColumnString16(3));
+ profile->SetRawInfo(NAME_LAST, s.ColumnString16(4));
+ profile->SetRawInfo(EMAIL_ADDRESS, s.ColumnString16(5));
+ profile->SetRawInfo(COMPANY_NAME, s.ColumnString16(6));
+ profile->SetRawInfo(ADDRESS_HOME_LINE1, s.ColumnString16(7));
+ profile->SetRawInfo(ADDRESS_HOME_LINE2, s.ColumnString16(8));
+ profile->SetRawInfo(ADDRESS_HOME_CITY, s.ColumnString16(9));
+ profile->SetRawInfo(ADDRESS_HOME_STATE, s.ColumnString16(10));
+ profile->SetRawInfo(ADDRESS_HOME_ZIP, s.ColumnString16(11));
+ profile->SetInfo(ADDRESS_HOME_COUNTRY, s.ColumnString16(12), "en-US");
+ profile->SetRawInfo(PHONE_HOME_WHOLE_NUMBER, s.ColumnString16(13));
+ *date_modified = s.ColumnInt64(15);
+ profile->set_guid(s.ColumnString(16));
+ EXPECT_TRUE(base::IsValidGUID(profile->guid()));
+}
+
+void AutofillProfile33FromStatement(const sql::Statement& s,
+ AutofillProfile* profile,
+ int64* date_modified) {
+ DCHECK(profile);
+ DCHECK(date_modified);
+ profile->set_guid(s.ColumnString(0));
+ EXPECT_TRUE(base::IsValidGUID(profile->guid()));
+ profile->SetRawInfo(COMPANY_NAME, s.ColumnString16(1));
+ profile->SetRawInfo(ADDRESS_HOME_LINE1, s.ColumnString16(2));
+ profile->SetRawInfo(ADDRESS_HOME_LINE2, s.ColumnString16(3));
+ profile->SetRawInfo(ADDRESS_HOME_CITY, s.ColumnString16(4));
+ profile->SetRawInfo(ADDRESS_HOME_STATE, s.ColumnString16(5));
+ profile->SetRawInfo(ADDRESS_HOME_ZIP, s.ColumnString16(6));
+ profile->SetInfo(ADDRESS_HOME_COUNTRY, s.ColumnString16(7), "en-US");
+ *date_modified = s.ColumnInt64(8);
+}
+
+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->SetRawInfo(CREDIT_CARD_NAME, s.ColumnString16(2));
+ credit_card->SetRawInfo(CREDIT_CARD_TYPE, s.ColumnString16(3));
+ credit_card->SetRawInfo(CREDIT_CARD_EXP_MONTH, s.ColumnString16(5));
+ credit_card->SetRawInfo(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(base::IsValidGUID(credit_card->guid()));
+}
+
+void CreditCard32FromStatement(const sql::Statement& s,
+ CreditCard* credit_card,
+ std::string* encrypted_number,
+ int64* date_modified) {
+ DCHECK(credit_card);
+ DCHECK(encrypted_number);
+ DCHECK(date_modified);
+ credit_card->set_guid(s.ColumnString(0));
+ EXPECT_TRUE(base::IsValidGUID(credit_card->guid()));
+ credit_card->SetRawInfo(CREDIT_CARD_NAME, s.ColumnString16(1));
+ credit_card->SetRawInfo(CREDIT_CARD_EXP_MONTH, s.ColumnString16(2));
+ credit_card->SetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR, s.ColumnString16(3));
+ int encrypted_number_len = s.ColumnByteLength(4);
+ if (encrypted_number_len) {
+ encrypted_number->resize(encrypted_number_len);
+ memcpy(&(*encrypted_number)[0], s.ColumnBlob(4), encrypted_number_len);
+ }
+ *date_modified = s.ColumnInt64(5);
+}
+
+void CheckHasBackupData(sql::MetaTable* meta_table) {
+ std::string value;
+ EXPECT_TRUE(meta_table->GetValue(
+ "Default Search Provider ID Backup", &value));
+ EXPECT_TRUE(meta_table->GetValue(
+ "Default Search Provider ID Backup Signature", &value));
+}
+
+void CheckNoBackupData(const sql::Connection& connection,
+ sql::MetaTable* meta_table) {
+ std::string value;
+ EXPECT_FALSE(meta_table->GetValue(
+ "Default Search Provider ID Backup", &value));
+ EXPECT_FALSE(meta_table->GetValue(
+ "Default Search Provider ID Backup Signature", &value));
+ EXPECT_FALSE(connection.DoesTableExist("keywords_backup"));
+}
+
+} // anonymous namespace
+
+// 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:
+ // In order to access the application locale -- which the tested functions do
+ // internally -- this test must run on the UI thread.
+ // TODO(isherman): The WebDatabase code should probably verify that it is
+ // running on the DB thread. Once that verification is added, this code will
+ // need to be updated to create both threads.
+ WebDatabaseMigrationTest()
+ : ui_thread_(BrowserThread::UI, &message_loop_for_ui_) {}
+ virtual ~WebDatabaseMigrationTest() {}
+
+ virtual void SetUp() {
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ }
+
+ // Load the database via the WebDatabase class and migrate the database to
+ // the current version.
+ void DoMigration() {
+ // TODO(joi): This whole unit test file needs to stay in //chrome
+ // for now, as it needs to know about all the different table
+ // types. Once all webdata datatypes have been componentized, this
+ // could move to components_unittests.
+ AutofillTable autofill_table;
+ KeywordTable keyword_table;
+ LoginsTable logins_table;
+ TokenServiceTable token_service_table;
+ WebAppsTable web_apps_table;
+ WebIntentsTable web_intents_table;
+
+ WebDatabase db;
+ db.AddTable(&autofill_table);
+ db.AddTable(&keyword_table);
+ db.AddTable(&logins_table);
+ db.AddTable(&token_service_table);
+ db.AddTable(&web_apps_table);
+ db.AddTable(&web_intents_table);
+
+ // This causes the migration to occur.
+ ASSERT_EQ(sql::INIT_OK, db.Init(GetDatabasePath()));
+ }
+
+ 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;
+
+ base::FilePath GetDatabasePath() {
+ const base::FilePath::CharType kWebDatabaseFilename[] =
+ FILE_PATH_LITERAL("TestWebDatabase.sqlite3");
+ return temp_dir_.path().Append(base::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 base::FilePath& file, std::string* contents) {
+ base::FilePath path = ui_test_utils::GetTestFilePath(
+ base::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 base::FilePath::StringType& file);
+
+ private:
+ MessageLoopForUI message_loop_for_ui_;
+ content::TestBrowserThread ui_thread_;
+ base::ScopedTempDir temp_dir_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebDatabaseMigrationTest);
+};
+
+const int WebDatabaseMigrationTest::kCurrentTestedVersionNumber = 49;
+
+void WebDatabaseMigrationTest::LoadDatabase(
+ const base::FilePath::StringType& file) {
+ std::string contents;
+ ASSERT_TRUE(GetWebDatabaseData(base::FilePath(file), &contents));
+
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+ ASSERT_TRUE(connection.Execute(contents.data()));
+}
+
+// Tests that the all migrations from an empty database succeed.
+TEST_F(WebDatabaseMigrationTest, MigrateEmptyToCurrent) {
+ DoMigration();
+
+ // 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("autofill"));
+ EXPECT_TRUE(connection.DoesTableExist("autofill_dates"));
+ EXPECT_TRUE(connection.DoesTableExist("autofill_profiles"));
+ EXPECT_TRUE(connection.DoesTableExist("credit_cards"));
+ EXPECT_TRUE(connection.DoesTableExist("keywords"));
+ // The logins table is obsolete. (We used to store saved passwords here.)
+ EXPECT_FALSE(connection.DoesTableExist("logins"));
+ EXPECT_TRUE(connection.DoesTableExist("meta"));
+ EXPECT_TRUE(connection.DoesTableExist("token_service"));
+ EXPECT_TRUE(connection.DoesTableExist("web_app_icons"));
+ EXPECT_TRUE(connection.DoesTableExist("web_apps"));
+ EXPECT_TRUE(connection.DoesTableExist("web_intents"));
+ EXPECT_TRUE(connection.DoesTableExist("web_intents_defaults"));
+ }
+}
+
+// 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(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"));
+ }
+
+ DoMigration();
+
+ // 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(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"));
+ }
+
+ DoMigration();
+
+ // 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"));
+ }
+}
+
+// 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(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()));
+ }
+
+ DoMigration();
+
+ // 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| |created_by_policy| 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(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);
+ }
+
+ DoMigration();
+
+ // 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, name_on_card, expiration_month, expiration_year, "
+ "card_number_encrypted, date_modified "
+ "FROM credit_cards"));
+ ASSERT_TRUE(s.Step());
+ EXPECT_EQ("Jack", s.ColumnString(1));
+ EXPECT_EQ(2, s.ColumnInt(2));
+ EXPECT_EQ(2012, s.ColumnInt(3));
+ // 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(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);
+ }
+
+ DoMigration();
+
+ // 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| |created_by_policy| 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, name_on_card, expiration_month, expiration_year, "
+ "card_number_encrypted, date_modified "
+ "FROM credit_cards"));
+ ASSERT_TRUE(s.Step());
+ EXPECT_EQ("Jack", s.ColumnString(1));
+ EXPECT_EQ(2, s.ColumnInt(2));
+ EXPECT_EQ(2012, s.ColumnInt(3));
+ // Column 5 is encrypted credit card number blo b.
+ // Column 6 is date_modified.
+ }
+}
+
+// Makes sure instant_url is added correctly to keywords.
+TEST_F(WebDatabaseMigrationTest, MigrateVersion27ToCurrent) {
+ // Initialize the database.
+ ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_27.sql")));
+
+ // Verify pre-conditions. These are expectations for version 27 of the
+ // database.
+ {
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+
+ ASSERT_FALSE(connection.DoesColumnExist("keywords", "instant_url"));
+ }
+
+ DoMigration();
+
+ // 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 (added in Version 28) was ultimately dropped
+ // again 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 " + KeywordTable::GetKeywordColumns() + " 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_TRUE(s2.ColumnBool(5));
+ EXPECT_EQ(std::string(), s2.ColumnString(6));
+ EXPECT_EQ(0, s2.ColumnInt(7));
+ EXPECT_EQ(0, s2.ColumnInt(8));
+ EXPECT_EQ(std::string("UTF-8"), s2.ColumnString(9));
+ EXPECT_TRUE(s2.ColumnBool(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(false, s2.ColumnBool(13));
+ EXPECT_EQ(std::string(), s2.ColumnString(14));
+ EXPECT_EQ(0, s2.ColumnInt(15));
+ EXPECT_EQ(std::string(), s2.ColumnString(16));
+ }
+}
+
+// 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(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"));
+ }
+
+ Time pre_creation_time = Time::Now();
+ DoMigration();
+ 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.is_valid());
+ 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.is_valid());
+ 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(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"));
+ }
+
+ DoMigration();
+
+ // 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(base::IsValidGUID(guid1));
+
+ ASSERT_TRUE(s.Step());
+ std::string guid2 = s.ColumnString(0);
+ EXPECT_TRUE(base::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(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());
+ }
+
+ DoMigration();
+
+ // 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, company_name, address_line_1, address_line_2, "
+ "city, state, zipcode, country, date_modified "
+ "FROM autofill_profiles"));
+ ASSERT_TRUE(s1.Step());
+
+ AutofillProfile profile_a;
+ int64 profile_date_modified_a = 0;
+ EXPECT_NO_FATAL_FAILURE(AutofillProfile33FromStatement(
+ s1, &profile_a, &profile_date_modified_a));
+ EXPECT_EQ(profile.guid(), profile_a.guid());
+ EXPECT_EQ(profile.GetRawInfo(COMPANY_NAME),
+ profile_a.GetRawInfo(COMPANY_NAME));
+ EXPECT_EQ(profile.GetRawInfo(ADDRESS_HOME_LINE1),
+ profile_a.GetRawInfo(ADDRESS_HOME_LINE1));
+ EXPECT_EQ(profile.GetRawInfo(ADDRESS_HOME_LINE2),
+ profile_a.GetRawInfo(ADDRESS_HOME_LINE2));
+ EXPECT_EQ(profile.GetRawInfo(ADDRESS_HOME_CITY),
+ profile_a.GetRawInfo(ADDRESS_HOME_CITY));
+ EXPECT_EQ(profile.GetRawInfo(ADDRESS_HOME_STATE),
+ profile_a.GetRawInfo(ADDRESS_HOME_STATE));
+ EXPECT_EQ(profile.GetRawInfo(ADDRESS_HOME_ZIP),
+ profile_a.GetRawInfo(ADDRESS_HOME_ZIP));
+ EXPECT_EQ(profile.GetRawInfo(ADDRESS_HOME_COUNTRY),
+ profile_a.GetRawInfo(ADDRESS_HOME_COUNTRY));
+ EXPECT_EQ(profile_date_modified, profile_date_modified_a);
+
+ sql::Statement s2(
+ connection.GetUniqueStatement(
+ "SELECT guid, 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_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);
+ }
+}
+
+// Factor |autofill_profiles| address information separately from name, email,
+// and phone.
+TEST_F(WebDatabaseMigrationTest, MigrateVersion32ToCurrent) {
+ // Initialize the database.
+ ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_32.sql")));
+
+ // Verify pre-conditions. These are expectations for version 32 of the
+ // database.
+ {
+ 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", "label"));
+ EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "first_name"));
+ EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "middle_name"));
+ EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "last_name"));
+ EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "email"));
+ EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles",
+ "company_name"));
+ EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles",
+ "address_line_1"));
+ EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles",
+ "address_line_2"));
+ EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "city"));
+ EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "state"));
+ EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "zipcode"));
+ EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "country"));
+ EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "phone"));
+ EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "fax"));
+ EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles",
+ "date_modified"));
+
+ EXPECT_FALSE(connection.DoesTableExist("autofill_profile_names"));
+ EXPECT_FALSE(connection.DoesTableExist("autofill_profile_emails"));
+ EXPECT_FALSE(connection.DoesTableExist("autofill_profile_phones"));
+
+ EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "label"));
+ }
+
+ DoMigration();
+
+ // 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 changes to columns.
+ EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "guid"));
+ EXPECT_FALSE(connection.DoesColumnExist("autofill_profiles", "label"));
+ EXPECT_FALSE(connection.DoesColumnExist("autofill_profiles", "first_name"));
+ EXPECT_FALSE(connection.DoesColumnExist("autofill_profiles",
+ "middle_name"));
+ EXPECT_FALSE(connection.DoesColumnExist("autofill_profiles", "last_name"));
+ EXPECT_FALSE(connection.DoesColumnExist("autofill_profiles", "email"));
+ EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles",
+ "company_name"));
+ EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles",
+ "address_line_1"));
+ EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles",
+ "address_line_2"));
+ EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "city"));
+ EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "state"));
+ EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "zipcode"));
+ EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "country"));
+ EXPECT_FALSE(connection.DoesColumnExist("autofill_profiles", "phone"));
+ EXPECT_FALSE(connection.DoesColumnExist("autofill_profiles", "fax"));
+ EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles",
+ "date_modified"));
+
+ // New "names" table.
+ EXPECT_TRUE(connection.DoesColumnExist("autofill_profile_names", "guid"));
+ EXPECT_TRUE(connection.DoesColumnExist("autofill_profile_names",
+ "first_name"));
+ EXPECT_TRUE(connection.DoesColumnExist("autofill_profile_names",
+ "middle_name"));
+ EXPECT_TRUE(connection.DoesColumnExist("autofill_profile_names",
+ "last_name"));
+
+ // New "emails" table.
+ EXPECT_TRUE(connection.DoesColumnExist("autofill_profile_emails", "guid"));
+ EXPECT_TRUE(connection.DoesColumnExist("autofill_profile_emails", "email"));
+
+ // New "phones" table.
+ EXPECT_TRUE(connection.DoesColumnExist("autofill_profile_phones", "guid"));
+ EXPECT_TRUE(connection.DoesColumnExist("autofill_profile_phones", "type"));
+ EXPECT_TRUE(connection.DoesColumnExist("autofill_profile_phones",
+ "number"));
+
+ EXPECT_FALSE(connection.DoesColumnExist("credit_cards", "label"));
+
+ // Verify data in the database after the migration.
+ sql::Statement s1(
+ connection.GetUniqueStatement(
+ "SELECT guid, company_name, address_line_1, address_line_2, "
+ "city, state, zipcode, country, date_modified "
+ "FROM autofill_profiles"));
+
+ // John Doe.
+ ASSERT_TRUE(s1.Step());
+ EXPECT_EQ("00580526-FF81-EE2A-0546-1AC593A32E2F", s1.ColumnString(0));
+ EXPECT_EQ(ASCIIToUTF16("Doe Enterprises"), s1.ColumnString16(1));
+ EXPECT_EQ(ASCIIToUTF16("1 Main St"), s1.ColumnString16(2));
+ EXPECT_EQ(ASCIIToUTF16("Apt 1"), s1.ColumnString16(3));
+ EXPECT_EQ(ASCIIToUTF16("Los Altos"), s1.ColumnString16(4));
+ EXPECT_EQ(ASCIIToUTF16("CA"), s1.ColumnString16(5));
+ EXPECT_EQ(ASCIIToUTF16("94022"), s1.ColumnString16(6));
+ EXPECT_EQ(ASCIIToUTF16("United States"), s1.ColumnString16(7));
+ EXPECT_EQ(1297882100L, s1.ColumnInt64(8));
+
+ // John P. Doe.
+ // Gets merged during migration from 35 to 37 due to multi-valued fields.
+
+ // Dave Smith.
+ ASSERT_TRUE(s1.Step());
+ EXPECT_EQ("4C74A9D8-7EEE-423E-F9C2-E7FA70ED1396", s1.ColumnString(0));
+ EXPECT_EQ(string16(), s1.ColumnString16(1));
+ EXPECT_EQ(ASCIIToUTF16("2 Main Street"), s1.ColumnString16(2));
+ EXPECT_EQ(string16(), s1.ColumnString16(3));
+ EXPECT_EQ(ASCIIToUTF16("Los Altos"), s1.ColumnString16(4));
+ EXPECT_EQ(ASCIIToUTF16("CA"), s1.ColumnString16(5));
+ EXPECT_EQ(ASCIIToUTF16("94022"), s1.ColumnString16(6));
+ EXPECT_EQ(ASCIIToUTF16("United States"), s1.ColumnString16(7));
+ EXPECT_EQ(1297882100L, s1.ColumnInt64(8));
+
+ // Dave Smith (Part 2).
+ ASSERT_TRUE(s1.Step());
+ EXPECT_EQ("722DF5C4-F74A-294A-46F0-31FFDED0D635", s1.ColumnString(0));
+ EXPECT_EQ(string16(), s1.ColumnString16(1));
+ EXPECT_EQ(ASCIIToUTF16("2 Main St"), s1.ColumnString16(2));
+ EXPECT_EQ(string16(), s1.ColumnString16(3));
+ EXPECT_EQ(ASCIIToUTF16("Los Altos"), s1.ColumnString16(4));
+ EXPECT_EQ(ASCIIToUTF16("CA"), s1.ColumnString16(5));
+ EXPECT_EQ(ASCIIToUTF16("94022"), s1.ColumnString16(6));
+ EXPECT_EQ(ASCIIToUTF16("United States"), s1.ColumnString16(7));
+ EXPECT_EQ(1297882100L, s1.ColumnInt64(8));
+
+ // Alfred E Newman.
+ // Gets culled during migration from 35 to 36 due to incomplete address.
+
+ // 3 Main St.
+ ASSERT_TRUE(s1.Step());
+ EXPECT_EQ("9E5FE298-62C7-83DF-6293-381BC589183F", s1.ColumnString(0));
+ EXPECT_EQ(string16(), s1.ColumnString16(1));
+ EXPECT_EQ(ASCIIToUTF16("3 Main St"), s1.ColumnString16(2));
+ EXPECT_EQ(string16(), s1.ColumnString16(3));
+ EXPECT_EQ(ASCIIToUTF16("Los Altos"), s1.ColumnString16(4));
+ EXPECT_EQ(ASCIIToUTF16("CA"), s1.ColumnString16(5));
+ EXPECT_EQ(ASCIIToUTF16("94022"), s1.ColumnString16(6));
+ EXPECT_EQ(ASCIIToUTF16("United States"), s1.ColumnString16(7));
+ EXPECT_EQ(1297882100L, s1.ColumnInt64(8));
+
+ // That should be all.
+ EXPECT_FALSE(s1.Step());
+
+ sql::Statement s2(
+ connection.GetUniqueStatement(
+ "SELECT guid, first_name, middle_name, last_name "
+ "FROM autofill_profile_names"));
+
+ // John Doe.
+ ASSERT_TRUE(s2.Step());
+ EXPECT_EQ("00580526-FF81-EE2A-0546-1AC593A32E2F", s2.ColumnString(0));
+ EXPECT_EQ(ASCIIToUTF16("John"), s2.ColumnString16(1));
+ EXPECT_EQ(string16(), s2.ColumnString16(2));
+ EXPECT_EQ(ASCIIToUTF16("Doe"), s2.ColumnString16(3));
+
+ // John P. Doe. Note same guid as above due to merging of multi-valued
+ // fields.
+ ASSERT_TRUE(s2.Step());
+ EXPECT_EQ("00580526-FF81-EE2A-0546-1AC593A32E2F", s2.ColumnString(0));
+ EXPECT_EQ(ASCIIToUTF16("John"), s2.ColumnString16(1));
+ EXPECT_EQ(ASCIIToUTF16("P."), s2.ColumnString16(2));
+ EXPECT_EQ(ASCIIToUTF16("Doe"), s2.ColumnString16(3));
+
+ // Dave Smith.
+ ASSERT_TRUE(s2.Step());
+ EXPECT_EQ("4C74A9D8-7EEE-423E-F9C2-E7FA70ED1396", s2.ColumnString(0));
+ EXPECT_EQ(ASCIIToUTF16("Dave"), s2.ColumnString16(1));
+ EXPECT_EQ(string16(), s2.ColumnString16(2));
+ EXPECT_EQ(ASCIIToUTF16("Smith"), s2.ColumnString16(3));
+
+ // Dave Smith (Part 2).
+ ASSERT_TRUE(s2.Step());
+ EXPECT_EQ("722DF5C4-F74A-294A-46F0-31FFDED0D635", s2.ColumnString(0));
+ EXPECT_EQ(ASCIIToUTF16("Dave"), s2.ColumnString16(1));
+ EXPECT_EQ(string16(), s2.ColumnString16(2));
+ EXPECT_EQ(ASCIIToUTF16("Smith"), s2.ColumnString16(3));
+
+ // Alfred E Newman.
+ // Gets culled during migration from 35 to 36 due to incomplete address.
+
+ // 3 Main St.
+ ASSERT_TRUE(s2.Step());
+ EXPECT_EQ("9E5FE298-62C7-83DF-6293-381BC589183F", s2.ColumnString(0));
+ EXPECT_EQ(string16(), s2.ColumnString16(1));
+ EXPECT_EQ(string16(), s2.ColumnString16(2));
+ EXPECT_EQ(string16(), s2.ColumnString16(3));
+
+ // Should be all.
+ EXPECT_FALSE(s2.Step());
+
+ sql::Statement s3(
+ connection.GetUniqueStatement(
+ "SELECT guid, email "
+ "FROM autofill_profile_emails"));
+
+ // John Doe.
+ ASSERT_TRUE(s3.Step());
+ EXPECT_EQ("00580526-FF81-EE2A-0546-1AC593A32E2F", s3.ColumnString(0));
+ EXPECT_EQ(ASCIIToUTF16("john@doe.com"), s3.ColumnString16(1));
+
+ // John P. Doe.
+ // Gets culled during migration from 35 to 37 due to merging of John Doe and
+ // John P. Doe addresses.
+
+ // 2 Main Street.
+ ASSERT_TRUE(s3.Step());
+ EXPECT_EQ("4C74A9D8-7EEE-423E-F9C2-E7FA70ED1396", s3.ColumnString(0));
+ EXPECT_EQ(string16(), s3.ColumnString16(1));
+
+ // 2 Main St.
+ ASSERT_TRUE(s3.Step());
+ EXPECT_EQ("722DF5C4-F74A-294A-46F0-31FFDED0D635", s3.ColumnString(0));
+ EXPECT_EQ(string16(), s3.ColumnString16(1));
+
+ // Alfred E Newman.
+ // Gets culled during migration from 35 to 36 due to incomplete address.
+
+ // 3 Main St.
+ ASSERT_TRUE(s3.Step());
+ EXPECT_EQ("9E5FE298-62C7-83DF-6293-381BC589183F", s3.ColumnString(0));
+ EXPECT_EQ(string16(), s3.ColumnString16(1));
+
+ // Should be all.
+ EXPECT_FALSE(s3.Step());
+
+ sql::Statement s4(
+ connection.GetUniqueStatement(
+ "SELECT guid, type, number "
+ "FROM autofill_profile_phones"));
+
+ // John Doe phone.
+ ASSERT_TRUE(s4.Step());
+ EXPECT_EQ("00580526-FF81-EE2A-0546-1AC593A32E2F", s4.ColumnString(0));
+ EXPECT_EQ(0, s4.ColumnInt(1)); // 0 means phone.
+ EXPECT_EQ(ASCIIToUTF16("4151112222"), s4.ColumnString16(2));
+
+ // John Doe fax.
+ // Gets culled after fax type removed.
+
+ // John P. Doe phone.
+ // Gets culled during migration from 35 to 37 due to merging of John Doe and
+ // John P. Doe addresses.
+
+ // John P. Doe fax.
+ // Gets culled during migration from 35 to 37 due to merging of John Doe and
+ // John P. Doe addresses.
+
+ // 2 Main Street phone.
+ ASSERT_TRUE(s4.Step());
+ EXPECT_EQ("4C74A9D8-7EEE-423E-F9C2-E7FA70ED1396", s4.ColumnString(0));
+ EXPECT_EQ(0, s4.ColumnInt(1)); // 0 means phone.
+ EXPECT_EQ(string16(), s4.ColumnString16(2));
+
+ // 2 Main Street fax.
+ // Gets culled after fax type removed.
+
+ // 2 Main St phone.
+ ASSERT_TRUE(s4.Step());
+ EXPECT_EQ("722DF5C4-F74A-294A-46F0-31FFDED0D635", s4.ColumnString(0));
+ EXPECT_EQ(0, s4.ColumnInt(1)); // 0 means phone.
+ EXPECT_EQ(string16(), s4.ColumnString16(2));
+
+ // 2 Main St fax.
+ // Gets culled after fax type removed.
+
+ // Note no phone or fax for Alfred E Newman.
+
+ // 3 Main St phone.
+ ASSERT_TRUE(s4.Step());
+ EXPECT_EQ("9E5FE298-62C7-83DF-6293-381BC589183F", s4.ColumnString(0));
+ EXPECT_EQ(0, s4.ColumnInt(1)); // 0 means phone.
+ EXPECT_EQ(string16(), s4.ColumnString16(2));
+
+ // 2 Main St fax.
+ // Gets culled after fax type removed.
+
+ // Should be all.
+ EXPECT_FALSE(s4.Step());
+ }
+}
+
+// Adds a column for the autofill profile's country code.
+TEST_F(WebDatabaseMigrationTest, MigrateVersion33ToCurrent) {
+ // Initialize the database.
+ ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_33.sql")));
+
+ // Verify pre-conditions. These are expectations for version 33 of the
+ // database.
+ {
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+
+ EXPECT_FALSE(connection.DoesColumnExist("autofill_profiles",
+ "country_code"));
+
+ // Check that the country value is the one we expect.
+ sql::Statement s(
+ connection.GetUniqueStatement("SELECT country FROM autofill_profiles"));
+
+ ASSERT_TRUE(s.Step());
+ std::string country = s.ColumnString(0);
+ EXPECT_EQ("United States", country);
+ }
+
+ DoMigration();
+
+ // 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",
+ "country_code"));
+
+ // Check that the country code is properly converted.
+ sql::Statement s(connection.GetUniqueStatement(
+ "SELECT country_code FROM autofill_profiles"));
+
+ ASSERT_TRUE(s.Step());
+ std::string country_code = s.ColumnString(0);
+ EXPECT_EQ("US", country_code);
+ }
+}
+
+// Cleans up bad country code "UK" in favor of good country code "GB".
+TEST_F(WebDatabaseMigrationTest, MigrateVersion34ToCurrent) {
+ // Initialize the database.
+ ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_34.sql")));
+
+ // Verify pre-conditions. These are expectations for version 34 of the
+ // database.
+ {
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+
+ EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles",
+ "country_code"));
+
+ // Check that the country_code value is the one we expect.
+ sql::Statement s(
+ connection.GetUniqueStatement("SELECT country_code "
+ "FROM autofill_profiles"));
+
+ ASSERT_TRUE(s.Step());
+ std::string country_code = s.ColumnString(0);
+ EXPECT_EQ("UK", country_code);
+
+ // Should have only one.
+ ASSERT_FALSE(s.Step());
+ }
+
+ DoMigration();
+
+ // 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",
+ "country_code"));
+
+ // Check that the country_code code is properly converted.
+ sql::Statement s(connection.GetUniqueStatement(
+ "SELECT country_code FROM autofill_profiles"));
+
+ ASSERT_TRUE(s.Step());
+ std::string country_code = s.ColumnString(0);
+ EXPECT_EQ("GB", country_code);
+
+ // Should have only one.
+ ASSERT_FALSE(s.Step());
+ }
+}
+
+// Cleans up invalid profiles based on more agressive merging. Filters out
+// profiles that are subsets of other profiles, and profiles with invalid email,
+// state, and incomplete address.
+TEST_F(WebDatabaseMigrationTest, MigrateVersion35ToCurrent) {
+ // Initialize the database.
+ ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_35.sql")));
+
+ // Verify pre-conditions. These are expectations for version 34 of the
+ // database.
+ {
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+
+ EXPECT_FALSE(connection.DoesTableExist("autofill_profiles_trash"));
+ ASSERT_TRUE(connection.DoesColumnExist("autofill_profiles", "guid"));
+
+ // Check that there are 6 profiles prior to merge.
+ sql::Statement s(
+ connection.GetUniqueStatement("SELECT guid FROM autofill_profiles"));
+ int i = 0;
+ while (s.Step())
+ ++i;
+ EXPECT_EQ(6, i);
+ }
+
+ DoMigration();
+
+ // 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.DoesTableExist("autofill_profiles_trash"));
+ ASSERT_TRUE(connection.DoesColumnExist("autofill_profiles_trash", "guid"));
+ ASSERT_TRUE(connection.DoesColumnExist("autofill_profiles", "guid"));
+
+ // Verify data in the database after the migration.
+ sql::Statement s1(
+ connection.GetUniqueStatement(
+ "SELECT guid, company_name, address_line_1, address_line_2, "
+ "city, state, zipcode, country, date_modified "
+ "FROM autofill_profiles"));
+
+ // John Doe.
+ ASSERT_TRUE(s1.Step());
+ EXPECT_EQ("00000000-0000-0000-0000-000000000001", s1.ColumnString(0));
+ EXPECT_EQ(ASCIIToUTF16("Acme Inc."), s1.ColumnString16(1));
+ EXPECT_EQ(ASCIIToUTF16("1 Main Street"), s1.ColumnString16(2));
+ EXPECT_EQ(ASCIIToUTF16("Apt 2"), s1.ColumnString16(3));
+ EXPECT_EQ(ASCIIToUTF16("San Francisco"), s1.ColumnString16(4));
+ EXPECT_EQ(ASCIIToUTF16("CA"), s1.ColumnString16(5));
+ EXPECT_EQ(ASCIIToUTF16("94102"), s1.ColumnString16(6));
+ EXPECT_EQ(ASCIIToUTF16("United States"), s1.ColumnString16(7));
+ EXPECT_EQ(1300131704, s1.ColumnInt64(8));
+
+ // That should be it.
+ ASSERT_FALSE(s1.Step());
+
+ // Check that there 5 trashed profile after the merge.
+ sql::Statement s2(
+ connection.GetUniqueStatement("SELECT guid "
+ "FROM autofill_profiles_trash"));
+ ASSERT_TRUE(s2.Step());
+ EXPECT_EQ("00000000-0000-0000-0000-000000000002", s2.ColumnString(0));
+
+ ASSERT_TRUE(s2.Step());
+ EXPECT_EQ("00000000-0000-0000-0000-000000000003", s2.ColumnString(0));
+
+ ASSERT_TRUE(s2.Step());
+ EXPECT_EQ("00000000-0000-0000-0000-000000000004", s2.ColumnString(0));
+
+ ASSERT_TRUE(s2.Step());
+ EXPECT_EQ("00000000-0000-0000-0000-000000000005", s2.ColumnString(0));
+
+ ASSERT_TRUE(s2.Step());
+ EXPECT_EQ("00000000-0000-0000-0000-000000000006", s2.ColumnString(0));
+
+ // That should be it.
+ ASSERT_FALSE(s2.Step());
+ }
+}
+
+// Tests that the |keywords| |last_modified| column gets added to the schema for
+// a version 37 database.
+TEST_F(WebDatabaseMigrationTest, MigrateVersion37ToCurrent) {
+ // This schema is taken from a build prior to the addition of the |keywords|
+ // |last_modified| column.
+ ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_37.sql")));
+
+ // Verify pre-conditions. These are expectations for version 37 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", "last_modified"));
+ }
+
+ DoMigration();
+
+ // 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| |last_modified| column should have been added.
+ EXPECT_TRUE(connection.DoesColumnExist("keywords", "id"));
+ EXPECT_TRUE(connection.DoesColumnExist("keywords", "last_modified"));
+ }
+}
+
+// Tests that the |keywords| |sync_guid| column gets added to the schema for
+// a version 38 database.
+TEST_F(WebDatabaseMigrationTest, MigrateVersion38ToCurrent) {
+ // This schema is taken from a build prior to the addition of the |keywords|
+ // |sync_guid| column.
+ ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_38.sql")));
+
+ // Verify pre-conditions. These are expectations for version 38 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", "sync_guid"));
+ }
+
+ DoMigration();
+
+ // 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| |sync_guid| column should have been added.
+ EXPECT_TRUE(connection.DoesColumnExist("keywords", "id"));
+ EXPECT_TRUE(connection.DoesColumnExist("keywords", "sync_guid"));
+ }
+}
+
+// Tests that no backup data is added to a version 39 database.
+TEST_F(WebDatabaseMigrationTest, MigrateVersion39ToCurrent) {
+ // This schema is taken from a build prior to the addition of the default
+ // search provider backup field to the meta table.
+ ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_39.sql")));
+
+ // Verify pre-conditions. These are expectations for version 39 of the
+ // database.
+ {
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+ ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
+
+ sql::MetaTable meta_table;
+ ASSERT_TRUE(meta_table.Init(&connection, 39, 39));
+
+ int64 default_search_provider_id = 0;
+ EXPECT_TRUE(meta_table.GetValue(KeywordTable::kDefaultSearchProviderKey,
+ &default_search_provider_id));
+
+ EXPECT_NO_FATAL_FAILURE(CheckNoBackupData(connection, &meta_table));
+ }
+
+ DoMigration();
+
+ // Verify post-conditions. These are expectations for current version of the
+ // database.
+ {
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+ ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
+
+ // Check version.
+ EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
+
+ sql::MetaTable meta_table;
+ ASSERT_TRUE(meta_table.Init(&connection, kCurrentTestedVersionNumber,
+ kCurrentTestedVersionNumber));
+
+ int64 default_search_provider_id = 0;
+ EXPECT_TRUE(meta_table.GetValue(KeywordTable::kDefaultSearchProviderKey,
+ &default_search_provider_id));
+ EXPECT_NE(0, default_search_provider_id);
+
+ EXPECT_NO_FATAL_FAILURE(CheckNoBackupData(connection, &meta_table));
+ }
+}
+
+// Tests that the backup data is removed from the database.
+TEST_F(WebDatabaseMigrationTest, MigrateVersion40ToCurrent) {
+ ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_40.sql")));
+
+ // Verify pre-conditions. These are expectations for version 40 of the
+ // database.
+ {
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+ ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
+
+ sql::MetaTable meta_table;
+ ASSERT_TRUE(meta_table.Init(&connection, 40, 40));
+
+ int64 default_search_provider_id = 0;
+ EXPECT_TRUE(meta_table.GetValue(KeywordTable::kDefaultSearchProviderKey,
+ &default_search_provider_id));
+
+ EXPECT_NO_FATAL_FAILURE(CheckHasBackupData(&meta_table));
+ }
+
+ DoMigration();
+
+ // Verify post-conditions. These are expectations for current version of the
+ // database.
+ {
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+ ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
+
+ // Check version.
+ EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
+
+ sql::MetaTable meta_table;
+ ASSERT_TRUE(meta_table.Init(&connection, kCurrentTestedVersionNumber,
+ kCurrentTestedVersionNumber));
+
+ int64 default_search_provider_id = 0;
+ EXPECT_TRUE(meta_table.GetValue(KeywordTable::kDefaultSearchProviderKey,
+ &default_search_provider_id));
+ EXPECT_NE(0, default_search_provider_id);
+
+ EXPECT_NO_FATAL_FAILURE(CheckNoBackupData(connection, &meta_table));
+ }
+}
+
+// Tests that the backup data is removed from the database.
+TEST_F(WebDatabaseMigrationTest, MigrateVersion41ToCurrent) {
+ ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_41.sql")));
+
+ // Verify pre-conditions. These are expectations for version 41 of the
+ // database.
+ {
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+ ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
+
+ sql::MetaTable meta_table;
+ ASSERT_TRUE(meta_table.Init(&connection, 41, 41));
+
+ int64 default_search_provider_id = 0;
+ EXPECT_TRUE(meta_table.GetValue(KeywordTable::kDefaultSearchProviderKey,
+ &default_search_provider_id));
+
+ EXPECT_NO_FATAL_FAILURE(CheckHasBackupData(&meta_table));
+ }
+
+ DoMigration();
+
+ // Verify post-conditions. These are expectations for current version of the
+ // database.
+ {
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+ ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
+
+ // Check version.
+ EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
+
+ sql::MetaTable meta_table;
+ ASSERT_TRUE(meta_table.Init(&connection, kCurrentTestedVersionNumber,
+ kCurrentTestedVersionNumber));
+
+ int64 default_search_provider_id = 0;
+ EXPECT_TRUE(meta_table.GetValue(KeywordTable::kDefaultSearchProviderKey,
+ &default_search_provider_id));
+ EXPECT_NE(0, default_search_provider_id);
+
+ EXPECT_NO_FATAL_FAILURE(CheckNoBackupData(connection, &meta_table));
+ }
+}
+
+// Tests that the backup data is removed from the database.
+TEST_F(WebDatabaseMigrationTest, MigrateVersion42ToCurrent) {
+ ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_42.sql")));
+
+ // Verify pre-conditions. These are expectations for version 42 of the
+ // database.
+ {
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+ ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
+
+ sql::MetaTable meta_table;
+ ASSERT_TRUE(meta_table.Init(&connection, 42, 42));
+
+ int64 default_search_provider_id = 0;
+ EXPECT_TRUE(meta_table.GetValue(KeywordTable::kDefaultSearchProviderKey,
+ &default_search_provider_id));
+
+ EXPECT_NO_FATAL_FAILURE(CheckHasBackupData(&meta_table));
+
+ EXPECT_FALSE(connection.DoesTableExist("keywords_backup"));
+ }
+
+ DoMigration();
+
+ // Verify post-conditions. These are expectations for current version of the
+ // database.
+ {
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+ ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
+
+ // Check version.
+ EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
+
+ sql::MetaTable meta_table;
+ ASSERT_TRUE(meta_table.Init(&connection, kCurrentTestedVersionNumber,
+ kCurrentTestedVersionNumber));
+
+ int64 default_search_provider_id = 0;
+ EXPECT_TRUE(meta_table.GetValue(KeywordTable::kDefaultSearchProviderKey,
+ &default_search_provider_id));
+ EXPECT_NE(0, default_search_provider_id);
+
+ EXPECT_NO_FATAL_FAILURE(CheckNoBackupData(connection, &meta_table));
+ }
+}
+
+// Tests that the backup data is removed from the database.
+TEST_F(WebDatabaseMigrationTest, MigrateVersion43ToCurrent) {
+ ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_43.sql")));
+
+ int64 previous_default_search_provider_id;
+
+ // Verify pre-conditions. These are expectations for version 43 of the
+ // database.
+ {
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+ ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
+
+ sql::MetaTable meta_table;
+ ASSERT_TRUE(meta_table.Init(&connection, 43, 43));
+
+ int64 default_search_provider_id = 0;
+ EXPECT_TRUE(meta_table.GetValue(KeywordTable::kDefaultSearchProviderKey,
+ &default_search_provider_id));
+ EXPECT_NE(default_search_provider_id, 0);
+ previous_default_search_provider_id = default_search_provider_id;
+
+ EXPECT_NO_FATAL_FAILURE(CheckHasBackupData(&meta_table));
+ EXPECT_TRUE(connection.DoesTableExist("keywords_backup"));
+ }
+
+ DoMigration();
+
+ // Verify post-conditions. These are expectations for current version of the
+ // database.
+ {
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+ ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
+
+ // Check version.
+ EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
+
+ sql::MetaTable meta_table;
+ ASSERT_TRUE(meta_table.Init(
+ &connection,
+ kCurrentTestedVersionNumber,
+ kCurrentTestedVersionNumber));
+
+ int64 default_search_provider_id = 0;
+ EXPECT_TRUE(meta_table.GetValue(KeywordTable::kDefaultSearchProviderKey,
+ &default_search_provider_id));
+ // Default search provider ID should not change.
+ EXPECT_EQ(previous_default_search_provider_id, default_search_provider_id);
+
+ EXPECT_NO_FATAL_FAILURE(CheckNoBackupData(connection, &meta_table));
+ }
+}
+
+// Tests that the |autogenerate_keyword| and |logo_id| columns get removed from
+// the keyword table schema for a version 45 database.
+TEST_F(WebDatabaseMigrationTest, MigrateVersion44ToCurrent) {
+ ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_44.sql")));
+
+ // Verify pre-conditions. These are expectations for version 44 of the
+ // database.
+ {
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+ ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
+
+ sql::MetaTable meta_table;
+ ASSERT_TRUE(meta_table.Init(&connection, 44, 44));
+
+ ASSERT_TRUE(connection.DoesColumnExist("keywords", "autogenerate_keyword"));
+ ASSERT_TRUE(connection.DoesColumnExist("keywords", "logo_id"));
+ }
+
+ DoMigration();
+
+ // Verify post-conditions. These are expectations for current version of the
+ // database.
+ {
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+ ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
+
+ // Check version.
+ EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
+
+ sql::MetaTable meta_table;
+ ASSERT_TRUE(meta_table.Init(&connection, kCurrentTestedVersionNumber,
+ kCurrentTestedVersionNumber));
+
+ // We should have removed this obsolete key.
+ std::string default_search_provider_backup;
+ EXPECT_FALSE(meta_table.GetValue("Default Search Provider Backup",
+ &default_search_provider_backup));
+
+ // Two columns should have been removed.
+ EXPECT_FALSE(connection.DoesColumnExist("keywords",
+ "autogenerate_keyword"));
+ EXPECT_FALSE(connection.DoesColumnExist("keywords", "logo_id"));
+
+ // Backup data should have been removed.
+ EXPECT_NO_FATAL_FAILURE(CheckNoBackupData(connection, &meta_table));
+ }
+}
+
+// Tests that the web_intents and web_intents_defaults tables are
+// modified to include "scheme" columns.
+TEST_F(WebDatabaseMigrationTest, MigrateVersion45ToCurrent) {
+ ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_45.sql")));
+
+ // Verify pre-conditions. These are expectations for version 45 of the
+ // database.
+ {
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+ ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
+
+ sql::MetaTable meta_table;
+ ASSERT_TRUE(meta_table.Init(&connection, 45, 45));
+
+ ASSERT_FALSE(connection.DoesColumnExist("scheme", "web_intents"));
+ ASSERT_FALSE(connection.DoesColumnExist(
+ "scheme", "web_intents_defaults"));
+ }
+
+ DoMigration();
+
+ // Verify post-conditions. These are expectations for current version of the
+ // database.
+ {
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+ ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
+
+ // Check version.
+ EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
+
+ sql::MetaTable meta_table;
+ ASSERT_TRUE(meta_table.Init(
+ &connection,
+ kCurrentTestedVersionNumber,
+ kCurrentTestedVersionNumber));
+
+ // A new "scheme" column should have been added to each web_intents table.
+ EXPECT_TRUE(connection.DoesColumnExist("web_intents", "scheme"));
+ EXPECT_TRUE(connection.DoesColumnExist("web_intents_defaults", "scheme"));
+
+ // Verify existing user data was copied.
+ sql::Statement s1(
+ connection.GetUniqueStatement("SELECT * FROM web_intents"));
+
+ ASSERT_TRUE(s1.Step());
+ EXPECT_EQ("http://poodles.com/fuzzer", s1.ColumnString(0));
+ EXPECT_EQ(ASCIIToUTF16("fuzz"), s1.ColumnString16(1));
+ EXPECT_EQ(ASCIIToUTF16("poodle/*"), s1.ColumnString16(2));
+ EXPECT_EQ(ASCIIToUTF16("Poodle Fuzzer"), s1.ColumnString16(3));
+ EXPECT_EQ(ASCIIToUTF16("window"), s1.ColumnString16(4));
+ EXPECT_EQ(ASCIIToUTF16(""), s1.ColumnString16(5));
+ ASSERT_FALSE(s1.Step());
+
+ // Now we want to verify existing user data was copied
+ sql::Statement s2(
+ connection.GetUniqueStatement("SELECT * FROM web_intents_defaults"));
+
+ ASSERT_TRUE(s2.Step());
+ EXPECT_EQ("fuzz", s2.ColumnString(0));
+ EXPECT_EQ(ASCIIToUTF16("poodle/*"), s2.ColumnString16(1));
+ EXPECT_EQ(ASCIIToUTF16(""), s2.ColumnString16(2));
+ EXPECT_EQ(0, s2.ColumnInt(3));
+ EXPECT_EQ(0, s2.ColumnInt(4));
+ EXPECT_EQ(ASCIIToUTF16("http://poodles.com/fuzzer"), s2.ColumnString16(5));
+ EXPECT_EQ(ASCIIToUTF16(""), s2.ColumnString16(6));
+ ASSERT_FALSE(s2.Step());
+
+ // finally ensure the migration code cleaned up after itself
+ EXPECT_FALSE(connection.DoesTableExist("old_web_intents"));
+ EXPECT_FALSE(connection.DoesTableExist("old_web_intents_defaults"));
+ }
+}
+
+// Tests that the web_intents and web_intents_defaults tables are
+// modified to include "scheme" columns.
+TEST_F(WebDatabaseMigrationTest, MigrateVersion45InvalidToCurrent) {
+ ASSERT_NO_FATAL_FAILURE(
+ LoadDatabase(FILE_PATH_LITERAL("version_45_invalid.sql")));
+
+ // Verify pre-conditions. These are expectations for version 45 of the
+ // database.
+ {
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+ ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
+
+ sql::MetaTable meta_table;
+ ASSERT_TRUE(meta_table.Init(&connection, 45, 45));
+
+ ASSERT_FALSE(connection.DoesColumnExist("scheme", "web_intents"));
+ ASSERT_FALSE(connection.DoesColumnExist(
+ "scheme", "web_intents_defaults"));
+ }
+
+ DoMigration();
+
+ // Verify post-conditions. These are expectations for current version of the
+ // database.
+ {
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+ ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
+
+ // Check version.
+ EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
+
+ sql::MetaTable meta_table;
+ ASSERT_TRUE(meta_table.Init(
+ &connection,
+ kCurrentTestedVersionNumber,
+ kCurrentTestedVersionNumber));
+
+ // A new "scheme" column should have been added to each web_intents table.
+ EXPECT_TRUE(connection.DoesColumnExist("web_intents", "scheme"));
+ EXPECT_TRUE(connection.DoesColumnExist("web_intents_defaults", "scheme"));
+
+ // Verify existing user data was copied.
+ sql::Statement s1(
+ connection.GetUniqueStatement("SELECT * FROM web_intents"));
+
+ ASSERT_FALSE(s1.Step()); // Basically should be empty at this point.
+
+ // Now we want to verify existing user data was copied
+ sql::Statement s2(
+ connection.GetUniqueStatement("SELECT * FROM web_intents_defaults"));
+
+ // We were able to create the new tables, but unable to copy any data
+ // Given the initial bad state of the tables.
+ ASSERT_FALSE(s2.Step());
+
+ // Finally ensure the migration code cleaned up after itself.
+ EXPECT_FALSE(connection.DoesTableExist("old_web_intents"));
+ EXPECT_FALSE(connection.DoesTableExist("old_web_intents_defaults"));
+ }
+}
+
+// Check that current version is forced to compatible version before migration,
+// if the former is smaller.
+TEST_F(WebDatabaseMigrationTest, MigrateVersion45CompatibleToCurrent) {
+ ASSERT_NO_FATAL_FAILURE(
+ LoadDatabase(FILE_PATH_LITERAL("version_45_compatible.sql")));
+
+ // Verify pre-conditions. These are expectations for version 45 of the
+ // database.
+ {
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+ ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
+
+ sql::MetaTable meta_table;
+ // Database is actually version 45 but the version field states 40.
+ ASSERT_TRUE(meta_table.Init(&connection, 40, 45));
+ }
+
+ DoMigration();
+
+ // Verify post-conditions. These are expectations for current version of the
+ // database.
+ {
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+ ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
+
+ // Check version.
+ EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
+ EXPECT_LE(45, VersionFromConnection(&connection));
+ }
+}
+
+// Tests that the |alternate_urls| column is added to the keyword table schema
+// for a version 47 database.
+TEST_F(WebDatabaseMigrationTest, MigrateVersion46ToCurrent) {
+ ASSERT_NO_FATAL_FAILURE(
+ LoadDatabase(FILE_PATH_LITERAL("version_46.sql")));
+
+ // Verify pre-conditions. These are expectations for version 46 of the
+ // database.
+ {
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+ ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
+
+ sql::MetaTable meta_table;
+ ASSERT_TRUE(meta_table.Init(&connection, 46, 46));
+
+ ASSERT_FALSE(connection.DoesColumnExist("keywords", "alternate_urls"));
+ ASSERT_FALSE(connection.DoesColumnExist("keywords_backup",
+ "alternate_urls"));
+ }
+
+ DoMigration();
+
+ // Verify post-conditions. These are expectations for current version of the
+ // database.
+ {
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+ ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
+
+ // Check version.
+ EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
+
+ // A new column should have been created.
+ EXPECT_TRUE(connection.DoesColumnExist("keywords", "alternate_urls"));
+ }
+}
+
+// Tests that the backup data is removed from the database.
+TEST_F(WebDatabaseMigrationTest, MigrateVersion47ToCurrent) {
+ ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_47.sql")));
+
+ // Verify pre-conditions. These are expectations for version 47 of the
+ // database.
+ {
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+ ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
+
+ sql::MetaTable meta_table;
+ ASSERT_TRUE(meta_table.Init(&connection, 47, 47));
+
+ int64 default_search_provider_id = 0;
+ EXPECT_TRUE(meta_table.GetValue(KeywordTable::kDefaultSearchProviderKey,
+ &default_search_provider_id));
+ EXPECT_NE(0, default_search_provider_id);
+
+ EXPECT_NO_FATAL_FAILURE(CheckHasBackupData(&meta_table));
+ EXPECT_TRUE(connection.DoesTableExist("keywords_backup"));
+ }
+
+ DoMigration();
+
+ // Verify post-conditions. These are expectations for current version of the
+ // database.
+ {
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+ ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
+
+ // Check version.
+ EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
+
+ sql::MetaTable meta_table;
+ ASSERT_TRUE(meta_table.Init(&connection, kCurrentTestedVersionNumber,
+ kCurrentTestedVersionNumber));
+
+ int64 default_search_provider_id = 0;
+ EXPECT_TRUE(meta_table.GetValue(KeywordTable::kDefaultSearchProviderKey,
+ &default_search_provider_id));
+ EXPECT_NE(0, default_search_provider_id);
+
+ EXPECT_NO_FATAL_FAILURE(CheckNoBackupData(connection, &meta_table));
+ }
+}
+
+// Tests that the |search_terms_replacement_key| column is added to the keyword
+// table schema for a version 49 database.
+TEST_F(WebDatabaseMigrationTest, MigrateVersion48ToCurrent) {
+ ASSERT_NO_FATAL_FAILURE(
+ LoadDatabase(FILE_PATH_LITERAL("version_48.sql")));
+
+ // Verify pre-conditions. These are expectations for version 48 of the
+ // database.
+ {
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+ ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
+
+ sql::MetaTable meta_table;
+ ASSERT_TRUE(meta_table.Init(&connection, 48, 48));
+
+ ASSERT_FALSE(connection.DoesColumnExist("keywords",
+ "search_terms_replacement_key"));
+ }
+
+ DoMigration();
+
+ // Verify post-conditions. These are expectations for current version of the
+ // database.
+ {
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+ ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
+
+ // Check version.
+ EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
+
+ // A new column should have been created.
+ EXPECT_TRUE(connection.DoesColumnExist("keywords",
+ "search_terms_replacement_key"));
+ }
+}
diff --git a/components/webdata/common/web_data_service_test_util.cc b/components/webdata/common/web_data_service_test_util.cc
new file mode 100644
index 0000000..13cc591
--- /dev/null
+++ b/components/webdata/common/web_data_service_test_util.cc
@@ -0,0 +1,38 @@
+// Copyright 2013 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 "components/webdata/common/web_data_service_test_util.h"
+
+#include "components/webdata/autofill/autofill_webdata_service.h"
+
+MockWebDataServiceWrapperBase::MockWebDataServiceWrapperBase() {
+}
+
+MockWebDataServiceWrapperBase::~MockWebDataServiceWrapperBase() {
+}
+
+void MockWebDataServiceWrapperBase::Shutdown() {
+}
+
+// TODO(caitkp): This won't scale well. As we get more WebData subclasses, we
+// will probably need a better way to create these mocks rather than passing
+// all the webdatas in.
+MockWebDataServiceWrapper::MockWebDataServiceWrapper(
+ scoped_refptr<WebDataService> fake_service,
+ scoped_refptr<AutofillWebDataService> fake_autofill)
+ : fake_autofill_web_data_(fake_autofill),
+ fake_web_data_(fake_service) {
+}
+
+MockWebDataServiceWrapper::~MockWebDataServiceWrapper() {
+}
+
+scoped_refptr<AutofillWebDataService>
+ MockWebDataServiceWrapper::GetAutofillWebData() {
+ return fake_autofill_web_data_;
+}
+
+scoped_refptr<WebDataService> MockWebDataServiceWrapper::GetWebData() {
+ return fake_web_data_;
+}
diff --git a/components/webdata/common/web_data_service_test_util.h b/components/webdata/common/web_data_service_test_util.h
new file mode 100644
index 0000000..e037a15
--- /dev/null
+++ b/components/webdata/common/web_data_service_test_util.h
@@ -0,0 +1,76 @@
+// Copyright (c) 2011 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.
+
+#ifndef COMPONENTS_WEBDATA_COMMON_WEB_DATA_SERVICE_TEST_UTIL_H__
+#define COMPONENTS_WEBDATA_COMMON_WEB_DATA_SERVICE_TEST_UTIL_H__
+
+#include "base/basictypes.h"
+#include "base/message_loop.h"
+#include "chrome/browser/webdata/web_data_service.h"
+#include "chrome/browser/webdata/web_data_service_factory.h"
+#include "content/public/browser/browser_thread.h"
+
+template <class T>
+class AutofillWebDataServiceConsumer: public WebDataServiceConsumer {
+ public:
+ AutofillWebDataServiceConsumer() : handle_(0) {}
+ virtual ~AutofillWebDataServiceConsumer() {}
+
+ virtual void OnWebDataServiceRequestDone(WebDataService::Handle handle,
+ const WDTypedResult* result) {
+ using content::BrowserThread;
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ handle_ = handle;
+ const WDResult<T>* wrapped_result =
+ static_cast<const WDResult<T>*>(result);
+ result_ = wrapped_result->GetValue();
+
+ MessageLoop::current()->Quit();
+ }
+
+ WebDataService::Handle handle() { return handle_; }
+ T& result() { return result_; }
+
+ private:
+ WebDataService::Handle handle_;
+ T result_;
+ DISALLOW_COPY_AND_ASSIGN(AutofillWebDataServiceConsumer);
+};
+
+// Base class for mocks of WebDataService, that does nothing in
+// Shutdown().
+class MockWebDataServiceWrapperBase : public WebDataServiceWrapper {
+ public:
+ MockWebDataServiceWrapperBase();
+ virtual ~MockWebDataServiceWrapperBase();
+
+ virtual void Shutdown() OVERRIDE;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockWebDataServiceWrapperBase);
+};
+
+// Pass your fake WebDataService in the constructor and this will
+// serve it up via GetWebData().
+class MockWebDataServiceWrapper : public MockWebDataServiceWrapperBase {
+ public:
+ MockWebDataServiceWrapper(
+ scoped_refptr<WebDataService> fake_service,
+ scoped_refptr<AutofillWebDataService> fake_autofill);
+
+ virtual ~MockWebDataServiceWrapper();
+
+ virtual scoped_refptr<AutofillWebDataService> GetAutofillWebData() OVERRIDE;
+
+ virtual scoped_refptr<WebDataService> GetWebData() OVERRIDE;
+
+ protected:
+ scoped_refptr<AutofillWebDataService> fake_autofill_web_data_;
+ scoped_refptr<WebDataService> fake_web_data_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockWebDataServiceWrapper);
+};
+
+#endif // COMPONENTS_WEBDATA_COMMON_WEB_DATA_SERVICE_TEST_UTIL_H__