<commit_before>#ifndef INC_METTLE_RUNNER_HPP
#define INC_METTLE_RUNNER_HPP

#include <fcntl.h>
#include <poll.h>
#include <sys/wait.h>

#include <chrono>
#include <thread>

#include "optional.hpp"
#include "scoped_pipe.hpp"
#include "suite.hpp"
#include "log/core.hpp"

namespace mettle {

using test_runner = std::function<
  test_result(const test_function &, log::test_output &)
>;

namespace detail {
  template<typename T>
  void run_tests_impl(const T &suites, log::test_logger &logger,
                      const test_runner &runner,
                      std::vector<std::string> &parents) {
    for(const auto &suite : suites) {
      parents.push_back(suite.name());

      logger.start_suite(parents);

      for(const auto &test : suite) {
        const log::test_name name = {parents, test.name, test.id};
        logger.start_test(name);

        if(test.skip) {
          logger.skipped_test(name);
          continue;
        }

        using namespace std::literals::chrono_literals;

        log::test_output output;
        auto result = runner(test.function, output);
        if(result.passed)
          logger.passed_test(name, output);
        else
          logger.failed_test(name, result.message, output);
      }

      logger.end_suite(parents);

      run_tests_impl(suite.subsuites(), logger, runner, parents);
      parents.pop_back();
    }
  }
}

class forked_test_runner {<commit_msg>Remove using decl<commit_after>#ifndef INC_METTLE_RUNNER_HPP
#define INC_METTLE_RUNNER_HPP

#include <fcntl.h>
#include <poll.h>
#include <sys/wait.h>

#include <chrono>
#include <thread>

#include "optional.hpp"
#include "scoped_pipe.hpp"
#include "suite.hpp"
#include "log/core.hpp"

namespace mettle {

using test_runner = std::function<
  test_result(const test_function &, log::test_output &)
>;

namespace detail {
  template<typename T>
  void run_tests_impl(const T &suites, log::test_logger &logger,
                      const test_runner &runner,
                      std::vector<std::string> &parents) {
    for(const auto &suite : suites) {
      parents.push_back(suite.name());

      logger.start_suite(parents);

      for(const auto &test : suite) {
        const log::test_name name = {parents, test.name, test.id};
        logger.start_test(name);

        if(test.skip) {
          logger.skipped_test(name);
          continue;
        }

        log::test_output output;
        auto result = runner(test.function, output);
        if(result.passed)
          logger.passed_test(name, output);
        else
          logger.failed_test(name, result.message, output);
      }

      logger.end_suite(parents);

      run_tests_impl(suite.subsuites(), logger, runner, parents);
      parents.pop_back();
    }
  }
}

class forked_test_runner {
{'fraction_non_alphanumeric': 0.1218109953287819, 'fraction_numerical': 0.0, 'mean_word_length': 2.9046283309957923, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '630793', 'n_tokens_mistral': 913, 'n_tokens_neox': 885, 'n_words': 177}