Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Rule keyword #414

Closed
wants to merge 3 commits into from
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
222 changes: 222 additions & 0 deletions gherkin/c/gherkin-languages.json

Large diffs are not rendered by default.

7 changes: 5 additions & 2 deletions gherkin/c/gherkin.berp
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
[
Tokens -> #Empty,#Comment,#TagLine,#FeatureLine,#BackgroundLine,#ScenarioLine,#ExamplesLine,#StepLine,#DocStringSeparator,#TableRow,#Language
Tokens -> #Empty,#Comment,#TagLine,#FeatureLine,#RuleLine,#BackgroundLine,#ScenarioLine,#ExamplesLine,#StepLine,#DocStringSeparator,#TableRow,#Language
IgnoredTokens -> #Comment,#Empty
ClassName -> Parser
Namespace -> Gherkin
]

GherkinDocument! := Feature?
Feature! := FeatureHeader Background? ScenarioDefinition*
Feature! := FeatureHeader Background? ScenarioDefinition* Rule*
FeatureHeader! := #Language? Tags? #FeatureLine DescriptionHelper

Rule! := RuleHeader Background? ScenarioDefinition*
RuleHeader! := #RuleLine DescriptionHelper

Background! := #BackgroundLine DescriptionHelper Step*

// we could avoid defining ScenarioDefinition, but that would require regular look-aheads, so worse performance
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
{"data":"(2:1): expected: #EOF, #Language, #TagLine, #FeatureLine, #Comment, #Empty, got 'invalid line here'","media":{"encoding":"utf-8","type":"text/x.cucumber.stacktrace+plain"},"source":{"start":{"column":1,"line":2},"uri":"testdata/bad/multiple_parser_errors.feature"},"type":"attachment"}
{"data":"(9:1): expected: #EOF, #TableRow, #DocStringSeparator, #StepLine, #TagLine, #ExamplesLine, #ScenarioLine, #Comment, #Empty, got 'another invalid line here'","media":{"encoding":"utf-8","type":"text/x.cucumber.stacktrace+plain"},"source":{"start":{"column":1,"line":9},"uri":"testdata/bad/multiple_parser_errors.feature"},"type":"attachment"}
{"data":"(9:1): expected: #EOF, #TableRow, #DocStringSeparator, #StepLine, #TagLine, #ExamplesLine, #ScenarioLine, #RuleLine, #Comment, #Empty, got 'another invalid line here'","media":{"encoding":"utf-8","type":"text/x.cucumber.stacktrace+plain"},"source":{"start":{"column":1,"line":9},"uri":"testdata/bad/multiple_parser_errors.feature"},"type":"attachment"}
44 changes: 1 addition & 43 deletions gherkin/c/testdata/good/minimal-example.feature.ast.ndjson
Original file line number Diff line number Diff line change
@@ -1,43 +1 @@
{
"document": {
"comments": [],
"feature": {
"children": [
{
"examples": [],
"keyword": "Example",
"location": {
"column": 3,
"line": 3
},
"name": "minimalistic",
"steps": [
{
"keyword": "Given ",
"location": {
"column": 5,
"line": 4
},
"text": "the minimalism",
"type": "Step"
}
],
"tags": [],
"type": "Scenario"
}
],
"keyword": "Feature",
"language": "en",
"location": {
"column": 1,
"line": 1
},
"name": "Minimal",
"tags": [],
"type": "Feature"
},
"type": "GherkinDocument"
},
"type": "gherkin-document",
"uri": "testdata/good/minimal-example.feature"
}
{"document":{"comments":[],"feature":{"children":[{"examples":[],"keyword":"Example","location":{"column":3,"line":3},"name":"minimalistic","steps":[{"keyword":"Given ","location":{"column":5,"line":4},"text":"the minimalism","type":"Step"}],"tags":[],"type":"Scenario"}],"keyword":"Feature","language":"en","location":{"column":1,"line":1},"name":"Minimal","tags":[],"type":"Feature"},"type":"GherkinDocument"},"type":"gherkin-document","uri":"testdata/good/minimal-example.feature"}
19 changes: 19 additions & 0 deletions gherkin/c/testdata/good/rule.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
Feature: Some rules

Background:
Given fb

Rule: A
The rule A description

Background:
Given ab

Example: Example A
Given a

Rule: B
The rule B description

