diff --git a/cucumber_cpp/acceptance_test/MainCustom.cpp b/cucumber_cpp/acceptance_test/MainCustom.cpp index 0c76e52b..279de60d 100644 --- a/cucumber_cpp/acceptance_test/MainCustom.cpp +++ b/cucumber_cpp/acceptance_test/MainCustom.cpp @@ -5,6 +5,7 @@ int main(int argc, char** argv) cucumber_cpp::Application application{}; application.CliParser().add_flag("--required", *application.ProgramContext().EmplaceAt("--required"))->required(); + application.CliParser().add_flag("--failprogramhook", *application.ProgramContext().EmplaceAt("--failprogramhook")); return application.Run(argc, argv); } diff --git a/cucumber_cpp/acceptance_test/hooks/Hooks.cpp b/cucumber_cpp/acceptance_test/hooks/Hooks.cpp index 3e74e36d..8c9fc719 100644 --- a/cucumber_cpp/acceptance_test/hooks/Hooks.cpp +++ b/cucumber_cpp/acceptance_test/hooks/Hooks.cpp @@ -6,6 +6,9 @@ HOOK_BEFORE_ALL() { std::cout << "HOOK_BEFORE_ALL\n"; + + if (context.Contains("--failprogramhook") && context.Get("--failprogramhook")) + ASSERT_THAT(false, testing::IsTrue()); } HOOK_AFTER_ALL() @@ -47,3 +50,9 @@ HOOK_BEFORE_SCENARIO("@throw_scenariohook") { throw std::string{ "error" }; } + +HOOK_BEFORE_SCENARIO() +{ + if (context.Contains("--failprogramhook") && context.Get("--failprogramhook")) + std::cout << "should not be executed\n"; +} diff --git a/cucumber_cpp/acceptance_test/test.bats b/cucumber_cpp/acceptance_test/test.bats index 1c060a78..a3e0d515 100644 --- a/cucumber_cpp/acceptance_test/test.bats +++ b/cucumber_cpp/acceptance_test/test.bats @@ -176,3 +176,12 @@ teardown() { assert_output --partial "skipped Given a given step" assert_output --partial "tests : 0/1 passed" } + + +@test "Test error program hook results in error and skipped steps" { + run .build/Host/cucumber_cpp/acceptance_test/Debug/cucumber_cpp.acceptance_test.custom run --feature cucumber_cpp/acceptance_test/features --tag "@smoke and @result:OK" --report console --required --failprogramhook + assert_failure + assert_output --partial "skipped Given a given step" + refute_output --partial "should not be executed" + # assert_output --partial "tests : 0/1 passed" +} diff --git a/cucumber_cpp/library/Application.cpp b/cucumber_cpp/library/Application.cpp index 18ea07bf..20bf035f 100644 --- a/cucumber_cpp/library/Application.cpp +++ b/cucumber_cpp/library/Application.cpp @@ -224,7 +224,7 @@ namespace cucumber_cpp::library int Application::GetExitCode() const { - if (contextManager.ProgramContext().ExecutionStatus() == engine::Result::passed) + if (contextManager.ProgramContext().EffectiveExecutionStatus() == engine::Result::passed) return 0; else return 1; diff --git a/cucumber_cpp/library/engine/ContextManager.cpp b/cucumber_cpp/library/engine/ContextManager.cpp index 88f5d59f..dae3bb7a 100644 --- a/cucumber_cpp/library/engine/ContextManager.cpp +++ b/cucumber_cpp/library/engine/ContextManager.cpp @@ -5,6 +5,7 @@ #include "cucumber_cpp/library/engine/RuleInfo.hpp" #include "cucumber_cpp/library/engine/ScenarioInfo.hpp" #include "cucumber_cpp/library/engine/StepInfo.hpp" +#include #include #include #include @@ -48,11 +49,29 @@ namespace cucumber_cpp::library::engine Start(); } + [[nodiscard]] Result CurrentContext::InheritedExecutionStatus() const + { + if (parent == nullptr) + return executionStatus; + else + return std::max(executionStatus, parent->InheritedExecutionStatus()); + } + + [[nodiscard]] Result CurrentContext::EffectiveExecutionStatus() const + { + return std::max(executionStatus, nestedExecutionStatus); + } + [[nodiscard]] Result CurrentContext::ExecutionStatus() const { return executionStatus; } + [[nodiscard]] Result CurrentContext::NestedExecutionStatus() const + { + return nestedExecutionStatus; + } + void CurrentContext::Start() { traceTime.Start(); @@ -69,7 +88,16 @@ namespace cucumber_cpp::library::engine executionStatus = result; if (parent != nullptr) - parent->ExecutionStatus(result); + parent->NestedExecutionStatus(result); + } + + void CurrentContext::NestedExecutionStatus(Result result) + { + if (result > nestedExecutionStatus) + nestedExecutionStatus = result; + + if (parent != nullptr) + parent->NestedExecutionStatus(result); } ProgramContext::ProgramContext(std::shared_ptr contextStorageFactory) @@ -189,14 +217,11 @@ namespace cucumber_cpp::library::engine ContextManager::ScopedStepContext ContextManager::CreateStepContext(const StepInfo& stepInfo) { stepContext.push(std::make_shared(*scenarioContext, stepInfo)); - runnerContext.push(stepContext.top()); - return ScopedStepContext{ *this }; } void ContextManager::DisposeStepContext() { - runnerContext.pop(); stepContext.pop(); } @@ -212,4 +237,12 @@ namespace cucumber_cpp::library::engine { return *runnerContext.top(); } + + cucumber_cpp::library::engine::RunnerContext* ContextManager::CurrentStepContext() + { + if (stepContext.empty()) + return nullptr; + + return stepContext.top().get(); + } } diff --git a/cucumber_cpp/library/engine/ContextManager.hpp b/cucumber_cpp/library/engine/ContextManager.hpp index 6943380c..280fc925 100644 --- a/cucumber_cpp/library/engine/ContextManager.hpp +++ b/cucumber_cpp/library/engine/ContextManager.hpp @@ -19,7 +19,10 @@ namespace cucumber_cpp::library::engine explicit CurrentContext(std::shared_ptr contextStorageFactory); explicit CurrentContext(CurrentContext* parent); + [[nodiscard]] Result InheritedExecutionStatus() const; + [[nodiscard]] Result EffectiveExecutionStatus() const; [[nodiscard]] Result ExecutionStatus() const; + [[nodiscard]] Result NestedExecutionStatus() const; void Start(); [[nodiscard]] TraceTime::Duration Duration() const; @@ -28,9 +31,12 @@ namespace cucumber_cpp::library::engine void ExecutionStatus(Result result); private: + void NestedExecutionStatus(Result result); + CurrentContext* parent{ nullptr }; Result executionStatus{ Result::passed }; + Result nestedExecutionStatus{ Result::passed }; TraceTime traceTime; }; @@ -93,6 +99,7 @@ namespace cucumber_cpp::library::engine cucumber_cpp::library::engine::StepContext& StepContext(); cucumber_cpp::library::engine::RunnerContext& CurrentContext(); + cucumber_cpp::library::engine::RunnerContext* CurrentStepContext(); private: void DisposeFeatureContext(); diff --git a/cucumber_cpp/library/engine/FailureHandler.cpp b/cucumber_cpp/library/engine/FailureHandler.cpp index dee65a20..8fc22aa7 100644 --- a/cucumber_cpp/library/engine/FailureHandler.cpp +++ b/cucumber_cpp/library/engine/FailureHandler.cpp @@ -53,6 +53,9 @@ namespace cucumber_cpp::library::engine contextManager.CurrentContext().ExecutionStatus(cucumber_cpp::library::engine::Result::failed); + if (auto* stepContext = contextManager.CurrentStepContext(); stepContext != nullptr) + stepContext->ExecutionStatus(cucumber_cpp::library::engine::Result::failed); + reportHandler.Failure(message, relativeFilePath, line); } diff --git a/cucumber_cpp/library/engine/HookExecutor.cpp b/cucumber_cpp/library/engine/HookExecutor.cpp index 3ee295e2..eb07fdab 100644 --- a/cucumber_cpp/library/engine/HookExecutor.cpp +++ b/cucumber_cpp/library/engine/HookExecutor.cpp @@ -7,7 +7,9 @@ #include "cucumber_cpp/library/engine/StepInfo.hpp" #include #include +#include #include +#include namespace cucumber_cpp::library::engine { @@ -20,8 +22,7 @@ namespace cucumber_cpp::library::engine void ExecuteHook(cucumber_cpp::library::engine::RunnerContext& runnerContext, HookType hook, const std::set>& tags) { - try - { + if (runnerContext.InheritedExecutionStatus() == Result::passed) for (const auto& match : HookRegistry::Instance().Query(hook, tags)) { match.factory(runnerContext)->Execute(); @@ -29,11 +30,6 @@ namespace cucumber_cpp::library::engine if (runnerContext.ExecutionStatus() != cucumber_cpp::library::engine::Result::passed) return; } - } - catch (...) - { - runnerContext.ExecutionStatus(cucumber_cpp::library::engine::Result::failed); - } } } diff --git a/cucumber_cpp/library/engine/TestExecution.cpp b/cucumber_cpp/library/engine/TestExecution.cpp index dca81068..912ecfb9 100644 --- a/cucumber_cpp/library/engine/TestExecution.cpp +++ b/cucumber_cpp/library/engine/TestExecution.cpp @@ -84,7 +84,8 @@ namespace cucumber_cpp::library::engine void TestExecutionImpl::RunStep(const cucumber_cpp::library::engine::StepInfo& stepInfo) { auto scopedContext = contextManager.CreateStepContext(stepInfo); - if (contextManager.ScenarioContext().ExecutionStatus() == cucumber_cpp::library::engine::Result::passed) + if (contextManager.ScenarioContext().InheritedExecutionStatus() == Result::passed && + contextManager.ScenarioContext().EffectiveExecutionStatus() == Result::passed) { const auto scopedStepReport = reportHandler.StepStart(); const auto scopedStepHook = hookExecution.StepStart(); diff --git a/cucumber_cpp/library/engine/TestRunner.cpp b/cucumber_cpp/library/engine/TestRunner.cpp index f6e76607..0a48f286 100644 --- a/cucumber_cpp/library/engine/TestRunner.cpp +++ b/cucumber_cpp/library/engine/TestRunner.cpp @@ -35,11 +35,11 @@ namespace cucumber_cpp::library::engine { } - void TestRunnerImpl::Run(const std::vector>& feature) + void TestRunnerImpl::Run(const std::vector>& features) { auto scope = testExecution.StartRun(); - for (const auto& featurePtr : feature) + for (const auto& featurePtr : features) RunFeature(*featurePtr); } diff --git a/cucumber_cpp/library/engine/test/TestFailureHandler.cpp b/cucumber_cpp/library/engine/test/TestFailureHandler.cpp index 752d6c30..a84a98c6 100644 --- a/cucumber_cpp/library/engine/test/TestFailureHandler.cpp +++ b/cucumber_cpp/library/engine/test/TestFailureHandler.cpp @@ -2,13 +2,9 @@ #include "cucumber_cpp/library/engine/FailureHandler.hpp" #include "cucumber_cpp/library/engine/Result.hpp" #include "cucumber_cpp/library/engine/test_helper/ContextManagerInstance.hpp" -#include "cucumber_cpp/library/report/Report.hpp" -#include -#include +#include "cucumber_cpp/library/report/test_helper/ReportForwarderMock.hpp" #include #include -#include -#include namespace cucumber_cpp::library::engine { @@ -29,41 +25,32 @@ namespace cucumber_cpp::library::engine CucumberAssertHelper{ testing::TestPartResult::kNonFatalFailure, "custom_file.cpp", 0, failure } = testing::Message() << user; } - struct ReportForwarderMock : report::ReportForwarderImpl - { - using ReportForwarderImpl::ReportForwarderImpl; - virtual ~ReportForwarderMock() = default; - - MOCK_METHOD(void, Failure, (const std::string& error, std::optional path, std::optional line, std::optional column), (override)); - MOCK_METHOD(void, Error, (const std::string& error, std::optional path, std::optional line, std::optional column), (override)); - }; - struct TestFailureHandler : testing::Test { test_helper::ContextManagerInstance contextManager; - ReportForwarderMock reportHandler{ contextManager }; + report::test_helper::ReportForwarderMock reportHandler{ contextManager }; TestAssertionHandlerImpl testAssertionHandler{ contextManager, reportHandler }; }; } TEST_F(TestFailureHandler, SetContextToFailed) { - ASSERT_THAT(contextManager.CurrentContext().ExecutionStatus(), testing::Eq(Result::passed)); - ASSERT_THAT(contextManager.ProgramContext().ExecutionStatus(), testing::Eq(Result::passed)); - ASSERT_THAT(contextManager.FeatureContext().ExecutionStatus(), testing::Eq(Result::passed)); - ASSERT_THAT(contextManager.RuleContext().ExecutionStatus(), testing::Eq(Result::passed)); - ASSERT_THAT(contextManager.ScenarioContext().ExecutionStatus(), testing::Eq(Result::passed)); - ASSERT_THAT(contextManager.StepContext().ExecutionStatus(), testing::Eq(Result::passed)); + ASSERT_THAT(contextManager.CurrentContext().EffectiveExecutionStatus(), testing::Eq(Result::passed)); + ASSERT_THAT(contextManager.ProgramContext().EffectiveExecutionStatus(), testing::Eq(Result::passed)); + ASSERT_THAT(contextManager.FeatureContext().EffectiveExecutionStatus(), testing::Eq(Result::passed)); + ASSERT_THAT(contextManager.RuleContext().EffectiveExecutionStatus(), testing::Eq(Result::passed)); + ASSERT_THAT(contextManager.ScenarioContext().EffectiveExecutionStatus(), testing::Eq(Result::passed)); + ASSERT_THAT(contextManager.StepContext().EffectiveExecutionStatus(), testing::Eq(Result::passed)); ErrorWithFailureMessage("failure"); - EXPECT_THAT(contextManager.CurrentContext().ExecutionStatus(), testing::Eq(Result::failed)); - EXPECT_THAT(contextManager.ProgramContext().ExecutionStatus(), testing::Eq(Result::failed)); - EXPECT_THAT(contextManager.FeatureContext().ExecutionStatus(), testing::Eq(Result::failed)); - EXPECT_THAT(contextManager.RuleContext().ExecutionStatus(), testing::Eq(Result::failed)); - EXPECT_THAT(contextManager.ScenarioContext().ExecutionStatus(), testing::Eq(Result::failed)); - EXPECT_THAT(contextManager.StepContext().ExecutionStatus(), testing::Eq(Result::failed)); + EXPECT_THAT(contextManager.CurrentContext().EffectiveExecutionStatus(), testing::Eq(Result::failed)); + EXPECT_THAT(contextManager.ProgramContext().EffectiveExecutionStatus(), testing::Eq(Result::failed)); + EXPECT_THAT(contextManager.FeatureContext().EffectiveExecutionStatus(), testing::Eq(Result::failed)); + EXPECT_THAT(contextManager.RuleContext().EffectiveExecutionStatus(), testing::Eq(Result::failed)); + EXPECT_THAT(contextManager.ScenarioContext().EffectiveExecutionStatus(), testing::Eq(Result::failed)); + EXPECT_THAT(contextManager.StepContext().EffectiveExecutionStatus(), testing::Eq(Result::failed)); } TEST_F(TestFailureHandler, ReportFailureMessage) diff --git a/cucumber_cpp/library/engine/test/TestHookExecutor.cpp b/cucumber_cpp/library/engine/test/TestHookExecutor.cpp index 72d1c08f..7546eb1d 100644 --- a/cucumber_cpp/library/engine/test/TestHookExecutor.cpp +++ b/cucumber_cpp/library/engine/test/TestHookExecutor.cpp @@ -1,13 +1,22 @@ +#include "cucumber_cpp/library/engine/FailureHandler.hpp" #include "cucumber_cpp/library/engine/HookExecutor.hpp" +#include "cucumber_cpp/library/engine/Result.hpp" #include "cucumber_cpp/library/engine/test_helper/ContextManagerInstance.hpp" +#include "cucumber_cpp/library/report/test_helper/ReportForwarderMock.hpp" +#include +#include #include +#include +#include +#include +#include namespace cucumber_cpp::library::engine { struct TestHookExecutor : testing::Test { - test_helper::ContextManagerInstance contextManagerInstance; - HookExecutorImpl hookExecutor{ contextManagerInstance }; + std::optional contextManagerInstance{ std::in_place }; + std::optional hookExecutor{ *contextManagerInstance }; }; TEST_F(TestHookExecutor, Construct) @@ -16,49 +25,62 @@ namespace cucumber_cpp::library::engine TEST_F(TestHookExecutor, ExecuteProgramHooks) { - ASSERT_FALSE(contextManagerInstance.ProgramContext().Contains("hookBeforeAll")); - ASSERT_FALSE(contextManagerInstance.ProgramContext().Contains("hookAfterAll")); + ASSERT_FALSE(contextManagerInstance->ProgramContext().Contains("hookBeforeAll")); + ASSERT_FALSE(contextManagerInstance->ProgramContext().Contains("hookAfterAll")); { - auto scope = hookExecutor.BeforeAll(); - EXPECT_TRUE(contextManagerInstance.ProgramContext().Contains("hookBeforeAll")); + auto scope = hookExecutor->BeforeAll(); + EXPECT_TRUE(contextManagerInstance->ProgramContext().Contains("hookBeforeAll")); } - EXPECT_TRUE(contextManagerInstance.ProgramContext().Contains("hookAfterAll")); + EXPECT_TRUE(contextManagerInstance->ProgramContext().Contains("hookAfterAll")); } TEST_F(TestHookExecutor, ExecuteBeforeFeature) { - ASSERT_FALSE(contextManagerInstance.FeatureContext().Contains("hookBeforeFeature")); - ASSERT_FALSE(contextManagerInstance.FeatureContext().Contains("hookAfterFeature")); + ASSERT_FALSE(contextManagerInstance->FeatureContext().Contains("hookBeforeFeature")); + ASSERT_FALSE(contextManagerInstance->FeatureContext().Contains("hookAfterFeature")); { - auto scope = hookExecutor.FeatureStart(); - EXPECT_TRUE(contextManagerInstance.FeatureContext().Contains("hookBeforeFeature")); + auto scope = hookExecutor->FeatureStart(); + EXPECT_TRUE(contextManagerInstance->FeatureContext().Contains("hookBeforeFeature")); } - EXPECT_TRUE(contextManagerInstance.FeatureContext().Contains("hookAfterFeature")); + EXPECT_TRUE(contextManagerInstance->FeatureContext().Contains("hookAfterFeature")); } TEST_F(TestHookExecutor, ExecuteBeforeScenario) { - ASSERT_FALSE(contextManagerInstance.ScenarioContext().Contains("hookBeforeScenario")); - ASSERT_FALSE(contextManagerInstance.ScenarioContext().Contains("hookAfterScenario")); + ASSERT_FALSE(contextManagerInstance->ScenarioContext().Contains("hookBeforeScenario")); + ASSERT_FALSE(contextManagerInstance->ScenarioContext().Contains("hookAfterScenario")); { - auto scope = hookExecutor.ScenarioStart(); - EXPECT_TRUE(contextManagerInstance.ScenarioContext().Contains("hookBeforeScenario")); + auto scope = hookExecutor->ScenarioStart(); + EXPECT_TRUE(contextManagerInstance->ScenarioContext().Contains("hookBeforeScenario")); } - EXPECT_TRUE(contextManagerInstance.ScenarioContext().Contains("hookAfterScenario")); + EXPECT_TRUE(contextManagerInstance->ScenarioContext().Contains("hookAfterScenario")); } TEST_F(TestHookExecutor, ExecuteBeforeStep) { - ASSERT_FALSE(contextManagerInstance.ScenarioContext().Contains("hookBeforeStep")); - ASSERT_FALSE(contextManagerInstance.ScenarioContext().Contains("hookAfterStep")); + ASSERT_FALSE(contextManagerInstance->ScenarioContext().Contains("hookBeforeStep")); + ASSERT_FALSE(contextManagerInstance->ScenarioContext().Contains("hookAfterStep")); { - auto scope = hookExecutor.StepStart(); - EXPECT_TRUE(contextManagerInstance.ScenarioContext().Contains("hookBeforeStep")); + auto scope = hookExecutor->StepStart(); + EXPECT_TRUE(contextManagerInstance->ScenarioContext().Contains("hookBeforeStep")); } - EXPECT_TRUE(contextManagerInstance.ScenarioContext().Contains("hookAfterStep")); + EXPECT_TRUE(contextManagerInstance->ScenarioContext().Contains("hookAfterStep")); + } + + TEST_F(TestHookExecutor, BeforeHookError) + { + contextManagerInstance.emplace(std::set>{ "@errorbefore" }); + hookExecutor.emplace(*contextManagerInstance); + + report::test_helper::ReportForwarderMock reportHandler{ *contextManagerInstance }; + TestAssertionHandlerImpl assertionHandler{ *contextManagerInstance, reportHandler }; + + auto hook = hookExecutor->StepStart(); + + EXPECT_THAT(contextManagerInstance->CurrentStepContext()->ExecutionStatus(), testing::Eq(Result::failed)); } } diff --git a/cucumber_cpp/library/engine/test/TestHookExecutorHooks.cpp b/cucumber_cpp/library/engine/test/TestHookExecutorHooks.cpp index a4e0c1b2..15888377 100644 --- a/cucumber_cpp/library/engine/test/TestHookExecutorHooks.cpp +++ b/cucumber_cpp/library/engine/test/TestHookExecutorHooks.cpp @@ -43,4 +43,9 @@ namespace cucumber_cpp::library::engine { context.InsertAt("hookAfterStep", std::string{ "hookAfterStep" }); } + + HOOK_BEFORE_STEP("@errorbefore") + { + ASSERT_FALSE(true); + } } diff --git a/cucumber_cpp/library/engine/test/TestTestRunner.cpp b/cucumber_cpp/library/engine/test/TestTestRunner.cpp index c233862a..24520d7f 100644 --- a/cucumber_cpp/library/engine/test/TestTestRunner.cpp +++ b/cucumber_cpp/library/engine/test/TestTestRunner.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include namespace cucumber_cpp::library::engine @@ -79,7 +80,7 @@ namespace cucumber_cpp::library::engine struct TestTestRunner : testing::Test { - TestExecutionMockInstance testExecutionMock; + testing::StrictMock testExecutionMock; TestRunnerImpl runner{ testExecutionMock }; FeatureTreeFactory featureTreeFactory; @@ -109,6 +110,18 @@ namespace cucumber_cpp::library::engine runner.Run(features); } + TEST_F(TestTestRunner, DontRunEmptyFeature) + { + EXPECT_CALL(testExecutionMock, StartRunMock); + EXPECT_CALL(testExecutionMock, StartFeatureMock).Times(0); + + auto tmp = test_helper::TemporaryFile{ "tmpfile.feature" }; + tmp << "Feature: Test feature\n"; + features.push_back(featureTreeFactory.Create(tmp.Path(), "")); + + runner.Run(features); + } + TEST_F(TestTestRunner, StartFeatureContextForEveryFeature) { EXPECT_CALL(testExecutionMock, StartRunMock); @@ -198,11 +211,11 @@ namespace cucumber_cpp::library::engine features.push_back(featureTreeFactory.Create(tmp.Path(), "")); - ASSERT_THAT(contextManager.ProgramContext().ExecutionStatus(), testing::Eq(Result::passed)); + ASSERT_THAT(contextManager.ProgramContext().EffectiveExecutionStatus(), testing::Eq(Result::passed)); runner.Run(features); - ASSERT_THAT(contextManager.ProgramContext().ExecutionStatus(), testing::Eq(Result::passed)); + ASSERT_THAT(contextManager.ProgramContext().EffectiveExecutionStatus(), testing::Eq(Result::passed)); } TEST_F(TestTestRunner, TestExceptionContinuesWithNextScenario) @@ -222,13 +235,13 @@ namespace cucumber_cpp::library::engine features.push_back(featureTreeFactory.Create(tmp.Path(), "")); - ASSERT_THAT(contextManager.ProgramContext().ExecutionStatus(), testing::Eq(Result::passed)); + ASSERT_THAT(contextManager.ProgramContext().EffectiveExecutionStatus(), testing::Eq(Result::passed)); testing::internal::CaptureStdout(); runner.Run(features); const auto stdoutString = testing::internal::GetCapturedStdout(); - EXPECT_THAT(contextManager.ProgramContext().ExecutionStatus(), testing::Eq(Result::failed)); + EXPECT_THAT(contextManager.ProgramContext().EffectiveExecutionStatus(), testing::Eq(Result::failed)); EXPECT_THAT(stdoutString, testing::HasSubstr("Exception thrown")); EXPECT_THAT(stdoutString, testing::Not(testing::HasSubstr("Should Not Be Thrown"))); diff --git a/cucumber_cpp/library/engine/test_helper/ContextManagerInstance.hpp b/cucumber_cpp/library/engine/test_helper/ContextManagerInstance.hpp index 18ca3455..6950a5fa 100644 --- a/cucumber_cpp/library/engine/test_helper/ContextManagerInstance.hpp +++ b/cucumber_cpp/library/engine/test_helper/ContextManagerInstance.hpp @@ -7,7 +7,10 @@ #include "cucumber_cpp/library/engine/RuleInfo.hpp" #include "cucumber_cpp/library/engine/ScenarioInfo.hpp" #include "cucumber_cpp/library/engine/StepInfo.hpp" +#include #include +#include +#include namespace cucumber_cpp::library::engine::test_helper { @@ -20,16 +23,20 @@ namespace cucumber_cpp::library::engine::test_helper struct ContextManagerInstance : private ContextManagerInstanceStorage , cucumber_cpp::library::engine::ContextManager { - ContextManagerInstance() + ContextManagerInstance(std::set> tags = {}) : cucumber_cpp::library::engine::ContextManager{ contextStorageFactory } + , feature{ tags, {}, {}, {}, {}, {} } + , rule{ feature, {}, {}, {}, {}, {} } + , scenario{ rule, tags, {}, {}, {}, {} } + , step{ scenario, {}, {}, {}, {}, {} } { } private: - 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::FeatureInfo feature; + cucumber_cpp::library::engine::RuleInfo rule; + cucumber_cpp::library::engine::ScenarioInfo scenario; + cucumber_cpp::library::engine::StepInfo step; ContextManager::ScopedFeatureContext featureContextScope{ CreateFeatureContext(feature) }; ContextManager::ScopedRuleContext ruleContextScope{ CreateRuleContext(rule) }; diff --git a/cucumber_cpp/library/report/CMakeLists.txt b/cucumber_cpp/library/report/CMakeLists.txt index 167fae75..bba15987 100644 --- a/cucumber_cpp/library/report/CMakeLists.txt +++ b/cucumber_cpp/library/report/CMakeLists.txt @@ -17,3 +17,7 @@ target_link_libraries(cucumber_cpp.library.report PUBLIC pugixml::pugixml cucumber_cpp.library ) + +if (CCR_BUILD_TESTS) + add_subdirectory(test_helper) +endif() diff --git a/cucumber_cpp/library/report/test_helper/CMakeLists.txt b/cucumber_cpp/library/report/test_helper/CMakeLists.txt new file mode 100644 index 00000000..8791d028 --- /dev/null +++ b/cucumber_cpp/library/report/test_helper/CMakeLists.txt @@ -0,0 +1,10 @@ +add_library(cucumber_cpp.library.report.test_helper INTERFACE) + +target_link_libraries(cucumber_cpp.library.report.test_helper INTERFACE + cucumber_cpp.library.report + gmock_main +) + +target_sources(cucumber_cpp.library.report.test_helper INTERFACE + ReportForwarderMock.hpp +) diff --git a/cucumber_cpp/library/report/test_helper/ReportForwarderMock.hpp b/cucumber_cpp/library/report/test_helper/ReportForwarderMock.hpp new file mode 100644 index 00000000..8451dbfc --- /dev/null +++ b/cucumber_cpp/library/report/test_helper/ReportForwarderMock.hpp @@ -0,0 +1,23 @@ +#ifndef TEST_HELPER_REPORTFORWARDERMOCK_HPP +#define TEST_HELPER_REPORTFORWARDERMOCK_HPP + +#include "cucumber_cpp/library/report/Report.hpp" +#include +#include +#include +#include +#include + +namespace cucumber_cpp::library::report::test_helper +{ + struct ReportForwarderMock : report::ReportForwarderImpl + { + using ReportForwarderImpl::ReportForwarderImpl; + virtual ~ReportForwarderMock() = default; + + MOCK_METHOD(void, Failure, (const std::string& error, std::optional path, std::optional line, std::optional column), (override)); + MOCK_METHOD(void, Error, (const std::string& error, std::optional path, std::optional line, std::optional column), (override)); + }; +} + +#endif