|  | // Copyright 2023 The Chromium Authors | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #ifndef COMPONENTS_AUTOFILL_CONTENT_BROWSER_TEST_AUTOFILL_CLIENT_INJECTOR_H_ | 
|  | #define COMPONENTS_AUTOFILL_CONTENT_BROWSER_TEST_AUTOFILL_CLIENT_INJECTOR_H_ | 
|  |  | 
|  | #include <concepts> | 
|  |  | 
|  | #include "components/autofill/content/browser/content_autofill_client.h" | 
|  | #include "content/public/browser/web_contents.h" | 
|  | #include "content/public/test/browser_test_utils.h" | 
|  |  | 
|  | namespace autofill { | 
|  |  | 
|  | // Asserts that at construction time, no other TestAutofillClientInjector, no | 
|  | // other TestAutofillDriverInjector, and no TestAutofillManagerInjector are | 
|  | // alive. | 
|  | class TestAutofillClientInjectorBase { | 
|  | public: | 
|  | static bool some_instance_is_alive() { return num_instances_ > 0; } | 
|  |  | 
|  | TestAutofillClientInjectorBase(const TestAutofillClientInjectorBase&) = | 
|  | delete; | 
|  | TestAutofillClientInjectorBase& operator=( | 
|  | const TestAutofillClientInjectorBase&) = delete; | 
|  |  | 
|  | protected: | 
|  | TestAutofillClientInjectorBase(); | 
|  | ~TestAutofillClientInjectorBase(); | 
|  |  | 
|  | private: | 
|  | static size_t num_instances_; | 
|  | }; | 
|  |  | 
|  | // RAII type that installs new AutofillClients of type `T` in all newly created | 
|  | // WebContents. | 
|  | // | 
|  | // This happens *before* the production-code ContentAutofillClient is | 
|  | // associated. It thus avoids dangling pointers to the production-code | 
|  | // ContentAutofillClient. | 
|  | // | 
|  | // To prevent hard-to-find bugs, only one TestAutofillClientInjector may be | 
|  | // alive at a time. It is compatible with TestAutofillDriverInjector and/or | 
|  | // TestAutofillManagerInjector, but the client injector must be created first. | 
|  | // These conditions are CHECKed. | 
|  | // | 
|  | // Usage: | 
|  | // | 
|  | //   class AutofillFooTest : public ... { | 
|  | //    public: | 
|  | //     TestContentAutofillClient* autofill_client( | 
|  | //         content::WebContents* web_contents) { | 
|  | //       return autofill_client_injector_[web_contents]; | 
|  | //     } | 
|  | // | 
|  | //    private: | 
|  | //     TestAutofillClientInjector<TestContentAutofillClient> | 
|  | //         autofill_client_injector_; | 
|  | //   }; | 
|  | template <std::derived_from<ContentAutofillClient> T> | 
|  | class TestAutofillClientInjector : public TestAutofillClientInjectorBase { | 
|  | public: | 
|  | TestAutofillClientInjector() = default; | 
|  | TestAutofillClientInjector(const TestAutofillClientInjector&) = delete; | 
|  | TestAutofillClientInjector& operator=(const TestAutofillClientInjector&) = | 
|  | delete; | 
|  | ~TestAutofillClientInjector() = default; | 
|  |  | 
|  | T* operator[](content::WebContents* web_contents) const { | 
|  | auto it = clients_.find(web_contents); | 
|  | return it != clients_.end() ? it->second : nullptr; | 
|  | } | 
|  |  | 
|  | private: | 
|  | void InjectClient(content::WebContents* web_contents) { | 
|  | auto client = std::make_unique<T>(web_contents); | 
|  | clients_[web_contents] = client.get(); | 
|  | web_contents->SetUserData(T::UserDataKey(), std::move(client)); | 
|  | } | 
|  |  | 
|  | std::map<content::WebContents*, T*> clients_; | 
|  |  | 
|  | // Registers the lambda for the lifetime of `subscription_`. | 
|  | base::CallbackListSubscription subscription_ = | 
|  | content::RegisterWebContentsCreationCallback( | 
|  | base::BindRepeating(&TestAutofillClientInjector::InjectClient, | 
|  | base::Unretained(this))); | 
|  | }; | 
|  |  | 
|  | }  // namespace autofill | 
|  |  | 
|  | #endif  // COMPONENTS_AUTOFILL_CONTENT_BROWSER_TEST_AUTOFILL_CLIENT_INJECTOR_H_ |