[iOS][MF] Adds password fetcher for manual fill

This object will be in charge to fetch the passwords for Manual Fill.
A Passwords Mediator will be the delegate and owner of it.

Bug: 845472
Cq-Include-Trybots: luci.chromium.try:ios-simulator-full-configs;master.tryserver.chromium.mac:ios-simulator-cronet
Change-Id: I7e15656c4d9979aff5c86d79bab7a42e5161408b
Reviewed-on: https://chromium-review.googlesource.com/1148813
Reviewed-by: Olivier Robin <olivierrobin@chromium.org>
Reviewed-by: Rohit Rao <rohitrao@chromium.org>
Commit-Queue: Javier Ernesto Flores Robles <javierrobles@chromium.org>
Cr-Commit-Position: refs/heads/master@{#578337}
diff --git a/ios/chrome/browser/autofill/manual_fill/BUILD.gn b/ios/chrome/browser/autofill/manual_fill/BUILD.gn
index 8497e82..12f6da7f 100644
--- a/ios/chrome/browser/autofill/manual_fill/BUILD.gn
+++ b/ios/chrome/browser/autofill/manual_fill/BUILD.gn
@@ -8,12 +8,37 @@
   sources = [
     "accessory_provider.h",
     "accessory_provider.mm",
+    "passwords_fetcher.h",
+    "passwords_fetcher.mm",
   ]
   deps = [
     "//base",
-    "//ios/chrome/browser/autofill",
+    "//components/autofill/core/common:common",
+    "//components/keyed_service/core:core",
+    "//components/password_manager/core/browser:browser",
+    "//ios/chrome/browser/autofill:autofill_shared",
+    "//ios/chrome/browser/browser_state:browser_state",
+    "//ios/chrome/browser/passwords:passwords",
     "//ios/chrome/browser/ui/autofill/manual_fill",
   ]
   libs = [ "UIKit.framework" ]
   configs += [ "//build/config/compiler:enable_arc" ]
 }
