Home | History | Annotate | Download | only in password_manager
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include <algorithm>
      6 #include <map>
      7 #include <string>
      8 #include <vector>
      9 
     10 #include "base/bind.h"
     11 #include "base/pickle.h"
     12 #include "base/prefs/pref_service.h"
     13 #include "base/stl_util.h"
     14 #include "base/strings/utf_string_conversions.h"
     15 #include "base/synchronization/waitable_event.h"
     16 #include "chrome/browser/password_manager/native_backend_kwallet_x.h"
     17 #include "chrome/common/pref_names.h"
     18 #include "chrome/test/base/testing_profile.h"
     19 #include "content/public/test/test_browser_thread.h"
     20 #include "dbus/message.h"
     21 #include "dbus/mock_bus.h"
     22 #include "dbus/mock_object_proxy.h"
     23 #include "dbus/object_path.h"
     24 #include "dbus/object_proxy.h"
     25 #include "testing/gmock/include/gmock/gmock.h"
     26 #include "testing/gtest/include/gtest/gtest.h"
     27 
     28 using content::BrowserThread;
     29 using testing::_;
     30 using testing::Invoke;
     31 using testing::Return;
     32 using content::PasswordForm;
     33 
     34 namespace {
     35 
     36 // This class implements a very simple version of KWallet in memory.
     37 // We only provide the parts we actually use; the real version has more.
     38 class TestKWallet {
     39  public:
     40   typedef std::basic_string<uint8_t> Blob;  // std::string is binary-safe.
     41 
     42   TestKWallet() : reject_local_folders_(false) {}
     43 
     44   void set_reject_local_folders(bool value) { reject_local_folders_ = value; }
     45 
     46   // NOTE: The method names here are the same as the corresponding DBus
     47   // methods, and therefore have names that don't match our style guide.
     48 
     49   // Check for presence of a given password folder.
     50   bool hasFolder(const std::string& folder) const {
     51     return data_.find(folder) != data_.end();
     52   }
     53 
     54   // Check for presence of a given password in a given password folder.
     55   bool hasEntry(const std::string& folder, const std::string& key) const {
     56     Data::const_iterator it = data_.find(folder);
     57     return it != data_.end() && it->second.find(key) != it->second.end();
     58   }
     59 
     60   // Get a list of password keys in a given password folder.
     61   bool entryList(const std::string& folder,
     62                  std::vector<std::string>* entries) const {
     63     Data::const_iterator it = data_.find(folder);
     64     if (it == data_.end()) return false;
     65     for (Folder::const_iterator fit = it->second.begin();
     66          fit != it->second.end(); ++fit)
     67       entries->push_back(fit->first);
     68     return true;
     69   }
     70 
     71   // Read the password data for a given password in a given password folder.
     72   bool readEntry(const std::string& folder, const std::string& key,
     73                  Blob* value) const {
     74     Data::const_iterator it = data_.find(folder);
     75     if (it == data_.end()) return false;
     76     Folder::const_iterator fit = it->second.find(key);
     77     if (fit == it->second.end()) return false;
     78     *value = fit->second;
     79     return true;
     80   }
     81 
     82   // Create the given password folder.
     83   bool createFolder(const std::string& folder) {
     84     if (reject_local_folders_ && folder.find('(') != std::string::npos)
     85       return false;
     86     return data_.insert(make_pair(folder, Folder())).second;
     87   }
     88 
     89   // Remove the given password from the given password folder.
     90   bool removeEntry(const std::string& folder, const std::string& key) {
     91     Data::iterator it = data_.find(folder);
     92     if (it == data_.end()) return false;
     93     return it->second.erase(key) > 0;
     94   }
     95 
     96   // Write the given password data to the given password folder.
     97   bool writeEntry(const std::string& folder, const std::string& key,
     98                   const Blob& value) {
     99     Data::iterator it = data_.find(folder);
    100     if (it == data_.end()) return false;
    101     it->second[key] = value;
    102     return true;
    103   }
    104 
    105  private:
    106   typedef std::map<std::string, Blob> Folder;
    107   typedef std::map<std::string, Folder> Data;
    108 
    109   Data data_;
    110   // "Local" folders are folders containing local profile IDs in their names. We
    111   // can reject attempts to create them in order to make it easier to create
    112   // legacy shared passwords in these tests, for testing the migration code.
    113   bool reject_local_folders_;
    114 
    115   // No need to disallow copy and assign. This class is safe to copy and assign.
    116 };
    117 
    118 }  // anonymous namespace
    119 
    120 // Obscure magic: we need to declare storage for this constant because we use it
    121 // in ways that require its address in this test, but not in the actual code.
    122 const int NativeBackendKWallet::kInvalidKWalletHandle;
    123 
    124 // Subclass NativeBackendKWallet to promote some members to public for testing.
    125 class NativeBackendKWalletStub : public NativeBackendKWallet {
    126  public:
    127   NativeBackendKWalletStub(LocalProfileId id, PrefService* pref_service)
    128       :  NativeBackendKWallet(id, pref_service) {
    129   }
    130   using NativeBackendKWallet::InitWithBus;
    131   using NativeBackendKWallet::kInvalidKWalletHandle;
    132   using NativeBackendKWallet::DeserializeValue;
    133 };
    134 
    135 // Provide some test forms to avoid having to set them up in each test.
    136 class NativeBackendKWalletTestBase : public testing::Test {
    137  protected:
    138   NativeBackendKWalletTestBase() {
    139     form_google_.origin = GURL("http://www.google.com/");
    140     form_google_.action = GURL("http://www.google.com/login");
    141     form_google_.username_element = UTF8ToUTF16("user");
    142     form_google_.username_value = UTF8ToUTF16("joeschmoe");
    143     form_google_.password_element = UTF8ToUTF16("pass");
    144     form_google_.password_value = UTF8ToUTF16("seekrit");
    145     form_google_.submit_element = UTF8ToUTF16("submit");
    146     form_google_.signon_realm = "Google";
    147 
    148     form_isc_.origin = GURL("http://www.isc.org/");
    149     form_isc_.action = GURL("http://www.isc.org/auth");
    150     form_isc_.username_element = UTF8ToUTF16("id");
    151     form_isc_.username_value = UTF8ToUTF16("janedoe");
    152     form_isc_.password_element = UTF8ToUTF16("passwd");
    153     form_isc_.password_value = UTF8ToUTF16("ihazabukkit");
    154     form_isc_.submit_element = UTF8ToUTF16("login");
    155     form_isc_.signon_realm = "ISC";
    156   }
    157 
    158   void CheckPasswordForm(const PasswordForm& expected,
    159                          const PasswordForm& actual);
    160 
    161   PasswordForm form_google_;
    162   PasswordForm form_isc_;
    163 };
    164 
    165 void NativeBackendKWalletTestBase::CheckPasswordForm(
    166     const PasswordForm& expected, const PasswordForm& actual) {
    167   EXPECT_EQ(expected.origin, actual.origin);
    168   EXPECT_EQ(expected.password_value, actual.password_value);
    169   EXPECT_EQ(expected.action, actual.action);
    170   EXPECT_EQ(expected.username_element, actual.username_element);
    171   EXPECT_EQ(expected.username_value, actual.username_value);
    172   EXPECT_EQ(expected.password_element, actual.password_element);
    173   EXPECT_EQ(expected.submit_element, actual.submit_element);
    174   EXPECT_EQ(expected.signon_realm, actual.signon_realm);
    175   EXPECT_EQ(expected.ssl_valid, actual.ssl_valid);
    176   EXPECT_EQ(expected.preferred, actual.preferred);
    177   // We don't check the date created. It varies.
    178   EXPECT_EQ(expected.blacklisted_by_user, actual.blacklisted_by_user);
    179   EXPECT_EQ(expected.scheme, actual.scheme);
    180 }
    181 
    182 class NativeBackendKWalletTest : public NativeBackendKWalletTestBase {
    183  protected:
    184   NativeBackendKWalletTest()
    185       : ui_thread_(BrowserThread::UI, &message_loop_),
    186         db_thread_(BrowserThread::DB), klauncher_ret_(0),
    187         klauncher_contacted_(false), kwallet_runnable_(true),
    188         kwallet_running_(true), kwallet_enabled_(true) {
    189   }
    190 
    191   virtual void SetUp();
    192   virtual void TearDown();
    193 
    194   // Let the DB thread run to completion of all current tasks.
    195   void RunDBThread() {
    196     base::WaitableEvent event(false, false);
    197     BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
    198                             base::Bind(ThreadDone, &event));
    199     event.Wait();
    200     // Some of the tests may post messages to the UI thread, but we don't need
    201     // to run those until after the DB thread is finished. So run it here.
    202     message_loop_.RunUntilIdle();
    203   }
    204   static void ThreadDone(base::WaitableEvent* event) {
    205     event->Signal();
    206   }
    207 
    208   // Utilities to help verify sets of expectations.
    209   typedef std::vector<
    210               std::pair<std::string,
    211                         std::vector<const PasswordForm*> > > ExpectationArray;
    212   void CheckPasswordForms(const std::string& folder,
    213                           const ExpectationArray& sorted_expected);
    214 
    215   base::MessageLoopForUI message_loop_;
    216   content::TestBrowserThread ui_thread_;
    217   content::TestBrowserThread db_thread_;
    218   TestingProfile profile_;
    219 
    220   scoped_refptr<dbus::MockBus> mock_session_bus_;
    221   scoped_refptr<dbus::MockObjectProxy> mock_klauncher_proxy_;
    222   scoped_refptr<dbus::MockObjectProxy> mock_kwallet_proxy_;
    223 
    224   int klauncher_ret_;
    225   std::string klauncher_error_;
    226   bool klauncher_contacted_;
    227 
    228   bool kwallet_runnable_;
    229   bool kwallet_running_;
    230   bool kwallet_enabled_;
    231 
    232   TestKWallet wallet_;
    233 
    234  private:
    235   dbus::Response* KLauncherMethodCall(
    236       dbus::MethodCall* method_call, testing::Unused);
    237 
    238   dbus::Response* KWalletMethodCall(
    239       dbus::MethodCall* method_call, testing::Unused);
    240 };
    241 
    242 void NativeBackendKWalletTest::SetUp() {
    243   ASSERT_TRUE(db_thread_.Start());
    244 
    245   dbus::Bus::Options options;
    246   options.bus_type = dbus::Bus::SESSION;
    247   mock_session_bus_ = new dbus::MockBus(options);
    248 
    249   mock_klauncher_proxy_ =
    250       new dbus::MockObjectProxy(mock_session_bus_.get(),
    251                                 "org.kde.klauncher",
    252                                 dbus::ObjectPath("/KLauncher"));
    253   EXPECT_CALL(*mock_klauncher_proxy_.get(), MockCallMethodAndBlock(_, _))
    254       .WillRepeatedly(
    255            Invoke(this, &NativeBackendKWalletTest::KLauncherMethodCall));
    256 
    257   mock_kwallet_proxy_ =
    258       new dbus::MockObjectProxy(mock_session_bus_.get(),
    259                                 "org.kde.kwalletd",
    260                                 dbus::ObjectPath("/modules/kwalletd"));
    261   EXPECT_CALL(*mock_kwallet_proxy_.get(), MockCallMethodAndBlock(_, _))
    262       .WillRepeatedly(
    263            Invoke(this, &NativeBackendKWalletTest::KWalletMethodCall));
    264 
    265   EXPECT_CALL(
    266       *mock_session_bus_.get(),
    267       GetObjectProxy("org.kde.klauncher", dbus::ObjectPath("/KLauncher")))
    268       .WillRepeatedly(Return(mock_klauncher_proxy_.get()));
    269   EXPECT_CALL(
    270       *mock_session_bus_.get(),
    271       GetObjectProxy("org.kde.kwalletd", dbus::ObjectPath("/modules/kwalletd")))
    272       .WillRepeatedly(Return(mock_kwallet_proxy_.get()));
    273 
    274   EXPECT_CALL(*mock_session_bus_.get(), ShutdownAndBlock()).WillOnce(Return())
    275       .WillRepeatedly(Return());
    276 }
    277 
    278 void NativeBackendKWalletTest::TearDown() {
    279   base::MessageLoop::current()->PostTask(FROM_HERE,
    280                                          base::MessageLoop::QuitClosure());
    281   base::MessageLoop::current()->Run();
    282   db_thread_.Stop();
    283 }
    284 
    285 dbus::Response* NativeBackendKWalletTest::KLauncherMethodCall(
    286     dbus::MethodCall* method_call, testing::Unused) {
    287   EXPECT_EQ("org.kde.KLauncher", method_call->GetInterface());
    288   EXPECT_EQ("start_service_by_desktop_name", method_call->GetMember());
    289 
    290   klauncher_contacted_ = true;
    291 
    292   dbus::MessageReader reader(method_call);
    293   std::string service_name;
    294   std::vector<std::string> urls;
    295   std::vector<std::string> envs;
    296   std::string startup_id;
    297   bool blind = false;
    298 
    299   EXPECT_TRUE(reader.PopString(&service_name));
    300   EXPECT_TRUE(reader.PopArrayOfStrings(&urls));
    301   EXPECT_TRUE(reader.PopArrayOfStrings(&envs));
    302   EXPECT_TRUE(reader.PopString(&startup_id));
    303   EXPECT_TRUE(reader.PopBool(&blind));
    304 
    305   EXPECT_EQ("kwalletd", service_name);
    306   EXPECT_TRUE(urls.empty());
    307   EXPECT_TRUE(envs.empty());
    308   EXPECT_TRUE(startup_id.empty());
    309   EXPECT_FALSE(blind);
    310 
    311   if (kwallet_runnable_)
    312     kwallet_running_ = true;
    313 
    314   scoped_ptr<dbus::Response> response(dbus::Response::CreateEmpty());
    315   dbus::MessageWriter writer(response.get());
    316   writer.AppendInt32(klauncher_ret_);
    317   writer.AppendString(std::string());  // dbus_name
    318   writer.AppendString(klauncher_error_);
    319   writer.AppendInt32(1234);  // pid
    320   return response.release();
    321 }
    322 
    323 dbus::Response* NativeBackendKWalletTest::KWalletMethodCall(
    324     dbus::MethodCall* method_call, testing::Unused) {
    325   if (!kwallet_running_)
    326     return NULL;
    327   EXPECT_EQ("org.kde.KWallet", method_call->GetInterface());
    328 
    329   scoped_ptr<dbus::Response> response;
    330   if (method_call->GetMember() == "isEnabled") {
    331     response = dbus::Response::CreateEmpty();
    332     dbus::MessageWriter writer(response.get());
    333     writer.AppendBool(kwallet_enabled_);
    334   } else if (method_call->GetMember() == "networkWallet") {
    335     response = dbus::Response::CreateEmpty();
    336     dbus::MessageWriter writer(response.get());
    337     writer.AppendString("test_wallet");  // Should match |open| below.
    338   } else if (method_call->GetMember() == "open") {
    339     dbus::MessageReader reader(method_call);
    340     std::string wallet_name;
    341     int64_t wallet_id;
    342     std::string app_name;
    343     EXPECT_TRUE(reader.PopString(&wallet_name));
    344     EXPECT_TRUE(reader.PopInt64(&wallet_id));
    345     EXPECT_TRUE(reader.PopString(&app_name));
    346     EXPECT_EQ("test_wallet", wallet_name);  // Should match |networkWallet|.
    347     response = dbus::Response::CreateEmpty();
    348     dbus::MessageWriter writer(response.get());
    349     writer.AppendInt32(1);  // Can be anything but kInvalidKWalletHandle.
    350   } else if (method_call->GetMember() == "hasFolder" ||
    351              method_call->GetMember() == "createFolder") {
    352     dbus::MessageReader reader(method_call);
    353     int handle = NativeBackendKWalletStub::kInvalidKWalletHandle;
    354     std::string folder_name;
    355     std::string app_name;
    356     EXPECT_TRUE(reader.PopInt32(&handle));
    357     EXPECT_TRUE(reader.PopString(&folder_name));
    358     EXPECT_TRUE(reader.PopString(&app_name));
    359     EXPECT_NE(NativeBackendKWalletStub::kInvalidKWalletHandle, handle);
    360     response = dbus::Response::CreateEmpty();
    361     dbus::MessageWriter writer(response.get());
    362     if (method_call->GetMember() == "hasFolder")
    363       writer.AppendBool(wallet_.hasFolder(folder_name));
    364     else
    365       writer.AppendBool(wallet_.createFolder(folder_name));
    366   } else if (method_call->GetMember() == "hasEntry" ||
    367              method_call->GetMember() == "removeEntry") {
    368     dbus::MessageReader reader(method_call);
    369     int handle = NativeBackendKWalletStub::kInvalidKWalletHandle;
    370     std::string folder_name;
    371     std::string key;
    372     std::string app_name;
    373     EXPECT_TRUE(reader.PopInt32(&handle));
    374     EXPECT_TRUE(reader.PopString(&folder_name));
    375     EXPECT_TRUE(reader.PopString(&key));
    376     EXPECT_TRUE(reader.PopString(&app_name));
    377     EXPECT_NE(NativeBackendKWalletStub::kInvalidKWalletHandle, handle);
    378     response = dbus::Response::CreateEmpty();
    379     dbus::MessageWriter writer(response.get());
    380     if (method_call->GetMember() == "hasEntry")
    381       writer.AppendBool(wallet_.hasEntry(folder_name, key));
    382     else
    383       writer.AppendInt32(wallet_.removeEntry(folder_name, key) ? 0 : 1);
    384   } else if (method_call->GetMember() == "entryList") {
    385     dbus::MessageReader reader(method_call);
    386     int handle = NativeBackendKWalletStub::kInvalidKWalletHandle;
    387     std::string folder_name;
    388     std::string app_name;
    389     EXPECT_TRUE(reader.PopInt32(&handle));
    390     EXPECT_TRUE(reader.PopString(&folder_name));
    391     EXPECT_TRUE(reader.PopString(&app_name));
    392     EXPECT_NE(NativeBackendKWalletStub::kInvalidKWalletHandle, handle);
    393     std::vector<std::string> entries;
    394     if (wallet_.entryList(folder_name, &entries)) {
    395       response = dbus::Response::CreateEmpty();
    396       dbus::MessageWriter writer(response.get());
    397       writer.AppendArrayOfStrings(entries);
    398     }
    399   } else if (method_call->GetMember() == "readEntry") {
    400     dbus::MessageReader reader(method_call);
    401     int handle = NativeBackendKWalletStub::kInvalidKWalletHandle;
    402     std::string folder_name;
    403     std::string key;
    404     std::string app_name;
    405     EXPECT_TRUE(reader.PopInt32(&handle));
    406     EXPECT_TRUE(reader.PopString(&folder_name));
    407     EXPECT_TRUE(reader.PopString(&key));
    408     EXPECT_TRUE(reader.PopString(&app_name));
    409     EXPECT_NE(NativeBackendKWalletStub::kInvalidKWalletHandle, handle);
    410     TestKWallet::Blob value;
    411     if (wallet_.readEntry(folder_name, key, &value)) {
    412       response = dbus::Response::CreateEmpty();
    413       dbus::MessageWriter writer(response.get());
    414       writer.AppendArrayOfBytes(value.data(), value.size());
    415     }
    416   } else if (method_call->GetMember() == "writeEntry") {
    417     dbus::MessageReader reader(method_call);
    418     int handle = NativeBackendKWalletStub::kInvalidKWalletHandle;
    419     std::string folder_name;
    420     std::string key;
    421     uint8_t* bytes = NULL;
    422     size_t length = 0;
    423     std::string app_name;
    424     EXPECT_TRUE(reader.PopInt32(&handle));
    425     EXPECT_TRUE(reader.PopString(&folder_name));
    426     EXPECT_TRUE(reader.PopString(&key));
    427     EXPECT_TRUE(reader.PopArrayOfBytes(&bytes, &length));
    428     EXPECT_TRUE(reader.PopString(&app_name));
    429     EXPECT_NE(NativeBackendKWalletStub::kInvalidKWalletHandle, handle);
    430     response = dbus::Response::CreateEmpty();
    431     dbus::MessageWriter writer(response.get());
    432     writer.AppendInt32(
    433         wallet_.writeEntry(folder_name, key,
    434                            TestKWallet::Blob(bytes, length)) ? 0 : 1);
    435   }
    436 
    437   EXPECT_FALSE(response.get() == NULL);
    438   return response.release();
    439 }
    440 
    441 void NativeBackendKWalletTest::CheckPasswordForms(
    442     const std::string& folder, const ExpectationArray& sorted_expected) {
    443   EXPECT_TRUE(wallet_.hasFolder(folder));
    444   std::vector<std::string> entries;
    445   EXPECT_TRUE(wallet_.entryList(folder, &entries));
    446   EXPECT_EQ(sorted_expected.size(), entries.size());
    447   std::sort(entries.begin(), entries.end());
    448   for (size_t i = 0; i < entries.size() && i < sorted_expected.size(); ++i) {
    449     EXPECT_EQ(sorted_expected[i].first, entries[i]);
    450     TestKWallet::Blob value;
    451     EXPECT_TRUE(wallet_.readEntry(folder, entries[i], &value));
    452     Pickle pickle(reinterpret_cast<const char*>(value.data()), value.size());
    453     std::vector<PasswordForm*> forms;
    454     NativeBackendKWalletStub::DeserializeValue(entries[i], pickle, &forms);
    455     const std::vector<const PasswordForm*>& expect = sorted_expected[i].second;
    456     EXPECT_EQ(expect.size(), forms.size());
    457     for (size_t j = 0; j < forms.size() && j < expect.size(); ++j)
    458       CheckPasswordForm(*expect[j], *forms[j]);
    459     STLDeleteElements(&forms);
    460   }
    461 }
    462 
    463 TEST_F(NativeBackendKWalletTest, NotEnabled) {
    464   NativeBackendKWalletStub kwallet(42, profile_.GetPrefs());
    465   kwallet_enabled_ = false;
    466   EXPECT_FALSE(kwallet.InitWithBus(mock_session_bus_));
    467   EXPECT_FALSE(klauncher_contacted_);
    468 }
    469 
    470 TEST_F(NativeBackendKWalletTest, NotRunnable) {
    471   NativeBackendKWalletStub kwallet(42, profile_.GetPrefs());
    472   kwallet_runnable_ = false;
    473   kwallet_running_ = false;
    474   EXPECT_FALSE(kwallet.InitWithBus(mock_session_bus_));
    475   EXPECT_TRUE(klauncher_contacted_);
    476 }
    477 
    478 TEST_F(NativeBackendKWalletTest, NotRunningOrEnabled) {
    479   NativeBackendKWalletStub kwallet(42, profile_.GetPrefs());
    480   kwallet_running_ = false;
    481   kwallet_enabled_ = false;
    482   EXPECT_FALSE(kwallet.InitWithBus(mock_session_bus_));
    483   EXPECT_TRUE(klauncher_contacted_);
    484 }
    485 
    486 TEST_F(NativeBackendKWalletTest, NotRunning) {
    487   NativeBackendKWalletStub kwallet(42, profile_.GetPrefs());
    488   kwallet_running_ = false;
    489   EXPECT_TRUE(kwallet.InitWithBus(mock_session_bus_));
    490   EXPECT_TRUE(klauncher_contacted_);
    491 }
    492 
    493 TEST_F(NativeBackendKWalletTest, BasicStartup) {
    494   NativeBackendKWalletStub kwallet(42, profile_.GetPrefs());
    495   EXPECT_TRUE(kwallet.InitWithBus(mock_session_bus_));
    496   EXPECT_FALSE(klauncher_contacted_);
    497 }
    498 
    499 TEST_F(NativeBackendKWalletTest, BasicAddLogin) {
    500   // Pretend that the migration has already taken place.
    501   profile_.GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, true);
    502 
    503   NativeBackendKWalletStub backend(42, profile_.GetPrefs());
    504   EXPECT_TRUE(backend.InitWithBus(mock_session_bus_));
    505 
    506   BrowserThread::PostTask(
    507       BrowserThread::DB, FROM_HERE,
    508       base::Bind(base::IgnoreResult(&NativeBackendKWalletStub::AddLogin),
    509                  base::Unretained(&backend), form_google_));
    510 
    511   RunDBThread();
    512 
    513   EXPECT_FALSE(wallet_.hasFolder("Chrome Form Data"));
    514 
    515   std::vector<const PasswordForm*> forms;
    516   forms.push_back(&form_google_);
    517   ExpectationArray expected;
    518   expected.push_back(make_pair(std::string(form_google_.signon_realm), forms));
    519   CheckPasswordForms("Chrome Form Data (42)", expected);
    520 }
    521 
    522 TEST_F(NativeBackendKWalletTest, BasicListLogins) {
    523   // Pretend that the migration has already taken place.
    524   profile_.GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, true);
    525 
    526   NativeBackendKWalletStub backend(42, profile_.GetPrefs());
    527   EXPECT_TRUE(backend.InitWithBus(mock_session_bus_));
    528 
    529   BrowserThread::PostTask(
    530       BrowserThread::DB, FROM_HERE,
    531       base::Bind(base::IgnoreResult(&NativeBackendKWalletStub::AddLogin),
    532                  base::Unretained(&backend), form_google_));
    533 
    534   std::vector<PasswordForm*> form_list;
    535   BrowserThread::PostTask(
    536       BrowserThread::DB, FROM_HERE,
    537       base::Bind(
    538           base::IgnoreResult(&NativeBackendKWalletStub::GetAutofillableLogins),
    539           base::Unretained(&backend), &form_list));
    540 
    541   RunDBThread();
    542 
    543   // Quick check that we got something back.
    544   EXPECT_EQ(1u, form_list.size());
    545   STLDeleteElements(&form_list);
    546 
    547   EXPECT_FALSE(wallet_.hasFolder("Chrome Form Data"));
    548 
    549   std::vector<const PasswordForm*> forms;
    550   forms.push_back(&form_google_);
    551   ExpectationArray expected;
    552   expected.push_back(make_pair(std::string(form_google_.signon_realm), forms));
    553   CheckPasswordForms("Chrome Form Data (42)", expected);
    554 }
    555 
    556 TEST_F(NativeBackendKWalletTest, BasicRemoveLogin) {
    557   // Pretend that the migration has already taken place.
    558   profile_.GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, true);
    559 
    560   NativeBackendKWalletStub backend(42, profile_.GetPrefs());
    561   EXPECT_TRUE(backend.InitWithBus(mock_session_bus_));
    562 
    563   BrowserThread::PostTask(
    564       BrowserThread::DB, FROM_HERE,
    565       base::Bind(base::IgnoreResult(&NativeBackendKWalletStub::AddLogin),
    566                  base::Unretained(&backend), form_google_));
    567 
    568   RunDBThread();
    569 
    570   EXPECT_FALSE(wallet_.hasFolder("Chrome Form Data"));
    571 
    572   std::vector<const PasswordForm*> forms;
    573   forms.push_back(&form_google_);
    574   ExpectationArray expected;
    575   expected.push_back(make_pair(std::string(form_google_.signon_realm), forms));
    576   CheckPasswordForms("Chrome Form Data (42)", expected);
    577 
    578   BrowserThread::PostTask(
    579       BrowserThread::DB, FROM_HERE,
    580       base::Bind(base::IgnoreResult(&NativeBackendKWalletStub::RemoveLogin),
    581                  base::Unretained(&backend), form_google_));
    582 
    583   RunDBThread();
    584 
    585   expected.clear();
    586   CheckPasswordForms("Chrome Form Data (42)", expected);
    587 }
    588 
    589 TEST_F(NativeBackendKWalletTest, RemoveNonexistentLogin) {
    590   // Pretend that the migration has already taken place.
    591   profile_.GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, true);
    592 
    593   NativeBackendKWalletStub backend(42, profile_.GetPrefs());
    594   EXPECT_TRUE(backend.InitWithBus(mock_session_bus_));
    595 
    596   // First add an unrelated login.
    597   BrowserThread::PostTask(
    598       BrowserThread::DB, FROM_HERE,
    599       base::Bind(base::IgnoreResult(&NativeBackendKWalletStub::AddLogin),
    600                  base::Unretained(&backend), form_google_));
    601 
    602   RunDBThread();
    603 
    604   EXPECT_FALSE(wallet_.hasFolder("Chrome Form Data"));
    605 
    606   std::vector<const PasswordForm*> forms;
    607   forms.push_back(&form_google_);
    608   ExpectationArray expected;
    609   expected.push_back(make_pair(std::string(form_google_.signon_realm), forms));
    610   CheckPasswordForms("Chrome Form Data (42)", expected);
    611 
    612   // Attempt to remove a login that doesn't exist.
    613   BrowserThread::PostTask(
    614       BrowserThread::DB, FROM_HERE,
    615       base::Bind(base::IgnoreResult(&NativeBackendKWalletStub::RemoveLogin),
    616                  base::Unretained(&backend), form_isc_));
    617 
    618   // Make sure we can still get the first form back.
    619   std::vector<PasswordForm*> form_list;
    620   BrowserThread::PostTask(
    621       BrowserThread::DB, FROM_HERE,
    622       base::Bind(
    623           base::IgnoreResult(&NativeBackendKWalletStub::GetAutofillableLogins),
    624           base::Unretained(&backend), &form_list));
    625 
    626   RunDBThread();
    627 
    628   // Quick check that we got something back.
    629   EXPECT_EQ(1u, form_list.size());
    630   STLDeleteElements(&form_list);
    631 
    632   CheckPasswordForms("Chrome Form Data (42)", expected);
    633 }
    634 
    635 TEST_F(NativeBackendKWalletTest, AddDuplicateLogin) {
    636   // Pretend that the migration has already taken place.
    637   profile_.GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, true);
    638 
    639   NativeBackendKWalletStub backend(42, profile_.GetPrefs());
    640   EXPECT_TRUE(backend.InitWithBus(mock_session_bus_));
    641 
    642   BrowserThread::PostTask(
    643       BrowserThread::DB, FROM_HERE,
    644       base::Bind(base::IgnoreResult(&NativeBackendKWalletStub::AddLogin),
    645                  base::Unretained(&backend), form_google_));
    646   BrowserThread::PostTask(
    647       BrowserThread::DB, FROM_HERE,
    648       base::Bind(base::IgnoreResult(&NativeBackendKWalletStub::AddLogin),
    649                  base::Unretained(&backend), form_google_));
    650 
    651   RunDBThread();
    652 
    653   EXPECT_FALSE(wallet_.hasFolder("Chrome Form Data"));
    654 
    655   std::vector<const PasswordForm*> forms;
    656   forms.push_back(&form_google_);
    657   ExpectationArray expected;
    658   expected.push_back(make_pair(std::string(form_google_.signon_realm), forms));
    659   CheckPasswordForms("Chrome Form Data (42)", expected);
    660 }
    661 
    662 TEST_F(NativeBackendKWalletTest, ListLoginsAppends) {
    663   // Pretend that the migration has already taken place.
    664   profile_.GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, true);
    665 
    666   NativeBackendKWalletStub backend(42, profile_.GetPrefs());
    667   EXPECT_TRUE(backend.InitWithBus(mock_session_bus_));
    668 
    669   BrowserThread::PostTask(
    670       BrowserThread::DB, FROM_HERE,
    671       base::Bind(base::IgnoreResult(&NativeBackendKWalletStub::AddLogin),
    672                  base::Unretained(&backend), form_google_));
    673 
    674   // Send the same request twice with the same list both times.
    675   std::vector<PasswordForm*> form_list;
    676   BrowserThread::PostTask(
    677       BrowserThread::DB, FROM_HERE,
    678       base::Bind(
    679           base::IgnoreResult(&NativeBackendKWalletStub::GetAutofillableLogins),
    680           base::Unretained(&backend), &form_list));
    681   BrowserThread::PostTask(
    682       BrowserThread::DB, FROM_HERE,
    683       base::Bind(
    684           base::IgnoreResult(&NativeBackendKWalletStub::GetAutofillableLogins),
    685           base::Unretained(&backend), &form_list));
    686 
    687   RunDBThread();
    688 
    689   // Quick check that we got two results back.
    690   EXPECT_EQ(2u, form_list.size());
    691   STLDeleteElements(&form_list);
    692 
    693   EXPECT_FALSE(wallet_.hasFolder("Chrome Form Data"));
    694 
    695   std::vector<const PasswordForm*> forms;
    696   forms.push_back(&form_google_);
    697   ExpectationArray expected;
    698   expected.push_back(make_pair(std::string(form_google_.signon_realm), forms));
    699   CheckPasswordForms("Chrome Form Data (42)", expected);
    700 }
    701 
    702 // TODO(mdm): add more basic (i.e. non-migration) tests here at some point.
    703 // (For example tests for storing >1 password per realm pickle.)
    704 
    705 TEST_F(NativeBackendKWalletTest, DISABLED_MigrateOneLogin) {
    706   // Reject attempts to migrate so we can populate the store.
    707   wallet_.set_reject_local_folders(true);
    708 
    709   {
    710     NativeBackendKWalletStub backend(42, profile_.GetPrefs());
    711     EXPECT_TRUE(backend.InitWithBus(mock_session_bus_));
    712 
    713     BrowserThread::PostTask(
    714         BrowserThread::DB, FROM_HERE,
    715         base::Bind(base::IgnoreResult(&NativeBackendKWalletStub::AddLogin),
    716                    base::Unretained(&backend), form_google_));
    717 
    718     // Make sure we can get the form back even when migration is failing.
    719     std::vector<PasswordForm*> form_list;
    720     BrowserThread::PostTask(
    721         BrowserThread::DB, FROM_HERE,
    722         base::Bind(
    723             base::IgnoreResult(
    724                 &NativeBackendKWalletStub::GetAutofillableLogins),
    725             base::Unretained(&backend), &form_list));
    726 
    727     RunDBThread();
    728 
    729     // Quick check that we got something back.
    730     EXPECT_EQ(1u, form_list.size());
    731     STLDeleteElements(&form_list);
    732   }
    733 
    734   EXPECT_FALSE(wallet_.hasFolder("Chrome Form Data (42)"));
    735 
    736   std::vector<const PasswordForm*> forms;
    737   forms.push_back(&form_google_);
    738   ExpectationArray expected;
    739   expected.push_back(make_pair(std::string(form_google_.signon_realm), forms));
    740   CheckPasswordForms("Chrome Form Data", expected);
    741 
    742   // Now allow the migration.
    743   wallet_.set_reject_local_folders(false);
    744 
    745   {
    746     NativeBackendKWalletStub backend(42, profile_.GetPrefs());
    747     EXPECT_TRUE(backend.InitWithBus(mock_session_bus_));
    748 
    749     // Trigger the migration by looking something up.
    750     std::vector<PasswordForm*> form_list;
    751     BrowserThread::PostTask(
    752         BrowserThread::DB, FROM_HERE,
    753         base::Bind(
    754             base::IgnoreResult(
    755                 &NativeBackendKWalletStub::GetAutofillableLogins),
    756             base::Unretained(&backend), &form_list));
    757 
    758     RunDBThread();
    759 
    760     // Quick check that we got something back.
    761     EXPECT_EQ(1u, form_list.size());
    762     STLDeleteElements(&form_list);
    763   }
    764 
    765   CheckPasswordForms("Chrome Form Data", expected);
    766   CheckPasswordForms("Chrome Form Data (42)", expected);
    767 
    768   // Check that we have set the persistent preference.
    769   EXPECT_TRUE(
    770       profile_.GetPrefs()->GetBoolean(prefs::kPasswordsUseLocalProfileId));
    771 }
    772 
    773 TEST_F(NativeBackendKWalletTest, DISABLED_MigrateToMultipleProfiles) {
    774   // Reject attempts to migrate so we can populate the store.
    775   wallet_.set_reject_local_folders(true);
    776 
    777   {
    778     NativeBackendKWalletStub backend(42, profile_.GetPrefs());
    779     EXPECT_TRUE(backend.InitWithBus(mock_session_bus_));
    780 
    781     BrowserThread::PostTask(
    782         BrowserThread::DB, FROM_HERE,
    783         base::Bind(base::IgnoreResult(&NativeBackendKWalletStub::AddLogin),
    784                    base::Unretained(&backend), form_google_));
    785 
    786     RunDBThread();
    787   }
    788 
    789   EXPECT_FALSE(wallet_.hasFolder("Chrome Form Data (42)"));
    790 
    791   std::vector<const PasswordForm*> forms;
    792   forms.push_back(&form_google_);
    793   ExpectationArray expected;
    794   expected.push_back(make_pair(std::string(form_google_.signon_realm), forms));
    795   CheckPasswordForms("Chrome Form Data", expected);
    796 
    797   // Now allow the migration.
    798   wallet_.set_reject_local_folders(false);
    799 
    800   {
    801     NativeBackendKWalletStub backend(42, profile_.GetPrefs());
    802     EXPECT_TRUE(backend.InitWithBus(mock_session_bus_));
    803 
    804     // Trigger the migration by looking something up.
    805     std::vector<PasswordForm*> form_list;
    806     BrowserThread::PostTask(
    807         BrowserThread::DB, FROM_HERE,
    808         base::Bind(
    809             base::IgnoreResult(
    810                 &NativeBackendKWalletStub::GetAutofillableLogins),
    811             base::Unretained(&backend), &form_list));
    812 
    813     RunDBThread();
    814 
    815     // Quick check that we got something back.
    816     EXPECT_EQ(1u, form_list.size());
    817     STLDeleteElements(&form_list);
    818   }
    819 
    820   CheckPasswordForms("Chrome Form Data", expected);
    821   CheckPasswordForms("Chrome Form Data (42)", expected);
    822 
    823   // Check that we have set the persistent preference.
    824   EXPECT_TRUE(
    825       profile_.GetPrefs()->GetBoolean(prefs::kPasswordsUseLocalProfileId));
    826 
    827   // Normally we'd actually have a different profile. But in the test just reset
    828   // the profile's persistent pref; we pass in the local profile id anyway.
    829   profile_.GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, false);
    830 
    831   {
    832     NativeBackendKWalletStub backend(24, profile_.GetPrefs());
    833     EXPECT_TRUE(backend.InitWithBus(mock_session_bus_));
    834 
    835     // Trigger the migration by looking something up.
    836     std::vector<PasswordForm*> form_list;
    837     BrowserThread::PostTask(
    838         BrowserThread::DB, FROM_HERE,
    839         base::Bind(
    840             base::IgnoreResult(
    841                 &NativeBackendKWalletStub::GetAutofillableLogins),
    842             base::Unretained(&backend), &form_list));
    843 
    844     RunDBThread();
    845 
    846     // Quick check that we got something back.
    847     EXPECT_EQ(1u, form_list.size());
    848     STLDeleteElements(&form_list);
    849   }
    850 
    851   CheckPasswordForms("Chrome Form Data", expected);
    852   CheckPasswordForms("Chrome Form Data (42)", expected);
    853   CheckPasswordForms("Chrome Form Data (24)", expected);
    854 }
    855 
    856 TEST_F(NativeBackendKWalletTest, DISABLED_NoMigrationWithPrefSet) {
    857   // Reject attempts to migrate so we can populate the store.
    858   wallet_.set_reject_local_folders(true);
    859 
    860   {
    861     NativeBackendKWalletStub backend(42, profile_.GetPrefs());
    862     EXPECT_TRUE(backend.InitWithBus(mock_session_bus_));
    863 
    864     BrowserThread::PostTask(
    865         BrowserThread::DB, FROM_HERE,
    866         base::Bind(base::IgnoreResult(&NativeBackendKWalletStub::AddLogin),
    867                    base::Unretained(&backend), form_google_));
    868 
    869     RunDBThread();
    870   }
    871 
    872   EXPECT_FALSE(wallet_.hasFolder("Chrome Form Data (42)"));
    873 
    874   std::vector<const PasswordForm*> forms;
    875   forms.push_back(&form_google_);
    876   ExpectationArray expected;
    877   expected.push_back(make_pair(std::string(form_google_.signon_realm), forms));
    878   CheckPasswordForms("Chrome Form Data", expected);
    879 
    880   // Now allow migration, but also pretend that the it has already taken place.
    881   wallet_.set_reject_local_folders(false);
    882   profile_.GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, true);
    883 
    884   {
    885     NativeBackendKWalletStub backend(42, profile_.GetPrefs());
    886     EXPECT_TRUE(backend.InitWithBus(mock_session_bus_));
    887 
    888     // Trigger the migration by adding a new login.
    889     BrowserThread::PostTask(
    890         BrowserThread::DB, FROM_HERE,
    891         base::Bind(base::IgnoreResult(&NativeBackendKWalletStub::AddLogin),
    892                    base::Unretained(&backend), form_isc_));
    893 
    894     // Look up all logins; we expect only the one we added.
    895     std::vector<PasswordForm*> form_list;
    896     BrowserThread::PostTask(
    897         BrowserThread::DB, FROM_HERE,
    898         base::Bind(
    899             base::IgnoreResult(
    900                 &NativeBackendKWalletStub::GetAutofillableLogins),
    901             base::Unretained(&backend), &form_list));
    902 
    903     RunDBThread();
    904 
    905     // Quick check that we got the right thing back.
    906     EXPECT_EQ(1u, form_list.size());
    907     if (form_list.size() > 0)
    908       EXPECT_EQ(form_isc_.signon_realm, form_list[0]->signon_realm);
    909     STLDeleteElements(&form_list);
    910   }
    911 
    912   CheckPasswordForms("Chrome Form Data", expected);
    913 
    914   forms[0] = &form_isc_;
    915   expected.clear();
    916   expected.push_back(make_pair(std::string(form_isc_.signon_realm), forms));
    917   CheckPasswordForms("Chrome Form Data (42)", expected);
    918 }
    919 
    920 TEST_F(NativeBackendKWalletTest, DISABLED_DeleteMigratedPasswordIsIsolated) {
    921   // Reject attempts to migrate so we can populate the store.
    922   wallet_.set_reject_local_folders(true);
    923 
    924   {
    925     NativeBackendKWalletStub backend(42, profile_.GetPrefs());
    926     EXPECT_TRUE(backend.InitWithBus(mock_session_bus_));
    927 
    928     BrowserThread::PostTask(
    929         BrowserThread::DB, FROM_HERE,
    930         base::Bind(
    931             base::IgnoreResult(&NativeBackendKWalletStub::AddLogin),
    932             base::Unretained(&backend), form_google_));
    933 
    934     RunDBThread();
    935   }
    936 
    937   EXPECT_FALSE(wallet_.hasFolder("Chrome Form Data (42)"));
    938 
    939   std::vector<const PasswordForm*> forms;
    940   forms.push_back(&form_google_);
    941   ExpectationArray expected;
    942   expected.push_back(make_pair(std::string(form_google_.signon_realm), forms));
    943   CheckPasswordForms("Chrome Form Data", expected);
    944 
    945   // Now allow the migration.
    946   wallet_.set_reject_local_folders(false);
    947 
    948   {
    949     NativeBackendKWalletStub backend(42, profile_.GetPrefs());
    950     EXPECT_TRUE(backend.InitWithBus(mock_session_bus_));
    951 
    952     // Trigger the migration by looking something up.
    953     std::vector<PasswordForm*> form_list;
    954     BrowserThread::PostTask(
    955         BrowserThread::DB, FROM_HERE,
    956         base::Bind(
    957             base::IgnoreResult(
    958                 &NativeBackendKWalletStub::GetAutofillableLogins),
    959             base::Unretained(&backend), &form_list));
    960 
    961     RunDBThread();
    962 
    963     // Quick check that we got something back.
    964     EXPECT_EQ(1u, form_list.size());
    965     STLDeleteElements(&form_list);
    966   }
    967 
    968   CheckPasswordForms("Chrome Form Data", expected);
    969   CheckPasswordForms("Chrome Form Data (42)", expected);
    970 
    971   // Check that we have set the persistent preference.
    972   EXPECT_TRUE(
    973       profile_.GetPrefs()->GetBoolean(prefs::kPasswordsUseLocalProfileId));
    974 
    975   // Normally we'd actually have a different profile. But in the test just reset
    976   // the profile's persistent pref; we pass in the local profile id anyway.
    977   profile_.GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, false);
    978 
    979   {
    980     NativeBackendKWalletStub backend(24, profile_.GetPrefs());
    981     EXPECT_TRUE(backend.InitWithBus(mock_session_bus_));
    982 
    983     // Trigger the migration by looking something up.
    984     std::vector<PasswordForm*> form_list;
    985     BrowserThread::PostTask(
    986         BrowserThread::DB, FROM_HERE,
    987         base::Bind(
    988             base::IgnoreResult(
    989                 &NativeBackendKWalletStub::GetAutofillableLogins),
    990             base::Unretained(&backend), &form_list));
    991 
    992     RunDBThread();
    993 
    994     // Quick check that we got something back.
    995     EXPECT_EQ(1u, form_list.size());
    996     STLDeleteElements(&form_list);
    997 
    998     // There should be three passwords now.
    999     CheckPasswordForms("Chrome Form Data", expected);
   1000     CheckPasswordForms("Chrome Form Data (42)", expected);
   1001     CheckPasswordForms("Chrome Form Data (24)", expected);
   1002 
   1003     // Now delete the password from this second profile.
   1004     BrowserThread::PostTask(
   1005         BrowserThread::DB, FROM_HERE,
   1006         base::Bind(
   1007             base::IgnoreResult(&NativeBackendKWalletStub::RemoveLogin),
   1008             base::Unretained(&backend), form_google_));
   1009 
   1010     RunDBThread();
   1011 
   1012     // The other two copies of the password in different profiles should remain.
   1013     CheckPasswordForms("Chrome Form Data", expected);
   1014     CheckPasswordForms("Chrome Form Data (42)", expected);
   1015     expected.clear();
   1016     CheckPasswordForms("Chrome Form Data (24)", expected);
   1017   }
   1018 }
   1019 
   1020 class NativeBackendKWalletPickleTest : public NativeBackendKWalletTestBase {
   1021  protected:
   1022   void CreateVersion0Pickle(bool size_32,
   1023                             const PasswordForm& form,
   1024                             Pickle* pickle);
   1025   void CheckVersion0Pickle(bool size_32, PasswordForm::Scheme scheme);
   1026 };
   1027 
   1028 void NativeBackendKWalletPickleTest::CreateVersion0Pickle(
   1029     bool size_32, const PasswordForm& form, Pickle* pickle) {
   1030   const int kPickleVersion0 = 0;
   1031   pickle->WriteInt(kPickleVersion0);
   1032   if (size_32)
   1033     pickle->WriteUInt32(1);  // Size of form list. 32 bits.
   1034   else
   1035     pickle->WriteUInt64(1);  // Size of form list. 64 bits.
   1036   pickle->WriteInt(form.scheme);
   1037   pickle->WriteString(form.origin.spec());
   1038   pickle->WriteString(form.action.spec());
   1039   pickle->WriteString16(form.username_element);
   1040   pickle->WriteString16(form.username_value);
   1041   pickle->WriteString16(form.password_element);
   1042   pickle->WriteString16(form.password_value);
   1043   pickle->WriteString16(form.submit_element);
   1044   pickle->WriteBool(form.ssl_valid);
   1045   pickle->WriteBool(form.preferred);
   1046   pickle->WriteBool(form.blacklisted_by_user);
   1047   pickle->WriteInt64(form.date_created.ToTimeT());
   1048 }
   1049 
   1050 void NativeBackendKWalletPickleTest::CheckVersion0Pickle(
   1051     bool size_32, PasswordForm::Scheme scheme) {
   1052   Pickle pickle;
   1053   PasswordForm form = form_google_;
   1054   form.scheme = scheme;
   1055   CreateVersion0Pickle(size_32, form, &pickle);
   1056   std::vector<PasswordForm*> form_list;
   1057   NativeBackendKWalletStub::DeserializeValue(form.signon_realm,
   1058                                              pickle, &form_list);
   1059   EXPECT_EQ(1u, form_list.size());
   1060   if (form_list.size() > 0)
   1061     CheckPasswordForm(form, *form_list[0]);
   1062   STLDeleteElements(&form_list);
   1063 }
   1064 
   1065 // We try both SCHEME_HTML and SCHEME_BASIC since the scheme is stored right
   1066 // after the size in the pickle, so it's what gets read as part of the count
   1067 // when reading 32-bit pickles on 64-bit systems. SCHEME_HTML is 0 (so we'll
   1068 // detect errors later) while SCHEME_BASIC is 1 (so we'll detect it then). We
   1069 // try both 32-bit and 64-bit pickles since only one will be the "other" size
   1070 // for whatever architecture we're running on, but we want to make sure we can
   1071 // read all combinations in any event.
   1072 
   1073 TEST_F(NativeBackendKWalletPickleTest, ReadsOld32BitHTMLPickles) {
   1074   CheckVersion0Pickle(true, PasswordForm::SCHEME_HTML);
   1075 }
   1076 
   1077 TEST_F(NativeBackendKWalletPickleTest, ReadsOld32BitHTTPPickles) {
   1078   CheckVersion0Pickle(true, PasswordForm::SCHEME_BASIC);
   1079 }
   1080 
   1081 TEST_F(NativeBackendKWalletPickleTest, ReadsOld64BitHTMLPickles) {
   1082   CheckVersion0Pickle(false, PasswordForm::SCHEME_HTML);
   1083 }
   1084 
   1085 TEST_F(NativeBackendKWalletPickleTest, ReadsOld64BitHTTPPickles) {
   1086   CheckVersion0Pickle(false, PasswordForm::SCHEME_BASIC);
   1087 }
   1088