blob: 4440f7d1fd4a561f64720727470abc960214e65c [file] [log] [blame]
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_TEST_BASE_MIXIN_BASED_IN_PROCESS_BROWSER_TEST_H_
#define CHROME_TEST_BASE_MIXIN_BASED_IN_PROCESS_BROWSER_TEST_H_
#include <concepts>
#include <memory>
#include <vector>
#include "base/memory/raw_ptr.h"
#include "build/build_config.h"
#if BUILDFLAG(IS_ANDROID)
#include "chrome/test/base/android/android_browser_test.h"
#else
#include "chrome/test/base/in_process_browser_test.h"
#endif
//
// InProcessBrowserTestMixin enables writing isolated test helpers which depend
// on the standard test lifecycle but should not be test bases.
//
// A new mixin is created by deriving from InProcessBrowserTestMixin and
// overriding methods as needed.
//
// class MyMixin : public InProcessBrowserTestMixin {
// public:
// explicit MyMixin(InProcessBrowserTestMixinHost* host)
// : InProcessBrowserTestMixin(host) {}
// MyMixin(const MyMixin&) = delete;
// MyMixin& operator=(const MyMixin&) = delete;
// ~MyMixin() override = default;
//
// // InProcessBrowserTestMixin:
// void SetUpCommandLine(base::CommandLine* command_line) { /* ... */ }
//
// };
//
//
// To use the mixin, declare it as a member variable on the class and call the
// constructor with the InProcessBrowserTestMixinHost also declared on the class
// (or parent class). The mixin will register itself with the host and the host
// will invoke all registered mixin methods.
//
// For example, here is how to use MixinBasedInProcessBrowserTest:
//
// class SimpleUsage : public MixinBasedInProcessBrowserTest {
// public:
// SimpleUsage() = default;
// SimpleUsage(const SimpleUsage&) = delete;
// SimpleUsage& operator=(const SimpleUsage&) = delete;
// ~SimpleUsage() override = default;
//
// private:
// MyMixin my_mixin_{&mixin_host_};
// SomeOtherMixin some_other_mixin_{&mixin_host_};
// };
//
//
// See WizardInProcessBrowserTest for an example of how to correctly embed a
// mixin host.
//
class InProcessBrowserTestMixinHost;
class PrefService;
// Derive from this type to create a class which depends on the test lifecycle
// without also becoming a test base.
class InProcessBrowserTestMixin {
public:
explicit InProcessBrowserTestMixin(InProcessBrowserTestMixinHost* host);
InProcessBrowserTestMixin(const InProcessBrowserTestMixin&) = delete;
InProcessBrowserTestMixin& operator=(const InProcessBrowserTestMixin&) =
delete;
virtual ~InProcessBrowserTestMixin() = default;
// See InProcessBrowserTest for docs. The call order is:
//
// SetUp
// SetUpCommandLine
// SetUpDefaultCommandLine
// SetUpUserDataDirectory
// SetUpInProcessBrowserTestFixture
// SetUpLocalStatePrefService
// CreatedBrowserMainParts
// SetUpOnMainThread
// TearDownOnMainThread
// PostRunTestOnMainThread
// TearDownInProcessBrowserTestFixture
// TearDown
//
// SetUp is the function which calls SetUpCommandLine,
// SetUpDefaultCommandLine, etc.
virtual void SetUp();
virtual void SetUpCommandLine(base::CommandLine* command_line);
virtual void SetUpDefaultCommandLine(base::CommandLine* command_line);
virtual bool SetUpUserDataDirectory();
virtual void SetUpInProcessBrowserTestFixture();
virtual void SetUpLocalStatePrefService(PrefService* local_state);
virtual void CreatedBrowserMainParts(
content::BrowserMainParts* browser_main_parts);
virtual void SetUpOnMainThread();
virtual void TearDownOnMainThread();
virtual void PostRunTestOnMainThread();
virtual void TearDownInProcessBrowserTestFixture();
virtual void TearDown();
};
// The mixin host executes the callbacks on the mixin instances.
class InProcessBrowserTestMixinHost final {
public:
InProcessBrowserTestMixinHost();
InProcessBrowserTestMixinHost(const InProcessBrowserTestMixinHost&) = delete;
InProcessBrowserTestMixinHost& operator=(
const InProcessBrowserTestMixinHost&) = delete;
~InProcessBrowserTestMixinHost();
void SetUp();
void SetUpCommandLine(base::CommandLine* command_line);
void SetUpDefaultCommandLine(base::CommandLine* command_line);
bool SetUpUserDataDirectory();
void SetUpInProcessBrowserTestFixture();
void SetUpLocalStatePrefService(PrefService* local_state);
void CreatedBrowserMainParts(content::BrowserMainParts* browser_main_parts);
void SetUpOnMainThread();
void TearDownOnMainThread();
void PostRunTestOnMainThread();
void TearDownInProcessBrowserTestFixture();
void TearDown();
private:
// The constructor of InProcessBrowserTestMixin injects itself directly into
// mixins_. This is done instead of an explicit AddMixin to make API usage
// simpler.
friend class InProcessBrowserTestMixin;
std::vector<raw_ptr<InProcessBrowserTestMixin, VectorExperimental>> mixins_;
};
template <typename Fixture>
#if BUILDFLAG(IS_ANDROID)
requires std::derived_from<Fixture, AndroidBrowserTest>
#else
requires std::derived_from<Fixture, InProcessBrowserTest>
#endif
class InProcessBrowserTestMixinHostSupport : public Fixture {
public:
// Inherit ctors from the base class.
using Fixture::Fixture;
// Fixture:
void SetUp() override {
mixin_host_.SetUp();
Fixture::SetUp();
}
void SetUpCommandLine(base::CommandLine* command_line) override {
mixin_host_.SetUpCommandLine(command_line);
Fixture::SetUpCommandLine(command_line);
}
void SetUpDefaultCommandLine(base::CommandLine* command_line) override {
mixin_host_.SetUpDefaultCommandLine(command_line);
Fixture::SetUpDefaultCommandLine(command_line);
}
bool SetUpUserDataDirectory() override {
return mixin_host_.SetUpUserDataDirectory() &&
Fixture::SetUpUserDataDirectory();
}
void SetUpInProcessBrowserTestFixture() override {
mixin_host_.SetUpInProcessBrowserTestFixture();
Fixture::SetUpInProcessBrowserTestFixture();
}
void SetUpLocalStatePrefService(PrefService* local_state) override {
mixin_host_.SetUpLocalStatePrefService(local_state);
Fixture::SetUpLocalStatePrefService(local_state);
}
void CreatedBrowserMainParts(
content::BrowserMainParts* browser_main_parts) override {
mixin_host_.CreatedBrowserMainParts(browser_main_parts);
Fixture::CreatedBrowserMainParts(browser_main_parts);
}
void SetUpOnMainThread() override {
mixin_host_.SetUpOnMainThread();
Fixture::SetUpOnMainThread();
}
void TearDownOnMainThread() override {
mixin_host_.TearDownOnMainThread();
Fixture::TearDownOnMainThread();
}
void PostRunTestOnMainThread() override {
mixin_host_.PostRunTestOnMainThread();
Fixture::PostRunTestOnMainThread();
}
void TearDownInProcessBrowserTestFixture() override {
mixin_host_.TearDownInProcessBrowserTestFixture();
Fixture::TearDownInProcessBrowserTestFixture();
}
void TearDown() override {
mixin_host_.TearDown();
Fixture::TearDown();
}
protected:
InProcessBrowserTestMixinHost mixin_host_;
};
#if BUILDFLAG(IS_ANDROID)
// An AndroidBrowserTest which supports mixins.
using MixinBasedAndroidBrowserTest =
InProcessBrowserTestMixinHostSupport<AndroidBrowserTest>;
// The implementation is included in mixin_based_in_process_browser_test.cc
extern template class InProcessBrowserTestMixinHostSupport<AndroidBrowserTest>;
#else
// An InProcessBrowserTest which supports mixins.
using MixinBasedInProcessBrowserTest =
InProcessBrowserTestMixinHostSupport<InProcessBrowserTest>;
// The implementation is included in mixin_based_in_process_browser_test.cc
extern template class InProcessBrowserTestMixinHostSupport<
InProcessBrowserTest>;
#endif
#if BUILDFLAG(IS_ANDROID)
using MixinBasedPlatformBrowserTest = MixinBasedAndroidBrowserTest;
#else
using MixinBasedPlatformBrowserTest = MixinBasedInProcessBrowserTest;
#endif
#endif // CHROME_TEST_BASE_MIXIN_BASED_IN_PROCESS_BROWSER_TEST_H_