Skip to content

Commit 60f598c

Browse files
authored
feat: provide value like access to context and table for steps and hooks (#3)
* feat: separated step registry and macros, made all steps as a factory pattern, they are created when invoked * feat: separated hook registry and macros, made all hooks as a factory pattern, they are created when invoked * chore: fix clang-cl build
1 parent f6ce586 commit 60f598c

32 files changed

+960
-780
lines changed

cucumber-cpp-example/CMakeLists.txt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@ add_executable(cucumber-cpp-example ${CCR_EXCLUDE_FROM_ALL})
44

55
target_sources(cucumber-cpp-example PRIVATE
66
fixtures/Fixture.hpp
7-
hooks/hooks.cpp
8-
steps/steps.cpp
97
)
108

119
target_link_libraries(cucumber-cpp-example PRIVATE
1210
cucumber-cpp-runner
11+
cucumber-cpp-example.hooks
12+
cucumber-cpp-example.steps
1313
)
14+
15+
add_subdirectory(hooks)
16+
add_subdirectory(steps)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
set(CMAKE_COMPILE_WARNING_AS_ERROR On)
2+
3+
add_library(cucumber-cpp-example.hooks OBJECT ${CCR_EXCLUDE_FROM_ALL})
4+
5+
target_sources(cucumber-cpp-example.hooks PRIVATE
6+
hooks.cpp
7+
)
8+
9+
target_link_libraries(cucumber-cpp-example.hooks PRIVATE
10+
cucumber-cpp-runner
11+
)

cucumber-cpp-example/hooks/hooks.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,11 @@ HOOK_BEFORE_ALL()
2424
// spawn eventdispatcher
2525
}
2626

27-
HOOK_BEFORE()
27+
HOOK_BEFORE_SCENARIO()
2828
{
2929
}
3030

31-
HOOK_BEFORE_COND("@dingus")
31+
HOOK_BEFORE_SCENARIO("@dingus")
3232
{
3333
std::cout << "running only for dingus tests\n";
3434
}
@@ -41,7 +41,7 @@ HOOK_AFTER_STEP()
4141
{
4242
}
4343

44-
HOOK_AFTER()
44+
HOOK_AFTER_SCENARIO()
4545
{
4646
}
4747

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
set(CMAKE_COMPILE_WARNING_AS_ERROR On)
2+
3+
add_library(cucumber-cpp-example.steps OBJECT ${CCR_EXCLUDE_FROM_ALL})
4+
5+
target_sources(cucumber-cpp-example.steps PRIVATE
6+
steps.cpp
7+
)
8+
9+
target_link_libraries(cucumber-cpp-example.steps PRIVATE
10+
cucumber-cpp-runner
11+
)

cucumber-cpp-example/steps/steps.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,23 +16,23 @@ GIVEN(R"(a background step)")
1616

1717
GIVEN(R"(a simple data table)")
1818
{
19-
auto fixture = context->Get<NordicBleFixture>();
19+
auto fixture = context.Get<NordicBleFixture>();
2020
}
2121

2222
GIVEN(R"(there are ([0-9]+) cucumbers)", (std::uint32_t num))
2323
{
24-
context->InsertAt("cucumbers_before", num);
24+
context.InsertAt("cucumbers_before", num);
2525
}
2626

2727
STEP(R"(I eat {int} cucumbers)", (std::uint32_t num))
2828
{
29-
context->InsertAt("cucumbers_eaten", num);
29+
context.InsertAt("cucumbers_eaten", num);
3030
}
3131

