diff --git a/cucumber_cpp/acceptance_test/features/test_doc_strings.feature b/cucumber_cpp/acceptance_test/features/test_doc_strings.feature
new file mode 100644
index 00000000..88659432
--- /dev/null
+++ b/cucumber_cpp/acceptance_test/features/test_doc_strings.feature
@@ -0,0 +1,8 @@
+Feature: Doc Strings
+
+ Scenario: Multiline doc strings
+ Given Next block of text enclosed in """ characters
+ """
+ Multiline
+ Docstring
+ """
diff --git a/cucumber_cpp/acceptance_test/steps/Steps.cpp b/cucumber_cpp/acceptance_test/steps/Steps.cpp
index fc55018d..2d2033ac 100644
--- a/cucumber_cpp/acceptance_test/steps/Steps.cpp
+++ b/cucumber_cpp/acceptance_test/steps/Steps.cpp
@@ -54,3 +54,9 @@ THEN("this should be skipped")
{
FAIL();
}
+
+GIVEN("Next block of text enclosed in \"\"\" characters")
+{
+
+ ASSERT_THAT(docString, testing::Eq("Multiline\nDocstring"));
+}
diff --git a/cucumber_cpp/library/StepRegistry.cpp b/cucumber_cpp/library/StepRegistry.cpp
index 336dc5d2..0e9ef169 100644
--- a/cucumber_cpp/library/StepRegistry.cpp
+++ b/cucumber_cpp/library/StepRegistry.cpp
@@ -64,7 +64,7 @@ namespace cucumber_cpp::library
return list;
}
- void StepRegistry::Register(const std::string& matcher, engine::StepType stepType, std::unique_ptr
(&factory)(Context& context, const engine::Table& table))
+ void StepRegistry::Register(const std::string& matcher, engine::StepType stepType, std::unique_ptr (&factory)(Context& context, const engine::Table& table, const std::string& docString))
{
if (matcher.starts_with('^') || matcher.ends_with('$'))
registry.emplace_back(stepType, cucumber_expression::Matcher{ std::in_place_type, matcher }, factory);
diff --git a/cucumber_cpp/library/StepRegistry.hpp b/cucumber_cpp/library/StepRegistry.hpp
index ab0d3b4a..e6dc4746 100644
--- a/cucumber_cpp/library/StepRegistry.hpp
+++ b/cucumber_cpp/library/StepRegistry.hpp
@@ -8,7 +8,6 @@
#include "cucumber_cpp/library/engine/StepType.hpp"
#include "cucumber_cpp/library/engine/Table.hpp"
#include
-#include
#include
#include
#include
@@ -22,20 +21,20 @@
namespace cucumber_cpp::library
{
template
- std::unique_ptr StepBodyFactory(Context& context, const engine::Table& table)
+ std::unique_ptr StepBodyFactory(Context& context, const engine::Table& table, const std::string& docString)
{
- return std::make_unique(context, table);
+ return std::make_unique(context, table, docString);
}
struct StepMatch
{
- StepMatch(std::unique_ptr (&factory)(Context& context, const engine::Table& table), std::variant, std::vector> matches, std::string_view stepRegexStr)
+ StepMatch(std::unique_ptr (&factory)(Context& context, const engine::Table& table, const std::string& docString), std::variant, std::vector> matches, std::string_view stepRegexStr)
: factory(factory)
, matches(std::move(matches))
, stepRegexStr(stepRegexStr)
{}
- std::unique_ptr (&factory)(Context& context, const engine::Table& table);
+ std::unique_ptr (&factory)(Context& context, const engine::Table& table, const std::string& docString);
std::variant, std::vector> matches{};
std::string_view stepRegexStr{};
};
@@ -58,7 +57,7 @@ namespace cucumber_cpp::library
struct Entry
{
- Entry(engine::StepType type, cucumber_expression::Matcher regex, std::unique_ptr (&factory)(Context& context, const engine::Table& table))
+ Entry(engine::StepType type, cucumber_expression::Matcher regex, std::unique_ptr (&factory)(Context& context, const engine::Table& table, const std::string& docString))
: type(type)
, regex(std::move(regex))
, factory(factory)
@@ -66,7 +65,7 @@ namespace cucumber_cpp::library
engine::StepType type{};
cucumber_expression::Matcher regex;
- std::unique_ptr (&factory)(Context& context, const engine::Table& table);
+ std::unique_ptr (&factory)(Context& context, const engine::Table& table, const std::string& docString);
std::uint32_t used{ 0 };
};
@@ -91,7 +90,7 @@ namespace cucumber_cpp::library
[[nodiscard]] std::vector List() const;
private:
- void Register(const std::string& matcher, engine::StepType stepType, std::unique_ptr (&factory)(Context& context, const engine::Table& table));
+ void Register(const std::string& matcher, engine::StepType stepType, std::unique_ptr (&factory)(Context& context, const engine::Table& table, const std::string& docString));
std::vector registry;
cucumber_expression::ParameterRegistry& parameterRegistry;
@@ -107,7 +106,7 @@ namespace cucumber_cpp::library
struct Entry
{
- Entry(engine::StepType type, std::string regex, std::unique_ptr (&factory)(Context& context, const engine::Table& table))
+ Entry(engine::StepType type, std::string regex, std::unique_ptr (&factory)(Context& context, const engine::Table& table, const std::string& docString))
: type(type)
, regex(std::move(regex))
, factory(factory)
@@ -115,7 +114,7 @@ namespace cucumber_cpp::library
engine::StepType type{};
std::string regex;
- std::unique_ptr (&factory)(Context& context, const engine::Table& table);
+ std::unique_ptr (&factory)(Context& context, const engine::Table& table, const std::string& docString);
};
template
diff --git a/cucumber_cpp/library/engine/FeatureFactory.cpp b/cucumber_cpp/library/engine/FeatureFactory.cpp
index 56dfc797..b254e627 100644
--- a/cucumber_cpp/library/engine/FeatureFactory.cpp
+++ b/cucumber_cpp/library/engine/FeatureFactory.cpp
@@ -124,7 +124,7 @@ namespace cucumber_cpp::library::engine
return table;
for (const auto& dataTable = optionalPickleStepArgument.value().data_table.value();
- const auto& row : dataTable.rows)
+ const auto& row : dataTable.rows)
{
table.emplace_back();
auto& back = table.back();
@@ -136,6 +136,17 @@ namespace cucumber_cpp::library::engine
return table;
}
+ std::string DocStringFactory(const std::optional& optionalPickleStepArgument)
+ {
+ if (!optionalPickleStepArgument)
+ return "";
+
+ if (!optionalPickleStepArgument.value().doc_string.has_value())
+ return "";
+
+ return optionalPickleStepArgument.value().doc_string.value().content;
+ }
+
std::set> TagsFactory(const std::vector& tags)
{
const auto range = tags | std::views::transform(&cucumber::messages::tag::name);
@@ -151,10 +162,11 @@ namespace cucumber_cpp::library::engine
void ConstructStep(const FeatureTreeFactory& featureTreeFactory, ScenarioInfo& scenarioInfo, const cucumber::messages::step& step, const cucumber::messages::pickle_step& pickleStep)
{
auto table = TableFactory(pickleStep.argument);
+ auto docString = DocStringFactory(pickleStep.argument);
try
{
- 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)));
+ 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)));
}
catch (const std::out_of_range&)
{
@@ -287,20 +299,20 @@ namespace cucumber_cpp::library::engine
: stepRegistry{ stepRegistry }
{}
- std::unique_ptr FeatureTreeFactory::CreateStepInfo(StepType stepType, std::string stepText, const ScenarioInfo& scenarioInfo, std::size_t line, std::size_t column, std::vector> table) const
+ std::unique_ptr FeatureTreeFactory::CreateStepInfo(StepType stepType, std::string stepText, const ScenarioInfo& scenarioInfo, std::size_t line, std::size_t column, std::vector> table, std::string docString) const
{
try
{
auto stepMatch = stepRegistry.Query(stepText);
- return std::make_unique(scenarioInfo, std::move(stepText), stepType, line, column, std::move(table), std::move(stepMatch));
+ return std::make_unique(scenarioInfo, std::move(stepText), stepType, line, column, std::move(table), std::move(docString), std::move(stepMatch));
}
catch (const StepRegistry::StepNotFoundError&)
{
- return std::make_unique(scenarioInfo, std::move(stepText), stepType, line, column, std::move(table));
+ return std::make_unique(scenarioInfo, std::move(stepText), stepType, line, column, std::move(table), std::move(docString));
}
catch (StepRegistry::AmbiguousStepError& ase)
{
- return std::make_unique(scenarioInfo, std::move(stepText), stepType, line, column, std::move(table), std::move(ase.matches));
+ return std::make_unique(scenarioInfo, std::move(stepText), stepType, line, column, std::move(table), std::move(docString), std::move(ase.matches));
}
}
diff --git a/cucumber_cpp/library/engine/FeatureFactory.hpp b/cucumber_cpp/library/engine/FeatureFactory.hpp
index 7e71d904..a064f366 100644
--- a/cucumber_cpp/library/engine/FeatureFactory.hpp
+++ b/cucumber_cpp/library/engine/FeatureFactory.hpp
@@ -20,7 +20,7 @@ namespace cucumber_cpp::library::engine
{
explicit FeatureTreeFactory(StepRegistry& stepRegistry);
- [[nodiscard]] std::unique_ptr CreateStepInfo(StepType stepType, std::string stepText, const ScenarioInfo& scenarioInfo, std::size_t line, std::size_t column, std::vector> table) const;
+ [[nodiscard]] std::unique_ptr CreateStepInfo(StepType stepType, std::string stepText, const ScenarioInfo& scenarioInfo, std::size_t line, std::size_t column, std::vector> table, std::string docString) const;
[[nodiscard]] std::unique_ptr Create(const std::filesystem::path& path, std::string_view tagExpression) const;
diff --git a/cucumber_cpp/library/engine/Step.cpp b/cucumber_cpp/library/engine/Step.cpp
index 12022b3d..140b26eb 100644
--- a/cucumber_cpp/library/engine/Step.cpp
+++ b/cucumber_cpp/library/engine/Step.cpp
@@ -8,9 +8,10 @@
namespace cucumber_cpp::library::engine
{
- Step::Step(Context& context, const Table& table)
+ Step::Step(Context& context, const Table& table, const std::string& docString)
: context{ context }
, table{ table }
+ , docString{ docString }
{}
void Step::Given(const std::string& step) const
diff --git a/cucumber_cpp/library/engine/Step.hpp b/cucumber_cpp/library/engine/Step.hpp
index d71bc0c4..3420171f 100644
--- a/cucumber_cpp/library/engine/Step.hpp
+++ b/cucumber_cpp/library/engine/Step.hpp
@@ -24,7 +24,7 @@ namespace cucumber_cpp::library::engine
std::source_location sourceLocation;
};
- Step(Context& context, const Table& table);
+ Step(Context& context, const Table& table, const std::string& docString);
virtual ~Step() = default;
virtual void SetUp()
@@ -46,6 +46,7 @@ namespace cucumber_cpp::library::engine
Context& context;
const Table& table;
+ const std::string& docString;
};
}
diff --git a/cucumber_cpp/library/engine/StepInfo.cpp b/cucumber_cpp/library/engine/StepInfo.cpp
index 29b8c29e..f21b6f24 100644
--- a/cucumber_cpp/library/engine/StepInfo.cpp
+++ b/cucumber_cpp/library/engine/StepInfo.cpp
@@ -10,34 +10,37 @@
namespace cucumber_cpp::library::engine
{
- StepInfo::StepInfo(const struct ScenarioInfo& scenarioInfo, std::string text, StepType type, std::size_t line, std::size_t column, std::vector> table)
+ StepInfo::StepInfo(const struct ScenarioInfo& scenarioInfo, std::string text, StepType type, std::size_t line, std::size_t column, std::vector> table, std::string docString)
: scenarioInfo{ scenarioInfo }
, text{ std::move(text) }
, type{ type }
, line{ line }
, column{ column }
, table{ std::move(table) }
+ , docString{ std::move(docString) }
{
}
- StepInfo::StepInfo(const struct ScenarioInfo& scenarioInfo, std::string text, StepType type, std::size_t line, std::size_t column, std::vector> table, struct StepMatch stepMatch)
+ StepInfo::StepInfo(const struct ScenarioInfo& scenarioInfo, std::string text, StepType type, std::size_t line, std::size_t column, std::vector> table, std::string docString, struct StepMatch stepMatch)
: scenarioInfo{ scenarioInfo }
, text{ std::move(text) }
, type{ type }
, line{ line }
, column{ column }
, table{ std::move(table) }
+ , docString{ std::move(docString) }
, stepMatch{ std::move(stepMatch) }
{
}
- StepInfo::StepInfo(const struct ScenarioInfo& scenarioInfo, std::string text, StepType type, std::size_t line, std::size_t column, std::vector> table, std::vector stepMatches)
+ StepInfo::StepInfo(const struct ScenarioInfo& scenarioInfo, std::string text, StepType type, std::size_t line, std::size_t column, std::vector> table, std::string docString, std::vector stepMatches)
: scenarioInfo{ scenarioInfo }
, text{ std::move(text) }
, type{ type }
, line{ line }
, column{ column }
, table{ std::move(table) }
+ , docString{ std::move(docString) }
, stepMatch{ std::move(stepMatches) }
{
}
@@ -72,6 +75,11 @@ namespace cucumber_cpp::library::engine
return table;
}
+ const std::string& StepInfo::DocString() const
+ {
+ return docString;
+ }
+
const std::variant>& StepInfo::StepMatch() const
{
return stepMatch;
diff --git a/cucumber_cpp/library/engine/StepInfo.hpp b/cucumber_cpp/library/engine/StepInfo.hpp
index d158ca0c..2e3b841c 100644
--- a/cucumber_cpp/library/engine/StepInfo.hpp
+++ b/cucumber_cpp/library/engine/StepInfo.hpp
@@ -16,9 +16,9 @@ namespace cucumber_cpp::library::engine
struct StepInfo
{
- StepInfo(const struct ScenarioInfo& scenarioInfo, std::string text, StepType type, std::size_t line, std::size_t column, std::vector> table);
- StepInfo(const struct ScenarioInfo& scenarioInfo, std::string text, StepType type, std::size_t line, std::size_t column, std::vector> table, StepMatch);
- StepInfo(const struct ScenarioInfo& scenarioInfo, std::string text, StepType type, std::size_t line, std::size_t column, std::vector> table, std::vector);
+ StepInfo(const struct ScenarioInfo& scenarioInfo, std::string text, StepType type, std::size_t line, std::size_t column, std::vector> table, std::string docString);
+ StepInfo(const struct ScenarioInfo& scenarioInfo, std::string text, StepType type, std::size_t line, std::size_t column, std::vector> table, std::string docString, StepMatch);
+ StepInfo(const struct ScenarioInfo& scenarioInfo, std::string text, StepType type, std::size_t line, std::size_t column, std::vector> table, std::string docString, std::vector);
[[nodiscard]] const struct ScenarioInfo& ScenarioInfo() const;
@@ -29,6 +29,7 @@ namespace cucumber_cpp::library::engine
[[nodiscard]] std::size_t Column() const;
[[nodiscard]] const std::vector>& Table() const;
+ [[nodiscard]] const std::string& DocString() const;
[[nodiscard]] const std::variant>& StepMatch() const;
private:
@@ -41,6 +42,7 @@ namespace cucumber_cpp::library::engine
std::size_t column;
std::vector> table;
+ std::string docString;
std::variant> stepMatch;
};
diff --git a/cucumber_cpp/library/engine/TestExecution.cpp b/cucumber_cpp/library/engine/TestExecution.cpp
index d48b735c..9420a4d7 100644
--- a/cucumber_cpp/library/engine/TestExecution.cpp
+++ b/cucumber_cpp/library/engine/TestExecution.cpp
@@ -63,7 +63,7 @@ namespace cucumber_cpp::library::engine
const auto& stepContext = contextManager.StepContext();
auto& scenarioContext = contextManager.ScenarioContext();
- stepMatch.factory(scenarioContext, stepContext.info.Table())->Execute(stepMatch.matches);
+ stepMatch.factory(scenarioContext, stepContext.info.Table(), stepContext.info.DocString())->Execute(stepMatch.matches);
}
TestExecutionImpl::TestExecutionImpl(cucumber_cpp::library::engine::ContextManager& contextManager, report::ReportForwarder& reportHandler, HookExecutor& hookExecution, const Policy& executionPolicy)
diff --git a/cucumber_cpp/library/engine/TestRunner.cpp b/cucumber_cpp/library/engine/TestRunner.cpp
index 75dd32d6..c56709ca 100644
--- a/cucumber_cpp/library/engine/TestRunner.cpp
+++ b/cucumber_cpp/library/engine/TestRunner.cpp
@@ -50,7 +50,7 @@ namespace cucumber_cpp::library::engine
void TestRunnerImpl::NestedStep(StepType type, std::string step)
{
- const auto nestedStep = featureTreeFactory.CreateStepInfo(type, std::move(step), *currentScenario, 0, 0, {});
+ const auto nestedStep = featureTreeFactory.CreateStepInfo(type, std::move(step), *currentScenario, 0, 0, {}, "");
testExecution.RunStep(*nestedStep);
}
diff --git a/cucumber_cpp/library/engine/test/TestContextManager.cpp b/cucumber_cpp/library/engine/test/TestContextManager.cpp
index 6b9c083b..b048917a 100644
--- a/cucumber_cpp/library/engine/test/TestContextManager.cpp
+++ b/cucumber_cpp/library/engine/test/TestContextManager.cpp
@@ -20,7 +20,7 @@ namespace cucumber_cpp::library::engine
cucumber_cpp::library::engine::FeatureInfo feature{ {}, {}, {}, {}, {}, {} };
cucumber_cpp::library::engine::RuleInfo rule{ feature, {}, {}, {}, {}, {} };
cucumber_cpp::library::engine::ScenarioInfo scenario{ rule, {}, {}, {}, {}, {} };
- cucumber_cpp::library::engine::StepInfo step{ scenario, {}, {}, {}, {}, {} };
+ cucumber_cpp::library::engine::StepInfo step{ scenario, {}, {}, {}, {}, {}, {} };
};
TEST_F(TestContextManager, Construct)
diff --git a/cucumber_cpp/library/engine/test/TestStep.cpp b/cucumber_cpp/library/engine/test/TestStep.cpp
index 309b5c8f..a8f7e141 100644
--- a/cucumber_cpp/library/engine/test/TestStep.cpp
+++ b/cucumber_cpp/library/engine/test/TestStep.cpp
@@ -33,10 +33,12 @@ namespace cucumber_cpp::library::engine
std::vector{ TableValue{ "value1" }, TableValue{ "value2}" } }
};
+ const std::string docString = "multiline \n string";
+
library::engine::test_helper::ContextManagerInstance contextManager;
engine::test_helper::TestRunnerMock testRunnerMock;
- StepMock step{ contextManager.StepContext(), table };
+ StepMock step{ contextManager.StepContext(), table, docString };
};
TEST_F(TestStep, StepProvidesAccessToSetUpFunction)
diff --git a/cucumber_cpp/library/engine/test_helper/ContextManagerInstance.hpp b/cucumber_cpp/library/engine/test_helper/ContextManagerInstance.hpp
index 6950a5fa..fecbcc0a 100644
--- a/cucumber_cpp/library/engine/test_helper/ContextManagerInstance.hpp
+++ b/cucumber_cpp/library/engine/test_helper/ContextManagerInstance.hpp
@@ -28,7 +28,7 @@ namespace cucumber_cpp::library::engine::test_helper
, feature{ tags, {}, {}, {}, {}, {} }
, rule{ feature, {}, {}, {}, {}, {} }
, scenario{ rule, tags, {}, {}, {}, {} }
- , step{ scenario, {}, {}, {}, {}, {} }
+ , step{ scenario, {}, {}, {}, {}, {}, {} }
{
}
diff --git a/cucumber_cpp/library/test/TestSteps.cpp b/cucumber_cpp/library/test/TestSteps.cpp
index 9abac6ba..8b4fc419 100644
--- a/cucumber_cpp/library/test/TestSteps.cpp
+++ b/cucumber_cpp/library/test/TestSteps.cpp
@@ -58,7 +58,7 @@ namespace cucumber_cpp::library
auto contextStorage{ std::make_shared() };
Context context{ contextStorage };
- matches.factory(context, {})->Execute(matches.matches);
+ matches.factory(context, {}, "")->Execute(matches.matches);
EXPECT_THAT(context.Contains("float"), testing::IsTrue());
EXPECT_THAT(context.Contains("std::string"), testing::IsTrue());
@@ -85,7 +85,7 @@ namespace cucumber_cpp::library
auto contextStorage{ std::make_shared() };
Context context{ contextStorage };
- matches.factory(context, {})->Execute(matches.matches);
+ matches.factory(context, {}, {})->Execute(matches.matches);
}
TEST_F(TestSteps, EscapedParenthesis)
diff --git a/external/cucumber/gherkin/CMakeLists.txt b/external/cucumber/gherkin/CMakeLists.txt
index 16ac4462..fbaf6e59 100644
--- a/external/cucumber/gherkin/CMakeLists.txt
+++ b/external/cucumber/gherkin/CMakeLists.txt
@@ -1,6 +1,6 @@
FetchContent_Declare(cucumber_gherkin
GIT_REPOSITORY https://github.com/cucumber/gherkin.git
- GIT_TAG "0022bb07791485cda296e1785f4d0de47a04e5c9"
+ GIT_TAG "7cd0304c39a51ac139a22264ebe2a7ce6c68819d"
)
FetchContent_MakeAvailable(cucumber_gherkin)