// 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_
