Skip to content

Commit 9a4615f

Browse files
daantimmeralextech
andauthored
feat: add gherkin doc string support (#214)
* Add gherkin doc string support * Add gherkin doc string support - string move * Add gherkin doc string support - missed doctype parameter in tests --------- Co-authored-by: Alexander Romanenko <[email protected]>
1 parent 5eea664 commit 9a4615f

File tree

17 files changed

+73
-34
lines changed

17 files changed

+73
-34
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
Feature: Doc Strings
2+
3+
Scenario: Multiline doc strings
4+
Given Next block of text enclosed in """ characters
5+
"""
6+
Multiline
7+
Docstring
8+
"""

cucumber_cpp/acceptance_test/steps/Steps.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,9 @@ THEN("this should be skipped")
5454
{
5555
FAIL();
5656
}
57+
58+
GIVEN("Next block of text enclosed in \"\"\" characters")
59+
{
60+
61+
ASSERT_THAT(docString, testing::Eq("Multiline\nDocstring"));
62+
}

cucumber_cpp/library/StepRegistry.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ namespace cucumber_cpp::library
6464
return list;
6565
}
6666

67-
void StepRegistry::Register(const std::string& matcher, engine::StepType stepType, std::unique_ptr<Body> (&factory)(Context& context, const engine::Table& table))
67+
void StepRegistry::Register(const std::string& matcher, engine::StepType stepType, std::unique_ptr<Body> (&factory)(Context& context, const engine::Table& table, const std::string& docString))
6868
{
6969
if (matcher.starts_with('^') || matcher.ends_with('$'))
7070
registry.emplace_back(stepType, cucumber_expression::Matcher{ std::in_place_type<cucumber_expression::RegularExpression>, matcher }, factory);

cucumber_cpp/library/StepRegistry.hpp

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
#include "cucumber_cpp/library/engine/StepType.hpp"
99
#include "cucumber_cpp/library/engine/Table.hpp"
1010
#include <any>
11-
#include <cstddef>
1211
#include <cstdint>
1312
#include <exception>
1413
#include <memory>
@@ -22,20 +21,20 @@
2221
namespace cucumber_cpp::library
2322
{
2423
template<class T>
25-
std::unique_ptr<Body> StepBodyFactory(Context& context, const engine::Table& table)
24+
std::unique_ptr<Body> StepBodyFactory(Context& context, const engine::Table& table, const std::string& docString)
2625
{
27-
return std::make_unique<T>(context, table);
26+
return std::make_unique<T>(context, table, docString);
2827
}
2928

3029
struct StepMatch
3130
{
32-
StepMatch(std::unique_ptr<Body> (&factory)(Context& context, const engine::Table& table), std::variant<std::vector<std::string>, std::vector<std::any>> matches, std::string_view stepRegexStr)
31+
StepMatch(std::unique_ptr<Body> (&factory)(Context& context, const engine::Table& table, const std::string& docString), std::variant<std::vector<std::string>, std::vector<std::any>> matches, std::string_view stepRegexStr)
3332
: factory(factory)
3433
, matches(std::move(matches))
3534
, stepRegexStr(stepRegexStr)
3635
{}
3736

38-
std::unique_ptr<Body> (&factory)(Context& context, const engine::Table& table);
37+
std::unique_ptr<Body> (&factory)(Context& context, const engine::Table& table, const std::string& docString);
3938
std::variant<std::vector<std::string>, std::vector<std::any>> matches{};
4039
std::string_view stepRegexStr{};
4140
};
@@ -58,15 +57,15 @@ namespace cucumber_cpp::library
5857

5958
struct Entry
6059
{
61-
Entry(engine::StepType type, cucumber_expression::Matcher regex, std::unique_ptr<Body> (&factory)(Context& context, const engine::Table& table))
60+
Entry(engine::StepType type, cucumber_expression::Matcher regex, std::unique_ptr<Body> (&factory)(Context& context, const engine::Table& table, const std::string& docString))
6261
: type(type)
6362
, regex(std::move(regex))
6463
, factory(factory)
6564
{}
6665

6766
engine::StepType type{};
6867
cucumber_expression::Matcher regex;
69-
std::unique_ptr<Body> (&factory)(Context& context, const engine::Table& table);
68+
std::unique_ptr<Body> (&factory)(Context& context, const engine::Table& table, const std::string& docString);
7069

7170
std::uint32_t used{ 0 };
7271
};
@@ -91,7 +90,7 @@ namespace cucumber_cpp::library
9190
[[nodiscard]] std::vector<EntryView> List() const;
9291

9392
private:
94-
void Register(const std::string& matcher, engine::StepType stepType, std::unique_ptr<Body> (&factory)(Context& context, const engine::Table& table));
93+
void Register(const std::string& matcher, engine::StepType stepType, std::unique_ptr<Body> (&factory)(Context& context, const engine::Table& table, const std::string& docString));
9594

9695
std::vector<Entry> registry;
9796
cucumber_expression::ParameterRegistry& parameterRegistry;
@@ -107,15 +106,15 @@ namespace cucumber_cpp::library
107106

108107
struct Entry
109108
{
110-
Entry(engine::StepType type, std::string regex, std::unique_ptr<Body> (&factory)(Context& context, const engine::Table& table))
109+
Entry(engine::StepType type, std::string regex, std::unique_ptr<Body> (&factory)(Context& context, const engine::Table& table, const std::string& docString))
111110
: type(type)
112111
, regex(std::move(regex))
113112
, factory(factory)
114113
{}
115114

116115
engine::StepType type{};
117116
std::string regex;
118-
std::unique_ptr<Body> (&factory)(Context& context, const engine::Table& table);
117+
std::unique_ptr<Body> (&factory)(Context& context, const engine::Table& table, const std::string& docString);
119118
};
120119

121120
template<class T>

cucumber_cpp/library/engine/FeatureFactory.cpp

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ namespace cucumber_cpp::library::engine
124124
return table;
125125

126126
for (const auto& dataTable = optionalPickleStepArgument.value().data_table.value();
127-
const auto& row : dataTable.rows)
127+
const auto& row : dataTable.rows)
128128
{
129129
table.emplace_back();
130130
auto& back = table.back();
@@ -136,6 +136,17 @@ namespace cucumber_cpp::library::engine
136136
return table;
137137
}
138138

139+
std::string DocStringFactory(const std::optional<cucumber::messages::pickle_step_argument>& optionalPickleStepArgument)
140+
{
141+
if (!optionalPickleStepArgument)
142+
return "";
143+
144+
if (!optionalPickleStepArgument.value().doc_string.has_value())
145+
return "";
146+
147+
return optionalPickleStepArgument.value().doc_string.value().content;
148+
}
149+
139150
std::set<std::string, std::less<>> TagsFactory(const std::vector<cucumber::messages::tag>& tags)
140151
{
141152
const auto range = tags | std::views::transform(&cucumber::messages::tag::name);
@@ -151,10 +162,11 @@ namespace cucumber_cpp::library::engine
151162
void ConstructStep(const FeatureTreeFactory& featureTreeFactory, ScenarioInfo& scenarioInfo, const cucumber::messages::step& step, const cucumber::messages::pickle_step& pickleStep)
152163
{
153164
auto table = TableFactory(pickleStep.argument);
165+
auto docString = DocStringFactory(pickleStep.argument);
154166

155167
try
156168
{
157-
scenarioInfo.Children().push_back(featureTreeFactory.CreateStepInfo(stepTypeLut.at(*pickleStep.type), pickleStep.text, scenarioInfo, step.location.line, step.location.column.value_or(0), std::move(table)));
169+
scenarioInfo.Children().push_back(featureTreeFactory.CreateStepInfo(stepTypeLut.at(*pickleStep.type), pickleStep.text, scenarioInfo, step.location.line, step.location.column.value_or(0), std::move(table), std::move(docString)));
158170
}
159171
catch (const std::out_of_range&)
160172
{
@@ -287,20 +299,20 @@ namespace cucumber_cpp::library::engine
287299
: stepRegistry{ stepRegistry }
288300
{}
289301

290-
std::unique_ptr<StepInfo> FeatureTreeFactory::CreateStepInfo(StepType stepType, std::string stepText, const ScenarioInfo& scenarioInfo, std::size_t line, std::size_t column, std::vector<std::vector<TableValue>> table) const
302+
std::unique_ptr<StepInfo> FeatureTreeFactory::CreateStepInfo(StepType stepType, std::string stepText, const ScenarioInfo& scenarioInfo, std::size_t line, std::size_t column, std::vector<std::vector<TableValue>> table, std::string docString) const
291303
{
292304
try
293305
{
294306
auto stepMatch = stepRegistry.Query(stepText);
295-
return std::make_unique<StepInfo>(scenarioInfo, std::move(stepText), stepType, line, column, std::move(table), std::move(stepMatch));
307+
return std::make_unique<StepInfo>(scenarioInfo, std::move(stepText), stepType, line, column, std::move(table), std::move(docString), std::move(stepMatch));
296308
}
297309
catch (const StepRegistry::StepNotFoundError&)
298310
{
299-
return std::make_unique<StepInfo>(scenarioInfo, std::move(stepText), stepType, line, column, std::move(table));
311+
return std::make_unique<StepInfo>(scenarioInfo, std::move(stepText), stepType, line, column, std::move(table), std::move(docString));
300312
}
301313
catch (StepRegistry::AmbiguousStepError& ase)
302314
{
303-
return std::make_unique<StepInfo>(scenarioInfo, std::move(stepText), stepType, line, column, std::move(table), std::move(ase.matches));
315+
return std::make_unique<StepInfo>(scenarioInfo, std::move(stepText), stepType, line, column, std::move(table), std::move(docString), std::move(ase.matches));
304316
}
305317
}
306318

cucumber_cpp/library/engine/FeatureFactory.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ namespace cucumber_cpp::library::engine
2020
{
2121
explicit FeatureTreeFactory(StepRegistry& stepRegistry);
2222

23-
[[nodiscard]] std::unique_ptr<StepInfo> CreateStepInfo(StepType stepType, std::string stepText, const ScenarioInfo& scenarioInfo, std::size_t line, std::size_t column, std::vector<std::vector<TableValue>> table) const;
23+
[[nodiscard]] std::unique_ptr<StepInfo> CreateStepInfo(StepType stepType, std::string stepText, const ScenarioInfo& scenarioInfo, std::size_t line, std::size_t column, std::vector<std::vector<TableValue>> table, std::string docString) const;
2424

2525
[[nodiscard]] std::unique_ptr<FeatureInfo> Create(const std::filesystem::path& path, std::string_view tagExpression) const;
2626

cucumber_cpp/library/engine/Step.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@
88

99
namespace cucumber_cpp::library::engine
1010
{
11-
Step::Step(Context& context, const Table& table)
11+
Step::Step(Context& context, const Table& table, const std::string& docString)
1212
: context{ context }
1313
, table{ table }
14+
, docString{ docString }
1415
{}
1516

1617
void Step::Given(const std::string& step) const

cucumber_cpp/library/engine/Step.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ namespace cucumber_cpp::library::engine
2424
std::source_location sourceLocation;
2525
};
2626

27-
Step(Context& context, const Table& table);
27+
Step(Context& context, const Table& table, const std::string& docString);
2828
virtual ~Step() = default;
2929

3030
virtual void SetUp()
@@ -46,6 +46,7 @@ namespace cucumber_cpp::library::engine
4646

4747
Context& context;
4848
const Table& table;
49+
const std::string& docString;
4950
};
5051
}
5152

cucumber_cpp/library/engine/StepInfo.cpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,34 +10,37 @@
1010

1111
namespace cucumber_cpp::library::engine
1212
{
13-
StepInfo::StepInfo(const struct ScenarioInfo& scenarioInfo, std::string text, StepType type, std::size_t line, std::size_t column, std::vector<std::vector<TableValue>> table)
13+
StepInfo::StepInfo(const struct ScenarioInfo& scenarioInfo, std::string text, StepType type, std::size_t line, std::size_t column, std::vector<std::vector<TableValue>> table, std::string docString)
1414
: scenarioInfo{ scenarioInfo }
1515
, text{ std::move(text) }
1616
, type{ type }
1717
, line{ line }
1818
, column{ column }
1919
, table{ std::move(table) }
20+
, docString{ std::move(docString) }
2021
{
2122
}
2223

23-
StepInfo::StepInfo(const struct ScenarioInfo& scenarioInfo, std::string text, StepType type, std::size_t line, std::size_t column, std::vector<std::vector<TableValue>> table, struct StepMatch stepMatch)
24+
StepInfo::StepInfo(const struct ScenarioInfo& scenarioInfo, std::string text, StepType type, std::size_t line, std::size_t column, std::vector<std::vector<TableValue>> table, std::string docString, struct StepMatch stepMatch)
2425
: scenarioInfo{ scenarioInfo }
2526
, text{ std::move(text) }
2627
, type{ type }
2728
, line{ line }
2829
, column{ column }
2930
, table{ std::move(table) }
31+
, docString{ std::move(docString) }
3032
, stepMatch{ std::move(stepMatch) }
3133
{
3234
}
3335

34-
StepInfo::StepInfo(const struct ScenarioInfo& scenarioInfo, std::string text, StepType type, std::size_t line, std::size_t column, std::vector<std::vector<TableValue>> table, std::vector<struct StepMatch> stepMatches)
36+
StepInfo::StepInfo(const struct ScenarioInfo& scenarioInfo, std::string text, StepType type, std::size_t line, std::size_t column, std::vector<std::vector<TableValue>> table, std::string docString, std::vector<struct StepMatch> stepMatches)
3537
: scenarioInfo{ scenarioInfo }
3638
, text{ std::move(text) }
3739
, type{ type }
3840
, line{ line }
3941
, column{ column }
4042
, table{ std::move(table) }
43+
, docString{ std::move(docString) }
4144
, stepMatch{ std::move(stepMatches) }
4245
{
4346
}
@@ -72,6 +75,11 @@ namespace cucumber_cpp::library::engine
7275
return table;
7376
}
7477

78+
const std::string& StepInfo::DocString() const
79+
{
80+
return docString;
81+
}
82+
7583
const std::variant<std::monostate, struct StepMatch, std::vector<struct StepMatch>>& StepInfo::StepMatch() const
7684
{
7785
return stepMatch;

cucumber_cpp/library/engine/StepInfo.hpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ namespace cucumber_cpp::library::engine
1616

1717
struct StepInfo
1818
{
19-
StepInfo(const struct ScenarioInfo& scenarioInfo, std::string text, StepType type, std::size_t line, std::size_t column, std::vector<std::vector<TableValue>> table);
20-
StepInfo(const struct ScenarioInfo& scenarioInfo, std::string text, StepType type, std::size_t line, std::size_t column, std::vector<std::vector<TableValue>> table, StepMatch);
21-
StepInfo(const struct ScenarioInfo& scenarioInfo, std::string text, StepType type, std::size_t line, std::size_t column, std::vector<std::vector<TableValue>> table, std::vector<StepMatch>);
19+
StepInfo(const struct ScenarioInfo& scenarioInfo, std::string text, StepType type, std::size_t line, std::size_t column, std::vector<std::vector<TableValue>> table, std::string docString);
20+
StepInfo(const struct ScenarioInfo& scenarioInfo, std::string text, StepType type, std::size_t line, std::size_t column, std::vector<std::vector<TableValue>> table, std::string docString, StepMatch);
21+
StepInfo(const struct ScenarioInfo& scenarioInfo, std::string text, StepType type, std::size_t line, std::size_t column, std::vector<std::vector<TableValue>> table, std::string docString, std::vector<StepMatch>);
2222

2323
[[nodiscard]] const struct ScenarioInfo& ScenarioInfo() const;
2424

@@ -29,6 +29,7 @@ namespace cucumber_cpp::library::engine
2929
[[nodiscard]] std::size_t Column() const;
3030

3131
[[nodiscard]] const std::vector<std::vector<TableValue>>& Table() const;
32+
[[nodiscard]] const std::string& DocString() const;
3233
[[nodiscard]] const std::variant<std::monostate, struct StepMatch, std::vector<struct StepMatch>>& StepMatch() const;
3334

3435
private:
@@ -41,6 +42,7 @@ namespace cucumber_cpp::library::engine
4142
std::size_t column;
4243

4344
std::vector<std::vector<TableValue>> table;
45+
std::string docString;
4446
std::variant<std::monostate, struct StepMatch, std::vector<struct StepMatch>> stepMatch;
4547
};
4648

0 commit comments

Comments
 (0)