普通文本  |  1453行  |  56.55 KB

// 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.

#include <string>

#include "app/sql/statement.h"
#include "base/file_util.h"
#include "base/memory/scoped_temp_dir.h"
#include "base/stl_util-inl.h"
#include "base/string16.h"
#include "base/string_number_conversions.h"
#include "base/time.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/autofill/autofill_profile.h"
#include "chrome/browser/autofill/autofill_type.h"
#include "chrome/browser/autofill/credit_card.h"
#include "chrome/browser/webdata/autofill_change.h"
#include "chrome/browser/webdata/autofill_entry.h"
#include "chrome/browser/webdata/web_database.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/guid.h"
#include "chrome/test/ui_test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"

using base::Time;

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->SetInfo(NAME_FIRST, s.ColumnString16(2));
  profile->SetInfo(NAME_MIDDLE, s.ColumnString16(3));
  profile->SetInfo(NAME_LAST,s.ColumnString16(4));
  profile->SetInfo(EMAIL_ADDRESS, s.ColumnString16(5));
  profile->SetInfo(COMPANY_NAME, s.ColumnString16(6));
  profile->SetInfo(ADDRESS_HOME_LINE1, s.ColumnString16(7));
  profile->SetInfo(ADDRESS_HOME_LINE2, s.ColumnString16(8));
  profile->SetInfo(ADDRESS_HOME_CITY, s.ColumnString16(9));
  profile->SetInfo(ADDRESS_HOME_STATE, s.ColumnString16(10));
  profile->SetInfo(ADDRESS_HOME_ZIP, s.ColumnString16(11));
  profile->SetInfo(ADDRESS_HOME_COUNTRY, s.ColumnString16(12));
  profile->SetInfo(PHONE_HOME_WHOLE_NUMBER, s.ColumnString16(13));
  profile->SetInfo(PHONE_FAX_WHOLE_NUMBER, s.ColumnString16(14));
  *date_modified = s.ColumnInt64(15);
  profile->set_guid(s.ColumnString(16));
  EXPECT_TRUE(guid::IsValidGUID(profile->guid()));
}

void AutofillProfile32FromStatement(const sql::Statement& s,
                                    AutofillProfile* profile,
                                    string16* label,
                                    int64* date_modified) {
  DCHECK(profile);
  DCHECK(label);
  DCHECK(date_modified);
  profile->set_guid(s.ColumnString(0));
  EXPECT_TRUE(guid::IsValidGUID(profile->guid()));
  *label = s.ColumnString16(1);
  profile->SetInfo(NAME_FIRST, s.ColumnString16(2));
  profile->SetInfo(NAME_MIDDLE, s.ColumnString16(3));
  profile->SetInfo(NAME_LAST,s.ColumnString16(4));
  profile->SetInfo(EMAIL_ADDRESS, s.ColumnString16(5));
  profile->SetInfo(COMPANY_NAME, s.ColumnString16(6));
  profile->SetInfo(ADDRESS_HOME_LINE1, s.ColumnString16(7));
  profile->SetInfo(ADDRESS_HOME_LINE2, s.ColumnString16(8));
  profile->SetInfo(ADDRESS_HOME_CITY, s.ColumnString16(9));
  profile->SetInfo(ADDRESS_HOME_STATE, s.ColumnString16(10));
  profile->SetInfo(ADDRESS_HOME_ZIP, s.ColumnString16(11));
  profile->SetInfo(ADDRESS_HOME_COUNTRY, s.ColumnString16(12));
  profile->SetInfo(PHONE_HOME_WHOLE_NUMBER, s.ColumnString16(13));
  profile->SetInfo(PHONE_FAX_WHOLE_NUMBER, s.ColumnString16(14));
  *date_modified = s.ColumnInt64(15);
}

void AutofillProfile33FromStatement(const sql::Statement& s,
                                    AutofillProfile* profile,
                                    int64* date_modified) {
  DCHECK(profile);
  DCHECK(date_modified);
  profile->set_guid(s.ColumnString(0));
  EXPECT_TRUE(guid::IsValidGUID(profile->guid()));
  profile->SetInfo(COMPANY_NAME, s.ColumnString16(1));
  profile->SetInfo(ADDRESS_HOME_LINE1, s.ColumnString16(2));
  profile->SetInfo(ADDRESS_HOME_LINE2, s.ColumnString16(3));
  profile->SetInfo(ADDRESS_HOME_CITY, s.ColumnString16(4));
  profile->SetInfo(ADDRESS_HOME_STATE, s.ColumnString16(5));
  profile->SetInfo(ADDRESS_HOME_ZIP, s.ColumnString16(6));
  profile->SetInfo(ADDRESS_HOME_COUNTRY, s.ColumnString16(7));
  *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->SetInfo(CREDIT_CARD_NAME, s.ColumnString16(2));
  credit_card->SetInfo(CREDIT_CARD_TYPE, s.ColumnString16(3));
  credit_card->SetInfo(CREDIT_CARD_EXP_MONTH, s.ColumnString16(5));
  credit_card->SetInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR, s.ColumnString16(6));
  int encrypted_number_len = s.ColumnByteLength(10);
  if (encrypted_number_len) {
    encrypted_number->resize(encrypted_number_len);
    memcpy(&(*encrypted_number)[0], s.ColumnBlob(10), encrypted_number_len);
  }
  *date_modified = s.ColumnInt64(12);
  credit_card->set_guid(s.ColumnString(13));
  EXPECT_TRUE(guid::IsValidGUID(credit_card->guid()));
}

