Skip to content

Commit e85ecc0

Browse files
authored
feat!: follow the Gherkin standard by not differentiating between step types (#199)
Previously a each type of step definition (`Given`, `When` and `Then`) was given its own category. That means the following steps were considered different: ```cpp GIVEN("I am different"){} When("I am different"){} Then("I am different"){} ``` With this change the above are now considered duplicate steps and they'll result in an ambiguous error. This is considered a breaking change.
1 parent 552df48 commit e85ecc0

File tree

7 files changed

+26
-71
lines changed

7 files changed

+26
-71
lines changed

cucumber_cpp/acceptance_test/features/test_scenarios.feature

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,5 @@ Feature: Simple feature file
1818

1919
@result:UNDEFINED
2020
Scenario: A scenario with undefined step
21-
Given a given step
22-
When a when step
23-
Then a when step
24-
Then a then step
21+
Given a missing step
22+
Then this should be skipped

cucumber_cpp/acceptance_test/steps/Steps.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,8 @@ GIVEN("a ← tuple\\({float}, {float}, {float}, {float}\\)", (float /* unused */
5050
{
5151
// empty
5252
}
53+
54+
THEN("this should be skipped")
55+
{
56+
FAIL();
57+
}

cucumber_cpp/acceptance_test/test.bats

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ teardown() {
3030
run .build/Host/cucumber_cpp/acceptance_test/Debug/cucumber_cpp.acceptance_test run --tag "@result:UNDEFINED" --feature cucumber_cpp/acceptance_test/features --report console
3131
assert_failure
3232
assert_output --partial "undefined \"cucumber_cpp/acceptance_test/features/test_scenarios.feature\""
33-
assert_output --partial "skipped Then a then step"
33+
assert_output --partial "skipped Then this should be skipped"
3434
}
3535

3636
@test "No tests" {
@@ -127,7 +127,7 @@ teardown() {
127127
run .build/Host/cucumber_cpp/acceptance_test/Debug/cucumber_cpp.acceptance_test run --feature cucumber_cpp/acceptance_test/features --tag "@result:UNDEFINED" --report console --dry
128128
assert_failure
129129
assert_output --partial "undefined \"cucumber_cpp/acceptance_test/features/test_scenarios.feature\""
130-
assert_output --partial "skipped Then a then step"
130+
assert_output --partial "skipped Then this should be skipped"
131131
}
132132

133133
@test "Test the and keyword" {

cucumber_cpp/library/StepRegistry.cpp

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,8 @@
77
#include "cucumber_cpp/library/cucumber_expression/RegularExpression.hpp"
88
#include "cucumber_cpp/library/engine/StepType.hpp"
99
#include "cucumber_cpp/library/engine/Table.hpp"
10-
#include <algorithm>
1110
#include <cstddef>
1211
#include <memory>
13-
#include <ranges>
1412
#include <span>
1513
#include <string>
1614
#include <utility>
@@ -19,29 +17,18 @@
1917

2018
namespace cucumber_cpp::library
2119
{
22-
namespace
23-
{
24-
auto TypeFilter(engine::StepType stepType)
25-
{
26-
return [stepType](const StepRegistry::Entry& entry)
27-
{
28-
return entry.type == stepType || entry.type == engine::StepType::any;
29-
};
30-
};
31-
}
32-
3320
StepRegistry::StepRegistry(cucumber_expression::ParameterRegistry& parameterRegistry)
3421
: parameterRegistry{ parameterRegistry }
3522
{
3623
for (const auto& matcher : StepStringRegistration::Instance().GetEntries())
3724
Register(matcher.regex, matcher.type, matcher.factory);
3825
}
3926

40-
StepMatch StepRegistry::Query(engine::StepType stepType, const std::string& expression)
27+
StepMatch StepRegistry::Query(const std::string& expression)
4128
{
4229
std::vector<StepMatch> matches;
4330

44-
for (Entry& entry : registry | std::views::filter(TypeFilter(stepType)))
31+
for (Entry& entry : registry)
4532
{
4633
auto match = std::visit(cucumber_expression::MatchVisitor{ expression }, entry.regex);
4734
if (match)
@@ -65,11 +52,6 @@ namespace cucumber_cpp::library
6552
return registry.size();
6653
}
6754

68-
std::size_t StepRegistry::Size(engine::StepType stepType) const
69-
{
70-
return std::ranges::count(registry, stepType, &Entry::type);
71-
}
72-
7355
std::vector<StepRegistry::EntryView> StepRegistry::List() const
7456
{
7557
std::vector<StepRegistry::EntryView> list;

cucumber_cpp/library/StepRegistry.hpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,9 @@ namespace cucumber_cpp::library
8484

8585
explicit StepRegistry(cucumber_expression::ParameterRegistry& parameterRegistry);
8686

87-
[[nodiscard]] StepMatch Query(engine::StepType stepType, const std::string& expression);
87+
[[nodiscard]] StepMatch Query(const std::string& expression);
8888

8989
[[nodiscard]] std::size_t Size() const;
90-
[[nodiscard]] std::size_t Size(engine::StepType stepType) const;
9190

9291
[[nodiscard]] std::vector<EntryView> List() const;
9392

cucumber_cpp/library/engine/FeatureFactory.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,6 @@ namespace cucumber_cpp::library::engine
158158
}
159159
catch (const std::out_of_range&)
160160
{
161-
162161
throw UnsupportedAsteriskError{ std::format("{}:{}: * steps are not supported", scenarioInfo.FeatureInfo().Path().string(), step.location.line) };
163162
}
164163
}
@@ -292,7 +291,7 @@ namespace cucumber_cpp::library::engine
292291
{
293292
try
294293
{
295-
auto stepMatch = stepRegistry.Query(stepType, stepText);
294+
auto stepMatch = stepRegistry.Query(stepText);
296295
return std::make_unique<StepInfo>(scenarioInfo, std::move(stepText), stepType, line, column, std::move(table), std::move(stepMatch));
297296
}
298297
catch (const StepRegistry::StepNotFoundError&)
Lines changed: 13 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
#include "cucumber_cpp/library/Context.hpp"
22
#include "cucumber_cpp/library/StepRegistry.hpp"
33
#include "cucumber_cpp/library/cucumber_expression/ParameterRegistry.hpp"
4-
#include "cucumber_cpp/library/engine/StepType.hpp"
54
#include "gtest/gtest.h"
65
#include <cstdint>
76
#include <gmock/gmock.h>
@@ -22,43 +21,19 @@ namespace cucumber_cpp::library
2221
TEST_F(TestSteps, RegisterThroughPreregistration)
2322
{
2423
EXPECT_THAT(stepRegistry.Size(), testing::Ge(1));
25-
EXPECT_THAT(stepRegistry.Size(engine::StepType::given), testing::Ge(1));
26-
EXPECT_THAT(stepRegistry.Size(engine::StepType::when), testing::Ge(1));
27-
EXPECT_THAT(stepRegistry.Size(engine::StepType::then), testing::Ge(1));
28-
EXPECT_THAT(stepRegistry.Size(engine::StepType::any), testing::Ge(1));
2924
}
3025

3126
TEST_F(TestSteps, GetGivenStep)
3227
{
33-
const auto matches = stepRegistry.Query(engine::StepType::given, "This is a GIVEN step");
34-
35-
EXPECT_THAT(matches.stepRegexStr, testing::StrEq("^This is a GIVEN step$"));
36-
}
37-
38-
TEST_F(TestSteps, GetWhenStep)
39-
{
40-
const auto matches = stepRegistry.Query(engine::StepType::when, "This is a WHEN step");
41-
42-
EXPECT_THAT(matches.stepRegexStr, testing::StrEq("^This is a WHEN step$"));
43-
}
44-
45-
TEST_F(TestSteps, GetThenStep)
46-
{
47-
const auto matches = stepRegistry.Query(engine::StepType::then, "This is a THEN step");
48-
49-
EXPECT_THAT(matches.stepRegexStr, testing::StrEq("^This is a THEN step$"));
50-
}
51-
52-
TEST_F(TestSteps, GetAnyStep)
53-
{
54-
const auto matches = stepRegistry.Query(engine::StepType::given, "This is a STEP step");
55-
56-
EXPECT_THAT(matches.stepRegexStr, testing::StrEq("^This is a STEP step$"));
28+
EXPECT_THAT(stepRegistry.Query("This is a GIVEN step").stepRegexStr, testing::StrEq("^This is a GIVEN step$"));
29+
EXPECT_THAT(stepRegistry.Query("This is a WHEN step").stepRegexStr, testing::StrEq("^This is a WHEN step$"));
30+
EXPECT_THAT(stepRegistry.Query("This is a THEN step").stepRegexStr, testing::StrEq("^This is a THEN step$"));
31+
EXPECT_THAT(stepRegistry.Query("This is a STEP step").stepRegexStr, testing::StrEq("^This is a STEP step$"));
5732
}
5833

5934
TEST_F(TestSteps, GetStepWithMatches)
6035
{
61-
const auto matches = stepRegistry.Query(engine::StepType::when, "This is a step with a 10s delay");
36+
const auto matches = stepRegistry.Query("This is a step with a 10s delay");
6237

6338
EXPECT_THAT(matches.stepRegexStr, testing::StrEq("^This is a step with a ([0-9]+)s delay$"));
6439

@@ -68,20 +43,17 @@ namespace cucumber_cpp::library
6843

6944
TEST_F(TestSteps, GetInvalidStep)
7045
{
71-
EXPECT_THROW((void)stepRegistry.Query(engine::StepType::when, "This step does not exist"), StepRegistry::StepNotFoundError);
46+
EXPECT_THROW((void)stepRegistry.Query("This step does not exist"), StepRegistry::StepNotFoundError);
7247
}
7348

7449
TEST_F(TestSteps, GetAmbiguousStep)
7550
{
76-
EXPECT_NO_THROW((void)stepRegistry.Query(engine::StepType::given, "an ambiguous step"));
77-
EXPECT_NO_THROW((void)stepRegistry.Query(engine::StepType::when, "an ambiguous step"));
78-
79-
EXPECT_THROW((void)stepRegistry.Query(engine::StepType::then, "an ambiguous step"), StepRegistry::AmbiguousStepError);
51+
EXPECT_THROW((void)stepRegistry.Query("an ambiguous step"), StepRegistry::AmbiguousStepError);
8052
}
8153

8254
TEST_F(TestSteps, InvokeTestWithCucumberExpressions)
8355
{
84-
const auto matches = stepRegistry.Query(engine::StepType::when, R"(Step with cucumber expression syntax 1.5 "abcdef" 10)");
56+
const auto matches = stepRegistry.Query(R"(Step with cucumber expression syntax 1.5 "abcdef" 10)");
8557

8658
auto contextStorage{ std::make_shared<ContextStorageFactoryImpl>() };
8759
Context context{ contextStorage };
@@ -99,16 +71,16 @@ namespace cucumber_cpp::library
9971

10072
TEST_F(TestSteps, EscapedCucumberExpression)
10173
{
102-
const auto matchesParens = stepRegistry.Query(engine::StepType::then, R"(An expression with (parenthesis) should remain as is)");
74+
const auto matchesParens = stepRegistry.Query(R"(An expression with (parenthesis) should remain as is)");
10375
EXPECT_THAT(matchesParens.stepRegexStr, testing::StrEq(R"(^An expression with \(parenthesis\) should remain as is$)"));
10476

105-
const auto matchesBrace = stepRegistry.Query(engine::StepType::then, R"(An expression with {braces} should remain as is)");
77+
const auto matchesBrace = stepRegistry.Query(R"(An expression with {braces} should remain as is)");
10678
EXPECT_THAT(matchesBrace.stepRegexStr, testing::StrEq(R"(^An expression with \{braces\} should remain as is$)"));
10779
}
10880

10981
TEST_F(TestSteps, FunctionLikeStep)
11082
{
111-
const auto matches = stepRegistry.Query(engine::StepType::then, R"(An expression that looks like a function func(1, 2) should keep its parameters)");
83+
const auto matches = stepRegistry.Query(R"(An expression that looks like a function func(1, 2) should keep its parameters)");
11284

11385
auto contextStorage{ std::make_shared<ContextStorageFactoryImpl>() };
11486
Context context{ contextStorage };
@@ -118,7 +90,7 @@ namespace cucumber_cpp::library
11890

11991
TEST_F(TestSteps, EscapedParenthesis)
12092
{
121-
const auto matches1 = stepRegistry.Query(engine::StepType::then, R"(An expression with \(escaped parenthesis\) should keep the slash)");
122-
const auto matches2 = stepRegistry.Query(engine::StepType::then, R"(An expression with \{escaped braces\} should keep the slash)");
93+
const auto matches1 = stepRegistry.Query(R"(An expression with \(escaped parenthesis\) should keep the slash)");
94+
const auto matches2 = stepRegistry.Query(R"(An expression with \{escaped braces\} should keep the slash)");
12395
}
12496
}

0 commit comments

Comments
 (0)