Echo Writes Code

suite.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#include "crucible/test/suite.hpp"

#include <memory>

namespace crucible::test::suite
{
  struct Suite::ConstructorPermission {};

  auto Suite::get_reference() -> Suite &
  {
    static auto instance { std::make_unique<Suite>(ConstructorPermission()) };
    return *instance;
  }

  Suite::Suite(ConstructorPermission const &)
  {}

  auto Suite::set_name(std::string const &name) -> void
  {
    my_name = name;
  }

  auto Suite::set_group_filter(std::set<core::string::String> const &group_filter) -> void 
  {
    my_group_filter = group_filter;
  }

  auto Suite::add_scenario(std::string const &group, std::string const &name, test::scenario::ScenarioFunction const &function) -> void
  {
    auto emplace_result { my_scenarios_by_group.emplace(group, core::memory::make_heap_buffer<test::scenario::Scenario>()) };
    auto &iterator { emplace_result.first };
    auto &scenario_list { iterator->second };
    scenario_list.push(group, name, function);
  }

  auto Suite::execute(test::reporter::Reporter &reporter) -> bool
  {
    if (my_scenarios_by_group.empty()) {
      reporter.handle_empty_suite(my_name);
      return true;
    }

    reporter.handle_suite_start(my_name);
    execute_scenarios(reporter);
    reporter.handle_suite_end(my_pass_count, my_fail_count, my_scenario_count, my_fixture_count);

    return my_fail_count == 0;
  }

  auto Suite::execute_scenarios(test::reporter::Reporter &reporter) -> void
  {
    for (auto &pair : my_scenarios_by_group) {
      auto const &group = pair.first;

      auto const execute_scenario {
        [&group, &reporter, this](test::scenario::Scenario const &scenario) {
          execute_fixtures_with_group<test::fixture::BeforeEach>(group, reporter);
          reporter.handle_scenario_start(scenario);

          auto const outcome { scenario.execute() };

          reporter.handle_scenario_end(scenario, outcome);
          execute_fixtures_with_group<test::fixture::AfterEach>(group, reporter);

          ++my_scenario_count;

          if (outcome.passed()) {
            ++my_pass_count;
            return;
          }

          ++my_fail_count;
        }
      };

      auto const hack { core::string::make_string_from_char_array(group.data(), group.size()) };

      bool const do_filtering { !my_group_filter.empty() };
      bool const is_filtered_out { my_group_filter.find(hack) == my_group_filter.end() };

      if (do_filtering && is_filtered_out) {
        continue;
      }

      execute_fixtures_with_group<test::fixture::BeforeAll>(group, reporter);
      reporter.handle_group_start(group);

      auto &scenario_list { pair.second };

      core::iterators::iterate(scenario_list)
        .consume(execute_scenario);

      reporter.handle_group_end(group);
      execute_fixtures_with_group<test::fixture::AfterAll>(group, reporter);
    }
  }

  ScenarioRegistrar::ScenarioRegistrar(std::string const &group, std::string const &name, test::scenario::ScenarioFunction const &test)
  {
    auto &suite { Suite::get_reference() };
    suite.add_scenario(group, name, test);
  }
}