void CreditCard32FromStatement(const sql::Statement& s,
                               CreditCard* credit_card,
                               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(guid::IsValidGUID(credit_card->guid()));
  credit_card->SetInfo(CREDIT_CARD_NAME, s.ColumnString16(1));
  credit_card->SetInfo(CREDIT_CARD_EXP_MONTH, s.ColumnString16(2));
  credit_card->SetInfo(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);
}

}  // 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:
  WebDatabaseMigrationTest() {}
  virtual ~WebDatabaseMigrationTest() {}

  virtual void SetUp() {
    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
  }

 protected:
  // Current tested version number.  When adding a migration in
  // |WebDatabase::MigrateOldVersionsAsNeeded()| and changing the version number
  // |kCurrentVersionNumber| this value should change to reflect the new version
  // number and a new migration test added below.
  static const int kCurrentTestedVersionNumber;

  FilePath GetDatabasePath() {
    const FilePath::CharType kWebDatabaseFilename[] =
        FILE_PATH_LITERAL("TestWebDatabase.sqlite3");
    return temp_dir_.path().Append(FilePath(kWebDatabaseFilename));
  }

  // The textual contents of |file| are read from
  // "chrome/test/data/web_database" and returned in the string |contents|.
  // Returns true if the file exists and is read successfully, false otherwise.
  bool GetWebDatabaseData(const FilePath& file, std::string* contents) {
    FilePath path = ui_test_utils::GetTestFilePath(
        FilePath(FILE_PATH_LITERAL("web_database")), file);
    return file_util::PathExists(path) &&
        file_util::ReadFileToString(path, contents);
  }

  static int VersionFromConnection(sql::Connection* connection) {
    // Get version.
    sql::Statement s(connection->GetUniqueStatement(
        "SELECT value FROM meta WHERE key='version'"));
    if (!s.Step())
      return 0;
    return s.ColumnInt(0);
  }

  // The sql files located in "chrome/test/data/web_database" were generated by
  // launching the Chromium application prior to schema change, then using the
  // sqlite3 command-line application to dump the contents of the "Web Data"
  // database.
  // Like this:
  //   > .output version_nn.sql
  //   > .dump
  void LoadDatabase(const FilePath::StringType& file);

  // Assertion testing for migrating from version 27 and 28.
  void MigrateVersion28Assertions();

 private:
  ScopedTempDir temp_dir_;

  DISALLOW_COPY_AND_ASSIGN(WebDatabaseMigrationTest);
};

const int WebDatabaseMigrationTest::kCurrentTestedVersionNumber = 37;

void WebDatabaseMigrationTest::LoadDatabase(const FilePath::StringType& file) {
  std::string contents;
  ASSERT_TRUE(GetWebDatabaseData(FilePath(file), &contents));

  sql::Connection connection;
  ASSERT_TRUE(connection.Open(GetDatabasePath()));
  ASSERT_TRUE(connection.Execute(contents.data()));
}

