summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorstuartmorgan@chromium.org <stuartmorgan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-23 18:56:34 +0000
committerstuartmorgan@chromium.org <stuartmorgan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-23 18:56:34 +0000
commit12eb8e78f183c10e08df3dbb080c09669df94424 (patch)
tree1bac8d46beafd943662d147145ad3afcd4a98115 /chrome
parentd7e5b443612b102a8d2adf5717bc571136e788dd (diff)
downloadchromium_src-12eb8e78f183c10e08df3dbb080c09669df94424.zip
chromium_src-12eb8e78f183c10e08df3dbb080c09669df94424.tar.gz
chromium_src-12eb8e78f183c10e08df3dbb080c09669df94424.tar.bz2
Move MockKeychain into its own file.
The unit test file has become very unwieldy, and I no longer believe that the Keychain mock is temporary code that should be replaced with GMock (since the dummy implementation makes certain tests much easier). BUG=none TEST=none Review URL: http://codereview.chromium.org/146041 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@19041 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/keychain_mock_mac.cc408
-rw-r--r--chrome/browser/keychain_mock_mac.h120
-rw-r--r--chrome/browser/password_manager/password_store_mac_unittest.cc682
-rw-r--r--chrome/chrome.gyp2
4 files changed, 625 insertions, 587 deletions
diff --git a/chrome/browser/keychain_mock_mac.cc b/chrome/browser/keychain_mock_mac.cc
new file mode 100644
index 0000000..858fdb6
--- /dev/null
+++ b/chrome/browser/keychain_mock_mac.cc
@@ -0,0 +1,408 @@
+// Copyright (c) 2009 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 "base/logging.h"
+#include "base/time.h"
+#include "chrome/browser/keychain_mock_mac.h"
+
+MockKeychain::MockKeychain()
+ : search_copy_count_(0), keychain_item_copy_count_(0),
+ attribute_data_copy_count_(0) {
+ UInt32 tags[] = { kSecAccountItemAttr,
+ kSecServerItemAttr,
+ kSecPortItemAttr,
+ kSecPathItemAttr,
+ kSecProtocolItemAttr,
+ kSecAuthenticationTypeItemAttr,
+ kSecSecurityDomainItemAttr,
+ kSecCreationDateItemAttr,
+ kSecNegativeItemAttr };
+
+ // Create the test keychain data to return from ItemCopyAttributesAndData,
+ // and set up everything that's consistent across all the items.
+ item_capacity_ = 9;
+ keychain_attr_list_ = static_cast<SecKeychainAttributeList*>(
+ calloc(item_capacity_, sizeof(SecKeychainAttributeList)));
+ keychain_data_ = static_cast<KeychainPasswordData*>(
+ calloc(item_capacity_, sizeof(KeychainPasswordData)));
+ for (unsigned int i = 0; i < item_capacity_; ++i) {
+ keychain_attr_list_[i].count = arraysize(tags);
+ keychain_attr_list_[i].attr = static_cast<SecKeychainAttribute*>(
+ calloc(keychain_attr_list_[i].count, sizeof(SecKeychainAttribute)));
+ for (unsigned int j = 0; j < keychain_attr_list_[i].count; ++j) {
+ keychain_attr_list_[i].attr[j].tag = tags[j];
+ size_t data_size = 0;
+ switch (tags[j]) {
+ case kSecPortItemAttr:
+ data_size = sizeof(UInt32);
+ break;
+ case kSecProtocolItemAttr:
+ data_size = sizeof(SecProtocolType);
+ break;
+ case kSecAuthenticationTypeItemAttr:
+ data_size = sizeof(SecAuthenticationType);
+ break;
+ case kSecNegativeItemAttr:
+ data_size = sizeof(Boolean);
+ break;
+ }
+ if (data_size > 0) {
+ keychain_attr_list_[i].attr[j].length = data_size;
+ keychain_attr_list_[i].attr[j].data = calloc(1, data_size);
+ }
+ }
+ }
+
+ // Save one slot for use by AddInternetPassword.
+ unsigned int available_slots = item_capacity_ - 1;
+ item_count_ = 0;
+
+ // Basic HTML form.
+ CHECK(item_count_ < available_slots);
+ SetTestDataString(item_count_, kSecAccountItemAttr, "joe_user");
+ SetTestDataString(item_count_, kSecServerItemAttr, "some.domain.com");
+ SetTestDataProtocol(item_count_, kSecProtocolTypeHTTP);
+ SetTestDataAuthType(item_count_, kSecAuthenticationTypeHTMLForm);
+ SetTestDataString(item_count_, kSecCreationDateItemAttr, "20020601171500Z");
+ SetTestDataPasswordString(item_count_, "sekrit");
+ ++item_count_;
+
+ // HTML form with path.
+ CHECK(item_count_ < available_slots);
+ SetTestDataString(item_count_, kSecAccountItemAttr, "joe_user");
+ SetTestDataString(item_count_, kSecServerItemAttr, "some.domain.com");
+ SetTestDataString(item_count_, kSecPathItemAttr, "/insecure.html");
+ SetTestDataProtocol(item_count_, kSecProtocolTypeHTTP);
+ SetTestDataAuthType(item_count_, kSecAuthenticationTypeHTMLForm);
+ SetTestDataString(item_count_, kSecCreationDateItemAttr, "19991231235959Z");
+ SetTestDataPasswordString(item_count_, "sekrit");
+ ++item_count_;
+
+ // Secure HTML form with path.
+ CHECK(item_count_ < available_slots);
+ SetTestDataString(item_count_, kSecAccountItemAttr, "secure_user");
+ SetTestDataString(item_count_, kSecServerItemAttr, "some.domain.com");
+ SetTestDataString(item_count_, kSecPathItemAttr, "/secure.html");
+ SetTestDataProtocol(item_count_, kSecProtocolTypeHTTPS);
+ SetTestDataAuthType(item_count_, kSecAuthenticationTypeHTMLForm);
+ SetTestDataString(item_count_, kSecCreationDateItemAttr, "20100908070605Z");
+ SetTestDataPasswordString(item_count_, "password");
+ ++item_count_;
+
+ // True negative item.
+ CHECK(item_count_ < available_slots);
+ SetTestDataString(item_count_, kSecServerItemAttr, "dont.remember.com");
+ SetTestDataProtocol(item_count_, kSecProtocolTypeHTTP);
+ SetTestDataAuthType(item_count_, kSecAuthenticationTypeHTMLForm);
+ SetTestDataString(item_count_, kSecCreationDateItemAttr, "20000101000000Z");
+ SetTestDataNegativeItem(item_count_, true);
+ ++item_count_;
+
+ // De-facto negative item, type one.
+ CHECK(item_count_ < available_slots);
+ SetTestDataString(item_count_, kSecAccountItemAttr, "Password Not Stored");
+ SetTestDataString(item_count_, kSecServerItemAttr, "dont.remember.com");
+ SetTestDataProtocol(item_count_, kSecProtocolTypeHTTP);
+ SetTestDataAuthType(item_count_, kSecAuthenticationTypeHTMLForm);
+ SetTestDataString(item_count_, kSecCreationDateItemAttr, "20000101000000Z");
+ SetTestDataPasswordString(item_count_, "");
+ ++item_count_;
+
+ // De-facto negative item, type two.
+ CHECK(item_count_ < available_slots);
+ SetTestDataString(item_count_, kSecServerItemAttr, "dont.remember.com");
+ SetTestDataProtocol(item_count_, kSecProtocolTypeHTTPS);
+ SetTestDataAuthType(item_count_, kSecAuthenticationTypeHTMLForm);
+ SetTestDataString(item_count_, kSecCreationDateItemAttr, "20000101000000Z");
+ SetTestDataPasswordString(item_count_, " ");
+ ++item_count_;
+
+ // HTTP auth basic, with port and path.
+ CHECK(item_count_ < available_slots);
+ SetTestDataString(item_count_, kSecAccountItemAttr, "basic_auth_user");
+ SetTestDataString(item_count_, kSecServerItemAttr, "some.domain.com");
+ SetTestDataString(item_count_, kSecSecurityDomainItemAttr, "low_security");
+ SetTestDataString(item_count_, kSecPathItemAttr, "/insecure.html");
+ SetTestDataProtocol(item_count_, kSecProtocolTypeHTTP);
+ SetTestDataPort(item_count_, 4567);
+ SetTestDataAuthType(item_count_, kSecAuthenticationTypeHTTPBasic);
+ SetTestDataString(item_count_, kSecCreationDateItemAttr, "19980330100000Z");
+ SetTestDataPasswordString(item_count_, "basic");
+ ++item_count_;
+
+ // HTTP auth digest, secure.
+ CHECK(item_count_ < available_slots);
+ SetTestDataString(item_count_, kSecAccountItemAttr, "digest_auth_user");
+ SetTestDataString(item_count_, kSecServerItemAttr, "some.domain.com");
+ SetTestDataString(item_count_, kSecSecurityDomainItemAttr, "high_security");
+ SetTestDataProtocol(item_count_, kSecProtocolTypeHTTPS);
+ SetTestDataAuthType(item_count_, kSecAuthenticationTypeHTTPDigest);
+ SetTestDataString(item_count_, kSecCreationDateItemAttr, "19980330100000Z");
+ SetTestDataPasswordString(item_count_, "digest");
+ ++item_count_;
+}
+
+MockKeychain::~MockKeychain() {
+ for (unsigned int i = 0; i < item_capacity_; ++i) {
+ for (unsigned int j = 0; j < keychain_attr_list_[i].count; ++j) {
+ if (keychain_attr_list_[i].attr[j].data) {
+ free(keychain_attr_list_[i].attr[j].data);
+ }
+ }
+ free(keychain_attr_list_[i].attr);
+ if (keychain_data_[i].data) {
+ free(keychain_data_[i].data);
+ }
+ }
+ free(keychain_attr_list_);
+ free(keychain_data_);
+}
+
+int MockKeychain::IndexForTag(const SecKeychainAttributeList& attribute_list,
+ UInt32 tag) {
+ for (unsigned int i = 0; i < attribute_list.count; ++i) {
+ if (attribute_list.attr[i].tag == tag) {
+ return i;
+ }
+ }
+ DCHECK(false);
+ return -1;
+}
+
+void MockKeychain::SetTestDataBytes(int item, UInt32 tag, const void* data,
+ size_t length) const {
+ int attribute_index = IndexForTag(keychain_attr_list_[item], tag);
+ keychain_attr_list_[item].attr[attribute_index].length = length;
+ if (length > 0) {
+ if (keychain_attr_list_[item].attr[attribute_index].data) {
+ free(keychain_attr_list_[item].attr[attribute_index].data);
+ }
+ keychain_attr_list_[item].attr[attribute_index].data = malloc(length);
+ CHECK(keychain_attr_list_[item].attr[attribute_index].data);
+ memcpy(keychain_attr_list_[item].attr[attribute_index].data, data, length);
+ } else {
+ keychain_attr_list_[item].attr[attribute_index].data = NULL;
+ }
+}
+
+void MockKeychain::SetTestDataString(int item, UInt32 tag,
+ const char* value) const {
+ SetTestDataBytes(item, tag, value, value ? strlen(value) : 0);
+}
+
+void MockKeychain::SetTestDataPort(int item, UInt32 value) const {
+ int attribute_index = IndexForTag(keychain_attr_list_[item],
+ kSecPortItemAttr);
+ void* data = keychain_attr_list_[item].attr[attribute_index].data;
+ *(static_cast<UInt32*>(data)) = value;
+}
+
+void MockKeychain::SetTestDataProtocol(int item, SecProtocolType value) const {
+ int attribute_index = IndexForTag(keychain_attr_list_[item],
+ kSecProtocolItemAttr);
+ void* data = keychain_attr_list_[item].attr[attribute_index].data;
+ *(static_cast<SecProtocolType*>(data)) = value;
+}
+
+void MockKeychain::SetTestDataAuthType(int item,
+ SecAuthenticationType value) const {
+ int attribute_index = IndexForTag(keychain_attr_list_[item],
+ kSecAuthenticationTypeItemAttr);
+ void* data = keychain_attr_list_[item].attr[attribute_index].data;
+ *(static_cast<SecAuthenticationType*>(data)) = value;
+}
+
+void MockKeychain::SetTestDataNegativeItem(int item, Boolean value) const {
+ int attribute_index = IndexForTag(keychain_attr_list_[item],
+ kSecNegativeItemAttr);
+ void* data = keychain_attr_list_[item].attr[attribute_index].data;
+ *(static_cast<Boolean*>(data)) = value;
+}
+
+void MockKeychain::SetTestDataPasswordBytes(int item, const void* data,
+ size_t length) const {
+ keychain_data_[item].length = length;
+ if (length > 0) {
+ if (keychain_data_[item].data) {
+ free(keychain_data_[item].data);
+ }
+ keychain_data_[item].data = malloc(length);
+ memcpy(keychain_data_[item].data, data, length);
+ } else {
+ keychain_data_[item].data = NULL;
+ }
+}
+
+void MockKeychain::SetTestDataPasswordString(int item,
+ const char* value) const {
+ SetTestDataPasswordBytes(item, value, value ? strlen(value) : 0);
+}
+
+OSStatus MockKeychain::ItemCopyAttributesAndData(
+ SecKeychainItemRef itemRef, SecKeychainAttributeInfo *info,
+ SecItemClass *itemClass, SecKeychainAttributeList **attrList,
+ UInt32 *length, void **outData) const {
+ DCHECK(itemRef);
+ unsigned int item_index = reinterpret_cast<unsigned int>(itemRef) - 1;
+ if (item_index >= item_count_) {
+ return errSecInvalidItemRef;
+ }
+
+ DCHECK(!itemClass); // itemClass not implemented in the Mock.
+ if (attrList) {
+ *attrList = &(keychain_attr_list_[item_index]);
+ }
+ if (outData) {
+ *outData = keychain_data_[item_index].data;
+ DCHECK(length);
+ *length = keychain_data_[item_index].length;
+ }
+
+ ++attribute_data_copy_count_;
+ return noErr;
+}
+
+OSStatus MockKeychain::ItemModifyAttributesAndData(
+ SecKeychainItemRef itemRef, const SecKeychainAttributeList *attrList,
+ UInt32 length, const void *data) const {
+ DCHECK(itemRef);
+ const char* fail_trigger = "fail_me";
+ if (length == strlen(fail_trigger) &&
+ memcmp(data, fail_trigger, length) == 0) {
+ return errSecAuthFailed;
+ }
+
+ unsigned int item_index = reinterpret_cast<unsigned int>(itemRef) - 1;
+ if (item_index >= item_count_) {
+ return errSecInvalidItemRef;
+ }
+
+ if (attrList) {
+ NOTIMPLEMENTED();
+ }
+ if (data) {
+ SetTestDataPasswordBytes(item_index, data, length);
+ }
+ return noErr;
+}
+
+OSStatus MockKeychain::ItemFreeAttributesAndData(
+ SecKeychainAttributeList *attrList,
+ void *data) const {
+ --attribute_data_copy_count_;
+ return noErr;
+}
+
+OSStatus MockKeychain::SearchCreateFromAttributes(
+ CFTypeRef keychainOrArray, SecItemClass itemClass,
+ const SecKeychainAttributeList *attrList,
+ SecKeychainSearchRef *searchRef) const {
+ // Figure out which of our mock items matches, and set up the array we'll use
+ // to generate results out of SearchCopyNext.
+ remaining_search_results_.clear();
+ for (unsigned int mock_item = 0; mock_item < item_count_; ++mock_item) {
+ bool mock_item_matches = true;
+ for (UInt32 search_attr = 0; search_attr < attrList->count; ++search_attr) {
+ int mock_attr = IndexForTag(keychain_attr_list_[mock_item],
+ attrList->attr[search_attr].tag);
+ SecKeychainAttribute* mock_attribute =
+ &(keychain_attr_list_[mock_item].attr[mock_attr]);
+ if (mock_attribute->length != attrList->attr[search_attr].length ||
+ memcmp(mock_attribute->data, attrList->attr[search_attr].data,
+ attrList->attr[search_attr].length) != 0) {
+ mock_item_matches = false;
+ break;
+ }
+ }
+ if (mock_item_matches) {
+ remaining_search_results_.push_back(mock_item);
+ }
+ }
+
+ DCHECK(searchRef);
+ *searchRef = reinterpret_cast<SecKeychainSearchRef>(kDummySearchRef);
+ ++search_copy_count_;
+ return noErr;
+}
+
+OSStatus MockKeychain::AddInternetPassword(
+ SecKeychainRef keychain,
+ UInt32 serverNameLength, const char *serverName,
+ UInt32 securityDomainLength, const char *securityDomain,
+ UInt32 accountNameLength, const char *accountName,
+ UInt32 pathLength, const char *path,
+ UInt16 port, SecProtocolType protocol,
+ SecAuthenticationType authenticationType,
+ UInt32 passwordLength, const void *passwordData,
+ SecKeychainItemRef *itemRef) const {
+
+ // Check for the magic duplicate item trigger.
+ if (strcmp(serverName, "some.domain.com") == 0) {
+ return errSecDuplicateItem;
+ }
+
+ // Use empty slots until they run out, then just keep replacing the last item.
+ int target_item = (item_count_ == item_capacity_) ? item_capacity_ - 1
+ : item_count_++;
+
+ SetTestDataBytes(target_item, kSecServerItemAttr, serverName,
+ serverNameLength);
+ SetTestDataBytes(target_item, kSecSecurityDomainItemAttr, securityDomain,
+ securityDomainLength);
+ SetTestDataBytes(target_item, kSecAccountItemAttr, accountName,
+ accountNameLength);
+ SetTestDataBytes(target_item, kSecPathItemAttr, path, pathLength);
+ SetTestDataPort(target_item, port);
+ SetTestDataProtocol(target_item, protocol);
+ SetTestDataAuthType(target_item, authenticationType);
+ SetTestDataPasswordBytes(target_item, passwordData, passwordLength);
+ base::Time::Exploded exploded_time;
+ base::Time::Now().UTCExplode(&exploded_time);
+ char time_string[128];
+ snprintf(time_string, sizeof(time_string), "%04d%02d%02d%02d%02d%02dZ",
+ exploded_time.year, exploded_time.month, exploded_time.day_of_month,
+ exploded_time.hour, exploded_time.minute, exploded_time.second);
+ SetTestDataString(target_item, kSecCreationDateItemAttr, time_string);
+
+ if (itemRef) {
+ *itemRef = reinterpret_cast<SecKeychainItemRef>(target_item + 1);
+ }
+ return noErr;
+}
+
+OSStatus MockKeychain::SearchCopyNext(SecKeychainSearchRef searchRef,
+ SecKeychainItemRef *itemRef) const {
+ if (remaining_search_results_.empty()) {
+ return errSecItemNotFound;
+ }
+ unsigned int index = remaining_search_results_.front();
+ remaining_search_results_.erase(remaining_search_results_.begin());
+ *itemRef = reinterpret_cast<SecKeychainItemRef>(index + 1);
+ ++keychain_item_copy_count_;
+ return noErr;
+}
+
+void MockKeychain::Free(CFTypeRef ref) const {
+ if (!ref) {
+ return;
+ }
+
+ if (reinterpret_cast<int>(ref) == kDummySearchRef) {
+ --search_copy_count_;
+ } else {
+ --keychain_item_copy_count_;
+ }
+}
+
+int MockKeychain::UnfreedSearchCount() const {
+ return search_copy_count_;
+}
+
+int MockKeychain::UnfreedKeychainItemCount() const {
+ return keychain_item_copy_count_;
+}
+
+int MockKeychain::UnfreedAttributeDataCount() const {
+ return attribute_data_copy_count_;
+}
diff --git a/chrome/browser/keychain_mock_mac.h b/chrome/browser/keychain_mock_mac.h
new file mode 100644
index 0000000..1a98a3a
--- /dev/null
+++ b/chrome/browser/keychain_mock_mac.h
@@ -0,0 +1,120 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_KEYCHAIN_MOCK_MAC_H_
+#define CHROME_BROWSER_KEYCHAIN_MOCK_MAC_H_
+
+#include <vector>
+
+#include "chrome/browser/keychain_mac.h"
+
+// Mock Keychain wrapper for testing code that interacts with the OS Keychain.
+// The basic idea of this mock is that it has a static array of data, and
+// SecKeychainItemRef values are just indexes into that array (offset by 1 to
+// prevent problems with clients that null-check refs), cast to pointers.
+//
+// TODO(stuartmorgan): The test data is currently hard-coded; instead it should
+// be settable by tests so that there isn't a strong coupling between the mock
+// implementation and the tests.
+class MockKeychain : public MacKeychain {
+ public:
+ MockKeychain();
+ virtual ~MockKeychain();
+ virtual OSStatus ItemCopyAttributesAndData(
+ SecKeychainItemRef itemRef, SecKeychainAttributeInfo *info,
+ SecItemClass *itemClass, SecKeychainAttributeList **attrList,
+ UInt32 *length, void **outData) const;
+ // Pass "fail_me" as the data to get errSecAuthFailed.
+ virtual OSStatus ItemModifyAttributesAndData(
+ SecKeychainItemRef itemRef, const SecKeychainAttributeList *attrList,
+ UInt32 length, const void *data) const;
+ virtual OSStatus ItemFreeAttributesAndData(SecKeychainAttributeList *attrList,
+ void *data) const;
+ virtual OSStatus SearchCreateFromAttributes(
+ CFTypeRef keychainOrArray, SecItemClass itemClass,
+ const SecKeychainAttributeList *attrList,
+ SecKeychainSearchRef *searchRef) const;
+ virtual OSStatus SearchCopyNext(SecKeychainSearchRef searchRef,
+ SecKeychainItemRef *itemRef) const;
+ // Pass "some.domain.com" as the serverName to get errSecDuplicateItem.
+ virtual OSStatus AddInternetPassword(SecKeychainRef keychain,
+ UInt32 serverNameLength,
+ const char *serverName,
+ UInt32 securityDomainLength,
+ const char *securityDomain,
+ UInt32 accountNameLength,
+ const char *accountName,
+ UInt32 pathLength, const char *path,
+ UInt16 port, SecProtocolType protocol,
+ SecAuthenticationType authenticationType,
+ UInt32 passwordLength,
+ const void *passwordData,
+ SecKeychainItemRef *itemRef) const;
+ virtual void Free(CFTypeRef ref) const;
+
+ // Return the counts of objects returned by Create/Copy functions but never
+ // Free'd as they should have been.
+ int UnfreedSearchCount() const;
+ int UnfreedKeychainItemCount() const;
+ int UnfreedAttributeDataCount() const;
+
+ private:
+ // Note that "const" is pretty much meaningless for this class; the const-ness
+ // of MacKeychain doesn't apply to the actual keychain data, so all of our
+ // data is mutable. These helpers are all const because they are needed by
+ // some of the const API functions we are mocking.
+
+ // Sets the data and length of |tag| in the item-th test item.
+ void SetTestDataBytes(int item, UInt32 tag, const void* data,
+ size_t length) const;
+ // Sets the data and length of |tag| in the item-th test item based on
+ // |value|. The null-terminator will not be included; the Keychain Services
+ // docs don't indicate whether it is or not, so clients should not assume
+ // that it will be.
+ void SetTestDataString(int item, UInt32 tag, const char* value) const;
+ // Sets the data of the corresponding attribute of the item-th test item to
+ // |value|. Assumes that the space has alread been allocated, and the length
+ // set.
+ void SetTestDataPort(int item, UInt32 value) const;
+ void SetTestDataProtocol(int item, SecProtocolType value) const;
+ void SetTestDataAuthType(int item, SecAuthenticationType value) const;
+ void SetTestDataNegativeItem(int item, Boolean value) const;
+ // Sets the password data and length for the item-th test item.
+ void SetTestDataPasswordBytes(int item, const void* data,
+ size_t length) const;
+ // Sets the password for the item-th test item. As with SetTestDataString,
+ // the data will not be null-terminated.
+ void SetTestDataPasswordString(int item, const char* value) const;
+
+ // Returns the index of |tag| in |attribute_list|, or -1 if it's not found.
+ static int IndexForTag(const SecKeychainAttributeList& attribute_list,
+ UInt32 tag);
+
+ static const int kDummySearchRef = 1000;
+
+ typedef struct {
+ void* data;
+ UInt32 length;
+ } KeychainPasswordData;
+
+ SecKeychainAttributeList* keychain_attr_list_;
+ KeychainPasswordData* keychain_data_;
+ unsigned int item_capacity_;
+ mutable unsigned int item_count_;
+
+ // Tracks the items that should be returned in subsequent calls to
+ // SearchCopyNext, based on the last call to SearchCreateFromAttributes.
+ // We can't handle multiple active searches, since we don't track the search
+ // ref we return, but we don't need to for our mocking.
+ mutable std::vector<unsigned int> remaining_search_results_;
+
+ // Track copies and releases to make sure they balance. Really these should
+ // be maps to track per item, but this should be good enough to catch
+ // real mistakes.
+ mutable int search_copy_count_;
+ mutable int keychain_item_copy_count_;
+ mutable int attribute_data_copy_count_;
+};
+
+#endif // CHROME_BROWSER_KEYCHAIN_MOCK_MAC_H_
diff --git a/chrome/browser/password_manager/password_store_mac_unittest.cc b/chrome/browser/password_manager/password_store_mac_unittest.cc
index 1fcaff5..3ef66c1 100644
--- a/chrome/browser/password_manager/password_store_mac_unittest.cc
+++ b/chrome/browser/password_manager/password_store_mac_unittest.cc
@@ -5,518 +5,21 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "base/basictypes.h"
+#include "chrome/browser/keychain_mock_mac.h"
#include "chrome/browser/password_manager/password_store_mac.h"
#include "chrome/browser/password_manager/password_store_mac_internal.h"
using webkit_glue::PasswordForm;
-#pragma mark Mock Keychain
-
-// TODO(stuartmorgan): Replace this with gMock. You know, once we have it.
-// The basic idea of this mock is that it has a static array of data to use
-// for ItemCopyAttributesAndData, and SecKeychainItemRef values are just indexes
-// into that array (offset by 1 to prevent problems with client null-checking
-// refs), cast to pointers.
-class MockKeychain : public MacKeychain {
- public:
- MockKeychain();
- virtual ~MockKeychain();
- virtual OSStatus ItemCopyAttributesAndData(
- SecKeychainItemRef itemRef, SecKeychainAttributeInfo *info,
- SecItemClass *itemClass, SecKeychainAttributeList **attrList,
- UInt32 *length, void **outData) const;
- // Pass "fail_me" as the data to get errSecAuthFailed.
- virtual OSStatus ItemModifyAttributesAndData(
- SecKeychainItemRef itemRef, const SecKeychainAttributeList *attrList,
- UInt32 length, const void *data) const;
- virtual OSStatus ItemFreeAttributesAndData(SecKeychainAttributeList *attrList,
- void *data) const;
- virtual OSStatus SearchCreateFromAttributes(
- CFTypeRef keychainOrArray, SecItemClass itemClass,
- const SecKeychainAttributeList *attrList,
- SecKeychainSearchRef *searchRef) const;
- virtual OSStatus SearchCopyNext(SecKeychainSearchRef searchRef,
- SecKeychainItemRef *itemRef) const;
- // Pass "some.domain.com" as the serverName to get errSecDuplicateItem.
- virtual OSStatus AddInternetPassword(SecKeychainRef keychain,
- UInt32 serverNameLength,
- const char *serverName,
- UInt32 securityDomainLength,
- const char *securityDomain,
- UInt32 accountNameLength,
- const char *accountName,
- UInt32 pathLength, const char *path,
- UInt16 port, SecProtocolType protocol,
- SecAuthenticationType authenticationType,
- UInt32 passwordLength,
- const void *passwordData,
- SecKeychainItemRef *itemRef) const;
- virtual void Free(CFTypeRef ref) const;
-
- // Causes a test failure unless everything returned from
- // ItemCopyAttributesAndData, SearchCreateFromAttributes, and SearchCopyNext
- // was correctly freed.
- void ExpectCreatesAndFreesBalanced();
-
- private:
- // Note that "const" is pretty much meaningless for this class; the const-ness
- // of MacKeychain doesn't apply to the actual keychain data, so all of our
- // data is mutable. These helpers are all const because they are needed by
- // some of the const API functions we are mocking.
-
- // Sets the data and length of |tag| in the item-th test item.
- void SetTestDataBytes(int item, UInt32 tag, const void* data,
- size_t length) const;
- // Sets the data and length of |tag| in the item-th test item based on
- // |value|. The null-terminator will not be included; the Keychain Services
- // docs don't indicate whether it is or not, so clients should not assume
- // that it will be.
- void SetTestDataString(int item, UInt32 tag, const char* value) const;
- // Sets the data of the corresponding attribute of the item-th test item to
- // |value|. Assumes that the space has alread been allocated, and the length
- // set.
- void SetTestDataPort(int item, UInt32 value) const;
- void SetTestDataProtocol(int item, SecProtocolType value) const;
- void SetTestDataAuthType(int item, SecAuthenticationType value) const;
- void SetTestDataNegativeItem(int item, Boolean value) const;
- // Sets the password data and length for the item-th test item.
- void SetTestDataPasswordBytes(int item, const void* data,
- size_t length) const;
- // Sets the password for the item-th test item. As with SetTestDataString,
- // the data will not be null-terminated.
- void SetTestDataPasswordString(int item, const char* value) const;
-
- // Returns the index of |tag| in |attribute_list|, or -1 if it's not found.
- static int IndexForTag(const SecKeychainAttributeList& attribute_list,
- UInt32 tag);
-
- static const int kDummySearchRef = 1000;
-
- typedef struct {
- void* data;
- UInt32 length;
- } KeychainPasswordData;
-
- SecKeychainAttributeList* keychain_attr_list_;
- KeychainPasswordData* keychain_data_;
- unsigned int item_capacity_;
- mutable unsigned int item_count_;
-
- // Tracks the items that should be returned in subsequent calls to
- // SearchCopyNext, based on the last call to SearchCreateFromAttributes.
- // We can't handle multiple active searches, since we don't track the search
- // ref we return, but we don't need to for our mocking.
- mutable std::vector<unsigned int> remaining_search_results_;
-
- // Track copies and releases to make sure they balance. Really these should
- // be maps to track per item, but this should be good enough to catch
- // real mistakes.
- mutable int search_copy_count_;
- mutable int keychain_item_copy_count_;
- mutable int attribute_data_copy_count_;
-};
-
-#pragma mark -
-
-MockKeychain::MockKeychain()
- : search_copy_count_(0), keychain_item_copy_count_(0),
- attribute_data_copy_count_(0) {
- UInt32 tags[] = { kSecAccountItemAttr,
- kSecServerItemAttr,
- kSecPortItemAttr,
- kSecPathItemAttr,
- kSecProtocolItemAttr,
- kSecAuthenticationTypeItemAttr,
- kSecSecurityDomainItemAttr,
- kSecCreationDateItemAttr,
- kSecNegativeItemAttr };
-
- // Create the test keychain data to return from ItemCopyAttributesAndData,
- // and set up everything that's consistent across all the items.
- item_capacity_ = 9;
- keychain_attr_list_ = static_cast<SecKeychainAttributeList*>(
- calloc(item_capacity_, sizeof(SecKeychainAttributeList)));
- keychain_data_ = static_cast<KeychainPasswordData*>(
- calloc(item_capacity_, sizeof(KeychainPasswordData)));
- for (unsigned int i = 0; i < item_capacity_; ++i) {
- keychain_attr_list_[i].count = arraysize(tags);
- keychain_attr_list_[i].attr = static_cast<SecKeychainAttribute*>(
- calloc(keychain_attr_list_[i].count, sizeof(SecKeychainAttribute)));
- for (unsigned int j = 0; j < keychain_attr_list_[i].count; ++j) {
- keychain_attr_list_[i].attr[j].tag = tags[j];
- size_t data_size = 0;
- switch (tags[j]) {
- case kSecPortItemAttr:
- data_size = sizeof(UInt32);
- break;
- case kSecProtocolItemAttr:
- data_size = sizeof(SecProtocolType);
- break;
- case kSecAuthenticationTypeItemAttr:
- data_size = sizeof(SecAuthenticationType);
- break;
- case kSecNegativeItemAttr:
- data_size = sizeof(Boolean);
- break;
- }
- if (data_size > 0) {
- keychain_attr_list_[i].attr[j].length = data_size;
- keychain_attr_list_[i].attr[j].data = calloc(1, data_size);
- }
- }
- }
-
- // Save one slot for use by AddInternetPassword.
- unsigned int available_slots = item_capacity_ - 1;
- item_count_ = 0;
-
- // Basic HTML form.
- CHECK(item_count_ < available_slots);
- SetTestDataString(item_count_, kSecAccountItemAttr, "joe_user");
- SetTestDataString(item_count_, kSecServerItemAttr, "some.domain.com");
- SetTestDataProtocol(item_count_, kSecProtocolTypeHTTP);
- SetTestDataAuthType(item_count_, kSecAuthenticationTypeHTMLForm);
- SetTestDataString(item_count_, kSecCreationDateItemAttr, "20020601171500Z");
- SetTestDataPasswordString(item_count_, "sekrit");
- ++item_count_;
-
- // HTML form with path.
- CHECK(item_count_ < available_slots);
- SetTestDataString(item_count_, kSecAccountItemAttr, "joe_user");
- SetTestDataString(item_count_, kSecServerItemAttr, "some.domain.com");
- SetTestDataString(item_count_, kSecPathItemAttr, "/insecure.html");
- SetTestDataProtocol(item_count_, kSecProtocolTypeHTTP);
- SetTestDataAuthType(item_count_, kSecAuthenticationTypeHTMLForm);
- SetTestDataString(item_count_, kSecCreationDateItemAttr, "19991231235959Z");
- SetTestDataPasswordString(item_count_, "sekrit");
- ++item_count_;
-
- // Secure HTML form with path.
- CHECK(item_count_ < available_slots);
- SetTestDataString(item_count_, kSecAccountItemAttr, "secure_user");
- SetTestDataString(item_count_, kSecServerItemAttr, "some.domain.com");
- SetTestDataString(item_count_, kSecPathItemAttr, "/secure.html");
- SetTestDataProtocol(item_count_, kSecProtocolTypeHTTPS);
- SetTestDataAuthType(item_count_, kSecAuthenticationTypeHTMLForm);
- SetTestDataString(item_count_, kSecCreationDateItemAttr, "20100908070605Z");
- SetTestDataPasswordString(item_count_, "password");
- ++item_count_;
-
- // True negative item.
- CHECK(item_count_ < available_slots);
- SetTestDataString(item_count_, kSecServerItemAttr, "dont.remember.com");
- SetTestDataProtocol(item_count_, kSecProtocolTypeHTTP);
- SetTestDataAuthType(item_count_, kSecAuthenticationTypeHTMLForm);
- SetTestDataString(item_count_, kSecCreationDateItemAttr, "20000101000000Z");
- SetTestDataNegativeItem(item_count_, true);
- ++item_count_;
-
- // De-facto negative item, type one.
- CHECK(item_count_ < available_slots);
- SetTestDataString(item_count_, kSecAccountItemAttr, "Password Not Stored");
- SetTestDataString(item_count_, kSecServerItemAttr, "dont.remember.com");
- SetTestDataProtocol(item_count_, kSecProtocolTypeHTTP);
- SetTestDataAuthType(item_count_, kSecAuthenticationTypeHTMLForm);
- SetTestDataString(item_count_, kSecCreationDateItemAttr, "20000101000000Z");
- SetTestDataPasswordString(item_count_, "");
- ++item_count_;
-
- // De-facto negative item, type two.
- CHECK(item_count_ < available_slots);
- SetTestDataString(item_count_, kSecServerItemAttr, "dont.remember.com");
- SetTestDataProtocol(item_count_, kSecProtocolTypeHTTPS);
- SetTestDataAuthType(item_count_, kSecAuthenticationTypeHTMLForm);
- SetTestDataString(item_count_, kSecCreationDateItemAttr, "20000101000000Z");
- SetTestDataPasswordString(item_count_, " ");
- ++item_count_;
-
- // HTTP auth basic, with port and path.
- CHECK(item_count_ < available_slots);
- SetTestDataString(item_count_, kSecAccountItemAttr, "basic_auth_user");
- SetTestDataString(item_count_, kSecServerItemAttr, "some.domain.com");
- SetTestDataString(item_count_, kSecSecurityDomainItemAttr, "low_security");
- SetTestDataString(item_count_, kSecPathItemAttr, "/insecure.html");
- SetTestDataProtocol(item_count_, kSecProtocolTypeHTTP);
- SetTestDataPort(item_count_, 4567);
- SetTestDataAuthType(item_count_, kSecAuthenticationTypeHTTPBasic);
- SetTestDataString(item_count_, kSecCreationDateItemAttr, "19980330100000Z");
- SetTestDataPasswordString(item_count_, "basic");
- ++item_count_;
-
- // HTTP auth digest, secure.
- CHECK(item_count_ < available_slots);
- SetTestDataString(item_count_, kSecAccountItemAttr, "digest_auth_user");
- SetTestDataString(item_count_, kSecServerItemAttr, "some.domain.com");
- SetTestDataString(item_count_, kSecSecurityDomainItemAttr, "high_security");
- SetTestDataProtocol(item_count_, kSecProtocolTypeHTTPS);
- SetTestDataAuthType(item_count_, kSecAuthenticationTypeHTTPDigest);
- SetTestDataString(item_count_, kSecCreationDateItemAttr, "19980330100000Z");
- SetTestDataPasswordString(item_count_, "digest");
- ++item_count_;
-}
-
-MockKeychain::~MockKeychain() {
- for (unsigned int i = 0; i < item_capacity_; ++i) {
- for (unsigned int j = 0; j < keychain_attr_list_[i].count; ++j) {
- if (keychain_attr_list_[i].attr[j].data) {
- free(keychain_attr_list_[i].attr[j].data);
- }
- }
- free(keychain_attr_list_[i].attr);
- if (keychain_data_[i].data) {
- free(keychain_data_[i].data);
- }
- }
- free(keychain_attr_list_);
- free(keychain_data_);
-}
-
-void MockKeychain::ExpectCreatesAndFreesBalanced() {
- EXPECT_EQ(0, search_copy_count_);
- EXPECT_EQ(0, keychain_item_copy_count_);
- EXPECT_EQ(0, attribute_data_copy_count_);
-}
-
-int MockKeychain::IndexForTag(const SecKeychainAttributeList& attribute_list,
- UInt32 tag) {
- for (unsigned int i = 0; i < attribute_list.count; ++i) {
- if (attribute_list.attr[i].tag == tag) {
- return i;
- }
- }
- DCHECK(false);
- return -1;
-}
-
-void MockKeychain::SetTestDataBytes(int item, UInt32 tag, const void* data,
- size_t length) const {
- int attribute_index = IndexForTag(keychain_attr_list_[item], tag);
- keychain_attr_list_[item].attr[attribute_index].length = length;
- if (length > 0) {
- if (keychain_attr_list_[item].attr[attribute_index].data) {
- free(keychain_attr_list_[item].attr[attribute_index].data);
- }
- keychain_attr_list_[item].attr[attribute_index].data = malloc(length);
- CHECK(keychain_attr_list_[item].attr[attribute_index].data);
- memcpy(keychain_attr_list_[item].attr[attribute_index].data, data, length);
- } else {
- keychain_attr_list_[item].attr[attribute_index].data = NULL;
- }
-}
-
-void MockKeychain::SetTestDataString(int item, UInt32 tag,
- const char* value) const {
- SetTestDataBytes(item, tag, value, value ? strlen(value) : 0);
-}
-
-void MockKeychain::SetTestDataPort(int item, UInt32 value) const {
- int attribute_index = IndexForTag(keychain_attr_list_[item],
- kSecPortItemAttr);
- void* data = keychain_attr_list_[item].attr[attribute_index].data;
- *(static_cast<UInt32*>(data)) = value;
-}
-
-void MockKeychain::SetTestDataProtocol(int item, SecProtocolType value) const {
- int attribute_index = IndexForTag(keychain_attr_list_[item],
- kSecProtocolItemAttr);
- void* data = keychain_attr_list_[item].attr[attribute_index].data;
- *(static_cast<SecProtocolType*>(data)) = value;
-}
-
-void MockKeychain::SetTestDataAuthType(int item,
- SecAuthenticationType value) const {
- int attribute_index = IndexForTag(keychain_attr_list_[item],
- kSecAuthenticationTypeItemAttr);
- void* data = keychain_attr_list_[item].attr[attribute_index].data;
- *(static_cast<SecAuthenticationType*>(data)) = value;
-}
-
-void MockKeychain::SetTestDataNegativeItem(int item, Boolean value) const {
- int attribute_index = IndexForTag(keychain_attr_list_[item],
- kSecNegativeItemAttr);
- void* data = keychain_attr_list_[item].attr[attribute_index].data;
- *(static_cast<Boolean*>(data)) = value;
-}
-
-void MockKeychain::SetTestDataPasswordBytes(int item, const void* data,
- size_t length) const {
- keychain_data_[item].length = length;
- if (length > 0) {
- if (keychain_data_[item].data) {
- free(keychain_data_[item].data);
- }
- keychain_data_[item].data = malloc(length);
- memcpy(keychain_data_[item].data, data, length);
- } else {
- keychain_data_[item].data = NULL;
- }
-}
-
-void MockKeychain::SetTestDataPasswordString(int item,
- const char* value) const {
- SetTestDataPasswordBytes(item, value, value ? strlen(value) : 0);
-}
-
-OSStatus MockKeychain::ItemCopyAttributesAndData(
- SecKeychainItemRef itemRef, SecKeychainAttributeInfo *info,
- SecItemClass *itemClass, SecKeychainAttributeList **attrList,
- UInt32 *length, void **outData) const {
- DCHECK(itemRef);
- unsigned int item_index = reinterpret_cast<unsigned int>(itemRef) - 1;
- if (item_index >= item_count_) {
- return errSecInvalidItemRef;
- }
-
- DCHECK(!itemClass); // itemClass not implemented in the Mock.
- if (attrList) {
- *attrList = &(keychain_attr_list_[item_index]);
- }
- if (outData) {
- *outData = keychain_data_[item_index].data;
- DCHECK(length);
- *length = keychain_data_[item_index].length;
- }
-
- ++attribute_data_copy_count_;
- return noErr;
-}
-
-OSStatus MockKeychain::ItemModifyAttributesAndData(
- SecKeychainItemRef itemRef, const SecKeychainAttributeList *attrList,
- UInt32 length, const void *data) const {
- DCHECK(itemRef);
- const char* fail_trigger = "fail_me";
- if (length == strlen(fail_trigger) &&
- memcmp(data, fail_trigger, length) == 0) {
- return errSecAuthFailed;
- }
-
- unsigned int item_index = reinterpret_cast<unsigned int>(itemRef) - 1;
- if (item_index >= item_count_) {
- return errSecInvalidItemRef;
- }
-
- if (attrList) {
- NOTIMPLEMENTED();
- }
- if (data) {
- SetTestDataPasswordBytes(item_index, data, length);
- }
- return noErr;
+// Causes a test failure unless everything returned from
+// ItemCopyAttributesAndData, SearchCreateFromAttributes, and SearchCopyNext
+// was correctly freed.
+static void ExpectCreatesAndFreesBalanced(const MockKeychain& keychain) {
+ EXPECT_EQ(0, keychain.UnfreedSearchCount());
+ EXPECT_EQ(0, keychain.UnfreedKeychainItemCount());
+ EXPECT_EQ(0, keychain.UnfreedAttributeDataCount());
}
-OSStatus MockKeychain::ItemFreeAttributesAndData(
- SecKeychainAttributeList *attrList,
- void *data) const {
- --attribute_data_copy_count_;
- return noErr;
-}
-
-OSStatus MockKeychain::SearchCreateFromAttributes(
- CFTypeRef keychainOrArray, SecItemClass itemClass,
- const SecKeychainAttributeList *attrList,
- SecKeychainSearchRef *searchRef) const {
- // Figure out which of our mock items matches, and set up the array we'll use
- // to generate results out of SearchCopyNext.
- remaining_search_results_.clear();
- for (unsigned int mock_item = 0; mock_item < item_count_; ++mock_item) {
- bool mock_item_matches = true;
- for (UInt32 search_attr = 0; search_attr < attrList->count; ++search_attr) {
- int mock_attr = IndexForTag(keychain_attr_list_[mock_item],
- attrList->attr[search_attr].tag);
- SecKeychainAttribute* mock_attribute =
- &(keychain_attr_list_[mock_item].attr[mock_attr]);
- if (mock_attribute->length != attrList->attr[search_attr].length ||
- memcmp(mock_attribute->data, attrList->attr[search_attr].data,
- attrList->attr[search_attr].length) != 0) {
- mock_item_matches = false;
- break;
- }
- }
- if (mock_item_matches) {
- remaining_search_results_.push_back(mock_item);
- }
- }
-
- DCHECK(searchRef);
- *searchRef = reinterpret_cast<SecKeychainSearchRef>(kDummySearchRef);
- ++search_copy_count_;
- return noErr;
-}
-
-OSStatus MockKeychain::AddInternetPassword(
- SecKeychainRef keychain,
- UInt32 serverNameLength, const char *serverName,
- UInt32 securityDomainLength, const char *securityDomain,
- UInt32 accountNameLength, const char *accountName,
- UInt32 pathLength, const char *path,
- UInt16 port, SecProtocolType protocol,
- SecAuthenticationType authenticationType,
- UInt32 passwordLength, const void *passwordData,
- SecKeychainItemRef *itemRef) const {
-
- // Check for the magic duplicate item trigger.
- if (strcmp(serverName, "some.domain.com") == 0) {
- return errSecDuplicateItem;
- }
-
- // Use empty slots until they run out, then just keep replacing the last item.
- int target_item = (item_count_ == item_capacity_) ? item_capacity_ - 1
- : item_count_++;
-
- SetTestDataBytes(target_item, kSecServerItemAttr, serverName,
- serverNameLength);
- SetTestDataBytes(target_item, kSecSecurityDomainItemAttr, securityDomain,
- securityDomainLength);
- SetTestDataBytes(target_item, kSecAccountItemAttr, accountName,
- accountNameLength);
- SetTestDataBytes(target_item, kSecPathItemAttr, path, pathLength);
- SetTestDataPort(target_item, port);
- SetTestDataProtocol(target_item, protocol);
- SetTestDataAuthType(target_item, authenticationType);
- SetTestDataPasswordBytes(target_item, passwordData, passwordLength);
- base::Time::Exploded exploded_time;
- base::Time::Now().UTCExplode(&exploded_time);
- char time_string[128];
- snprintf(time_string, sizeof(time_string), "%04d%02d%02d%02d%02d%02dZ",
- exploded_time.year, exploded_time.month, exploded_time.day_of_month,
- exploded_time.hour, exploded_time.minute, exploded_time.second);
- SetTestDataString(target_item, kSecCreationDateItemAttr, time_string);
-
- if (itemRef) {
- *itemRef = reinterpret_cast<SecKeychainItemRef>(target_item + 1);
- }
- return noErr;
-}
-
-OSStatus MockKeychain::SearchCopyNext(SecKeychainSearchRef searchRef,
- SecKeychainItemRef *itemRef) const {
- if (remaining_search_results_.empty()) {
- return errSecItemNotFound;
- }
- unsigned int index = remaining_search_results_.front();
- remaining_search_results_.erase(remaining_search_results_.begin());
- *itemRef = reinterpret_cast<SecKeychainItemRef>(index + 1);
- ++keychain_item_copy_count_;
- return noErr;
-}
-
-void MockKeychain::Free(CFTypeRef ref) const {
- if (!ref) {
- return;
- }
-
- if (reinterpret_cast<int>(ref) == kDummySearchRef) {
- --search_copy_count_;
- } else {
- --keychain_item_copy_count_;
- }
-}
-
-#pragma mark -
-#pragma mark Unit Tests
-////////////////////////////////////////////////////////////////////////////////
-
// Struct used for creation of PasswordForms from static arrays of data.
struct PasswordFormData {
const PasswordForm::Scheme scheme;
@@ -564,6 +67,80 @@ static PasswordForm* CreatePasswordFormFromData(
return form;
}
+// Macro to simplify calling CheckFormsAgainstExpectations with a useful label.
+#define CHECK_FORMS(forms, expectations, i) \
+ CheckFormsAgainstExpectations(forms, expectations, #forms, i)
+
+// Ensures that the data in |forms| match |expectations|, causing test failures
+// for any discrepencies.
+// TODO(stuartmorgan): This is current order-dependent; ideally it shouldn't
+// matter if |forms| and |expectations| are scrambled.
+static void CheckFormsAgainstExpectations(
+ const std::vector<PasswordForm*>& forms,
+ const std::vector<PasswordFormData*>& expectations,
+ const char* forms_label, unsigned int test_number) {
+ const unsigned int kBufferSize = 128;
+ char test_label[kBufferSize];
+ snprintf(test_label, kBufferSize, "%s in test %u", forms_label, test_number);
+
+ EXPECT_EQ(expectations.size(), forms.size()) << test_label;
+ if (expectations.size() != forms.size())
+ return;
+
+ for (unsigned int i = 0; i < expectations.size(); ++i) {
+ snprintf(test_label, kBufferSize, "%s in test %u, item %u",
+ forms_label, test_number, i);
+ PasswordForm* form = forms[i];
+ PasswordFormData* expectation = expectations[i];
+ EXPECT_EQ(expectation->scheme, form->scheme) << test_label;
+ EXPECT_EQ(std::string(expectation->signon_realm), form->signon_realm)
+ << test_label;
+ EXPECT_EQ(GURL(expectation->origin), form->origin) << test_label;
+ EXPECT_EQ(GURL(expectation->action), form->action) << test_label;
+ EXPECT_EQ(std::wstring(expectation->submit_element), form->submit_element)
+ << test_label;
+ EXPECT_EQ(std::wstring(expectation->username_element),
+ form->username_element) << test_label;
+ EXPECT_EQ(std::wstring(expectation->password_element),
+ form->password_element) << test_label;
+ if (expectation->username_value) {
+ EXPECT_EQ(std::wstring(expectation->username_value),
+ form->username_value) << test_label;
+ EXPECT_EQ(std::wstring(expectation->password_value),
+ form->password_value) << test_label;
+ } else {
+ EXPECT_TRUE(form->blacklisted_by_user) << test_label;
+ }
+ EXPECT_EQ(expectation->preferred, form->preferred) << test_label;
+ EXPECT_EQ(expectation->ssl_valid, form->ssl_valid) << test_label;
+ EXPECT_DOUBLE_EQ(expectation->creation_time,
+ form->date_created.ToDoubleT()) << test_label;
+ }
+}
+
+// Frees all the Keychain items in |items|, and clears the vector.
+static void FreeKeychainItems(const MacKeychain& keychain,
+ std::vector<SecKeychainItemRef>* items) {
+ CHECK(items);
+ for (std::vector<SecKeychainItemRef>::iterator i = items->begin();
+ i != items->end(); ++i) {
+ keychain.Free(*i);
+ }
+ items->clear();
+}
+
+// Deletes all the PasswordForms in |forms|, and clears the vector.
+static void DeletePasswordForms(std::vector<PasswordForm*>* forms) {
+ CHECK(forms);
+ for (std::vector<PasswordForm*>::iterator i = forms->begin();
+ i != forms->end(); ++i) {
+ delete *i;
+ }
+ forms->clear();
+}
+
+#pragma mark -
+
TEST(PasswordStoreMacTest, TestSignonRealmParsing) {
typedef struct {
const char* signon_realm;
@@ -760,7 +337,7 @@ TEST(PasswordStoreMacTest, TestKeychainToFormTranslation) {
mock_keychain, keychain_item, &form);
EXPECT_TRUE(parsed) << "In iteration " << i;
- mock_keychain.ExpectCreatesAndFreesBalanced();
+ ExpectCreatesAndFreesBalanced(mock_keychain);
EXPECT_EQ(expected[i].scheme, form.scheme) << "In iteration " << i;
EXPECT_EQ(GURL(expected[i].origin), form.origin) << "In iteration " << i;
@@ -798,20 +375,11 @@ TEST(PasswordStoreMacTest, TestKeychainToFormTranslation) {
PasswordForm form;
bool parsed = internal_keychain_helpers::FillPasswordFormFromKeychainItem(
mock_keychain, keychain_item, &form);
- mock_keychain.ExpectCreatesAndFreesBalanced();
+ ExpectCreatesAndFreesBalanced(mock_keychain);
EXPECT_FALSE(parsed);
}
}
-static void FreeKeychainItems(const MacKeychain& keychain,
- std::vector<SecKeychainItemRef>* items) {
- for (std::vector<SecKeychainItemRef>::iterator i = items->begin();
- i != items->end(); ++i) {
- keychain.Free(*i);
- }
- items->clear();
-}
-
TEST(PasswordStoreMacTest, TestKeychainSearch) {
MockKeychain mock_keychain;
@@ -822,7 +390,7 @@ TEST(PasswordStoreMacTest, TestKeychainSearch) {
PasswordForm::SCHEME_HTML, &matching_items);
EXPECT_EQ(static_cast<size_t>(2), matching_items.size());
FreeKeychainItems(mock_keychain, &matching_items);
- mock_keychain.ExpectCreatesAndFreesBalanced();
+ ExpectCreatesAndFreesBalanced(mock_keychain);
}
{ // An HTML form we haven't seen
@@ -832,7 +400,7 @@ TEST(PasswordStoreMacTest, TestKeychainSearch) {
PasswordForm::SCHEME_HTML, &matching_items);
EXPECT_EQ(static_cast<size_t>(0), matching_items.size());
FreeKeychainItems(mock_keychain, &matching_items);
- mock_keychain.ExpectCreatesAndFreesBalanced();
+ ExpectCreatesAndFreesBalanced(mock_keychain);
}
{ // Basic auth that should match.
@@ -842,7 +410,7 @@ TEST(PasswordStoreMacTest, TestKeychainSearch) {
PasswordForm::SCHEME_BASIC, &matching_items);
EXPECT_EQ(static_cast<size_t>(1), matching_items.size());
FreeKeychainItems(mock_keychain, &matching_items);
- mock_keychain.ExpectCreatesAndFreesBalanced();
+ ExpectCreatesAndFreesBalanced(mock_keychain);
}
{ // Basic auth with the wrong port.
@@ -852,7 +420,7 @@ TEST(PasswordStoreMacTest, TestKeychainSearch) {
PasswordForm::SCHEME_BASIC, &matching_items);
EXPECT_EQ(static_cast<size_t>(0), matching_items.size());
FreeKeychainItems(mock_keychain, &matching_items);
- mock_keychain.ExpectCreatesAndFreesBalanced();
+ ExpectCreatesAndFreesBalanced(mock_keychain);
}
{ // Digest auth we've saved under https, visited with http.
@@ -862,7 +430,7 @@ TEST(PasswordStoreMacTest, TestKeychainSearch) {
PasswordForm::SCHEME_DIGEST, &matching_items);
EXPECT_EQ(static_cast<size_t>(0), matching_items.size());
FreeKeychainItems(mock_keychain, &matching_items);
- mock_keychain.ExpectCreatesAndFreesBalanced();
+ ExpectCreatesAndFreesBalanced(mock_keychain);
}
{ // Digest auth that should match.
@@ -872,7 +440,7 @@ TEST(PasswordStoreMacTest, TestKeychainSearch) {
PasswordForm::SCHEME_DIGEST, &matching_items);
EXPECT_EQ(static_cast<size_t>(1), matching_items.size());
FreeKeychainItems(mock_keychain, &matching_items);
- mock_keychain.ExpectCreatesAndFreesBalanced();
+ ExpectCreatesAndFreesBalanced(mock_keychain);
}
}
@@ -930,7 +498,7 @@ TEST(PasswordStoreMacTest, TestKeychainExactSearch) {
blacklist);
EXPECT_EQ(NULL, match);
- mock_keychain.ExpectCreatesAndFreesBalanced();
+ ExpectCreatesAndFreesBalanced(mock_keychain);
}
// Test an http auth entry (SCHEME_BASIC, but SCHEME_DIGEST works is searched
@@ -989,7 +557,7 @@ TEST(PasswordStoreMacTest, TestKeychainExactSearch) {
blacklist);
EXPECT_EQ(NULL, match);
- mock_keychain.ExpectCreatesAndFreesBalanced();
+ ExpectCreatesAndFreesBalanced(mock_keychain);
}
}
@@ -1013,7 +581,7 @@ TEST(PasswordStoreMacTest, TestKeychainModify) {
EXPECT_FALSE(internal_keychain_helpers::SetKeychainItemPassword(
mock_keychain, keychain_item, std::string("fail_me")));
- mock_keychain.ExpectCreatesAndFreesBalanced();
+ ExpectCreatesAndFreesBalanced(mock_keychain);
}
TEST(PasswordStoreMacTest, TestKeychainAdd) {
@@ -1068,7 +636,7 @@ TEST(PasswordStoreMacTest, TestKeychainAdd) {
EXPECT_EQ(out_form.password_value, in_form->password_value);
mock_keychain.Free(matching_item);
}
- mock_keychain.ExpectCreatesAndFreesBalanced();
+ ExpectCreatesAndFreesBalanced(mock_keychain);
delete in_form;
}
@@ -1091,7 +659,7 @@ TEST(PasswordStoreMacTest, TestKeychainAdd) {
delete update_form;
}
- mock_keychain.ExpectCreatesAndFreesBalanced();
+ ExpectCreatesAndFreesBalanced(mock_keychain);
}
TEST(PasswordStoreMacTest, TestFormMatch) {
@@ -1166,66 +734,6 @@ TEST(PasswordStoreMacTest, TestFormMatch) {
}
}
-// Macro to simplify calling CheckFormsAgainstExpectations with a useful label.
-#define CHECK_FORMS(forms, expectations, i) \
- CheckFormsAgainstExpectations(forms, expectations, #forms, i)
-
-// Ensures that the data in |forms| match |expectations|, causing test failures
-// for any discrepencies.
-// TODO(stuartmorgan): This is current order-dependent; ideally it shouldn't
-// matter if |forms| and |expectations| are scrambled.
-static void CheckFormsAgainstExpectations(
- const std::vector<PasswordForm*>& forms,
- const std::vector<PasswordFormData*>& expectations,
- const char* forms_label, unsigned int test_number) {
-
- const unsigned int kBufferSize = 128;
- char test_label[kBufferSize];
- snprintf(test_label, kBufferSize, "%s in test %u", forms_label, test_number);
-
- EXPECT_EQ(expectations.size(), forms.size()) << test_label;
- if (expectations.size() != forms.size())
- return;
-
- for (unsigned int i = 0; i < expectations.size(); ++i) {
- snprintf(test_label, kBufferSize, "%s in test %u, item %u",
- forms_label, test_number, i);
- PasswordForm* form = forms[i];
- PasswordFormData* expectation = expectations[i];
- EXPECT_EQ(expectation->scheme, form->scheme) << test_label;
- EXPECT_EQ(std::string(expectation->signon_realm), form->signon_realm)
- << test_label;
- EXPECT_EQ(GURL(expectation->origin), form->origin) << test_label;
- EXPECT_EQ(GURL(expectation->action), form->action) << test_label;
- EXPECT_EQ(std::wstring(expectation->submit_element), form->submit_element)
- << test_label;
- EXPECT_EQ(std::wstring(expectation->username_element),
- form->username_element) << test_label;
- EXPECT_EQ(std::wstring(expectation->password_element),
- form->password_element) << test_label;
- if (expectation->username_value) {
- EXPECT_EQ(std::wstring(expectation->username_value),
- form->username_value) << test_label;
- EXPECT_EQ(std::wstring(expectation->password_value),
- form->password_value) << test_label;
- } else {
- EXPECT_TRUE(form->blacklisted_by_user) << test_label;
- }
- EXPECT_EQ(expectation->preferred, form->preferred) << test_label;
- EXPECT_EQ(expectation->ssl_valid, form->ssl_valid) << test_label;
- EXPECT_DOUBLE_EQ(expectation->creation_time,
- form->date_created.ToDoubleT()) << test_label;
- }
-}
-
-// Deletes all the PasswordForms in |forms|, and clears the vector.
-static void DeletePasswordForms(std::vector<PasswordForm*>* forms) {
- for (std::vector<PasswordForm*>::iterator i = forms->begin();
- i != forms->end(); ++i) {
- delete *i;
- }
- forms->clear();
-}
TEST(PasswordStoreMacTest, TestFormMerge) {
// Set up a bunch of test data to use in varying combinations.
PasswordFormData keychain_user_1 =
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp
index e7e47e9..a78fd07 100644
--- a/chrome/chrome.gyp
+++ b/chrome/chrome.gyp
@@ -3448,6 +3448,8 @@
'browser/importer/firefox_importer_unittest.cc',
'browser/importer/importer_unittest.cc',
'browser/importer/toolbar_importer_unittest.cc',
+ 'browser/keychain_mock_mac.cc',
+ 'browser/keychain_mock_mac.h',
'browser/login_prompt_unittest.cc',
'browser/metrics/metrics_log_unittest.cc',
'browser/metrics/metrics_response_unittest.cc',