diff --git a/cucumber_cpp/Steps.hpp b/cucumber_cpp/Steps.hpp index 212ddd39..0c438194 100644 --- a/cucumber_cpp/Steps.hpp +++ b/cucumber_cpp/Steps.hpp @@ -9,6 +9,7 @@ #include "cucumber_cpp/library/cucumber_expression/ParameterRegistry.hpp" #include "cucumber_cpp/library/engine/ExecutionContext.hpp" #include "cucumber_cpp/library/engine/Hook.hpp" +#include "cucumber_cpp/library/engine/Step.hpp" #include "cucumber_cpp/library/util/DocString.hpp" #include "cucumber_cpp/library/util/Table.hpp" diff --git a/cucumber_cpp/acceptance_test/features/test_expose_scenario_info.feature b/cucumber_cpp/acceptance_test/features/test_expose_scenario_info.feature new file mode 100644 index 00000000..0db76187 --- /dev/null +++ b/cucumber_cpp/acceptance_test/features/test_expose_scenario_info.feature @@ -0,0 +1,31 @@ +@expose_scenario_info +Feature: Scenario begin and end hooks can expose scenario information + @store_scenario_info + Rule: Scenario begin and end hooks store the scenario information + Background: + Then the "ScenarioInfoHook" has the name "Scenario with @tag-a" or "Scenario with @tag-b" + And the "ScenarioInfoHook" has the tag "@tag-a" or "@tag-b" + And the "StepHookInfo" has the name "Scenario with @tag-a" or "Scenario with @tag-b" + And the "StepHookInfo" has the tag "@tag-a" or "@tag-b" + + Scenario Outline: Scenario with + Then the "" has the name "Scenario with " + And the "" has the tags "@expose_scenario_info" and "" + + @tag-a + Examples: + | scope | tag | + | ScenarioInfoHook | @tag-a | + | StepHookInfo | @tag-a | + + @tag-b + Examples: + | scope | tag | + | ScenarioInfoHook | @tag-b | + | StepHookInfo | @tag-b | + + @no_store_scenario_info + Rule: scenario begin and end hooks do not store the scenario information + Scenario: Scenario information is available + Then the "ScenarioInfoHook" is not available + And the "StepHookInfo" is not available diff --git a/cucumber_cpp/acceptance_test/features_with_parse_error/test_parse_error.feature b/cucumber_cpp/acceptance_test/features_with_parse_error/test_parse_error.feature new file mode 100644 index 00000000..287db957 --- /dev/null +++ b/cucumber_cpp/acceptance_test/features_with_parse_error/test_parse_error.feature @@ -0,0 +1,5 @@ +Feature: a parse error is printed to cerr + Scenario: a parse error is printed to cerr + Given a feature file with a parse error + when this line is a parse error (when should be When) + Then this should be skipped diff --git a/cucumber_cpp/acceptance_test/hooks/Hooks.cpp b/cucumber_cpp/acceptance_test/hooks/Hooks.cpp index de7fc35e..631f2744 100644 --- a/cucumber_cpp/acceptance_test/hooks/Hooks.cpp +++ b/cucumber_cpp/acceptance_test/hooks/Hooks.cpp @@ -1,4 +1,5 @@ #include "cucumber_cpp/CucumberCpp.hpp" +#include "cucumber_cpp/Steps.hpp" #include "gmock/gmock.h" #include #include @@ -57,3 +58,21 @@ HOOK_BEFORE_SCENARIO(.name = "fail if --failprogramhook is set") if (context.Contains("--failprogramhook") && context.Get("--failprogramhook")) std::cout << "should not be executed\n"; } + +HOOK_BEFORE_SCENARIO("@expose_scenario_info") +{ + const auto& scenarioInfo = ScenarioInfo(); + if (scenarioInfo.tags.contains("@store_scenario_info")) + { + context.InsertAt("ScenarioInfoHook", scenarioInfo); + } +} + +HOOK_BEFORE_STEP("@expose_scenario_info") +{ + const auto& scenarioInfo = ScenarioInfo(); + if (scenarioInfo.tags.contains("@store_scenario_info")) + { + context.InsertAt("StepHookInfo", scenarioInfo); + } +} diff --git a/cucumber_cpp/acceptance_test/steps/Steps.cpp b/cucumber_cpp/acceptance_test/steps/Steps.cpp index a5712fdc..ee59323f 100644 --- a/cucumber_cpp/acceptance_test/steps/Steps.cpp +++ b/cucumber_cpp/acceptance_test/steps/Steps.cpp @@ -1,4 +1,5 @@ #include "cucumber_cpp/Steps.hpp" +#include "cucumber_cpp/library/util/ScenarioInfo.hpp" #include "fmt/format.h" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -167,3 +168,32 @@ GIVEN("a step calls another step that will fail") { Step("a nested step that fails"); } + +THEN("the {string} has the name {string} or {string}", (const std::string& hookType, const std::string& expectedName1, const std::string& expectedName2)) +{ + const auto& scenarioInfo = context.Get(hookType); + ASSERT_THAT(scenarioInfo.name, testing::AnyOf(testing::StrEq(expectedName1), testing::StrEq(expectedName2))); +} + +THEN("the {string} has the name {string}", (const std::string& hookType, const std::string& expectedName)) +{ + const auto& scenarioInfo = context.Get(hookType); + ASSERT_THAT(scenarioInfo.name, testing::StrEq(expectedName)); +} + +THEN("the {string} has the tag {string} or {string}", (const std::string& hookType, const std::string& expectedTag1, const std::string& expectedTag2)) +{ + const auto& scenarioInfo = context.Get(hookType); + ASSERT_THAT(scenarioInfo.tags, testing::AnyOf(testing::Contains(expectedTag1), testing::Contains(expectedTag2))); +} + +THEN("the {string} has the tags {string} and {string}", (const std::string& hookType, const std::string& expectedTag1, const std::string& expectedTag2)) +{ + const auto& scenarioInfo = context.Get(hookType); + ASSERT_THAT(scenarioInfo.tags, testing::AllOf(testing::Contains(expectedTag1), testing::Contains(expectedTag2))); +} + +THEN("the {string} is not available", (const std::string& hookType)) +{ + ASSERT_THAT(context.Contains(hookType), testing::IsFalse()); +} diff --git a/cucumber_cpp/acceptance_test/test.bats b/cucumber_cpp/acceptance_test/test.bats index edf20970..fa3a1a9c 100644 --- a/cucumber_cpp/acceptance_test/test.bats +++ b/cucumber_cpp/acceptance_test/test.bats @@ -240,3 +240,15 @@ teardown() { assert_output --partial "Actual: false (of type bool)" assert_output --partial "↷ Then this should be skipped" } + +@test "Test providing access to scenario info in scenario and step hooks" { + run $acceptance_test --tags "@expose_scenario_info" -- cucumber_cpp/acceptance_test/features + assert_success +} + +@test "Test parse errors are printed to cerr" { + run $acceptance_test cucumber_cpp/acceptance_test/features_with_parse_error/test_parse_error.feature + assert_failure + assert_output --partial "Parse error in: \"cucumber_cpp/acceptance_test/features_with_parse_error/test_parse_error.feature:4:9\"" + assert_output --partial "got 'when this line is a parse error (when should be When)'" +} diff --git a/cucumber_cpp/library/Hooks.hpp b/cucumber_cpp/library/Hooks.hpp index 65685864..d5b2d04e 100644 --- a/cucumber_cpp/library/Hooks.hpp +++ b/cucumber_cpp/library/Hooks.hpp @@ -8,46 +8,54 @@ #include "cucumber_cpp/library/engine/Hook.hpp" #include "cucumber_cpp/library/support/DefinitionRegistration.hpp" -#define HOOK_(matcher, type) BODY(matcher, type, (), cucumber_cpp::library::support::DefinitionRegistration::Register, cucumber_cpp::library::engine::HookBase) +#define HOOK_(matcher, type, base) BODY(matcher, type, (), cucumber_cpp::library::support::DefinitionRegistration::Register, base) #define HOOK_BEFORE_ALL(...) \ HOOK_( \ (cucumber_cpp::library::support::GlobalHook{ __VA_ARGS__ }), \ - cucumber_cpp::library::util::HookType::beforeAll) + cucumber_cpp::library::util::HookType::beforeAll, \ + cucumber_cpp::library::engine::GlobalHookImpl) #define HOOK_AFTER_ALL(...) \ HOOK_( \ (cucumber_cpp::library::support::GlobalHook{ __VA_ARGS__ }), \ - cucumber_cpp::library::util::HookType::afterAll) + cucumber_cpp::library::util::HookType::afterAll, \ + cucumber_cpp::library::engine::GlobalHookImpl) #define HOOK_BEFORE_FEATURE(...) \ HOOK_( \ (cucumber_cpp::library::support::Hook{ __VA_ARGS__ }), \ - cucumber_cpp::library::util::HookType::beforeFeature) + cucumber_cpp::library::util::HookType::beforeFeature, \ + cucumber_cpp::library::engine::GlobalHookImpl) #define HOOK_AFTER_FEATURE(...) \ HOOK_( \ (cucumber_cpp::library::support::Hook{ __VA_ARGS__ }), \ - cucumber_cpp::library::util::HookType::afterFeature) + cucumber_cpp::library::util::HookType::afterFeature, \ + cucumber_cpp::library::engine::GlobalHookImpl) #define HOOK_BEFORE_SCENARIO(...) \ HOOK_( \ (cucumber_cpp::library::support::Hook{ __VA_ARGS__ }), \ - cucumber_cpp::library::util::HookType::before) + cucumber_cpp::library::util::HookType::before, \ + cucumber_cpp::library::engine::HookImpl) #define HOOK_AFTER_SCENARIO(...) \ HOOK_( \ (cucumber_cpp::library::support::Hook{ __VA_ARGS__ }), \ - cucumber_cpp::library::util::HookType::after) + cucumber_cpp::library::util::HookType::after, \ + cucumber_cpp::library::engine::HookImpl) #define HOOK_BEFORE_STEP(...) \ HOOK_( \ (cucumber_cpp::library::support::Hook{ __VA_ARGS__ }), \ - cucumber_cpp::library::util::HookType::beforeStep) + cucumber_cpp::library::util::HookType::beforeStep, \ + cucumber_cpp::library::engine::HookImpl) #define HOOK_AFTER_STEP(...) \ HOOK_( \ (cucumber_cpp::library::support::Hook{ __VA_ARGS__ }), \ - cucumber_cpp::library::util::HookType::afterStep) + cucumber_cpp::library::util::HookType::afterStep, \ + cucumber_cpp::library::engine::HookImpl) #endif diff --git a/cucumber_cpp/library/api/RunCucumber.cpp b/cucumber_cpp/library/api/RunCucumber.cpp index f07c0404..4bb82dc7 100644 --- a/cucumber_cpp/library/api/RunCucumber.cpp +++ b/cucumber_cpp/library/api/RunCucumber.cpp @@ -3,6 +3,7 @@ #include "cucumber/messages/envelope.hpp" #include "cucumber/messages/location.hpp" #include "cucumber/messages/parameter_type.hpp" +#include "cucumber/messages/parse_error.hpp" #include "cucumber/messages/pickle_tag.hpp" #include "cucumber/messages/source_reference.hpp" #include "cucumber/messages/step_definition.hpp" @@ -23,15 +24,19 @@ #include "cucumber_cpp/library/util/Broadcaster.hpp" #include "cucumber_cpp/library/util/HookData.hpp" #include "cucumber_cpp/library/util/TransformHookData.hpp" +#include "fmt/format.h" +#include "fmt/ostream.h" #include "nlohmann/json.hpp" #include "nlohmann/json_fwd.hpp" #include +#include #include #include #include #include #include #include +#include #include namespace cucumber_cpp::library::api @@ -92,12 +97,12 @@ namespace cucumber_cpp::library::api { auto beforeAllHooks = supportCodeLibrary.hookRegistry.HooksByType(util::HookType::before); - for (auto& hook : beforeAllHooks) + for (const auto& hook : beforeAllHooks) broadcaster.BroadcastEvent(cucumber::messages::envelope{ .hook = util::TransformHookData(hook) }); auto afterAllHooks = supportCodeLibrary.hookRegistry.HooksByType(util::HookType::after); - for (auto& hook : afterAllHooks) + for (const auto& hook : afterAllHooks) broadcaster.BroadcastEvent(cucumber::messages::envelope{ .hook = util::TransformHookData(hook) }); } @@ -105,12 +110,12 @@ namespace cucumber_cpp::library::api { auto beforeAllHooks = supportCodeLibrary.hookRegistry.HooksByType(util::HookType::beforeAll); - for (auto& hook : beforeAllHooks) + for (const auto& hook : beforeAllHooks) broadcaster.BroadcastEvent(cucumber::messages::envelope{ .hook = util::TransformHookData(hook) }); auto afterAllHooks = supportCodeLibrary.hookRegistry.HooksByType(util::HookType::afterAll); - for (auto& hook : afterAllHooks) + for (const auto& hook : afterAllHooks) broadcaster.BroadcastEvent(cucumber::messages::envelope{ .hook = util::TransformHookData(hook) }); } @@ -156,9 +161,33 @@ namespace cucumber_cpp::library::api }; if (sources.ordering == support::RunOptions::Ordering::defined) - return createOrderedPickleList(pickles); + return createOrderedPickleList(std::move(pickles)); else - return createOrderedPickleList(pickles | std::views::reverse); + return createOrderedPickleList(std::move(pickles) | std::views::reverse); + }; + + struct ParseErrorListener : util::Listener + { + explicit ParseErrorListener(util::Broadcaster& broadcaster) + : Listener{ broadcaster, [this](const cucumber::messages::envelope& envelope) + { + OnEvent(envelope); + } } + {} + + void OnEvent(const cucumber::messages::envelope& envelope) + { + if (envelope.parse_error) + parseErrors.push_back(*envelope.parse_error); + } + + [[nodiscard]] const std::vector& GetParseErrors() const + { + return parseErrors; + } + + private: + std::vector parseErrors; }; } @@ -182,7 +211,26 @@ namespace cucumber_cpp::library::api const auto formatOptionsJson = formatOptions.empty() ? nlohmann::json::object() : nlohmann::json::parse(formatOptions); const auto activeFormatters = formatters.EnableFormatters(format, formatOptionsJson, supportCodeLibrary, query); - const auto pickleSources = CollectPickles(options.sources, idGenerator, broadcaster); + ParseErrorListener parseErrorListener{ broadcaster }; + auto pickleSources = CollectPickles(options.sources, idGenerator, broadcaster); + + if (const auto& parseErrors = parseErrorListener.GetParseErrors(); !parseErrors.empty()) + { + for (const auto& parseError : parseErrors) + { + const auto uri = parseError.source.uri.value_or("unknown source"); + const auto line = parseError.source.location.has_value() ? fmt::format(":{}", parseError.source.location->line) : ""; + const auto column = parseError.source.location.has_value() && parseError.source.location->column.has_value() ? fmt::format(":{}", parseError.source.location->column.value()) : ""; + + const auto messageStart = parseError.message.find(": "); + const auto message = messageStart != std::string::npos ? parseError.message.substr(messageStart + 2) : parseError.message; + + fmt::println(std::cerr, "Parse error in: \"{}{}{}\" {}", uri, line, column, message); + } + + return false; + } + const auto orderedPickles = OrderPickles(options.sources, pickleSources | std::views::filter(FilterByTagExpression(options.sources))); EmitSupportCodeMessages(supportCodeLibrary, broadcaster, idGenerator); diff --git a/cucumber_cpp/library/engine/Hook.cpp b/cucumber_cpp/library/engine/Hook.cpp index fa20dd82..d6f0a4da 100644 --- a/cucumber_cpp/library/engine/Hook.cpp +++ b/cucumber_cpp/library/engine/Hook.cpp @@ -2,7 +2,9 @@ #include "cucumber_cpp/library/Context.hpp" #include "cucumber_cpp/library/engine/ExecutionContext.hpp" #include "cucumber_cpp/library/util/Broadcaster.hpp" +#include "cucumber_cpp/library/util/ScenarioInfo.hpp" #include "cucumber_cpp/library/util/StepOrHookStarted.hpp" +#include #include namespace cucumber_cpp::library::engine @@ -11,4 +13,18 @@ namespace cucumber_cpp::library::engine : engine::ExecutionContext{ broadCaster, context, std::move(stepOrHookStarted) } , hasError{ hasError } {} + + GlobalHookImpl::GlobalHookImpl(util::Broadcaster& broadCaster, Context& context, util::StepOrHookStarted stepOrHookStarted, [[maybe_unused]] const std::optional& scenarioInfo, bool hasError) + : HookBase{ broadCaster, context, std::move(stepOrHookStarted), hasError } + {} + + HookImpl::HookImpl(util::Broadcaster& broadCaster, Context& context, util::StepOrHookStarted stepOrHookStarted, std::optional scenarioInfo, bool hasError) + : HookBase{ broadCaster, context, std::move(stepOrHookStarted), hasError } + , scenarioInfo{ std::move(scenarioInfo.value()) } + {} + + const util::ScenarioInfo& HookImpl::ScenarioInfo() const + { + return scenarioInfo; + } } diff --git a/cucumber_cpp/library/engine/Hook.hpp b/cucumber_cpp/library/engine/Hook.hpp index 7f115812..a3009053 100644 --- a/cucumber_cpp/library/engine/Hook.hpp +++ b/cucumber_cpp/library/engine/Hook.hpp @@ -3,7 +3,9 @@ #include "cucumber_cpp/library/Context.hpp" #include "cucumber_cpp/library/engine/ExecutionContext.hpp" +#include "cucumber_cpp/library/util/ScenarioInfo.hpp" #include "cucumber_cpp/library/util/StepOrHookStarted.hpp" +#include namespace cucumber_cpp::library::util { @@ -31,6 +33,22 @@ namespace cucumber_cpp::library::engine protected: const bool hasError; }; + + struct GlobalHookImpl : HookBase + { + GlobalHookImpl(util::Broadcaster& broadCaster, Context& context, util::StepOrHookStarted stepOrHookStarted, const std::optional& scenarioInfo, bool hasError); + }; + + struct HookImpl : HookBase // NOSONAR(cpp:S3656) - + { + HookImpl(util::Broadcaster& broadCaster, Context& context, util::StepOrHookStarted stepOrHookStarted, std::optional scenarioInfo, bool hasError); + + protected: + [[nodiscard]] const util::ScenarioInfo& ScenarioInfo() const; + + private: + util::ScenarioInfo scenarioInfo; + }; } #endif diff --git a/cucumber_cpp/library/runtime/TestCaseRunner.cpp b/cucumber_cpp/library/runtime/TestCaseRunner.cpp index 30b6d6b9..f7756ac5 100644 --- a/cucumber_cpp/library/runtime/TestCaseRunner.cpp +++ b/cucumber_cpp/library/runtime/TestCaseRunner.cpp @@ -26,6 +26,7 @@ #include "cucumber_cpp/library/util/Duration.hpp" #include "cucumber_cpp/library/util/GetWorstTestStepResult.hpp" #include "cucumber_cpp/library/util/HookData.hpp" +#include "cucumber_cpp/library/util/ScenarioInfo.hpp" #include "cucumber_cpp/library/util/Timestamp.hpp" #include "cucumber_cpp/library/util/TransformDocString.hpp" #include "cucumber_cpp/library/util/TransformPickleTag.hpp" @@ -51,6 +52,11 @@ namespace cucumber_cpp::library::runtime { return util::TransformTestStepResult(util::ConstructAndExecute(bodyFactory, util::StepMatchArgumentsListToExecuteArgs(args))); } + + std::optional MakeScenarioInfo(const cucumber::messages::pickle& pickle) + { + return std::make_optional(pickle.name, util::TransformPickleTags(pickle.tags)); + } } TestCaseRunner::TestCaseRunner(util::Broadcaster& broadcaster, @@ -161,7 +167,7 @@ namespace cucumber_cpp::library::runtime const util::BodyFactory bodyFactory = [&hookDefinition, this, &testCaseContext, &testStepStarted, hasError] { - return hookDefinition.factory(broadcaster, testCaseContext, util::TransformTestStepStarted(testStepStarted), hasError); + return hookDefinition.factory(broadcaster, testCaseContext, util::TransformTestStepStarted(testStepStarted), MakeScenarioInfo(pickle), hasError); }; return InvokeStep(bodyFactory, {}); @@ -178,7 +184,7 @@ namespace cucumber_cpp::library::runtime const auto& definition = supportCodeLibrary.hookRegistry.GetDefinitionById(id); const auto bodyFactory = [&definition, this, &testCaseContext, &testStepStarted] { - return definition.factory(broadcaster, testCaseContext, util::TransformTestStepStarted(testStepStarted), false); + return definition.factory(broadcaster, testCaseContext, util::TransformTestStepStarted(testStepStarted), MakeScenarioInfo(pickle), false); }; results.emplace_back(InvokeStep(bodyFactory, {})); diff --git a/cucumber_cpp/library/runtime/Worker.cpp b/cucumber_cpp/library/runtime/Worker.cpp index 9c591dc8..b1a6e999 100644 --- a/cucumber_cpp/library/runtime/Worker.cpp +++ b/cucumber_cpp/library/runtime/Worker.cpp @@ -195,7 +195,7 @@ namespace cucumber_cpp::library::runtime { const util::BodyFactory bodyFactory = [&definition, this, &context, &testRunHookStarted] { - return definition.factory(broadcaster, context, util::TransformTestRunHookStarted(testRunHookStarted), false); + return definition.factory(broadcaster, context, util::TransformTestRunHookStarted(testRunHookStarted), std::nullopt, false); }; result = util::TransformTestStepResult(util::ConstructAndExecute(bodyFactory)); diff --git a/cucumber_cpp/library/support/DefinitionRegistration.cpp b/cucumber_cpp/library/support/DefinitionRegistration.cpp index f6dd7f5c..f331c71b 100644 --- a/cucumber_cpp/library/support/DefinitionRegistration.cpp +++ b/cucumber_cpp/library/support/DefinitionRegistration.cpp @@ -8,7 +8,6 @@ #include "cucumber_cpp/library/util/HookFactory.hpp" #include "cucumber_cpp/library/util/StepFactory.hpp" #include -#include #include #include #include @@ -20,14 +19,6 @@ #include #include -#if defined(CCR_STANDALONE) -#include "fmt/base.h" -#include "fmt/format.h" -#include "fmt/ostream.h" -#include "fmt/ranges.h" -#include "fmt/std.h" -#endif - namespace cucumber_cpp::library::support { bool SourceLocationOrder::operator()(const std::source_location& lhs, const std::source_location& rhs) const @@ -70,37 +61,21 @@ namespace cucumber_cpp::library::support return customParameters; } - namespace - { - void PrintContents(std::string_view type, std::source_location sourceLocation, const std::map& registry) - { -#if defined(CCR_STANDALONE) - fmt::println("Added ({}): {}:{}", type, std::filesystem::path{ sourceLocation.file_name() }, sourceLocation.line()); - fmt::println("Registry contents:"); - for (const auto& [key, item] : registry) - fmt::println(" {}:{}", std::filesystem::path{ key.file_name() }, key.line()); -#endif - } - } - std::size_t DefinitionRegistration::Register(Hook hook, util::HookType hookType, util::HookFactory factory, std::source_location sourceLocation) { - registry.emplace(sourceLocation, HookEntry{ hookType, hook, factory, sourceLocation }); - PrintContents("Hook", sourceLocation, registry); + registry.try_emplace(sourceLocation, HookEntry{ hookType, hook, factory, sourceLocation }); return registry.size(); } std::size_t DefinitionRegistration::Register(GlobalHook hook, util::HookType hookType, util::HookFactory factory, std::source_location sourceLocation) { - registry.emplace(sourceLocation, HookEntry{ hookType, hook, factory, sourceLocation }); - PrintContents("GlobalHook", sourceLocation, registry); + registry.try_emplace(sourceLocation, HookEntry{ hookType, hook, factory, sourceLocation }); return registry.size(); } std::size_t DefinitionRegistration::Register(std::string_view matcher, StepType stepType, util::StepFactory factory, std::source_location sourceLocation) { - registry.emplace(sourceLocation, StepStringRegistration::Entry{ stepType, std::string{ matcher }, factory, sourceLocation }); - PrintContents("Step", sourceLocation, registry); + registry.try_emplace(sourceLocation, StepStringRegistration::Entry{ stepType, std::string{ matcher }, factory, sourceLocation }); return registry.size(); } } diff --git a/cucumber_cpp/library/util/HookFactory.hpp b/cucumber_cpp/library/util/HookFactory.hpp index be0f8f4d..3663c897 100644 --- a/cucumber_cpp/library/util/HookFactory.hpp +++ b/cucumber_cpp/library/util/HookFactory.hpp @@ -4,17 +4,20 @@ #include "cucumber_cpp/library/Context.hpp" #include "cucumber_cpp/library/util/Body.hpp" #include "cucumber_cpp/library/util/Broadcaster.hpp" +#include "cucumber_cpp/library/util/ScenarioInfo.hpp" #include "cucumber_cpp/library/util/StepOrHookStarted.hpp" #include +#include +#include namespace cucumber_cpp::library::util { - using HookFactory = std::unique_ptr (&)(Broadcaster& broadCaster, Context& context, StepOrHookStarted stepOrHookStarted, bool hasError); + using HookFactory = std::unique_ptr (&)(Broadcaster& broadCaster, Context& context, StepOrHookStarted stepOrHookStarted, std::optional scenarioInfo, bool hasError); template - std::unique_ptr HookBodyFactory(Broadcaster& broadCaster, Context& context, StepOrHookStarted stepOrHookStarted, bool hasError) + std::unique_ptr HookBodyFactory(Broadcaster& broadCaster, Context& context, StepOrHookStarted stepOrHookStarted, std::optional scenarioInfo, bool hasError) { - return std::make_unique(broadCaster, context, stepOrHookStarted, hasError); + return std::make_unique(broadCaster, context, std::move(stepOrHookStarted), std::move(scenarioInfo), hasError); } } diff --git a/cucumber_cpp/library/util/ScenarioInfo.hpp b/cucumber_cpp/library/util/ScenarioInfo.hpp new file mode 100644 index 00000000..e5e1544d --- /dev/null +++ b/cucumber_cpp/library/util/ScenarioInfo.hpp @@ -0,0 +1,17 @@ +#ifndef UTIL_SCENARIO_INFO_HPP +#define UTIL_SCENARIO_INFO_HPP + +#include +#include +#include + +namespace cucumber_cpp::library::util +{ + struct ScenarioInfo + { + std::string name; + std::set> tags; + }; +} + +#endif