void WebDatabaseMigrationTest::MigrateVersion28Assertions() {
  // Load the database via the WebDatabase class and migrate the database to
  // the current version.
  {
    WebDatabase db;
    ASSERT_EQ(sql::INIT_OK, db.Init(GetDatabasePath()));
  }

  // Verify post-conditions.  These are expectations for current version of the
  // database.
  {
    sql::Connection connection;
    ASSERT_TRUE(connection.Open(GetDatabasePath()));

    // Check version.
    EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));

    // Make sure supports_instant was dropped and instant_url was added.
    EXPECT_FALSE(connection.DoesColumnExist("keywords", "supports_instant"));
    EXPECT_TRUE(connection.DoesColumnExist("keywords", "instant_url"));

    // Check that instant_url is empty.
    std::string stmt = "SELECT instant_url FROM keywords";
    sql::Statement s(connection.GetUniqueStatement(stmt.c_str()));
    ASSERT_TRUE(s.Step());
    EXPECT_EQ(std::string(), s.ColumnString(0));

    // Verify the data made it over.
    stmt = "SELECT id, short_name, keyword, favicon_url, url, "
        "show_in_default_list, safe_for_autoreplace, originating_url, "
        "date_created, usage_count, input_encodings, suggest_url, "
        "prepopulate_id, autogenerate_keyword, logo_id, created_by_policy, "
        "instant_url FROM keywords";
    sql::Statement s2(connection.GetUniqueStatement(stmt.c_str()));
    ASSERT_TRUE(s2.Step());
    EXPECT_EQ(2, s2.ColumnInt(0));
    EXPECT_EQ("Google", s2.ColumnString(1));
    EXPECT_EQ("google.com", s2.ColumnString(2));
    EXPECT_EQ("http://www.google.com/favicon.ico", s2.ColumnString(3));
    EXPECT_EQ("{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}"\
        "{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}"\
        "&q={searchTerms}",
        s2.ColumnString(4));
    EXPECT_EQ(1, s2.ColumnInt(5));
    EXPECT_EQ(1, s2.ColumnInt(6));
    EXPECT_EQ(std::string(), s2.ColumnString(7));
    EXPECT_EQ(0, s2.ColumnInt(8));
    EXPECT_EQ(0, s2.ColumnInt(9));
    EXPECT_EQ(std::string("UTF-8"), s2.ColumnString(10));
    EXPECT_EQ(std::string("{google:baseSuggestURL}search?client=chrome&hl="
                          "{language}&q={searchTerms}"), s2.ColumnString(11));
    EXPECT_EQ(1, s2.ColumnInt(12));
    EXPECT_EQ(1, s2.ColumnInt(13));
    EXPECT_EQ(6245, s2.ColumnInt(14));
    EXPECT_EQ(0, s2.ColumnInt(15));
    EXPECT_EQ(0, s2.ColumnInt(16));
    EXPECT_EQ(std::string(), s2.ColumnString(17));
  }
}

// Tests that the all migrations from an empty database succeed.
TEST_F(WebDatabaseMigrationTest, MigrateEmptyToCurrent) {
  // Load the database via the WebDatabase class and migrate the database to
  // the current version.
  {
    WebDatabase db;
    ASSERT_EQ(sql::INIT_OK, db.Init(GetDatabasePath()));
  }

  // Verify post-conditions.  These are expectations for current version of the
  // database.
  {
    sql::Connection connection;
    ASSERT_TRUE(connection.Open(GetDatabasePath()));

    // Check version.
    EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));

    // Check that expected tables are present.
    EXPECT_TRUE(connection.DoesTableExist("meta"));
    EXPECT_TRUE(connection.DoesTableExist("keywords"));
    EXPECT_TRUE(connection.DoesTableExist("logins"));
    EXPECT_TRUE(connection.DoesTableExist("web_app_icons"));
    EXPECT_TRUE(connection.DoesTableExist("web_apps"));
    EXPECT_TRUE(connection.DoesTableExist("autofill"));
    EXPECT_TRUE(connection.DoesTableExist("autofill_dates"));
    EXPECT_TRUE(connection.DoesTableExist("autofill_profiles"));
    EXPECT_TRUE(connection.DoesTableExist("credit_cards"));
    EXPECT_TRUE(connection.DoesTableExist("token_service"));
  }
}

// Tests that the |credit_card| table gets added to the schema for a version 22
// database.
TEST_F(WebDatabaseMigrationTest, MigrateVersion22ToCurrent) {
  // This schema is taken from a build prior to the addition of the
  // |credit_card| table.  Version 22 of the schema.  Contrast this with the
  // corrupt version below.
  ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_22.sql")));

  // Verify pre-conditions.
  {
    sql::Connection connection;
    ASSERT_TRUE(connection.Open(GetDatabasePath()));

    // No |credit_card| table prior to version 23.
    ASSERT_FALSE(connection.DoesColumnExist("credit_cards", "guid"));
    ASSERT_FALSE(
        connection.DoesColumnExist("credit_cards", "card_number_encrypted"));
  }

  // Load the database via the WebDatabase class and migrate the database to
  // the current version.
  {
    WebDatabase db;
    ASSERT_EQ(sql::INIT_OK, db.Init(GetDatabasePath()));
  }

  // Verify post-conditions.  These are expectations for current version of the
  // database.
  {
    sql::Connection connection;
    ASSERT_TRUE(connection.Open(GetDatabasePath()));

    // Check version.
    EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));

    // |credit_card| table now exists.
    EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "guid"));
    EXPECT_TRUE(
        connection.DoesColumnExist("credit_cards", "card_number_encrypted"));
  }
}