Example: Example B
Given b
1 change: 1 addition & 0 deletions gherkin/c/testdata/good/rule.feature.ast.ndjson
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"document":{"comments":[],"feature":{"children":[{"keyword":"Background","location":{"column":3,"line":3},"name":"","steps":[{"keyword":"Given ","location":{"column":5,"line":4},"text":"fb","type":"Step"}],"type":"Background"},{"children":[{"keyword":"Background","location":{"column":5,"line":9},"name":"","steps":[{"keyword":"Given ","location":{"column":7,"line":10},"text":"ab","type":"Step"}],"type":"Background"},{"examples":[],"keyword":"Example","location":{"column":5,"line":12},"name":"Example A","steps":[{"keyword":"Given ","location":{"column":7,"line":13},"text":"a","type":"Step"}],"tags":[],"type":"Scenario"}],"description":" The rule A description","keyword":"Rule","location":{"column":3,"line":6},"name":"A","type":"Rule"},{"children":[{"examples":[],"keyword":"Example","location":{"column":5,"line":18},"name":"Example B","steps":[{"keyword":"Given ","location":{"column":7,"line":19},"text":"b","type":"Step"}],"tags":[],"type":"Scenario"}],"description":" The rule B description","keyword":"Rule","location":{"column":3,"line":15},"name":"B","type":"Rule"}],"keyword":"Feature","language":"en","location":{"column":1,"line":1},"name":"Some rules","tags":[],"type":"Feature"},"type":"GherkinDocument"},"type":"gherkin-document","uri":"testdata/good/rule.feature"}
2 changes: 2 additions & 0 deletions gherkin/c/testdata/good/rule.feature.pickles.ndjson
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{"pickle":{"language":"en","locations":[{"column":5,"line":12}],"name":"Example A","steps":[{"arguments":[],"locations":[{"column":11,"line":4}],"text":"fb"},{"arguments":[],"locations":[{"column":13,"line":10}],"text":"ab"},{"arguments":[],"locations":[{"column":13,"line":13}],"text":"a"}],"tags":[]},"type":"pickle","uri":"testdata/good/rule.feature"}
{"pickle":{"language":"en","locations":[{"column":5,"line":18}],"name":"Example B","steps":[{"arguments":[],"locations":[{"column":11,"line":4}],"text":"fb"},{"arguments":[],"locations":[{"column":13,"line":19}],"text":"b"}],"tags":[]},"type":"pickle","uri":"testdata/good/rule.feature"}
1 change: 1 addition & 0 deletions gherkin/c/testdata/good/rule.feature.source.ndjson
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"data":"Feature: Some rules\n\n Background:\n Given fb\n\n Rule: A\n The rule A description\n\n Background:\n Given ab\n\n Example: Example A\n Given a\n\n Rule: B\n The rule B description\n\n Example: Example B\n Given b","media":{"encoding":"utf-8","type":"text/x.cucumber.gherkin+plain"},"type":"source","uri":"testdata/good/rule.feature"}
20 changes: 20 additions & 0 deletions gherkin/c/testdata/good/rule.feature.tokens
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
(1:1)FeatureLine:Feature/Some rules/
(2:1)Empty://
(3:3)BackgroundLine:Background//
(4:5)StepLine:Given /fb/
(5:1)Empty://
(6:3)RuleLine:Rule/A/
(7:1)Other:/ The rule A description/
(8:1)Other://
(9:5)BackgroundLine:Background//
(10:7)StepLine:Given /ab/
(11:1)Empty://
(12:5)ScenarioLine:Example/Example A/
(13:7)StepLine:Given /a/
(14:1)Empty://
(15:3)RuleLine:Rule/B/
(16:1)Other:/ The rule B description/
(17:1)Other://
(18:5)ScenarioLine:Example/Example B/
(19:7)StepLine:Given /b/
EOF
6 changes: 3 additions & 3 deletions gherkin/dotnet/Gherkin/Ast/Feature.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@

