blob: 76dfd21b05bd66c92a6c1db69ba8cd2dce7a0d51 [file] [log] [blame]
// Copyright 2024 The Fuchsia 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 LIB_DRIVER_TESTING_CPP_INTERNAL_INTERNALS_H_
#define LIB_DRIVER_TESTING_CPP_INTERNAL_INTERNALS_H_
#include <lib/async_patterns/testing/cpp/dispatcher_bound.h>
#include <lib/driver/component/cpp/driver_base.h>
#include <lib/driver/testing/cpp/driver_runtime.h>
#include <lib/driver/testing/cpp/internal/driver_lifecycle.h>
#include <lib/driver/testing/cpp/internal/test_environment.h>
#include <lib/driver/testing/cpp/test_node.h>
#include <type_traits>
namespace fdf_testing {
// Forward declare.
class Environment;
namespace internal {
template <typename EnvironmentType>
class EnvWrapper {
public:
fdf::DriverStartArgs Init() {
zx::result start_args = node_server_.CreateStartArgsAndServe();
ZX_ASSERT_MSG(start_args.is_ok(), "Failed to CreateStartArgsAndServe: %s.",
start_args.status_string());
zx::result result =
test_environment_.Initialize(std::move(start_args->incoming_directory_server));
ZX_ASSERT_MSG(result.is_ok(), "Failed to Initialize the test_environment: %s.",
result.status_string());
outgoing_client_ = std::move(start_args->outgoing_directory_client);
if (!user_env_served_) {
result = user_env_.Serve(test_environment_.incoming_directory());
ZX_ASSERT_MSG(result.is_ok(), "Failed to Serve the user's Environment: %s",
result.status_string());
user_env_served_ = true;
}
start_args->start_args.node_offers(std::vector<fuchsia_driver_framework::Offer>{});
for (auto& [service, instances] : test_environment_.incoming_directory().GetDriverServices()) {
for (auto& instance : instances) {
start_args->start_args.node_offers()->push_back(
fuchsia_driver_framework::Offer::WithDriverTransport(
fuchsia_component_decl::Offer::WithService(fuchsia_component_decl::OfferService{{
.source_name = service,
.target_name = service,
.renamed_instances = std::vector<fuchsia_component_decl::NameMapping>(
{fuchsia_component_decl::NameMapping(instance, instance)}),
}})));
}
}
for (auto& [service, instances] : test_environment_.incoming_directory().GetZirconServices()) {
for (auto& instance : instances) {
start_args->start_args.node_offers()->push_back(
fuchsia_driver_framework::Offer::WithZirconTransport(
fuchsia_component_decl::Offer::WithService(fuchsia_component_decl::OfferService{{
.source_name = service,
.target_name = service,
.renamed_instances = std::vector<fuchsia_component_decl::NameMapping>(
{fuchsia_component_decl::NameMapping(instance, instance)}),
}})));
}
}
return std::move(start_args->start_args);
}
fidl::ClientEnd<fuchsia_io::Directory> TakeOutgoingClient() {
ZX_ASSERT_MSG(outgoing_client_.is_valid(), "Cannot call TakeOutgoingClient more than once.");
return std::move(outgoing_client_);
}
fdf_testing::TestNode& node_server() { return node_server_; }
EnvironmentType& user_env() { return user_env_; }
private:
fdf_testing::TestNode node_server_{"root"};
TestEnvironment test_environment_;
fidl::ClientEnd<fuchsia_io::Directory> outgoing_client_;
// User env should be the last field as it could contain references to the test_environment_.
EnvironmentType user_env_;
bool user_env_served_ = false;
};
// Helper macros to validate the incoming configuration.
#define SETUP_HAS_USING(name) \
template <typename T, typename = void> \
struct Has##name : public ::std::false_type {}; \
\
template <typename T> \
struct Has##name<T, std::void_t<typename T::name>> : public std::true_type {}; \
\
template <typename T> \
constexpr inline auto Has##name##V = Has##name<T>::value;
SETUP_HAS_USING(DriverType)
SETUP_HAS_USING(EnvironmentType)
template <class Configuration>
class ConfigurationExtractor {
public:
// Validate DriverType.
static_assert(HasDriverTypeV<Configuration>,
"Ensure the Configuration class has defined a DriverType "
"through a using statement: 'using DriverType = MyDriverType;'");
using DriverType = typename Configuration::DriverType;
// Validate EnvironmentType.
static_assert(HasEnvironmentTypeV<Configuration>,
"Ensure the Configuration class has defined an EnvironmentType "
"through a using statement: 'using EnvironmentType = MyTestEnvironment;'");
using EnvironmentType = typename Configuration::EnvironmentType;
static_assert(std::is_base_of_v<fdf_testing::Environment, EnvironmentType>,
"The EnvironmentType must implement the fdf_testing::Environment class.");
static_assert(!std::is_abstract_v<EnvironmentType>, "The EnvironmentType cannot be abstract.");
static_assert(std::is_constructible_v<EnvironmentType>,
"The EnvironmentType must have a default constructor.");
};
template <typename T, typename = void>
struct HasGetDriverRegistration : public ::std::false_type {};
template <typename T>
struct HasGetDriverRegistration<T, std::void_t<decltype(T::GetDriverRegistration)>>
: public std::true_type {};
template <typename T>
constexpr static auto HasGetDriverRegistrationV = HasGetDriverRegistration<T>::value;
} // namespace internal
} // namespace fdf_testing
#endif // LIB_DRIVER_TESTING_CPP_INTERNAL_INTERNALS_H_