summaryrefslogtreecommitdiffstats
path: root/chrome/browser/webdata
diff options
context:
space:
mode:
authorjhawkins@chromium.org <jhawkins@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-09-13 20:38:57 +0000
committerjhawkins@chromium.org <jhawkins@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-09-13 20:38:57 +0000
commitc47c9d80e93941924c8d6c5e4d7845971552b390 (patch)
treeba148e054621c580be7c6ca48c217de344f5eb04 /chrome/browser/webdata
parent4cd978f396db700a1fb3e2d6e081e76817264c9b (diff)
downloadchromium_src-c47c9d80e93941924c8d6c5e4d7845971552b390.zip
chromium_src-c47c9d80e93941924c8d6c5e4d7845971552b390.tar.gz
chromium_src-c47c9d80e93941924c8d6c5e4d7845971552b390.tar.bz2
DOMUI: Implement adding and editing credit cards in the AutoFill page.
BUG=49094 TEST=none Review URL: http://codereview.chromium.org/3308006 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@59276 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/webdata')
-rw-r--r--chrome/browser/webdata/web_database.cc121
-rw-r--r--chrome/browser/webdata/web_database.h6
-rw-r--r--chrome/browser/webdata/web_database_unittest.cc222
3 files changed, 338 insertions, 11 deletions
diff --git a/chrome/browser/webdata/web_database.cc b/chrome/browser/webdata/web_database.cc
index 7028b1f..eaeb623 100644
--- a/chrome/browser/webdata/web_database.cc
+++ b/chrome/browser/webdata/web_database.cc
@@ -12,6 +12,7 @@
#include "app/l10n_util.h"
#include "app/sql/statement.h"
#include "app/sql/transaction.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/tuple.h"
#include "base/utf_string_conversions.h"
@@ -167,8 +168,8 @@ typedef std::vector<Tuple3<int64, string16, string16> > AutofillElementList;
// Current version number. Note: when changing the current version number,
// corresponding changes must happen in the unit tests, and new migration test
// added. See |WebDatabaseMigrationTest::kCurrentTestedVersionNumber|.
-const int kCurrentVersionNumber = 26;
-const int kCompatibleVersionNumber = 26;
+const int kCurrentVersionNumber = 27;
+const int kCompatibleVersionNumber = 27;
const int kUrlIdPosition = 15;
// Keys used in the meta table.
@@ -339,7 +340,7 @@ void BindCreditCardToStatement(const CreditCard& credit_card,
s->BindString16(6, LimitDataSize(text));
text.clear();
s->BindString16(7, LimitDataSize(text));
- s->BindString16(8, credit_card.billing_address());
+ s->BindInt(8, credit_card.billing_address_id());
// We don't store the shipping address anymore.
text.clear();
s->BindString16(9, LimitDataSize(text));
@@ -380,7 +381,7 @@ CreditCard* CreditCardFromStatement(const sql::Statement& s) {
string16 credit_card_verification_code = s.ColumnString16(7);
// We don't store the CVV anymore.
- credit_card->set_billing_address(s.ColumnString16(8));
+ credit_card->set_billing_address_id(s.ColumnInt(8));
// We don't store the shipping address anymore.
// Column 10 is processed above.
// Column 11 is processed above.
@@ -2039,11 +2040,123 @@ void WebDatabase::MigrateOldVersionsAsNeeded(){
LOG(WARNING) << "Unable to update web database to version 26.";
return;
}
+
+ meta_table_.SetVersionNumber(26);
+ meta_table_.SetCompatibleVersionNumber(
+ std::min(26, kCompatibleVersionNumber));
+ // FALL THROUGH
+
+ case 26: {
+ // Change the credit_cards.billing_address column from a string to an int.
+ // The stored string is the label of an address, so we have to select the
+ // unique ID of this address using the label as a foreign key into the
+ // |autofill_profiles| table.
+ std::string stmt =
+ "SELECT credit_cards.unique_id, autofill_profiles.unique_id "
+ "FROM autofill_profiles, credit_cards "
+ "WHERE credit_cards.billing_address = autofill_profiles.label";
+ sql::Statement s(db_.GetUniqueStatement(stmt.c_str()));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return;
+ }
+
+ std::map<int, int> cc_billing_map;
+ while (s.Step())
+ cc_billing_map[s.ColumnInt(0)] = s.ColumnInt(1);
+
+ // Windows already stores the IDs as strings in |billing_address|. Try to
+ // convert those.
+ if (cc_billing_map.empty()) {
+ std::string stmt =
+ "SELECT unique_id,billing_address FROM credit_cards";
+ sql::Statement s(db_.GetUniqueStatement(stmt.c_str()));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return;
+ }
+
+ while (s.Step()) {
+ int id = 0;
+ if (base::StringToInt(s.ColumnString(1), &id))
+ cc_billing_map[s.ColumnInt(0)] = id;
+ }
+ }
+
+ if (!db_.Execute("CREATE TABLE credit_cards_temp ( "
+ "label VARCHAR, "
+ "unique_id INTEGER PRIMARY KEY, "
+ "name_on_card VARCHAR, "
+ "type VARCHAR, "
+ "card_number VARCHAR, "
+ "expiration_month INTEGER, "
+ "expiration_year INTEGER, "
+ "verification_code VARCHAR, "
+ "billing_address INTEGER, "
+ "shipping_address VARCHAR, "
+ "card_number_encrypted BLOB, "
+ "verification_code_encrypted BLOB)")) {
+ NOTREACHED();
+ LOG(WARNING) << "Unable to update web database to version 27.";
+ return;
+ }
+
+ if (!db_.Execute(
+ "INSERT INTO credit_cards_temp "
+ "SELECT label,unique_id,name_on_card,type,card_number,"
+ "expiration_month,expiration_year,verification_code,0,"
+ "shipping_address,card_number_encrypted,verification_code_encrypted "
+ "FROM credit_cards")) {
+ NOTREACHED();
+ LOG(WARNING) << "Unable to update web database to version 27.";
+ return;
+ }
+
+ if (!db_.Execute("DROP TABLE credit_cards")) {
+ NOTREACHED();
+ LOG(WARNING) << "Unable to update web database to version 27.";
+ return;
+ }
+
+ if (!db_.Execute(
+ "ALTER TABLE credit_cards_temp RENAME TO credit_cards")) {
+ NOTREACHED();
+ LOG(WARNING) << "Unable to update web database to version 27.";
+ return;
+ }
+
meta_table_.SetVersionNumber(26);
meta_table_.SetCompatibleVersionNumber(
std::min(26, kCompatibleVersionNumber));
// FALL THROUGH
+ for (std::map<int, int>::const_iterator iter = cc_billing_map.begin();
+ iter != cc_billing_map.end(); ++iter) {
+ sql::Statement s(db_.GetCachedStatement(
+ SQL_FROM_HERE,
+ "UPDATE credit_cards SET billing_address=? WHERE unique_id=?"));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return;
+ }
+
+ s.BindInt(0, (*iter).second);
+ s.BindInt(1, (*iter).first);
+
+ if (!s.Run()) {
+ NOTREACHED();
+ LOG(WARNING) << "Unable to update web database to version 27.";
+ return;
+ }
+ }
+
+ meta_table_.SetVersionNumber(27);
+ meta_table_.SetCompatibleVersionNumber(
+ std::min(27, kCompatibleVersionNumber));
+
+ // FALL THROUGH
+ }
+
// Add successive versions here. Each should set the version number and
// compatible version number as appropriate, then fall through to the next
// case.
diff --git a/chrome/browser/webdata/web_database.h b/chrome/browser/webdata/web_database.h
index b15f688..9358533 100644
--- a/chrome/browser/webdata/web_database.h
+++ b/chrome/browser/webdata/web_database.h
@@ -129,14 +129,14 @@ class WebDatabase {
// Loads the complete list of password forms into the specified vector |forms|
// if include_blacklisted is true, otherwise only loads those which are
- // actually autofillable; i.e haven't been blacklisted by the user selecting
+ // actually autofill-able; i.e haven't been blacklisted by the user selecting
// the 'Never for this site' button.
bool GetAllLogins(std::vector<webkit_glue::PasswordForm*>* forms,
bool include_blacklisted);
//////////////////////////////////////////////////////////////////////////////
//
- // Autofill
+ // AutoFill
//
//////////////////////////////////////////////////////////////////////////////
@@ -285,7 +285,7 @@ class WebDatabase {
// Remove all tokens previously set with SetTokenForService.
bool RemoveAllTokens();
- // Retrives all tokens previously set with SetTokenForService.
+ // Retrieves all tokens previously set with SetTokenForService.
// Returns true if there were tokens and we decrypted them,
// false if there was a failure somehow
bool GetAllTokens(std::map<std::string, std::string>* tokens);
diff --git a/chrome/browser/webdata/web_database_unittest.cc b/chrome/browser/webdata/web_database_unittest.cc
index 998e027..4bfa827 100644
--- a/chrome/browser/webdata/web_database_unittest.cc
+++ b/chrome/browser/webdata/web_database_unittest.cc
@@ -1318,7 +1318,7 @@ TEST_F(WebDatabaseTest, CreditCard) {
ASCIIToUTF16("04"));
work_creditcard.SetInfo(AutoFillType(CREDIT_CARD_EXP_4_DIGIT_YEAR),
ASCIIToUTF16("2013"));
- work_creditcard.set_billing_address(ASCIIToUTF16("Overlook Hotel"));
+ work_creditcard.set_billing_address_id(1);
EXPECT_TRUE(db.AddCreditCard(work_creditcard));
@@ -1340,7 +1340,7 @@ TEST_F(WebDatabaseTest, CreditCard) {
ASCIIToUTF16("06"));
target_creditcard.SetInfo(AutoFillType(CREDIT_CARD_EXP_4_DIGIT_YEAR),
ASCIIToUTF16("2012"));
- target_creditcard.set_billing_address(ASCIIToUTF16("Overlook Hotel"));
+ target_creditcard.set_billing_address_id(1);
EXPECT_TRUE(db.AddCreditCard(target_creditcard));
ASSERT_TRUE(db.GetCreditCardForLabel(ASCIIToUTF16("Target"),
@@ -1350,7 +1350,7 @@ TEST_F(WebDatabaseTest, CreditCard) {
// Update the 'Target' profile.
target_creditcard.SetInfo(AutoFillType(CREDIT_CARD_NAME),
- ASCIIToUTF16("Charles Grady"));
+ ASCIIToUTF16("Charles Grady"));
EXPECT_TRUE(db.UpdateCreditCard(target_creditcard));
ASSERT_TRUE(db.GetCreditCardForLabel(ASCIIToUTF16("Target"), &db_creditcard));
EXPECT_EQ(target_creditcard, *db_creditcard);
@@ -1572,6 +1572,7 @@ class WebDatabaseMigrationTest : public testing::Test {
void SetUpVersion22CorruptDatabase();
void SetUpVersion24Database();
void SetUpVersion25Database();
+ void SetUpVersion26Database();
private:
ScopedTempDir temp_dir_;
@@ -1579,7 +1580,7 @@ class WebDatabaseMigrationTest : public testing::Test {
DISALLOW_COPY_AND_ASSIGN(WebDatabaseMigrationTest);
};
-const int WebDatabaseMigrationTest::kCurrentTestedVersionNumber = 26;
+const int WebDatabaseMigrationTest::kCurrentTestedVersionNumber = 27;
// 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
@@ -1868,6 +1869,67 @@ void WebDatabaseMigrationTest::SetUpVersion25Database() {
ASSERT_TRUE(connection.CommitTransaction());
}
+// This schema is taken from a build prior to the change of column type for
+// credit_cards.billing_address from string to int.
+void WebDatabaseMigrationTest::SetUpVersion26Database() {
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+ ASSERT_TRUE(connection.BeginTransaction());
+ ASSERT_TRUE(connection.Execute(
+ "CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,"
+ "value LONGVARCHAR);"
+ "INSERT INTO \"meta\" VALUES('version','25');"
+ "INSERT INTO \"meta\" VALUES('last_compatible_version','25');"
+ "CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,"
+ "keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,"
+ "url VARCHAR NOT NULL,show_in_default_list INTEGER,"
+ "safe_for_autoreplace INTEGER,originating_url VARCHAR,"
+ "date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,"
+ "input_encodings VARCHAR,suggest_url VARCHAR,"
+ "prepopulate_id INTEGER DEFAULT 0,"
+ "autogenerate_keyword INTEGER DEFAULT 0,"
+ "logo_id INTEGER DEFAULT 0,"
+ "created_by_policy INTEGER DEFAULT 0);"
+ "CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR,"
+ "username_element VARCHAR, username_value VARCHAR,"
+ "password_element VARCHAR, password_value BLOB, submit_element VARCHAR,"
+ "signon_realm VARCHAR NOT NULL,"
+ "ssl_valid INTEGER NOT NULL,preferred INTEGER NOT NULL,"
+ "date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT NULL,"
+ "scheme INTEGER NOT NULL,UNIQUE (origin_url, username_element,"
+ "username_value, password_element, submit_element, signon_realm));"
+ "CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,"
+ "image BLOB, UNIQUE (url, width, height));"
+ "CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,"
+ "has_all_images INTEGER NOT NULL);"
+ "CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR,"
+ "pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1);"
+ "CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0,"
+ "date_created INTEGER DEFAULT 0);"
+ "CREATE TABLE autofill_profiles ( label VARCHAR,"
+ "unique_id INTEGER PRIMARY KEY, first_name VARCHAR,"
+ "middle_name VARCHAR, last_name VARCHAR, email VARCHAR,"
+ "company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR,"
+ "city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR,"
+ "phone VARCHAR, fax VARCHAR);"
+ "CREATE TABLE credit_cards ( label VARCHAR, unique_id INTEGER PRIMARY KEY,"
+ "name_on_card VARCHAR, type VARCHAR, card_number VARCHAR,"
+ "expiration_month INTEGER, expiration_year INTEGER,"
+ "verification_code VARCHAR, billing_address VARCHAR,"
+ "shipping_address VARCHAR, card_number_encrypted BLOB,"
+ "verification_code_encrypted BLOB);"
+ "CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,"
+ "encrypted_token BLOB);"
+ "CREATE INDEX logins_signon ON logins (signon_realm);"
+ "CREATE INDEX web_apps_url_index ON web_apps (url);"
+ "CREATE INDEX autofill_name ON autofill (name);"
+ "CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower);"
+ "CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id);"
+ "CREATE INDEX autofill_profiles_label_index ON autofill_profiles (label);"
+ "CREATE INDEX credit_cards_label_index ON credit_cards (label);"));
+ ASSERT_TRUE(connection.CommitTransaction());
+}
+
// 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
@@ -2039,10 +2101,144 @@ TEST_F(WebDatabaseMigrationTest, MigrateVersion25ToCurrent) {
{
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) {
+ // Initialize the database.
+ SetUpVersion25Database();
+
+ // Verify pre-conditions. These are expectations for version 25 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", "created_by_policy"));
+ 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_TRUE(connection.DoesColumnExist("credit_cards", "billing_address"));
+
+ // |billing_address| is an integer. Also Verify the credit card data is
+ // converted.
+ std::string stmt = "SELECT * FROM credit_cards";
+ sql::Statement s(connection.GetUniqueStatement(stmt.c_str()));
+ ASSERT_TRUE(s.Step());
+ EXPECT_EQ(s.ColumnType(8), sql::COLUMN_TYPE_INTEGER);
+ EXPECT_EQ("label", s.ColumnString(0));
+ EXPECT_EQ(2, s.ColumnInt(1));
+ EXPECT_EQ("Jack", s.ColumnString(2));
+ EXPECT_EQ("Visa", s.ColumnString(3));
+ EXPECT_EQ("1234", s.ColumnString(4));
+ EXPECT_EQ(2, s.ColumnInt(5));
+ EXPECT_EQ(2012, s.ColumnInt(6));
+ EXPECT_EQ(std::string(), s.ColumnString(7));
+ EXPECT_EQ(1, s.ColumnInt(8));
+ // The remaining columns are unused or blobs.
+ }
+}
+
+// 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) {
+ // Initialize the database.
+ SetUpVersion25Database();
+
+ // Verify pre-conditions. These are expectations for version 25 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
@@ -2064,5 +2260,23 @@ TEST_F(WebDatabaseMigrationTest, MigrateVersion25ToCurrent) {
// |keywords| |logo_id| column should have been added.
EXPECT_TRUE(connection.DoesColumnExist("keywords", "id"));
EXPECT_TRUE(connection.DoesColumnExist("keywords", "created_by_policy"));
+ EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "billing_address"));
+
+ // |billing_address| is an integer. Also Verify the credit card data is
+ // converted.
+ std::string stmt = "SELECT * FROM credit_cards";
+ sql::Statement s(connection.GetUniqueStatement(stmt.c_str()));
+ ASSERT_TRUE(s.Step());
+ EXPECT_EQ(s.ColumnType(8), sql::COLUMN_TYPE_INTEGER);
+ EXPECT_EQ("label", s.ColumnString(0));
+ EXPECT_EQ(2, s.ColumnInt(1));
+ EXPECT_EQ("Jack", s.ColumnString(2));
+ EXPECT_EQ("Visa", s.ColumnString(3));
+ EXPECT_EQ("1234", s.ColumnString(4));
+ EXPECT_EQ(2, s.ColumnInt(5));
+ EXPECT_EQ(2012, s.ColumnInt(6));
+ EXPECT_EQ(std::string(), s.ColumnString(7));
+ EXPECT_EQ(1, s.ColumnInt(8));
+ // The remaining columns are unused or blobs.
}
}