namespace Gherkin.Ast
{
public class Feature : IHasLocation, IHasDescription, IHasTags
public class Feature : IHasLocation, IHasDescription, IHasTags, IHasChildren
{
public IEnumerable<Tag> Tags { get; private set; }
public Location Location { get; private set; }
public string Language { get; private set; }
public string Keyword { get; private set; }
public string Name { get; private set; }
public string Description { get; private set; }
public IEnumerable<StepsContainer> Children { get; private set; }
public IEnumerable<IHasLocation> Children { get; private set; }

public Feature(Tag[] tags, Location location, string language, string keyword, string name, string description, StepsContainer[] children)
public Feature(Tag[] tags, Location location, string language, string keyword, string name, string description, IHasLocation[] children)
{
Tags = tags;
Location = location;
Expand Down
9 changes: 9 additions & 0 deletions gherkin/dotnet/Gherkin/Ast/IHasChildren.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System.Collections.Generic;

namespace Gherkin.Ast
{
public interface IHasChildren
{
IEnumerable<IHasLocation> Children { get; }
}
}
22 changes: 22 additions & 0 deletions gherkin/dotnet/Gherkin/Ast/Rule.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System.Collections.Generic;

namespace Gherkin.Ast
{
public class Rule : IHasLocation, IHasDescription, IHasChildren
{
public Location Location { get; private set; }
public string Keyword { get; private set; }
public string Name { get; private set; }
public string Description { get; private set; }
public IEnumerable<IHasLocation> Children { get; private set; }

public Rule(Location location, string keyword, string name, string description, IHasLocation[] children)
{
Location = location;
Keyword = keyword;
Name = name;
Description = description;
Children = children;
}
}
}
32 changes: 29 additions & 3 deletions gherkin/dotnet/Gherkin/AstBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,19 +129,39 @@ private object GetTransformedNode(AstNode node)
var tags = GetTags(header);
var featureLine = header.GetToken(TokenType.FeatureLine);
if(featureLine == null) return null;
var children = new List<StepsContainer> ();
var children = new List<IHasLocation> ();
var background = node.GetSingle<Background>(RuleType.Background);
if (background != null)
{
children.Add (background);
}
var childrenEnumerable = children.Concat(node.GetItems<StepsContainer>(RuleType.ScenarioDefinition));
var childrenEnumerable = children.Concat(node.GetItems<IHasLocation>(RuleType.ScenarioDefinition))
.Concat(node.GetItems<IHasLocation>(RuleType.Rule));
var description = GetDescription(header);
if(featureLine.MatchedGherkinDialect == null) return null;
var language = featureLine.MatchedGherkinDialect.Language;

return CreateFeature(tags, GetLocation(featureLine), language, featureLine.MatchedKeyword, featureLine.MatchedText, description, childrenEnumerable.ToArray(), node);
}
case RuleType.Rule:
{
var header = node.GetSingle<AstNode>(RuleType.RuleHeader);
if (header == null) return null;
var ruleLine = header.GetToken(TokenType.RuleLine);
if (ruleLine == null) return null;
var children = new List<IHasLocation>();
var background = node.GetSingle<Background>(RuleType.Background);
if (background != null)
{
children.Add(background);
}
var childrenEnumerable = children.Concat(node.GetItems<IHasLocation>(RuleType.ScenarioDefinition));
var description = GetDescription(header);
if (ruleLine.MatchedGherkinDialect == null) return null;
var language = ruleLine.MatchedGherkinDialect.Language;

return CreateRule(GetLocation(ruleLine), ruleLine.MatchedKeyword, ruleLine.MatchedText, description, childrenEnumerable.ToArray(), node);
}
case RuleType.GherkinDocument:
{
var feature = node.GetSingle<Feature>(RuleType.Feature);
Expand Down Expand Up @@ -192,10 +212,16 @@ protected virtual GherkinDocument CreateGherkinDocument(Feature feature, Comment
return new GherkinDocument(feature, gherkinDocumentComments);
}

protected virtual Feature CreateFeature(Tag[] tags, Location location, string language, string keyword, string name, string description, StepsContainer[] children, AstNode node)
protected virtual Feature CreateFeature(Tag[] tags, Location location, string language, string keyword, string name, string description, IHasLocation[] children, AstNode node)
{
return new Feature(tags, location, language, keyword, name, description, children);
}

protected virtual Rule CreateRule(Location location, string keyword, string name, string description, IHasLocation[] children, AstNode node)
{
return new Rule(location, keyword, name, description, children);
}

protected virtual Tag CreateTag(Location location, string name, AstNode node)
{
return new Tag(location, name);
Expand Down
3 changes: 3 additions & 0 deletions gherkin/dotnet/Gherkin/GherkinDialect.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ public class GherkinDialect
public string Language { get; private set; }

public string[] FeatureKeywords { get; private set; }
public string[] RuleKeywords { get; private set; }
public string[] BackgroundKeywords { get; private set; }
public string[] ScenarioKeywords { get; private set; }
public string[] ScenarioOutlineKeywords { get; private set; }
Expand All @@ -23,6 +24,7 @@ public class GherkinDialect
public GherkinDialect(
string language,
string[] featureKeywords,
string[] ruleKeywords,
string[] backgroundKeywords,
string[] scenarioKeywords,
string[] scenarioOutlineKeywords,
Expand All @@ -35,6 +37,7 @@ public GherkinDialect(
{
Language = language;
FeatureKeywords = featureKeywords;
RuleKeywords = ruleKeywords;
BackgroundKeywords = backgroundKeywords;
ScenarioKeywords = scenarioKeywords;
ScenarioOutlineKeywords = scenarioOutlineKeywords;
Expand Down
3 changes: 3 additions & 0 deletions gherkin/dotnet/Gherkin/GherkinDialectProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ protected class GherkinLanguageSetting
public string name;
public string native;
public string[] feature;
public string[] rule;
public string[] background;
public string[] scenario;
public string[] scenarioOutline;
Expand Down Expand Up @@ -102,6 +103,7 @@ protected GherkinDialect CreateGherkinDialect(string language, GherkinLanguageSe
return new GherkinDialect(
language,
ParseTitleKeywords(languageSettings.feature),
ParseTitleKeywords(languageSettings.rule),
ParseTitleKeywords(languageSettings.background),
ParseTitleKeywords(languageSettings.scenario),
ParseTitleKeywords(languageSettings.scenarioOutline),
Expand Down Expand Up @@ -129,6 +131,7 @@ protected static GherkinDialect GetFactoryDefault()
return new GherkinDialect(
"en",
new[] {"Feature"},
new[] {"Rule"},
new[] {"Background"},
new[] {"Scenario"},
new[] {"Scenario Outline", "Scenario Template"},
Expand Down
Loading