3232
THEN(R"(^I should have ([0-9]+) cucumbers$)", (std::uint32_t num))
3333
{
34-
const auto& before = context->Get<std::uint32_t>("cucumbers_before");
35-
const auto& eaten = context->Get<std::uint32_t>("cucumbers_eaten");
34+
const auto& before = context.Get<std::uint32_t>("cucumbers_before");
35+
const auto& eaten = context.Get<std::uint32_t>("cucumbers_eaten");
3636

3737
const auto actual = before - eaten;
3838

@@ -41,8 +41,8 @@ THEN(R"(^I should have ([0-9]+) cucumbers$)", (std::uint32_t num))
4141

4242
THEN(R"(I should have ([0-9]+) cucumbers left)", (std::uint32_t num))
4343
{
44-
const auto& before = context->Get<std::uint32_t>("cucumbers_before");
45-
const auto& eaten = context->Get<std::uint32_t>("cucumbers_eaten");
44+
const auto& before = context.Get<std::uint32_t>("cucumbers_before");
45+
const auto& eaten = context.Get<std::uint32_t>("cucumbers_eaten");
4646

4747
const auto actual = before - eaten;
4848

cucumber-cpp/Application.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#include "cucumber-cpp/Application.hpp"
22
#include "cucumber-cpp/Context.hpp"
3-
#include "cucumber-cpp/FeatureRunner.hpp"
3+
#include "cucumber-cpp/CucumberRunner.hpp"
44
#include "cucumber-cpp/ResultStates.hpp"
55
#include "cucumber-cpp/report/JsonReport.hpp"
66
#include "cucumber-cpp/report/JunitReport.hpp"
@@ -186,7 +186,7 @@ namespace cucumber_cpp
186186

187187
const auto tagExpression = options.tags.empty() ? std::string() : std::accumulate(std::next(options.tags.begin()), options.tags.end(), std::string(options.tags.front()), JoinStringWithSpace);
188188

189-
CucumberRunner cucumberRunner{ GetForwardArgs(), hooks, stepRepository, tagExpression, contextStorageFactory };
189+
CucumberRunner cucumberRunner{ GetForwardArgs(), tagExpression, contextStorageFactory };
190190
cucumberRunner.Run(root);
191191

192192
if (!root.contains("result"))

cucumber-cpp/Application.hpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
#ifndef CUCUMBER_CPP_APPLICATION_HPP
22
#define CUCUMBER_CPP_APPLICATION_HPP
33

4-
#include "cucumber-cpp/CucumberRunner.hpp"
54
#include "cucumber-cpp/Hooks.hpp"
6-
#include "cucumber-cpp/Steps.hpp"
75
#include "cucumber-cpp/report/Report.hpp"
86
#include "gherkin/app.hpp"
97
#include <map>
@@ -38,9 +36,6 @@ namespace cucumber_cpp
3836
Options options;
3937
nlohmann::json root;
4038

41-
cucumber_cpp::Hooks hooks;
42-
cucumber_cpp::StepRepository stepRepository;
43-
4439
gherkin::app app;
4540
gherkin::app::callbacks cbs;
4641
};

cucumber-cpp/Body.hpp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#ifndef CUCUMBER_CPP_BODY_HPP
2+
#define CUCUMBER_CPP_BODY_HPP
3+
4+
#include "nlohmann/json.hpp"
5+
#include <cstddef>
6+
#include <utility>
7+
8+
namespace cucumber_cpp
9+
{
10+
template<class To>
11+
inline To StringTo(const std::string& s)
12+
{
13+
std::istringstream stream{ s };
14+
To to;
15+
stream >> to;
16+
if (stream.fail())
17+
{
18+
throw std::invalid_argument("Cannot convert parameter");
19+
}
20+
return to;
21+
}
22+
23+
template<>
24+
inline std::string StringTo<std::string>(const std::string& s)
25+
{
26+
return s;
27+
}
28+
29+
struct Body
30+
{
31+
virtual ~Body() = default;
32+
33+
virtual void Execute(const nlohmann::json& parameters = {}) = 0;
34+
35+
protected:
36+
template<class T, class... Args, std::size_t... I>
37+
void InvokeWithArgImpl(T* t, const nlohmann::json& json, void (T::*ptr)(Args...), std::index_sequence<I...>)
38+
{
39+
(t->*ptr)(StringTo<Args>(json[I])...);
40+
}
41+
42+
template<class T, class... Args>
43+
void InvokeWithArg(T* t, const nlohmann::json& json, void (T::*ptr)(Args...))
44+
{
45+
InvokeWithArgImpl(t, json, ptr, std::make_index_sequence<sizeof...(Args)>{});
46+
}
47+
};
48+
}
49+
50+
#endif

cucumber-cpp/BodyMacro.hpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#ifndef CUCUMBER_CPP_BODYMACRO_HPP
2+
#define CUCUMBER_CPP_BODYMACRO_HPP
3+
4+
#include "cucumber-cpp/Body.hpp"
5+
6+
#define BODY_MATCHER(matcher, ...) matcher
7+
#define BODY_ARGS(matcher, args, ...) args
8+
9+
#define CONCAT_(lhs, rhs) lhs##rhs
10+
#define CONCAT(lhs, rhs) CONCAT_(lhs, rhs)
11+
12+
#define BODY_STRUCT CONCAT(BodyImpl, __LINE__)
13+
14+
#define BODY(matcher, type, args, registration, base) \
15+
namespace \
16+
{ \
17+
struct BODY_STRUCT : cucumber_cpp::Body \
18+
, cucumber_cpp::base \
19+
{ \
20+
using cucumber_cpp::base::base; \
21+
void Execute(const nlohmann::json& parameters = {}) override \
22+
{ \
23+
InvokeWithArg(this, parameters, &BODY_STRUCT::ExecuteWithArgs); \
24+
} \
25+
\
26+
private: \
27+
void ExecuteWithArgs args; \
28+
static std::size_t ID; \
29+
}; \
30+
} \
31+
std::size_t BODY_STRUCT::ID = cucumber_cpp::registration<BODY_STRUCT>(matcher, type); \
32+
void BODY_STRUCT::ExecuteWithArgs args
33+
34+
#endif

cucumber-cpp/CMakeLists.txt

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,31 @@ add_library(cucumber-cpp STATIC ${CCR_EXCLUDE_FROM_ALL})
55
target_sources(cucumber-cpp PRIVATE
66
Application.cpp
77
Application.hpp
8+
BodyMacro.hpp
9+
Body.hpp
810
Context.hpp
911
CucumberRunner.cpp
1012
CucumberRunner.hpp
1113
FeatureRunner.cpp
1214
FeatureRunner.hpp
13-
Hooks.cpp
15+
HookRegistry.cpp
16+
HookRegistry.hpp
1417
Hooks.hpp
18+
HookScopes.cpp
19+
HookScopes.hpp
20+
JsonTagToSet.cpp
21+
JsonTagToSet.hpp
1522
OnTestPartResultEventListener.cpp
1623
OnTestPartResultEventListener.hpp
1724
Rtrim.cpp
1825
Rtrim.hpp
1926
ScenarioRunner.cpp
2027
ScenarioRunner.hpp
28+
Steps.hpp
29+
StepRegistry.cpp
30+
StepRegistry.hpp
2131
StepRunner.cpp
2232
StepRunner.hpp
23-
Steps.cpp
24-
Steps.hpp
2533
TagExpression.cpp
2634
TagExpression.hpp
2735
TraceTime.cpp

cucumber-cpp/CucumberRunner.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,30 @@
11
#include "cucumber-cpp/CucumberRunner.hpp"
22
#include "cucumber-cpp/FeatureRunner.hpp"
3+
#include "cucumber-cpp/HookScopes.hpp"
34
#include "cucumber-cpp/ResultStates.hpp"
45
#include "cucumber-cpp/ScenarioRunner.hpp"
56
#include "cucumber-cpp/TraceTime.hpp"
7+
#include "nlohmann/json.hpp"
68
#include "nlohmann/json_fwd.hpp"
79

810
namespace cucumber_cpp
911
{
10-
CucumberRunner::CucumberRunner(const std::vector<std::string_view>& args, Hooks& hooks, StepRepository& stepRepository, const std::string& tagExpr, std::shared_ptr<ContextStorageFactory> contextStorageFactory)
11-
: hooks{ hooks }
12-
, stepRepository{ stepRepository }
13-
, tagExpr{ tagExpr }
12+
CucumberRunner::CucumberRunner(const std::vector<std::string_view>& args, const std::string& tagExpr, std::shared_ptr<ContextStorageFactory> contextStorageFactory)
13+
: tagExpr{ tagExpr }
1414
, programContext(contextStorageFactory)
1515
{
1616
programContext.InsertAt("args", args);
1717
}
1818

1919
void CucumberRunner::Run(nlohmann::json& json)
2020
{
21-
BeforeAfterAllScope programHookeScope{ hooks, programContext };
21+
BeforeAfterAllScope programHookeScope{ programContext };
2222

2323
double totalTime = 0.0;
2424

2525
std::ranges::for_each(json["features"], [this, &json, &totalTime](nlohmann::json& featureJson)
2626
{
27-
FeatureRunner featureRunner{ hooks, stepRepository, programContext, tagExpr };
27+
FeatureRunner featureRunner{ programContext, tagExpr };
2828
featureRunner.Run(featureJson);
2929

3030
totalTime += featureJson.value("elapsed", 0.0);

cucumber-cpp/CucumberRunner.hpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
#include "cucumber-cpp/Context.hpp"
55
#include "cucumber-cpp/Hooks.hpp"
6-
#include "cucumber-cpp/Steps.hpp"
76
#include "nlohmann/json_fwd.hpp"
87
#include <memory>
98
#include <string>
@@ -12,13 +11,11 @@ namespace cucumber_cpp
1211
{
1312
struct CucumberRunner
1413
{
15-
CucumberRunner(const std::vector<std::string_view>& args, Hooks& hooks, StepRepository& stepRepository, const std::string& tagExpr, std::shared_ptr<ContextStorageFactory> contextStorageFactory);
14+
CucumberRunner(const std::vector<std::string_view>& args, const std::string& tagExpr, std::shared_ptr<ContextStorageFactory> contextStorageFactory);
1615

1716
void Run(nlohmann::json& json);
1817

1918
private:
20-
Hooks& hooks;
21-
StepRepository& stepRepository;
2219
std::string tagExpr;
2320
Context programContext;
2421
};

cucumber-cpp/FeatureRunner.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,24 @@
11
#include "cucumber-cpp/FeatureRunner.hpp"
2-
#include "cucumber-cpp/Hooks.hpp"
2+
#include "cucumber-cpp/HookScopes.hpp"
3+
#include "cucumber-cpp/JsonTagToSet.hpp"
34
#include "cucumber-cpp/ResultStates.hpp"
45
#include "cucumber-cpp/ScenarioRunner.hpp"
56
#include "cucumber-cpp/TagExpression.hpp"
67
#include "cucumber-cpp/TraceTime.hpp"
8+
#include "nlohmann/json.hpp"
79
#include <iomanip>
810
#include <ranges>
911

1012
namespace cucumber_cpp
1113
{
12-
FeatureRunner::FeatureRunner(Hooks& hooks, StepRepository& stepRepository, Context& programContext, const std::string& tagExpr)
13-
: hooks{ hooks }
14-
, tagExpr{ tagExpr }
15-
, stepRepository{ stepRepository }
14+
FeatureRunner::FeatureRunner(Context& programContext, const std::string& tagExpr)
15+
: tagExpr{ tagExpr }
1616
, featureContext{ &programContext }
1717
{}
1818

1919
void FeatureRunner::Run(nlohmann::json& json)
2020
{
21-
BeforeAfterFeatureHookScope featureHookScope{ hooks, featureContext, json };
21+
BeforeAfterFeatureHookScope featureHookScope{ featureContext, JsonTagsToSet(json["ast"]["feature"]["tags"]) };
2222

2323
const auto isTagExprSelected = [this](const auto& json)
2424
{
@@ -28,7 +28,7 @@ namespace cucumber_cpp
2828
double totalTime = 0.0;
2929
std::ranges::for_each(json["scenarios"] | std::views::filter(isTagExprSelected), [this, &json, &totalTime](nlohmann::json& scenarioJson)
3030
{
31-
ScenarioRunner scenarioRunner{ hooks, stepRepository, featureContext };
31+
ScenarioRunner scenarioRunner{ featureContext };
3232
scenarioRunner.Run(scenarioJson);
3333

3434
totalTime += scenarioJson.value("elapsed", 0.0);

cucumber-cpp/FeatureRunner.hpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,17 @@
22
#define CUCUMBER_CPP_FEATURERUNNER_HPP
33

44
#include "cucumber-cpp/Hooks.hpp"
5-
#include "cucumber-cpp/Steps.hpp"
65
#include <string>
76

87
namespace cucumber_cpp
98
{
109
struct FeatureRunner
1110
{
12-
FeatureRunner(Hooks& hooks, StepRepository& stepRepository, Context& programContext, const std::string& tagExpr);
11+
FeatureRunner(Context& programContext, const std::string& tagExpr);
1312

1413
void Run(nlohmann::json& json);
1514

1615
private:
17-
Hooks& hooks;
18-
StepRepository& stepRepository;
1916
std::string tagExpr;
2017
Context featureContext;
2118
};

0 commit comments

Comments
 (0)