// Tests that the |credit_card| table gets added to the schema for a corrupt
// version 22 database.  The corruption is that the |credit_cards| table exists
// but the schema version number was not set correctly to 23 or later.  This
// test exercises code introduced to fix bug http://crbug.com/50699 that
// resulted from the corruption.
TEST_F(WebDatabaseMigrationTest, MigrateVersion22CorruptedToCurrent) {
  // This schema is taken from a build after the addition of the |credit_card|
  // table.  Due to a bug in the migration logic the version is set incorrectly
  // to 22 (it should have been updated to 23 at least).
  ASSERT_NO_FATAL_FAILURE(
      LoadDatabase(FILE_PATH_LITERAL("version_22_corrupt.sql")));

  // Verify pre-conditions.  These are expectations for corrupt version 22 of
  // the database.
  {
    sql::Connection connection;
    ASSERT_TRUE(connection.Open(GetDatabasePath()));

    // Columns existing and not existing before current version.
    ASSERT_TRUE(connection.DoesColumnExist("credit_cards", "unique_id"));
    ASSERT_TRUE(
        connection.DoesColumnExist("credit_cards", "card_number_encrypted"));
    ASSERT_TRUE(connection.DoesColumnExist("keywords", "id"));
    ASSERT_FALSE(connection.DoesColumnExist("keywords", "logo_id"));
  }

  // Load the database via the WebDatabase class and migrate the database to
  // the current version.
  {
    WebDatabase db;
    ASSERT_EQ(sql::INIT_OK, db.Init(GetDatabasePath()));
  }

  // Verify post-conditions.  These are expectations for current version of the
  // database.
  {
    sql::Connection connection;
    ASSERT_TRUE(connection.Open(GetDatabasePath()));

    // Check version.
    EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));


    // Columns existing and not existing before version 25.
    EXPECT_FALSE(connection.DoesColumnExist("credit_cards", "unique_id"));
    EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "guid"));
    EXPECT_TRUE(
        connection.DoesColumnExist("credit_cards", "card_number_encrypted"));
    EXPECT_TRUE(connection.DoesColumnExist("keywords", "id"));
    EXPECT_TRUE(connection.DoesColumnExist("keywords", "logo_id"));
  }
}

// Tests that the |keywords| |logo_id| column gets added to the schema for a
// version 24 database.
TEST_F(WebDatabaseMigrationTest, MigrateVersion24ToCurrent) {
  // This schema is taken from a build prior to the addition of the |keywords|
  // |logo_id| column.
  ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_24.sql")));

  // Verify pre-conditions.  These are expectations for version 24 of the
  // database.
  {
    sql::Connection connection;
    ASSERT_TRUE(connection.Open(GetDatabasePath()));

    // Columns existing and not existing before current version.
    ASSERT_TRUE(connection.DoesColumnExist("keywords", "id"));
    ASSERT_FALSE(connection.DoesColumnExist("keywords", "logo_id"));
  }

  // Load the database via the WebDatabase class and migrate the database to
  // the current version.
  {
    WebDatabase db;
    ASSERT_EQ(sql::INIT_OK, db.Init(GetDatabasePath()));
  }

  // Verify post-conditions.  These are expectations for current version of the
  // database.
  {
    sql::Connection connection;
    ASSERT_TRUE(connection.Open(GetDatabasePath()));

    // Check version.
    EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));

    // |keywords| |logo_id| column should have been added.
    EXPECT_TRUE(connection.DoesColumnExist("keywords", "id"));
    EXPECT_TRUE(connection.DoesColumnExist("keywords", "logo_id"));
  }
}

// Tests that the |keywords| |created_by_policy| column gets added to the schema
// for a version 25 database.
TEST_F(WebDatabaseMigrationTest, MigrateVersion25ToCurrent) {
  // This schema is taken from a build prior to the addition of the |keywords|
  // |created_by_policy| column.
  ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_25.sql")));

  // Verify pre-conditions.  These are expectations for version 25 of the
  // database.
  {
    sql::Connection connection;
    ASSERT_TRUE(connection.Open(GetDatabasePath()));
  }

  // Load the database via the WebDatabase class and migrate the database to
  // the current version.
  {
    WebDatabase db;
    ASSERT_EQ(sql::INIT_OK, db.Init(GetDatabasePath()));
  }

  // Verify post-conditions.  These are expectations for current version of the
  // database.
  {
    sql::Connection connection;
    ASSERT_TRUE(connection.Open(GetDatabasePath()));

    // Check version.
    EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));

    // |keywords| |logo_id| column should have been added.
    EXPECT_TRUE(connection.DoesColumnExist("keywords", "id"));
    EXPECT_TRUE(connection.DoesColumnExist("keywords", "created_by_policy"));
  }
}

