blob: 3dc0c565539c1b3d92af2f18c3f1306beb1e036c [file] [log] [blame]
// Copyright 2021 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 ZXTEST_BASE_PARAMETERIZED_VALUE_H_
#define ZXTEST_BASE_PARAMETERIZED_VALUE_H_
#include <lib/stdcompat/string_view.h>
#include <zircon/assert.h>
#include <optional>
#include <fbl/string.h>
#include <fbl/vector.h>
#include <zxtest/base/observer.h>
#include <zxtest/base/types.h>
#include <zxtest/base/values.h>
namespace zxtest {
template <class ParamType>
struct TestParamInfo {
TestParamInfo(const ParamType& a_param, size_t an_index) : param(a_param), index(an_index) {}
ParamType param;
size_t index;
};
template <typename T>
class WithParamInterface {
public:
using ParamType = T;
template <typename TestImpl>
static internal::TestFactory CreateFactory(fit::function<const ParamType&()> value_getter) {
return [value_getter = std::move(value_getter)](
internal::TestDriver* driver) mutable -> std::unique_ptr<TestImpl> {
TestImpl::param_.emplace(value_getter());
std::unique_ptr<TestImpl> test = TestImpl::template Create<TestImpl>(driver);
return std::move(test);
};
}
virtual ~WithParamInterface() = default;
const ParamType& GetParam() const { return WithParamInterface<T>::param_.value(); }
protected:
WithParamInterface() = default;
private:
static std::optional<ParamType> param_;
};
template <typename T>
std::optional<T> WithParamInterface<T>::param_ = std::nullopt;
// Interface for Value Parameterized tests. This class also captures the type
// of the parameter and provides storage for such parameter type. This follows gTest interface
// to allow more familiarity for users.
template <typename T>
class TestWithParam : public zxtest::Test, public WithParamInterface<T> {
public:
TestWithParam() = default;
~TestWithParam() override = default;
};
namespace internal {
// Alias for a trick to provide minimal RTTI to prevent invalid test instantiations.
using TypeId = const void*;
// This class is meant to provide a unique ID per type, which can be used at runtime to prevent
// parameterized test cases to collide. Since the type is hidden under an interface, we need to
// validate that we are not mixing fixtures, which will prevent wrong SetUp/TearDown from happening.
// This works because the compiler will allocate a boolean for each type, and we can rely on its
// address uniqueness for comparing whether two types are equal or not. Any other operation is not
// permitted.
template <typename T>
struct TypeIdProvider {
public:
// Returns a unique id for a given type.
static TypeId Get() { return &unique_addr_; }
private:
// This is not marked const to prevent compiler optimization.
static bool unique_addr_;
};
template <typename T>
bool TypeIdProvider<T>::unique_addr_ = false;
// This class provides an interface for an instantiation of a WithParamInterface to defer
// registration.
class ParameterizedTestCaseInfo {
public:
ParameterizedTestCaseInfo() = default;
explicit ParameterizedTestCaseInfo(const fbl::String& test_case_name) : name_(test_case_name) {}
ParameterizedTestCaseInfo(const ParameterizedTestCaseInfo&) = delete;
ParameterizedTestCaseInfo(ParameterizedTestCaseInfo&&) = delete;
ParameterizedTestCaseInfo& operator=(const ParameterizedTestCaseInfo&) = delete;
ParameterizedTestCaseInfo& operator=(ParameterizedTestCaseInfo&&) = delete;
virtual ~ParameterizedTestCaseInfo() = default;
// Returns the name of the test case.
const fbl::String& name() const { return name_; }
// Registers all parametrized tests of this test case with |runner|.
virtual void RegisterTest(Runner* runner) = 0;
// Returns a unique Id representing the first fixture used to instantiate this Parameterized test
// case.
virtual TypeId GetFixtureId() const = 0;
private:
fbl::String name_;
};
class AddTestDelegate {
public:
virtual ~AddTestDelegate() = default;
virtual std::unique_ptr<ParameterizedTestCaseInfo> CreateSuite(
const cpp17::string_view& suite_name) = 0;
virtual bool AddTest(ParameterizedTestCaseInfo* base, const cpp17::string_view& test_name,
const SourceLocation& location) = 0;
};
template <typename ParamType>
class AddInstantiationDelegate {
public:
virtual ~AddInstantiationDelegate<ParamType>() = default;
virtual bool AddInstantiation(
ParameterizedTestCaseInfo* base, const fbl::String& instantiation_name,
const SourceLocation& location, zxtest::internal::ValueProvider<ParamType>& provider,
std::function<std::string(zxtest::TestParamInfo<ParamType>)> name_fn) = 0;
};
} // namespace internal
} // namespace zxtest
#endif // ZXTEST_BASE_PARAMETERIZED_VALUE_H_