blob: 4b53bc034c8772e93881db6b386e1f1688b175d7 [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_IMPL_H_
#define ZXTEST_BASE_PARAMETERIZED_VALUE_IMPL_H_
#include <lib/stdcompat/string_view.h>
#include <zxtest/base/parameterized-value.h>
#include <zxtest/base/runner.h>
namespace zxtest::internal {
// Templated version of ParameterizedTestCase. This class provides the implementation for the
// interface the registry relies on.
template <typename T, typename U>
class ParameterizedTestCaseInfoImpl : public ParameterizedTestCaseInfo {
public:
using FixtureType = T;
using ParamType = U;
// Returns a collection of factories for all registered tests of a test case.
using ParameterizedTestFactory =
fit::function<internal::TestFactory(fit::function<const ParamType&()>)>;
ParameterizedTestCaseInfoImpl() = default;
explicit ParameterizedTestCaseInfoImpl(const fbl::String& test_case_name)
: ParameterizedTestCaseInfo(test_case_name) {}
ParameterizedTestCaseInfoImpl(const ParameterizedTestCaseInfoImpl&) = delete;
ParameterizedTestCaseInfoImpl(ParameterizedTestCaseInfoImpl&&) = delete;
ParameterizedTestCaseInfoImpl& operator=(const ParameterizedTestCaseInfoImpl&) = delete;
ParameterizedTestCaseInfoImpl& operator=(ParameterizedTestCaseInfoImpl&&) = delete;
~ParameterizedTestCaseInfoImpl() override = default;
// Returns a unique Id representing the first fixture used to instantiate this Parametrized test
// case.
TypeId GetFixtureId() const final { return TypeIdProvider<FixtureType>::Get(); }
void AddInstantiation(const fbl::String& instantiation_name,
zxtest::internal::ValueProvider<ParamType>& provider,
const SourceLocation& location,
std::function<std::string(zxtest::TestParamInfo<ParamType>)> name_fn) {
instantiation_fns_.push_back([this, provider = std::move(provider), name_fn, location,
instantiation_name](Runner* runner) mutable {
Instantiate<FixtureType, ParamType>(instantiation_name, location, provider, name_fn, runner);
});
}
// Adds a test to the test case.
template <typename TestImpl>
void AddTest(const fbl::String& name, const SourceLocation& location) {
static_assert(std::is_base_of<FixtureType, TestImpl>::value,
"Must inherit from the same fixture to be part of the same test case.");
TestInfo info;
info.name = name;
info.location = location;
info.factory = &TestImpl::template CreateFactory<TestImpl>;
test_entries_.push_back(std::move(info));
}
// Registers all parametrized tests of this test case with |runner|.
void RegisterTest(Runner* runner) final {
for (auto& instantiation_fn : instantiation_fns_) {
instantiation_fn(runner);
}
}
private:
friend class ParameterizedTestCaseInfoImplTestPeer;
struct TestInfo {
fbl::String name;
SourceLocation location;
ParameterizedTestFactory factory;
};
template <typename TestImpl, typename ValueType>
void Instantiate(const fbl::String& instantiation_name, const SourceLocation& location,
zxtest::internal::ValueProvider<ValueType>& provider,
std::function<std::string(zxtest::TestParamInfo<ValueType>)> name_fn,
Runner* runner) {
for (size_t i = 0; i < provider.size(); ++i) {
zxtest::TestParamInfo<ValueType> info(provider[i], i);
for (auto& test_entry : test_entries_) {
// Add method for instantiation name as a param, and let the reporter decide how to
// print this.
std::initializer_list<fbl::String> prefix_name = {instantiation_name, fbl::String("/"),
name()};
std::initializer_list<fbl::String> test_name = {test_entry.name, fbl::String("/"),
name_fn(info)};
runner->RegisterTest<FixtureType, TestImpl>(
fbl::String::Concat(prefix_name), fbl::String::Concat(test_name),
test_entry.location.filename, static_cast<int>(test_entry.location.line_number),
test_entry.factory(
[&provider, i]() mutable -> const ValueType& { return provider[i]; }));
}
}
}
fbl::Vector<fit::function<void(Runner* runner)>> instantiation_fns_;
fbl::Vector<TestInfo> test_entries_;
fbl::String name_;
};
template <typename SuiteClass, typename Type, typename TestClass>
class AddTestDelegateImpl : public AddTestDelegate {
public:
std::unique_ptr<ParameterizedTestCaseInfo> CreateSuite(
const cpp17::string_view& suite_name) final {
return std::make_unique<ParameterizedTestCaseInfoImpl<SuiteClass, Type>>(suite_name);
}
bool AddTest(ParameterizedTestCaseInfo* base, const cpp17::string_view& test_name,
const SourceLocation& location) final {
ZX_ASSERT_MSG(base->GetFixtureId() == TypeIdProvider<SuiteClass>::Get(),
"ParameterizedTestCaseInfo type must match the suite type.");
ParameterizedTestCaseInfoImpl<SuiteClass, Type>* suite_impl =
reinterpret_cast<ParameterizedTestCaseInfoImpl<SuiteClass, Type>*>(base);
suite_impl->template AddTest<TestClass>(test_name, location);
return true;
}
};
template <typename SuiteClass, typename Type>
class AddInstantiationDelegateImpl : public AddInstantiationDelegate<Type> {
public:
bool AddInstantiation(ParameterizedTestCaseInfo* base, const fbl::String& instantiation_name,
const SourceLocation& location,
zxtest::internal::ValueProvider<Type>& provider,
std::function<std::string(zxtest::TestParamInfo<Type>)> name_fn) final {
ParameterizedTestCaseInfoImpl<SuiteClass, Type>* suite_impl =
reinterpret_cast<ParameterizedTestCaseInfoImpl<SuiteClass, Type>*>(base);
suite_impl->AddInstantiation(instantiation_name, provider, location, name_fn);
return true;
}
};
} // namespace zxtest::internal
#endif // ZXTEST_BASE_PARAMETERIZED_VALUE_IMPL_H_