// Tests that the credit_cards.billing_address column is changed from a string
// to an int whilst preserving the associated billing address. This version of
// the test makes sure a stored label is converted to an ID.
TEST_F(WebDatabaseMigrationTest, MigrateVersion26ToCurrentStringLabels) {
  // This schema is taken from a build prior to the change of column type for
  // credit_cards.billing_address from string to int.
  ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_26.sql")));

  // Verify pre-conditions. These are expectations for version 26 of the
  // database.
  {
    sql::Connection connection;
    ASSERT_TRUE(connection.Open(GetDatabasePath()));

    // Columns existing and not existing before current version.
    EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "billing_address"));

    std::string stmt = "INSERT INTO autofill_profiles"
      "(label, unique_id, first_name, middle_name, last_name, email,"
      " company_name, address_line_1, address_line_2, city, state, zipcode,"
      " country, phone, fax)"
      "VALUES ('Home',1,'','','','','','','','','','','','','')";
    sql::Statement s(connection.GetUniqueStatement(stmt.c_str()));
    ASSERT_TRUE(s.Run());

    // Insert a CC linked to an existing address.
    std::string stmt2 = "INSERT INTO credit_cards"
      "(label, unique_id, name_on_card, type, card_number,"
      " expiration_month, expiration_year, verification_code, billing_address,"
      " shipping_address, card_number_encrypted, verification_code_encrypted)"
      "VALUES ('label',2,'Jack','Visa','1234',2,2012,'','Home','','','')";
    sql::Statement s2(connection.GetUniqueStatement(stmt2.c_str()));
    ASSERT_TRUE(s2.Run());

    // |billing_address| is a string.
    std::string stmt3 = "SELECT billing_address FROM credit_cards";
    sql::Statement s3(connection.GetUniqueStatement(stmt3.c_str()));
    ASSERT_TRUE(s3.Step());
    EXPECT_EQ(s3.ColumnType(0), sql::COLUMN_TYPE_TEXT);
  }

  // Load the database via the WebDatabase class and migrate the database to
  // the current version.
  {
    WebDatabase db;
    ASSERT_EQ(sql::INIT_OK, db.Init(GetDatabasePath()));
  }

  // Verify post-conditions.  These are expectations for current version of the
  // database.
  {
    sql::Connection connection;
    ASSERT_TRUE(connection.Open(GetDatabasePath()));

    // Check version.
    EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
    EXPECT_FALSE(connection.DoesColumnExist("credit_cards", "billing_address"));

    // Verify the credit card data is converted.
    sql::Statement s(connection.GetUniqueStatement(
        "SELECT guid, 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);
  }

  // Load the database via the WebDatabase class and migrate the database to
  // the current version.
  {
    WebDatabase db;
    ASSERT_EQ(sql::INIT_OK, db.Init(GetDatabasePath()));
  }

  // Verify post-conditions.  These are expectations for current version of the
  // database.
  {
    sql::Connection connection;
    ASSERT_TRUE(connection.Open(GetDatabasePath()));

    // Check version.
    EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));

    // |keywords| |logo_id| column should have been added.
    EXPECT_TRUE(connection.DoesColumnExist("keywords", "id"));
    EXPECT_TRUE(connection.DoesColumnExist("keywords", "created_by_policy"));
    EXPECT_FALSE(connection.DoesColumnExist("credit_cards", "billing_address"));

    // Verify the credit card data is converted.
    sql::Statement s(connection.GetUniqueStatement(
        "SELECT guid, 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 blob.
    // Column 6 is date_modified.
  }
}

// Tests migration from 27->current. This test is now the same as 28->current
// as the column added in 28 was nuked in 29.
TEST_F(WebDatabaseMigrationTest, MigrateVersion27ToCurrent) {
  // Initialize the database.
  ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_27.sql")));

  // Verify pre-conditions. These are expectations for version 28 of the
  // database.
  {
    sql::Connection connection;
    ASSERT_TRUE(connection.Open(GetDatabasePath()));

    ASSERT_FALSE(connection.DoesColumnExist("keywords", "supports_instant"));
    ASSERT_FALSE(connection.DoesColumnExist("keywords", "instant_url"));
  }

  MigrateVersion28Assertions();
}

// Makes sure instant_url is added correctly to keywords.
TEST_F(WebDatabaseMigrationTest, MigrateVersion28ToCurrent) {
  // Initialize the database.
  ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_28.sql")));

  // Verify pre-conditions. These are expectations for version 28 of the
  // database.
  {
    sql::Connection connection;
    ASSERT_TRUE(connection.Open(GetDatabasePath()));

    ASSERT_TRUE(connection.DoesColumnExist("keywords", "supports_instant"));
    ASSERT_FALSE(connection.DoesColumnExist("keywords", "instant_url"));
  }

  MigrateVersion28Assertions();
}

// Makes sure date_modified is added correctly to autofill_profiles and
// credit_cards.
TEST_F(WebDatabaseMigrationTest, MigrateVersion29ToCurrent) {
  // Initialize the database.
  ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_29.sql")));

  // Verify pre-conditions.  These are expectations for version 29 of the
  // database.
  {
    sql::Connection connection;
    ASSERT_TRUE(connection.Open(GetDatabasePath()));

    EXPECT_FALSE(connection.DoesColumnExist("autofill_profiles",
                                            "date_modified"));
    EXPECT_FALSE(connection.DoesColumnExist("credit_cards",
                                            "date_modified"));
  }

  // Load the database via the WebDatabase class and migrate the database to
  // the current version.
  Time pre_creation_time = Time::Now();
  {
    WebDatabase db;
    ASSERT_EQ(sql::INIT_OK, db.Init(GetDatabasePath()));
  }
  Time post_creation_time = Time::Now();

  // Verify post-conditions.  These are expectations for current version of the
  // database.
  {
    sql::Connection connection;
    ASSERT_TRUE(connection.Open(GetDatabasePath()));

    // Check version.
    EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));

    // Check that the columns were created.
    EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles",
                                           "date_modified"));
    EXPECT_TRUE(connection.DoesColumnExist("credit_cards",
                                           "date_modified"));

    sql::Statement s_profiles(connection.GetUniqueStatement(
        "SELECT date_modified FROM autofill_profiles "));
    ASSERT_TRUE(s_profiles);
    while (s_profiles.Step()) {
      EXPECT_GE(s_profiles.ColumnInt64(0),
                pre_creation_time.ToTimeT());
      EXPECT_LE(s_profiles.ColumnInt64(0),
                post_creation_time.ToTimeT());
    }
    EXPECT_TRUE(s_profiles.Succeeded());

    sql::Statement s_credit_cards(connection.GetUniqueStatement(
        "SELECT date_modified FROM credit_cards "));
    ASSERT_TRUE(s_credit_cards);
    while (s_credit_cards.Step()) {
      EXPECT_GE(s_credit_cards.ColumnInt64(0),
                pre_creation_time.ToTimeT());
      EXPECT_LE(s_credit_cards.ColumnInt64(0),
                post_creation_time.ToTimeT());
    }
    EXPECT_TRUE(s_credit_cards.Succeeded());
  }
}

