/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
 * Copyright (c) 2014-2022,  Regents of the University of California,
 *                           Arizona Board of Regents,
 *                           Colorado State University,
 *                           University Pierre & Marie Curie, Sorbonne University,
 *                           Washington University in St. Louis,
 *                           Beijing Institute of Technology,
 *                           The University of Memphis.
 *
 * This file is part of NFD (Named Data Networking Forwarding Daemon).
 * See AUTHORS.md for complete list of NFD authors and contributors.
 *
 * NFD is free software: you can redistribute it and/or modify it under the terms
 * of the GNU General Public License as published by the Free Software Foundation,
 * either version 3 of the License, or (at your option) any later version.
 *
 * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 * PURPOSE.  See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef NFD_TESTS_DAEMON_FW_STRATEGY_TESTER_HPP
#define NFD_TESTS_DAEMON_FW_STRATEGY_TESTER_HPP

#include "fw/strategy.hpp"

#include "tests/daemon/limited-io.hpp"

namespace nfd::tests {

/** \brief Extends strategy S for unit testing.
 *
 *  Actions invoked by S are recorded but not passed to forwarder.
 *
 *  StrategyTester should be registered into the strategy registry prior to use.
 *  \code
 *  // appears in or included by every .cpp MyStrategyTester is used
 *  using MyStrategyTester = StrategyTester<MyStrategy>;
 *
 *  // appears in only one .cpp
 *  NFD_REGISTER_STRATEGY(MyStrategyTester);
 *  \endcode
 */
template<typename S>
class StrategyTester : public S
{
public:
  using S::S;

  static Name
  getStrategyName()
  {
    Name name = S::getStrategyName();
    if (!name.empty() && name[-1].isVersion()) {
      // insert "tester" before version component
      name::Component versionComp = name[-1];
      name = name.getPrefix(-1);
      name.append("tester");
      name.append(versionComp);
    }
    else {
      name.append("tester");
    }
    return name;
  }

  /** \brief Signal emitted after each action.
   */
  signal::Signal<StrategyTester<S>> afterAction;

  /** \brief Execute f and wait for a number of strategy actions.
   *  \note The actions may occur either during f() invocation or afterwards.
   *  \return whether expected number of actions have occurred
   */
  template<typename F>
  bool
  waitForAction(F&& f, LimitedIo& limitedIo, int nExpectedActions = 1)
  {
    int nActions = 0;

    signal::ScopedConnection conn = afterAction.connect([&] {
      limitedIo.afterOp();
      ++nActions;
    });

    std::invoke(std::forward<F>(f));

    if (nActions < nExpectedActions) {
      // If strategy doesn't forward anything (e.g., decides not to forward an Interest), the number
      // of expected actions should be 0; otherwise the test will get stuck.
      return limitedIo.run(nExpectedActions - nActions, LimitedIo::UNLIMITED_TIME) == LimitedIo::EXCEED_OPS;
    }
    return nActions == nExpectedActions;
  }

protected:
  pit::OutRecord*
  sendInterest(const Interest& interest, Face& egress,
               const shared_ptr<pit::Entry>& pitEntry) override
  {
    sendInterestHistory.push_back({pitEntry->getInterest(), egress.getId(), interest});
    auto it = pitEntry->insertOrUpdateOutRecord(egress, interest);
    BOOST_ASSERT(it != pitEntry->out_end());
    afterAction();
    return &*it;
  }

  void
  rejectPendingInterest(const shared_ptr<pit::Entry>& pitEntry) override
  {
    rejectPendingInterestHistory.push_back({pitEntry->getInterest()});
    afterAction();
  }

  bool
  sendNack(const lp::NackHeader& header, Face& egress,
           const shared_ptr<pit::Entry>& pitEntry) override
  {
    sendNackHistory.push_back({pitEntry->getInterest(), egress.getId(), header});
    pitEntry->deleteInRecord(egress);
    afterAction();
    return true;
  }

public:
  struct SendInterestArgs
  {
    Interest pitInterest;
    FaceId outFaceId;
    Interest interest;
  };
  std::vector<SendInterestArgs> sendInterestHistory;

  struct RejectPendingInterestArgs
  {
    Interest pitInterest;
  };
  std::vector<RejectPendingInterestArgs> rejectPendingInterestHistory;

  struct SendNackArgs
  {
    Interest pitInterest;
    FaceId outFaceId;
    lp::NackHeader header;
  };
  std::vector<SendNackArgs> sendNackHistory;
};

} // namespace nfd::tests

#endif // NFD_TESTS_DAEMON_FW_STRATEGY_TESTER_HPP