+
+source_set("unit_tests") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  testonly = true
+  sources = [
+    "passwords_fetcher_unittest.mm",
+  ]
+  deps = [
+    ":manual_fill",
+    "//base/test:test_support",
+    "//components/autofill/core/common:common",
+    "//components/keyed_service/core:core",
+    "//components/password_manager/core/browser:test_support",
+    "//ios/chrome/browser/browser_state:test_support",
+    "//ios/chrome/browser/passwords:passwords",
+    "//testing/gtest:gtest",
+  ]
+}
diff --git a/ios/chrome/browser/autofill/manual_fill/passwords_fetcher.h b/ios/chrome/browser/autofill/manual_fill/passwords_fetcher.h
new file mode 100644
index 0000000..13d5c4d
--- /dev/null
+++ b/ios/chrome/browser/autofill/manual_fill/passwords_fetcher.h
@@ -0,0 +1,43 @@
+// Copyright 2018 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 IOS_CHROME_BROWSER_AUTOFILL_MANUAL_FILL_PASSWORDS_FETCHER_H_
+#define IOS_CHROME_BROWSER_AUTOFILL_MANUAL_FILL_PASSWORDS_FETCHER_H_
+
+#import <Foundation/Foundation.h>
+#include <memory>
+#include <vector>
+
+namespace autofill {
+struct PasswordForm;
+}  // namespace autofill
+
+namespace ios {
+class ChromeBrowserState;
+}  // namespace ios
+
+@class PasswordFetcher;
+
+// Protocol to receive the passwords fetched asynchronously.
+@protocol PasswordFetcherDelegate
+
+// Saved passwords has been fetched or updated.
+- (void)passwordFetcher:(PasswordFetcher*)passwordFetcher
+      didFetchPasswords:
+          (std::vector<std::unique_ptr<autofill::PasswordForm>>&)passwords;
+
+@end
+
+@interface PasswordFetcher : NSObject
+
+// The designated initializer. |browserState| must not be nil.
+- (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState
+                            delegate:(id<PasswordFetcherDelegate>)delegate
+    NS_DESIGNATED_INITIALIZER;
+
+- (instancetype)init NS_UNAVAILABLE;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_AUTOFILL_MANUAL_FILL_PASSWORDS_FETCHER_H_
diff --git a/ios/chrome/browser/autofill/manual_fill/passwords_fetcher.mm b/ios/chrome/browser/autofill/manual_fill/passwords_fetcher.mm
new file mode 100644
index 0000000..5b2632f
--- /dev/null
+++ b/ios/chrome/browser/autofill/manual_fill/passwords_fetcher.mm
@@ -0,0 +1,74 @@
+// Copyright 2018 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.
+
+#import "ios/chrome/browser/autofill/manual_fill/passwords_fetcher.h"
+
+#include "components/autofill/core/common/password_form.h"
+#include "components/keyed_service/core/service_access_type.h"
+#include "components/password_manager/core/browser/password_list_sorter.h"
+#include "components/password_manager/core/browser/password_store.h"
+#include "components/password_manager/core/browser/password_store_consumer.h"
+#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
+#include "ios/chrome/browser/passwords/ios_chrome_password_store_factory.h"
+#include "ios/chrome/browser/passwords/save_passwords_consumer.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+@interface PasswordFetcher ()<SavePasswordsConsumerDelegate> {
+  // The interface for getting and manipulating a user's saved passwords.
+  scoped_refptr<password_manager::PasswordStore> _passwordStore;
+  // A helper object for passing data about saved passwords from a finished
+  // password store request to the SavePasswordsCollectionViewController.
+  std::unique_ptr<ios::SavePasswordsConsumer> _savedPasswordsConsumer;
+  // The list of the user's saved passwords.
+  std::vector<std::unique_ptr<autofill::PasswordForm>> _savedForms;
+  // The current Chrome browser state.
+  ios::ChromeBrowserState* _browserState;
+}
+
+// Delegate to send the fetchted passwords.
+@property(nonatomic, weak) id<PasswordFetcherDelegate> delegate;
+
+@end
+
+@implementation PasswordFetcher
+
+@synthesize delegate = _delegate;
+
+#pragma mark - Initialization
+
+- (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState
+                            delegate:(id<PasswordFetcherDelegate>)delegate {
+  DCHECK(browserState);
+  self = [super init];
+  if (self) {
+    _browserState = browserState;
+    _delegate = delegate;
+    _passwordStore = IOSChromePasswordStoreFactory::GetForBrowserState(
+        _browserState, ServiceAccessType::EXPLICIT_ACCESS);
+    DCHECK(_passwordStore);
+    _savedPasswordsConsumer.reset(new ios::SavePasswordsConsumer(self));
+    _passwordStore->GetAutofillableLogins(_savedPasswordsConsumer.get());
+  }
+  return self;
+}
+
+#pragma mark - SavePasswordsConsumerDelegate
+
+- (void)onGetPasswordStoreResults:
+    (std::vector<std::unique_ptr<autofill::PasswordForm>>&)result {
+  for (auto it = result.begin(); it != result.end(); ++it) {
+    if (!(*it)->blacklisted_by_user)
+      _savedForms.push_back(std::move(*it));
+  }
+
+  password_manager::DuplicatesMap savedPasswordDuplicates;
+  password_manager::SortEntriesAndHideDuplicates(&_savedForms,
+                                                 &savedPasswordDuplicates);
+  [self.delegate passwordFetcher:self didFetchPasswords:_savedForms];
+}
+
+@end
diff --git a/ios/chrome/browser/autofill/manual_fill/passwords_fetcher_unittest.mm b/ios/chrome/browser/autofill/manual_fill/passwords_fetcher_unittest.mm
new file mode 100644
index 0000000..4893308
--- /dev/null
+++ b/ios/chrome/browser/autofill/manual_fill/passwords_fetcher_unittest.mm
@@ -0,0 +1,217 @@
+// Copyright 2018 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.
+
+#import "ios/chrome/browser/autofill/manual_fill/passwords_fetcher.h"
+
+#import <Foundation/Foundation.h>
+
+#include "base/strings/utf_string_conversions.h"
+#import "base/test/ios/wait_util.h"
+#include "base/test/scoped_task_environment.h"
+#include "components/autofill/core/common/password_form.h"
+#include "components/keyed_service/core/service_access_type.h"
+#include "components/password_manager/core/browser/password_manager_test_utils.h"
+#include "components/password_manager/core/browser/test_password_store.h"
+#include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
+#include "ios/chrome/browser/passwords/ios_chrome_password_store_factory.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#import "testing/gtest_mac.h"
+#include "testing/platform_test.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+using base::test::ios::WaitUntilCondition;
+
+// Test object conforming to PasswordFetcherDelegate used to verify the results
+// from the password store.
+@interface TestPasswordFetcherDelegate : NSObject<PasswordFetcherDelegate> {
+  // Ivar to store the results from the store.
+  std::vector<std::unique_ptr<autofill::PasswordForm>> _passwords;
+}
+
+// Returns the count of recieved passwords.
+@property(nonatomic, readonly) size_t passwordNumber;
+
+@end
+
+@implementation TestPasswordFetcherDelegate
+
+- (void)passwordFetcher:(PasswordFetcher*)passwordFetcher
+      didFetchPasswords:
+          (std::vector<std::unique_ptr<autofill::PasswordForm>>&)passwords {
+  _passwords = std::move(passwords);
+}
+
+- (size_t)passwordNumber {
+  return _passwords.size();
+}
+
+@end
+
+namespace {
+
+class PasswordFetcherTest : public PlatformTest {
+ protected:
+  PasswordFetcherTest() = default;
+
+  void SetUp() override {
+    PlatformTest::SetUp();
+    TestChromeBrowserState::Builder test_cbs_builder;
+    chrome_browser_state_ = test_cbs_builder.Build();
+    IOSChromePasswordStoreFactory::GetInstance()->SetTestingFactory(
+        chrome_browser_state_.get(),
+        &password_manager::BuildPasswordStore<
+            web::BrowserState, password_manager::TestPasswordStore>);
+  }
+
+  password_manager::PasswordStore* GetPasswordStore() {
+    return IOSChromePasswordStoreFactory::GetForBrowserState(
+               chrome_browser_state_.get(), ServiceAccessType::EXPLICIT_ACCESS)
+        .get();
+  }
+
+  // Creates and adds a saved password form.
+  void AddSavedForm1() {
+    auto form = std::make_unique<autofill::PasswordForm>();
+    form->origin = GURL("http://www.example.com/accounts/LoginAuth");
+    form->action = GURL("http://www.example.com/accounts/Login");
+    form->username_element = base::ASCIIToUTF16("Email");
+    form->username_value = base::ASCIIToUTF16("test@egmail.com");
+    form->password_element = base::ASCIIToUTF16("Passwd");
+    form->password_value = base::ASCIIToUTF16("test");
+    form->submit_element = base::ASCIIToUTF16("signIn");
+    form->signon_realm = "http://www.example.com/";
+    form->preferred = false;
+    form->scheme = autofill::PasswordForm::SCHEME_HTML;
+    form->blacklisted_by_user = false;
+    GetPasswordStore()->AddLogin(*std::move(form));
+  }
+
+  // Creates and adds a saved password form.
+  void AddSavedForm2() {
+    auto form = std::make_unique<autofill::PasswordForm>();
+    form->origin = GURL("http://www.example2.com/accounts/LoginAuth");
+    form->action = GURL("http://www.example2.com/accounts/Login");
+    form->username_element = base::ASCIIToUTF16("Email");
+    form->username_value = base::ASCIIToUTF16("test@egmail.com");
+    form->password_element = base::ASCIIToUTF16("Passwd");
+    form->password_value = base::ASCIIToUTF16("test");
+    form->submit_element = base::ASCIIToUTF16("signIn");
+    form->signon_realm = "http://www.example2.com/";
+    form->preferred = false;
+    form->scheme = autofill::PasswordForm::SCHEME_HTML;
+    form->blacklisted_by_user = false;
+    GetPasswordStore()->AddLogin(*std::move(form));
+  }
+
+  // Creates and adds a blacklisted site form to never offer to save
+  // user's password to those sites.
+  void AddBlacklistedForm() {
+    auto form = std::make_unique<autofill::PasswordForm>();
+    form->origin = GURL("http://www.secret.com/login");
+    form->action = GURL("http://www.secret.com/action");
+    form->username_element = base::ASCIIToUTF16("email");
+    form->username_value = base::ASCIIToUTF16("test@secret.com");
+    form->password_element = base::ASCIIToUTF16("password");
+    form->password_value = base::ASCIIToUTF16("cantsay");
+    form->submit_element = base::ASCIIToUTF16("signIn");
+    form->signon_realm = "http://www.secret.com/";
+    form->preferred = false;
+    form->scheme = autofill::PasswordForm::SCHEME_HTML;
+    form->blacklisted_by_user = true;
+    GetPasswordStore()->AddLogin(*std::move(form));
+  }
+
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
+  std::unique_ptr<TestChromeBrowserState> chrome_browser_state_;
+};
+
+// Tests PasswordFetcher initialization.
+TEST_F(PasswordFetcherTest, Initialization) {
+  PasswordFetcher* passwordFetcher =
+      [[PasswordFetcher alloc] initWithBrowserState:chrome_browser_state_.get()
+                                           delegate:nil];
+  EXPECT_TRUE(passwordFetcher);
+}
+
+// Tests PasswordFetcher returns 1 passwords.
+TEST_F(PasswordFetcherTest, ReturnsPassword) {
+  AddSavedForm1();
+  TestPasswordFetcherDelegate* passwordFetcherDelegate =
+      [[TestPasswordFetcherDelegate alloc] init];
+  PasswordFetcher* passwordFetcher =
+      [[PasswordFetcher alloc] initWithBrowserState:chrome_browser_state_.get()
+                                           delegate:passwordFetcherDelegate];
+  WaitUntilCondition(
+      ^bool {
+        return passwordFetcherDelegate.passwordNumber > 0;
+      },
+      true, base::TimeDelta::FromSeconds(1000));
+
+  EXPECT_EQ(passwordFetcherDelegate.passwordNumber, 1u);
+  EXPECT_TRUE(passwordFetcher);
+}
+
+// Tests PasswordFetcher returns 2 passwords.
+TEST_F(PasswordFetcherTest, ReturnsTwoPasswords) {
+  AddSavedForm1();
+  AddSavedForm2();
+  TestPasswordFetcherDelegate* passwordFetcherDelegate =
+      [[TestPasswordFetcherDelegate alloc] init];
+  PasswordFetcher* passwordFetcher =
+      [[PasswordFetcher alloc] initWithBrowserState:chrome_browser_state_.get()
+                                           delegate:passwordFetcherDelegate];
+  WaitUntilCondition(
+      ^bool {
+        return passwordFetcherDelegate.passwordNumber > 0;
+      },
+      true, base::TimeDelta::FromSeconds(1000));
+
+  EXPECT_EQ(passwordFetcherDelegate.passwordNumber, 2u);
+  EXPECT_TRUE(passwordFetcher);
+}
+
+// Tests PasswordFetcher ignores blacklisted passwords.
+TEST_F(PasswordFetcherTest, IgnoresBlacklisted) {
+  AddSavedForm1();
+  AddBlacklistedForm();
+  TestPasswordFetcherDelegate* passwordFetcherDelegate =
+      [[TestPasswordFetcherDelegate alloc] init];
+  PasswordFetcher* passwordFetcher =
+      [[PasswordFetcher alloc] initWithBrowserState:chrome_browser_state_.get()
+                                           delegate:passwordFetcherDelegate];
+  WaitUntilCondition(
+      ^bool {
+        return passwordFetcherDelegate.passwordNumber > 0;
+      },
+      true, base::TimeDelta::FromSeconds(1000));
+
+  EXPECT_EQ(passwordFetcherDelegate.passwordNumber, 1u);
+  EXPECT_TRUE(passwordFetcher);
+}
+
+// Tests PasswordFetcher ignores duplicated passwords.
+TEST_F(PasswordFetcherTest, IgnoresDuplicated) {
+  AddSavedForm1();
+  AddSavedForm1();
+  AddSavedForm1();
+  AddSavedForm1();
+  TestPasswordFetcherDelegate* passwordFetcherDelegate =
+      [[TestPasswordFetcherDelegate alloc] init];
+  PasswordFetcher* passwordFetcher =
+      [[PasswordFetcher alloc] initWithBrowserState:chrome_browser_state_.get()
+                                           delegate:passwordFetcherDelegate];
+  WaitUntilCondition(
+      ^bool {
+        return passwordFetcherDelegate.passwordNumber > 0;
+      },
+      true, base::TimeDelta::FromSeconds(1000));
+
+  EXPECT_EQ(passwordFetcherDelegate.passwordNumber, 1u);
+  EXPECT_TRUE(passwordFetcher);
+}
+
+}  // namespace
diff --git a/ios/chrome/browser/passwords/save_passwords_consumer.h b/ios/chrome/browser/passwords/save_passwords_consumer.h
index 19cc0ba..f8efc8c 100644
--- a/ios/chrome/browser/passwords/save_passwords_consumer.h
+++ b/ios/chrome/browser/passwords/save_passwords_consumer.h
@@ -15,7 +15,7 @@
 // Callback called when the async request launched from
 // |getLoginsFromPasswordStore| finishes.
 - (void)onGetPasswordStoreResults:
-    (const std::vector<std::unique_ptr<autofill::PasswordForm>>&)result;
+    (std::vector<std::unique_ptr<autofill::PasswordForm>>&)result;
 
 @end
 
diff --git a/ios/chrome/browser/ui/settings/save_passwords_collection_view_controller.mm b/ios/chrome/browser/ui/settings/save_passwords_collection_view_controller.mm
index e4cec0b..8430ce8 100644
--- a/ios/chrome/browser/ui/settings/save_passwords_collection_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/save_passwords_collection_view_controller.mm
@@ -475,7 +475,7 @@
 #pragma mark - SavePasswordsConsumerDelegate
 
 - (void)onGetPasswordStoreResults:
-    (const std::vector<std::unique_ptr<autofill::PasswordForm>>&)result {
+    (std::vector<std::unique_ptr<autofill::PasswordForm>>&)result {
   for (auto it = result.begin(); it != result.end(); ++it) {
     // PasswordForm is needed when user wants to delete the site/password.
     auto form = std::make_unique<autofill::PasswordForm>(**it);
diff --git a/ios/chrome/test/BUILD.gn b/ios/chrome/test/BUILD.gn
index 5865592..a4facee 100644
--- a/ios/chrome/test/BUILD.gn
+++ b/ios/chrome/test/BUILD.gn
@@ -141,6 +141,7 @@
     "//ios/chrome/browser:unit_tests",
     "//ios/chrome/browser/app_launcher:unit_tests",
     "//ios/chrome/browser/autofill:unit_tests",
+    "//ios/chrome/browser/autofill/manual_fill:unit_tests",
     "//ios/chrome/browser/browser_state:unit_tests",
     "//ios/chrome/browser/browsing_data:unit_tests",
     "//ios/chrome/browser/crash_report:unit_tests",