// Makes sure guids are added to autofill_profiles and credit_cards tables.
TEST_F(WebDatabaseMigrationTest, MigrateVersion30ToCurrent) {
  // Initialize the database.
  ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_30.sql")));

  // Verify pre-conditions. These are expectations for version 29 of the
  // database.
  {
    sql::Connection connection;
    ASSERT_TRUE(connection.Open(GetDatabasePath()));

    EXPECT_FALSE(connection.DoesColumnExist("autofill_profiles", "guid"));
    EXPECT_FALSE(connection.DoesColumnExist("credit_cards", "guid"));
  }

  // Load the database via the WebDatabase class and migrate the database to
  // the current version.
  {
    WebDatabase db;
    ASSERT_EQ(sql::INIT_OK, db.Init(GetDatabasePath()));
  }

  // Verify post-conditions.  These are expectations for current version of the
  // database.
  {
    sql::Connection connection;
    ASSERT_TRUE(connection.Open(GetDatabasePath()));

    // Check version.
    EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));

    ASSERT_TRUE(connection.DoesColumnExist("autofill_profiles", "guid"));
    ASSERT_TRUE(connection.DoesColumnExist("credit_cards", "guid"));

    // Check that guids are non-null, non-empty, conforms to guid format, and
    // are different.
    sql::Statement s(
        connection.GetUniqueStatement("SELECT guid FROM autofill_profiles"));

    ASSERT_TRUE(s.Step());
    std::string guid1 = s.ColumnString(0);
    EXPECT_TRUE(guid::IsValidGUID(guid1));

    ASSERT_TRUE(s.Step());
    std::string guid2 = s.ColumnString(0);
    EXPECT_TRUE(guid::IsValidGUID(guid2));

    EXPECT_NE(guid1, guid2);
  }
}

