Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Feature: Doc Strings

Scenario: Multiline doc strings
Given Next block of text enclosed in """ characters
"""
Multiline
Docstring
"""
6 changes: 6 additions & 0 deletions cucumber_cpp/acceptance_test/steps/Steps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"));
}
2 changes: 1 addition & 1 deletion cucumber_cpp/library/StepRegistry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ namespace cucumber_cpp::library
return list;
}

void StepRegistry::Register(const std::string& matcher, engine::StepType stepType, std::unique_ptr<Body> (&factory)(Context& context, const engine::Table& table))
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))
{
if (matcher.starts_with('^') || matcher.ends_with('$'))
registry.emplace_back(stepType, cucumber_expression::Matcher{ std::in_place_type<cucumber_expression::RegularExpression>, matcher }, factory);
Expand Down
19 changes: 9 additions & 10 deletions cucumber_cpp/library/StepRegistry.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
#include "cucumber_cpp/library/engine/StepType.hpp"
#include "cucumber_cpp/library/engine/Table.hpp"
#include <any>
#include <cstddef>
#include <cstdint>
#include <exception>
#include <memory>
Expand All @@ -22,20 +21,20 @@
namespace cucumber_cpp::library
{
template<class T>
std::unique_ptr<Body> StepBodyFactory(Context& context, const engine::Table& table)
std::unique_ptr<Body> StepBodyFactory(Context& context, const engine::Table& table, const std::string& docString)
{
return std::make_unique<T>(context, table);
return std::make_unique<T>(context, table, docString);
}

struct StepMatch
{
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)
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)
: factory(factory)
, matches(std::move(matches))
, stepRegexStr(stepRegexStr)
{}

std::unique_ptr<Body> (&factory)(Context& context, const engine::Table& table);
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{};
};
Expand All @@ -58,15 +57,15 @@ namespace cucumber_cpp::library

struct Entry
{
Entry(engine::StepType type, cucumber_expression::Matcher regex, std::unique_ptr<Body> (&factory)(Context& context, const engine::Table& table))
Entry(engine::StepType type, cucumber_expression::Matcher regex, std::unique_ptr<Body> (&factory)(Context& context, const engine::Table& table, const std::string& docString))
: type(type)
, regex(std::move(regex))
, factory(factory)
{}

engine::StepType type{};
cucumber_expression::Matcher regex;
std::unique_ptr<Body> (&factory)(Context& context, const engine::Table& table);
std::unique_ptr<Body> (&factory)(Context& context, const engine::Table& table, const std::string& docString);

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

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

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

struct Entry
{
Entry(engine::StepType type, std::string regex, std::unique_ptr<Body> (&factory)(Context& context, const engine::Table& table))
Entry(engine::StepType type, std::string regex, std::unique_ptr<Body> (&factory)(Context& context, const engine::Table& table, const std::string& docString))
: type(type)
, regex(std::move(regex))
, factory(factory)
{}

engine::StepType type{};
std::string regex;
std::unique_ptr<Body> (&factory)(Context& context, const engine::Table& table);
std::unique_ptr<Body> (&factory)(Context& context, const engine::Table& table, const std::string& docString);
};

template<class T>
Expand Down
24 changes: 18 additions & 6 deletions cucumber_cpp/library/engine/FeatureFactory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -136,6 +136,17 @@ namespace cucumber_cpp::library::engine
return table;
}

std::string DocStringFactory(const std::optional<cucumber::messages::pickle_step_argument>& optionalPickleStepArgument)
{
if (!optionalPickleStepArgument)
return "";

if (!optionalPickleStepArgument.value().doc_string.has_value())
return "";

return optionalPickleStepArgument.value().doc_string.value().content;
}

std::set<std::string, std::less<>> TagsFactory(const std::vector<cucumber::messages::tag>& tags)
{
const auto range = tags | std::views::transform(&cucumber::messages::tag::name);
Expand All @@ -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&)
{
Expand Down Expand Up @@ -287,20 +299,20 @@ namespace cucumber_cpp::library::engine
: stepRegistry{ stepRegistry }
{}

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
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
{
try
{
auto stepMatch = stepRegistry.Query(stepText);
return std::make_unique<StepInfo>(scenarioInfo, std::move(stepText), stepType, line, column, std::move(table), std::move(stepMatch));
return std::make_unique<StepInfo>(scenarioInfo, std::move(stepText), stepType, line, column, std::move(table), std::move(docString), std::move(stepMatch));
}
catch (const StepRegistry::StepNotFoundError&)
{
return std::make_unique<StepInfo>(scenarioInfo, std::move(stepText), stepType, line, column, std::move(table));
return std::make_unique<StepInfo>(scenarioInfo, std::move(stepText), stepType, line, column, std::move(table), std::move(docString));
}
catch (StepRegistry::AmbiguousStepError& ase)
{
return std::make_unique<StepInfo>(scenarioInfo, std::move(stepText), stepType, line, column, std::move(table), std::move(ase.matches));
return std::make_unique<StepInfo>(scenarioInfo, std::move(stepText), stepType, line, column, std::move(table), std::move(docString), std::move(ase.matches));
}
}

Expand Down
2 changes: 1 addition & 1 deletion cucumber_cpp/library/engine/FeatureFactory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ namespace cucumber_cpp::library::engine
{
explicit FeatureTreeFactory(StepRegistry& stepRegistry);

[[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;
[[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;

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

Expand Down
3 changes: 2 additions & 1 deletion cucumber_cpp/library/engine/Step.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion cucumber_cpp/library/engine/Step.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -46,6 +46,7 @@ namespace cucumber_cpp::library::engine

Context& context;
const Table& table;
const std::string& docString;
};
}

Expand Down
14 changes: 11 additions & 3 deletions cucumber_cpp/library/engine/StepInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::vector<TableValue>> table)
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)
: 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<std::vector<TableValue>> 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<std::vector<TableValue>> 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<std::vector<TableValue>> table, std::vector<struct StepMatch> stepMatches)
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)
: scenarioInfo{ scenarioInfo }
, text{ std::move(text) }
, type{ type }
, line{ line }
, column{ column }
, table{ std::move(table) }
, docString{ std::move(docString) }
, stepMatch{ std::move(stepMatches) }
{
}
Expand Down Expand Up @@ -72,6 +75,11 @@ namespace cucumber_cpp::library::engine
return table;
}

const std::string& StepInfo::DocString() const
{
return docString;
}

const std::variant<std::monostate, struct StepMatch, std::vector<struct StepMatch>>& StepInfo::StepMatch() const
{
return stepMatch;
Expand Down
8 changes: 5 additions & 3 deletions cucumber_cpp/library/engine/StepInfo.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::vector<TableValue>> table);
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);
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>);
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);
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);
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>);

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

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

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

private:
Expand All @@ -41,6 +42,7 @@ namespace cucumber_cpp::library::engine
std::size_t column;

std::vector<std::vector<TableValue>> table;
std::string docString;
std::variant<std::monostate, struct StepMatch, std::vector<struct StepMatch>> stepMatch;
};

Expand Down
2 changes: 1 addition & 1 deletion cucumber_cpp/library/engine/TestExecution.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion cucumber_cpp/library/engine/TestRunner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
2 changes: 1 addition & 1 deletion cucumber_cpp/library/engine/test/TestContextManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 3 additions & 1 deletion cucumber_cpp/library/engine/test/TestStep.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ namespace cucumber_cpp::library::engine::test_helper
, feature{ tags, {}, {}, {}, {}, {} }
, rule{ feature, {}, {}, {}, {}, {} }
, scenario{ rule, tags, {}, {}, {}, {} }
, step{ scenario, {}, {}, {}, {}, {} }
, step{ scenario, {}, {}, {}, {}, {}, {} }
{
}

Expand Down
4 changes: 2 additions & 2 deletions cucumber_cpp/library/test/TestSteps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ namespace cucumber_cpp::library
auto contextStorage{ std::make_shared<ContextStorageFactoryImpl>() };
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());
Expand All @@ -85,7 +85,7 @@ namespace cucumber_cpp::library
auto contextStorage{ std::make_shared<ContextStorageFactoryImpl>() };
Context context{ contextStorage };

matches.factory(context, {})->Execute(matches.matches);
matches.factory(context, {}, {})->Execute(matches.matches);
}

TEST_F(TestSteps, EscapedParenthesis)
Expand Down
2 changes: 1 addition & 1 deletion external/cucumber/gherkin/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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)
Expand Down
Loading