Skip to content

Commit c4c4d13

Browse files
authored
Fix 95: Ambiguous step reported when definition matches via more than one tag (#96)
* Attempt to create reproduction Spec test by supporting creation of StepDefinitions that have mutliple tags. * Fix for Issue #95. Changed the discovery ProjectBindingRegistry to only take the first binding of those that match on multiple scopes but resolve to the same Implementation. Added a unit test and a Spec test. * Updated CHANGELOG.MD * Added a new project step method in the Specs to properly create the Stepdefinitions that have multiple scope tags without interfering with how it was being done for other tests. * Added EqualityComparer<T> for ProjectBindingImplementation so that the semantics are clear when the ProjectBindingRegistry disambiguates possibly ambiguous step definitions that happen to have multiple matching Scopes.
1 parent 5e63a61 commit c4c4d13

File tree

7 files changed

+252
-111
lines changed

7 files changed

+252
-111
lines changed

CHANGELOG.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
## Improvements:
44

55
## Bug fixes:
6-
7-
*Contributors of this release (in alphabetical order):*
6+
* Fix: Ambiguous steps reported wehn definition matches via more than one tag (#95)
7+
*Contributors of this release (in alphabetical order):* @clrudolphi
88

99
# v2025.1.256 - 2025-03-07
1010

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
namespace Reqnroll.VisualStudio.Discovery;
2+
public class ProjectBindingImplementationEqualityComparer : IEqualityComparer<ProjectBindingImplementation>
3+
{
4+
public bool Equals(ProjectBindingImplementation x, ProjectBindingImplementation y)
5+
{
6+
if (ReferenceEquals(x, y)) return true;
7+
if (x is null || y is null) return false;
8+
9+
return x.Method == y.Method &&
10+
x.ParameterTypes.SequenceEqual(y.ParameterTypes) &&
11+
Equals(x.SourceLocation, y.SourceLocation);
12+
}
13+
14+
public int GetHashCode(ProjectBindingImplementation obj)
15+
{
16+
if (obj is null) return 0;
17+
18+
unchecked // Use unchecked to handle potential integer overflow
19+
{
20+
int hash = 17;
21+
hash = hash * 23 + (obj.Method?.GetHashCode() ?? 0);
22+
23+
foreach (var paramType in obj.ParameterTypes)
24+
hash = hash * 23 + (paramType?.GetHashCode() ?? 0);
25+
26+
hash = hash * 23 + (obj.SourceLocation?.GetHashCode() ?? 0);
27+
return hash;
28+
}
29+
}
30+
}

Reqnroll.VisualStudio/Discovery/ProjectBindingRegistry.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ public record ProjectBindingRegistry
77
private const string DocStringDefaultTypeName = TypeShortcuts.StringType;
88
public static ProjectBindingRegistry Invalid = new(ImmutableArray<ProjectStepDefinitionBinding>.Empty, ImmutableArray<ProjectHookBinding>.Empty);
99

10+
private static ProjectBindingImplementationEqualityComparer _equalityComparerForProjectBindingImplementations = new();
1011
private static int _versionCounter;
1112

1213
private ProjectBindingRegistry(IEnumerable<ProjectStepDefinitionBinding> stepDefinitions, IEnumerable<ProjectHookBinding> hooks)
@@ -186,7 +187,14 @@ private MatchResultItem[] HandleScopeOverloads(MatchResultItem[] sdMatches)
186187
var matchesWithScope = sdMatches.Where(m =>
187188
m.MatchedStepDefinition.Scope != null).ToArray();
188189
if (matchesWithScope.Any())
189-
sdMatches = matchesWithScope;
190+
{
191+
// Group matches by everything except the Scope property
192+
// and take the first item from each group
193+
sdMatches = matchesWithScope
194+
.GroupBy(m => m.MatchedStepDefinition.Implementation, _equalityComparerForProjectBindingImplementations)
195+
.Select(g => g.First())
196+
.ToArray();
197+
}
190198
}
191199

192200
return sdMatches;

Tests/Reqnroll.VisualStudio.Specs/Features/Editor/StepAnalysis.feature

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,33 @@ Scenario: Matches combination scoped step definitions
274274
"""
275275
And no binding error should be highlighted
276276

277+
Scenario: Matches on multiple tags (without improperly highlighting as Ambiguous)
278+
Given there is a Reqnroll project scope
279+
And the following step definition with mulitple Tag Scopes in the project:
280+
| type | regex | tag scope |
281+
| When | I use a step with multiple tags | @mytag1,@mytag2 |
282+
When the following feature file is opened in the editor
283+
"""
284+
Feature: Addition
285+
286+
@mytag1
287+
@mytag2
288+
Scenario: Random scenario
289+
When I use a step with multiple tags
290+
291+
"""
292+
And the project is built and the initial binding discovery is performed
293+
Then all section of types DefinedStep should be highlighted as
294+
"""
295+
Feature: Addition
296+
297+
@mytag1
298+
@mytag2
299+
Scenario: Random scenario
300+
When {DefinedStep}I use a step with multiple tags{/DefinedStep}
301+
"""
302+
And no binding error should be highlighted
303+
277304
Scenario: Analyses all scopes of background steps
278305
Given there is a Reqnroll project scope
279306
And the following step definitions in the project:

0 commit comments

Comments
 (0)