// Removes unique IDs and make GUIDs the primary key.  Also removes unused
// columns.
TEST_F(WebDatabaseMigrationTest, MigrateVersion31ToCurrent) {
  // Initialize the database.
  ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_31.sql")));

  // Verify pre-conditions. These are expectations for version 30 of the
  // database.
  AutofillProfile profile;
  string16 profile_label;
  int profile_unique_id = 0;
  int64 profile_date_modified = 0;
  CreditCard credit_card;
  string16 cc_label;
  int cc_unique_id = 0;
  std::string cc_number_encrypted;
  int64 cc_date_modified = 0;
  {
    sql::Connection connection;
    ASSERT_TRUE(connection.Open(GetDatabasePath()));

    // Verify existence of columns we'll be changing.
    EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "guid"));
    EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "unique_id"));
    EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "guid"));
    EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "unique_id"));
    EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "type"));
    EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "card_number"));
    EXPECT_TRUE(connection.DoesColumnExist("credit_cards",
                                           "verification_code"));
    EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "billing_address"));
    EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "shipping_address"));
    EXPECT_TRUE(connection.DoesColumnExist("credit_cards",
                                           "verification_code_encrypted"));

    // Fetch data in the database prior to migration.
    sql::Statement s1(
        connection.GetUniqueStatement(
            "SELECT label, unique_id, first_name, middle_name, last_name, "
            "email, company_name, address_line_1, address_line_2, city, state, "
            "zipcode, country, phone, fax, date_modified, guid "
            "FROM autofill_profiles"));
    ASSERT_TRUE(s1.Step());
    EXPECT_NO_FATAL_FAILURE(AutofillProfile31FromStatement(
        s1, &profile, &profile_label, &profile_unique_id,
        &profile_date_modified));

    sql::Statement s2(
        connection.GetUniqueStatement(
            "SELECT label, unique_id, name_on_card, type, card_number, "
            "expiration_month, expiration_year, verification_code, "
            "billing_address, shipping_address, card_number_encrypted, "
            "verification_code_encrypted, date_modified, guid "
            "FROM credit_cards"));
    ASSERT_TRUE(s2.Step());
    EXPECT_NO_FATAL_FAILURE(CreditCard31FromStatement(s2,
                                                      &credit_card,
                                                      &cc_label,
                                                      &cc_unique_id,
                                                      &cc_number_encrypted,
                                                      &cc_date_modified));

    EXPECT_NE(profile_unique_id, cc_unique_id);
    EXPECT_NE(profile.guid(), credit_card.guid());
  }

  // Load the database via the WebDatabase class and migrate the database to
  // the current version.
  {
    WebDatabase db;
    ASSERT_EQ(sql::INIT_OK, db.Init(GetDatabasePath()));
  }

  // Verify post-conditions.  These are expectations for current version of the
  // database.
  {
    sql::Connection connection;
    ASSERT_TRUE(connection.Open(GetDatabasePath()));

    // Check version.
    EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));

    // Verify existence of columns we'll be changing.
    EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "guid"));
    EXPECT_FALSE(connection.DoesColumnExist("autofill_profiles", "unique_id"));
    EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "guid"));
    EXPECT_FALSE(connection.DoesColumnExist("credit_cards", "unique_id"));
    EXPECT_FALSE(connection.DoesColumnExist("credit_cards", "type"));
    EXPECT_FALSE(connection.DoesColumnExist("credit_cards", "card_number"));
    EXPECT_FALSE(connection.DoesColumnExist("credit_cards",
                                            "verification_code"));
    EXPECT_FALSE(connection.DoesColumnExist("credit_cards", "billing_address"));
    EXPECT_FALSE(connection.DoesColumnExist("credit_cards",
                                            "shipping_address"));
    EXPECT_FALSE(connection.DoesColumnExist("credit_cards",
                                            "verification_code_encrypted"));

    // Verify data in the database after the migration.
    sql::Statement s1(
        connection.GetUniqueStatement(
            "SELECT guid, 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.GetInfo(COMPANY_NAME),
              profile_a.GetInfo(COMPANY_NAME));
    EXPECT_EQ(profile.GetInfo(ADDRESS_HOME_LINE1),
              profile_a.GetInfo(ADDRESS_HOME_LINE1));
    EXPECT_EQ(profile.GetInfo(ADDRESS_HOME_LINE2),
              profile_a.GetInfo(ADDRESS_HOME_LINE2));
    EXPECT_EQ(profile.GetInfo(ADDRESS_HOME_CITY),
              profile_a.GetInfo(ADDRESS_HOME_CITY));
    EXPECT_EQ(profile.GetInfo(ADDRESS_HOME_STATE),
              profile_a.GetInfo(ADDRESS_HOME_STATE));
    EXPECT_EQ(profile.GetInfo(ADDRESS_HOME_ZIP),
              profile_a.GetInfo(ADDRESS_HOME_ZIP));
    EXPECT_EQ(profile.GetInfo(ADDRESS_HOME_COUNTRY),
              profile_a.GetInfo(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"));
  }

  // Load the database via the WebDatabase class and migrate the database to
  // the current version.
  {
    WebDatabase db;
    ASSERT_EQ(sql::INIT_OK, db.Init(GetDatabasePath()));
  }

  // Verify post-conditions.  These are expectations for current version of the
  // database.
  {
    sql::Connection connection;
    ASSERT_TRUE(connection.Open(GetDatabasePath()));

    // Check version.
    EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));

    // Verify 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(ASCIIToUTF16(""), s1.ColumnString16(1));
    EXPECT_EQ(ASCIIToUTF16("2 Main Street"), s1.ColumnString16(2));
    EXPECT_EQ(ASCIIToUTF16(""), 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(ASCIIToUTF16(""), s1.ColumnString16(1));
    EXPECT_EQ(ASCIIToUTF16("2 Main St"), s1.ColumnString16(2));
    EXPECT_EQ(ASCIIToUTF16(""), 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(ASCIIToUTF16(""), s1.ColumnString16(1));
    EXPECT_EQ(ASCIIToUTF16("3 Main St"), s1.ColumnString16(2));
    EXPECT_EQ(ASCIIToUTF16(""), 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(ASCIIToUTF16(""), 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(ASCIIToUTF16(""), 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(ASCIIToUTF16(""), 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(ASCIIToUTF16(""), s2.ColumnString16(1));
    EXPECT_EQ(ASCIIToUTF16(""), s2.ColumnString16(2));
    EXPECT_EQ(ASCIIToUTF16(""), 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(ASCIIToUTF16(""), s3.ColumnString16(1));

    // 2 Main St.
    ASSERT_TRUE(s3.Step());
    EXPECT_EQ("722DF5C4-F74A-294A-46F0-31FFDED0D635", s3.ColumnString(0));
    EXPECT_EQ(ASCIIToUTF16(""), 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(ASCIIToUTF16(""), 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.
    ASSERT_TRUE(s4.Step());
    EXPECT_EQ("00580526-FF81-EE2A-0546-1AC593A32E2F", s4.ColumnString(0));
    EXPECT_EQ(1, s4.ColumnInt(1)); // 1 means phone.
    EXPECT_EQ(ASCIIToUTF16("4153334444"), s4.ColumnString16(2));

    // 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(ASCIIToUTF16(""), s4.ColumnString16(2));

    // 2 Main Street fax.
    ASSERT_TRUE(s4.Step());
    EXPECT_EQ("4C74A9D8-7EEE-423E-F9C2-E7FA70ED1396", s4.ColumnString(0));
    EXPECT_EQ(1, s4.ColumnInt(1)); // 1 means fax.
    EXPECT_EQ(ASCIIToUTF16(""), s4.ColumnString16(2));

    // 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(ASCIIToUTF16(""), s4.ColumnString16(2));

    // 2 Main St fax.
    ASSERT_TRUE(s4.Step());
    EXPECT_EQ("722DF5C4-F74A-294A-46F0-31FFDED0D635", s4.ColumnString(0));
    EXPECT_EQ(1, s4.ColumnInt(1)); // 1 means fax.
    EXPECT_EQ(ASCIIToUTF16(""), s4.ColumnString16(2));

    // 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(ASCIIToUTF16(""), s4.ColumnString16(2));

    // 2 Main St fax.
    ASSERT_TRUE(s4.Step());
    EXPECT_EQ("9E5FE298-62C7-83DF-6293-381BC589183F", s4.ColumnString(0));
    EXPECT_EQ(1, s4.ColumnInt(1)); // 1 means fax.
    EXPECT_EQ(ASCIIToUTF16(""), s4.ColumnString16(2));

    // 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);
  }

  // Load the database via the WebDatabase class and migrate the database to
  // the current version.
  {
    WebDatabase db;
    ASSERT_EQ(sql::INIT_OK, db.Init(GetDatabasePath()));
  }

  // Verify post-conditions.  These are expectations for current version of the
  // database.
  {
    sql::Connection connection;
    ASSERT_TRUE(connection.Open(GetDatabasePath()));

    // Check version.
    EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));

    ASSERT_TRUE(connection.DoesColumnExist("autofill_profiles",
                                           "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());
  }

  // Load the database via the WebDatabase class and migrate the database to
  // the current version.
  {
    WebDatabase db;
    ASSERT_EQ(sql::INIT_OK, db.Init(GetDatabasePath()));
  }

  // Verify post-conditions.  These are expectations for current version of the
  // database.
  {
    sql::Connection connection;
    ASSERT_TRUE(connection.Open(GetDatabasePath()));

    // Check version.
    EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));

    ASSERT_TRUE(connection.DoesColumnExist("autofill_profiles",
                                           "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);
  }

  // Load the database via the WebDatabase class and migrate the database to
  // the current version.
  {
    WebDatabase db;
    ASSERT_EQ(sql::INIT_OK, db.Init(GetDatabasePath()));
  }

  // Verify post-conditions.  These are expectations for current version of the
  // database.
  {
    sql::Connection connection;
    ASSERT_TRUE(connection.Open(GetDatabasePath()));

    // Check version.
    EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));

    ASSERT_TRUE(connection.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());
  }
}