From 6fd2dd4aeb7ccfc839c8c66910e68cfbfcb234a1 Mon Sep 17 00:00:00 2001 From: Romfos Date: Thu, 15 Aug 2024 19:35:54 +0200 Subject: [PATCH] [.NET] Adopt c# 10 file scoped namespaces --- CHANGELOG.md | 1 + dotnet/Gherkin.Specs/AstBuildingTests.cs | 43 +- dotnet/Gherkin.Specs/CLI/Program.cs | 151 +++-- .../EventStubs/GherkinEventsProvider.cs | 125 ++-- .../EventStubs/SourceProvider.cs | 29 +- dotnet/Gherkin.Specs/EventTestBase.cs | 113 ++-- dotnet/Gherkin.Specs/GherkinDialectTests.cs | 57 +- .../Gherkin.Specs/Helper/LineEndingHelper.cs | 19 +- dotnet/Gherkin.Specs/Helper/NDJsonParser.cs | 25 +- .../Gherkin.Specs/Helper/TestFileProvider.cs | 41 +- dotnet/Gherkin.Specs/Helper/TestFolders.cs | 19 +- dotnet/Gherkin.Specs/PicklesTests.cs | 23 +- dotnet/Gherkin.Specs/SourceTests.cs | 23 +- dotnet/Gherkin.Specs/StringUtilsTests.cs | 31 +- .../Gherkin.Specs/SuccessfulParsingTests.cs | 19 +- dotnet/Gherkin.Specs/TokenizationTests.cs | 25 +- .../Tokens/TestTokenFormatter.cs | 55 +- .../Tokens/TokenFormatterBuilder.cs | 67 +- .../Gherkin.Specs/Tokens/TokensGenerator.cs | 35 +- dotnet/Gherkin/Ast/Background.cs | 11 +- dotnet/Gherkin/Ast/Comment.cs | 19 +- dotnet/Gherkin/Ast/DataTable.cs | 23 +- dotnet/Gherkin/Ast/DocString.cs | 27 +- dotnet/Gherkin/Ast/Examples.cs | 47 +- dotnet/Gherkin/Ast/Feature.cs | 39 +- dotnet/Gherkin/Ast/GherkinDocument.cs | 19 +- dotnet/Gherkin/Ast/IHasChildren.cs | 9 +- dotnet/Gherkin/Ast/IHasDescription.cs | 13 +- dotnet/Gherkin/Ast/IHasLocation.cs | 9 +- dotnet/Gherkin/Ast/IHasRows.cs | 9 +- dotnet/Gherkin/Ast/IHasSteps.cs | 9 +- dotnet/Gherkin/Ast/IHasTags.cs | 9 +- dotnet/Gherkin/Ast/Location.cs | 19 +- dotnet/Gherkin/Ast/Node.cs | 7 +- dotnet/Gherkin/Ast/Rule.cs | 35 +- dotnet/Gherkin/Ast/Scenario.cs | 21 +- dotnet/Gherkin/Ast/Step.cs | 31 +- dotnet/Gherkin/Ast/StepArgument.cs | 9 +- dotnet/Gherkin/Ast/StepsContainer.cs | 31 +- dotnet/Gherkin/Ast/TableCell.cs | 19 +- dotnet/Gherkin/Ast/TableRow.cs | 19 +- dotnet/Gherkin/Ast/Tag.cs | 19 +- dotnet/Gherkin/AstBuilder.cs | 507 ++++++++------- dotnet/Gherkin/AstNode.cs | 91 ++- .../CucumberMessages/AstMessagesConverter.cs | 379 ++++++----- .../CucumberMessagesDefaults.cs | 21 +- .../CucumberMessages/EnumerableExtensions.cs | 11 +- .../Gherkin/CucumberMessages/IdGenerator.cs | 41 +- .../Pickles/PickleCompiler.cs | 463 +++++++------- .../CucumberMessages/Types/Background.cs | 31 +- .../Gherkin/CucumberMessages/Types/Comment.cs | 15 +- .../CucumberMessages/Types/DataTable.cs | 15 +- .../CucumberMessages/Types/DocString.cs | 23 +- .../CucumberMessages/Types/Envelope.cs | 23 +- .../CucumberMessages/Types/Examples.cs | 39 +- .../Gherkin/CucumberMessages/Types/Feature.cs | 39 +- .../CucumberMessages/Types/FeatureChild.cs | 35 +- .../CucumberMessages/Types/GherkinDocument.cs | 19 +- .../CucumberMessages/Types/Location.cs | 29 +- .../CucumberMessages/Types/ParseError.cs | 15 +- .../Gherkin/CucumberMessages/Types/Pickle.cs | 73 ++- .../CucumberMessages/Types/PickleDocString.cs | 31 +- .../CucumberMessages/Types/PickleStep.cs | 47 +- .../Types/PickleStepArgument.cs | 15 +- .../CucumberMessages/Types/PickleTable.cs | 25 +- .../CucumberMessages/Types/PickleTableCell.cs | 25 +- .../CucumberMessages/Types/PickleTableRow.cs | 25 +- .../CucumberMessages/Types/PickleTag.cs | 29 +- dotnet/Gherkin/CucumberMessages/Types/Rule.cs | 35 +- .../CucumberMessages/Types/RuleChild.cs | 29 +- .../CucumberMessages/Types/Scenario.cs | 39 +- .../Gherkin/CucumberMessages/Types/Source.cs | 19 +- .../CucumberMessages/Types/SourceReference.cs | 17 +- dotnet/Gherkin/CucumberMessages/Types/Step.cs | 35 +- .../CucumberMessages/Types/TableCell.cs | 17 +- .../CucumberMessages/Types/TableRow.cs | 19 +- dotnet/Gherkin/CucumberMessages/Types/Tag.cs | 19 +- dotnet/Gherkin/GherkinDialect.cs | 127 ++-- dotnet/Gherkin/GherkinDialectProvider.cs | 221 ++++--- dotnet/Gherkin/GherkinLanguageConstants.cs | 23 +- dotnet/Gherkin/GherkinLine.cs | 248 ++++---- dotnet/Gherkin/GherkinLineSpan.cs | 31 +- dotnet/Gherkin/IGherkinLine.cs | 119 ++-- dotnet/Gherkin/Parser.Extensions.cs | 37 +- dotnet/Gherkin/ParserException.cs | 187 +++--- dotnet/Gherkin/StepKeywordType.cs | 19 +- dotnet/Gherkin/StringUtils.cs | 41 +- dotnet/Gherkin/TinyJson/JSONParser.cs | 591 +++++++++--------- dotnet/Gherkin/Token.cs | 59 +- dotnet/Gherkin/TokenMatcher.cs | 333 +++++----- dotnet/Gherkin/TokenScanner.cs | 49 +- 91 files changed, 2829 insertions(+), 2905 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fd602ece4..9477398ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ This document is formatted according to the principles of [Keep A CHANGELOG](htt ### Changed - [Ruby] Upgraded messages support to permit up to v26 - [.NET] Drop unsupported frameworks. Now supported target frameworks are .NET 8, .NET Framework 4.6.2, .NET Standard 2.0 +- [.NET] Adopt File Scoped Namespaces c# feature ## [29.0.0] - 2024-08-12 ### Added diff --git a/dotnet/Gherkin.Specs/AstBuildingTests.cs b/dotnet/Gherkin.Specs/AstBuildingTests.cs index 1e3ff9219..f4add7351 100644 --- a/dotnet/Gherkin.Specs/AstBuildingTests.cs +++ b/dotnet/Gherkin.Specs/AstBuildingTests.cs @@ -4,36 +4,35 @@ using Gherkin.Specs.Helper; using Xunit; -namespace Gherkin.Specs +namespace Gherkin.Specs; + +public class AstBuildingTests : EventTestBase { - public class AstBuildingTests : EventTestBase + [Theory, MemberData(nameof(TestFileProvider.GetValidTestFiles), MemberType = typeof(TestFileProvider))] + public void TestSuccessfulAstBuilding(string testFeatureFile) { - [Theory, MemberData(nameof(TestFileProvider.GetValidTestFiles), MemberType = typeof(TestFileProvider))] - public void TestSuccessfulAstBuilding(string testFeatureFile) - { - var testFile = GetFullPathToTestFeatureFile(testFeatureFile, "good", ".ast.ndjson"); - var expectedAstContent = GetExpectedContent(testFile.ExpectedFileFullPath); + var testFile = GetFullPathToTestFeatureFile(testFeatureFile, "good", ".ast.ndjson"); + var expectedAstContent = GetExpectedContent(testFile.ExpectedFileFullPath); - var expectedGherkinDocumentEvent = NDJsonParser.Deserialize(expectedAstContent); + var expectedGherkinDocumentEvent = NDJsonParser.Deserialize(expectedAstContent); - var raisedEvents = ProcessGherkinEvents(testFile.FullPath, false, true, false); + var raisedEvents = ProcessGherkinEvents(testFile.FullPath, false, true, false); - raisedEvents.Should().Match(list => list.All(e => e.GherkinDocument != null)); - AssertEvents(testFeatureFile, raisedEvents, expectedGherkinDocumentEvent, testFile); - } + raisedEvents.Should().Match(list => list.All(e => e.GherkinDocument != null)); + AssertEvents(testFeatureFile, raisedEvents, expectedGherkinDocumentEvent, testFile); + } - [Theory, MemberData(nameof(TestFileProvider.GetInvalidTestFiles), MemberType = typeof(TestFileProvider))] - public void TestFailedAstBuilding(string testFeatureFile) - { - var testFile = GetFullPathToTestFeatureFile(testFeatureFile, "bad", ".errors.ndjson"); - var expectedAstContent = GetExpectedContent(testFile.ExpectedFileFullPath); + [Theory, MemberData(nameof(TestFileProvider.GetInvalidTestFiles), MemberType = typeof(TestFileProvider))] + public void TestFailedAstBuilding(string testFeatureFile) + { + var testFile = GetFullPathToTestFeatureFile(testFeatureFile, "bad", ".errors.ndjson"); + var expectedAstContent = GetExpectedContent(testFile.ExpectedFileFullPath); - var expectedGherkinDocumentEvent = NDJsonParser.Deserialize(expectedAstContent); + var expectedGherkinDocumentEvent = NDJsonParser.Deserialize(expectedAstContent); - var raisedEvents = ProcessGherkinEvents(testFile.FullPath, false, true, false); + var raisedEvents = ProcessGherkinEvents(testFile.FullPath, false, true, false); - raisedEvents.Should().Match(list => list.All(e => e.ParseError != null)); - AssertEvents(testFeatureFile, raisedEvents, expectedGherkinDocumentEvent, testFile); - } + raisedEvents.Should().Match(list => list.All(e => e.ParseError != null)); + AssertEvents(testFeatureFile, raisedEvents, expectedGherkinDocumentEvent, testFile); } } diff --git a/dotnet/Gherkin.Specs/CLI/Program.cs b/dotnet/Gherkin.Specs/CLI/Program.cs index af3de51a1..e77d8cd5f 100644 --- a/dotnet/Gherkin.Specs/CLI/Program.cs +++ b/dotnet/Gherkin.Specs/CLI/Program.cs @@ -6,107 +6,106 @@ using Gherkin.Specs.Tokens; using Utf8Json.Resolvers; -namespace Gherkin.Specs.CLI +namespace Gherkin.Specs.CLI; + +class Program { - class Program + static int Main(string[] argv) { - static int Main(string[] argv) + if (argv.Length == 0) { - if (argv.Length == 0) - { - ShowUsage(); - return 100; - } - - switch (argv[0].ToLowerInvariant()) - { - case "tokens": - return PrintTokens(argv.Skip(1)); - case "events": - var printEventArgs = GetPrintEventsArgs(argv.Skip(1)); - return PrintEvents(printEventArgs); - default: - ShowUsage(); - return 110; - } + ShowUsage(); + return 100; } - private static void ShowUsage() + switch (argv[0].ToLowerInvariant()) { - Console.WriteLine(@"Usage: + case "tokens": + return PrintTokens(argv.Skip(1)); + case "events": + var printEventArgs = GetPrintEventsArgs(argv.Skip(1)); + return PrintEvents(printEventArgs); + default: + ShowUsage(); + return 110; + } + } + + private static void ShowUsage() + { + Console.WriteLine(@"Usage: dotnet Gherkin.Specs events [--no-source] [--no-ast] [--no-pickles] feature-file.feature - or - dotnet Gherkin.Specs tokens feature-file.feature "); - } + } - class PrintEventsArgs - { - public bool PrintSource { get; set; } = true; - public bool PrintAst { get; set; } = true; - public bool PrintPickles { get; set; } = true; - public List Paths { get; } = new(); - } + class PrintEventsArgs + { + public bool PrintSource { get; set; } = true; + public bool PrintAst { get; set; } = true; + public bool PrintPickles { get; set; } = true; + public List Paths { get; } = new(); + } - private static PrintEventsArgs GetPrintEventsArgs(IEnumerable args) - { - var result = new PrintEventsArgs(); + private static PrintEventsArgs GetPrintEventsArgs(IEnumerable args) + { + var result = new PrintEventsArgs(); - foreach (string arg in args) + foreach (string arg in args) + { + switch (arg) { - switch (arg) - { - case "--no-source": - result.PrintSource = false; - break; - case "--no-ast": - result.PrintAst = false; - break; - case "--no-pickles": - result.PrintPickles = false; - break; - default: - result.Paths.Add(arg); - break; - } + case "--no-source": + result.PrintSource = false; + break; + case "--no-ast": + result.PrintAst = false; + break; + case "--no-pickles": + result.PrintPickles = false; + break; + default: + result.Paths.Add(arg); + break; } - - return result; } - private static int PrintTokens(IEnumerable paths) + return result; + } + + private static int PrintTokens(IEnumerable paths) + { + foreach (var featureFilePath in paths) { - foreach (var featureFilePath in paths) + try { - try - { - var tokensText = TokensGenerator.GenerateTokens(featureFilePath); - Console.WriteLine(tokensText); - } - catch (Exception ex) - { - Console.Error.WriteLine(ex.Message); - return 1; - } + var tokensText = TokensGenerator.GenerateTokens(featureFilePath); + Console.WriteLine(tokensText); + } + catch (Exception ex) + { + Console.Error.WriteLine(ex.Message); + return 1; } - - return 0; } - private static int PrintEvents(PrintEventsArgs args) + return 0; + } + + private static int PrintEvents(PrintEventsArgs args) + { + var sourceProvider = new SourceProvider(); + var sources = sourceProvider.GetSources(args.Paths); + var gherkinEventsProvider = new GherkinEventsProvider(args.PrintSource, args.PrintAst, args.PrintPickles, new IncrementingIdGenerator()); + foreach (var sourceEventEvent in sources) { - var sourceProvider = new SourceProvider(); - var sources = sourceProvider.GetSources(args.Paths); - var gherkinEventsProvider = new GherkinEventsProvider(args.PrintSource, args.PrintAst, args.PrintPickles, new IncrementingIdGenerator()); - foreach (var sourceEventEvent in sources) + foreach (var evt in gherkinEventsProvider.GetEvents(sourceEventEvent)) { - foreach (var evt in gherkinEventsProvider.GetEvents(sourceEventEvent)) - { - var jsonString = Utf8Json.JsonSerializer.ToJsonString((object)evt, StandardResolver.ExcludeNullCamelCase); - Console.WriteLine(jsonString); - } + var jsonString = Utf8Json.JsonSerializer.ToJsonString((object)evt, StandardResolver.ExcludeNullCamelCase); + Console.WriteLine(jsonString); } - return 0; } + return 0; } } diff --git a/dotnet/Gherkin.Specs/EventStubs/GherkinEventsProvider.cs b/dotnet/Gherkin.Specs/EventStubs/GherkinEventsProvider.cs index af3d96b09..47b072800 100644 --- a/dotnet/Gherkin.Specs/EventStubs/GherkinEventsProvider.cs +++ b/dotnet/Gherkin.Specs/EventStubs/GherkinEventsProvider.cs @@ -5,91 +5,90 @@ using Gherkin.CucumberMessages.Pickles; using Gherkin.CucumberMessages.Types; -namespace Gherkin.Specs.EventStubs +namespace Gherkin.Specs.EventStubs; + +public class GherkinEventsProvider { - public class GherkinEventsProvider - { - private readonly Parser _parser = new Parser(); - private readonly PickleCompiler _pickleCompiler; - private readonly AstMessagesConverter _astMessagesConverter; + private readonly Parser _parser = new Parser(); + private readonly PickleCompiler _pickleCompiler; + private readonly AstMessagesConverter _astMessagesConverter; - readonly bool _printAst; - readonly bool _printPickles; - readonly bool _printSource; + readonly bool _printAst; + readonly bool _printPickles; + readonly bool _printSource; - public GherkinEventsProvider(bool printSource, bool printAst, bool printPickles, IIdGenerator idGenerator) - { - _printSource = printSource; - _astMessagesConverter = new AstMessagesConverter(idGenerator); - _pickleCompiler = new PickleCompiler(idGenerator); - _printAst = printAst; - _printPickles = printPickles; - } + public GherkinEventsProvider(bool printSource, bool printAst, bool printPickles, IIdGenerator idGenerator) + { + _printSource = printSource; + _astMessagesConverter = new AstMessagesConverter(idGenerator); + _pickleCompiler = new PickleCompiler(idGenerator); + _printAst = printAst; + _printPickles = printPickles; + } + + public IEnumerable GetEvents(Source source) + { + var events = new List(); - public IEnumerable GetEvents(Source source) + try { - var events = new List(); + var gherkinDocument = _parser.Parse(new StringReader(source.Data)); - try + if (_printSource) { - var gherkinDocument = _parser.Parse(new StringReader(source.Data)); - - if (_printSource) + events.Add(new Envelope { - events.Add(new Envelope - { - Source = source - }); - } - if (_printAst) - { - events.Add(new Envelope - { - GherkinDocument = - _astMessagesConverter.ConvertGherkinDocumentToEventArgs(gherkinDocument, source.Uri) - }); - } - if (_printPickles) + Source = source + }); + } + if (_printAst) + { + events.Add(new Envelope { - var pickles = _pickleCompiler.Compile(_astMessagesConverter.ConvertGherkinDocumentToEventArgs(gherkinDocument, source.Uri)); - foreach (Pickle pickle in pickles) - { - events.Add(new Envelope - { - Pickle = pickle - }); - } - } + GherkinDocument = + _astMessagesConverter.ConvertGherkinDocumentToEventArgs(gherkinDocument, source.Uri) + }); } - catch (CompositeParserException e) + if (_printPickles) { - foreach (ParserException error in e.Errors) + var pickles = _pickleCompiler.Compile(_astMessagesConverter.ConvertGherkinDocumentToEventArgs(gherkinDocument, source.Uri)); + foreach (Pickle pickle in pickles) { - AddParseError(events, error, source.Uri); + events.Add(new Envelope + { + Pickle = pickle + }); } } - catch (ParserException e) + } + catch (CompositeParserException e) + { + foreach (ParserException error in e.Errors) { - AddParseError(events, e, source.Uri); + AddParseError(events, error, source.Uri); } - return events; } + catch (ParserException e) + { + AddParseError(events, e, source.Uri); + } + return events; + } - private void AddParseError(List events, ParserException e, String uri) + private void AddParseError(List events, ParserException e, String uri) + { + events.Add(new Envelope { - events.Add(new Envelope + ParseError = new ParseError() { - ParseError = new ParseError() + Message = e.Message, + Source = new SourceReference() { - Message = e.Message, - Source = new SourceReference() - { - Location = new Location(e.Location.Column, e.Location.Line), - Uri = uri - } + Location = new Location(e.Location.Column, e.Location.Line), + Uri = uri } - }); - } + } + }); } } diff --git a/dotnet/Gherkin.Specs/EventStubs/SourceProvider.cs b/dotnet/Gherkin.Specs/EventStubs/SourceProvider.cs index 40d4297a2..8bf6d9f7b 100644 --- a/dotnet/Gherkin.Specs/EventStubs/SourceProvider.cs +++ b/dotnet/Gherkin.Specs/EventStubs/SourceProvider.cs @@ -3,25 +3,24 @@ using System.IO; using Gherkin.CucumberMessages.Types; -namespace Gherkin.Specs.EventStubs +namespace Gherkin.Specs.EventStubs; + +public class SourceProvider { - public class SourceProvider - { - private const string GherkinMediaType = "text/x.cucumber.gherkin+plain"; + private const string GherkinMediaType = "text/x.cucumber.gherkin+plain"; - public IEnumerable GetSources(IEnumerable paths) + public IEnumerable GetSources(IEnumerable paths) + { + foreach (var path in paths) { - foreach (var path in paths) + string data = File.ReadAllText(path); + yield return new Source { - string data = File.ReadAllText(path); - yield return new Source - { - Data = data, - Uri = path, - MediaType = GherkinMediaType - }; - } + Data = data, + Uri = path, + MediaType = GherkinMediaType + }; } - } + } diff --git a/dotnet/Gherkin.Specs/EventTestBase.cs b/dotnet/Gherkin.Specs/EventTestBase.cs index 5214ae8a7..1b4f41133 100644 --- a/dotnet/Gherkin.Specs/EventTestBase.cs +++ b/dotnet/Gherkin.Specs/EventTestBase.cs @@ -9,75 +9,74 @@ using Gherkin.Specs.EventStubs; using Gherkin.Specs.Helper; -namespace Gherkin.Specs +namespace Gherkin.Specs; + +public class EventTestBase { - public class EventTestBase + protected readonly IncrementingIdGenerator idGenerator = new IncrementingIdGenerator(); + + protected void AssertEvents(string testFeatureFile, List actualGherkinDocumentEvent, List expectedGherkinDocumentEvent, TestFile testFile) { - protected readonly IncrementingIdGenerator idGenerator = new IncrementingIdGenerator(); - - protected void AssertEvents(string testFeatureFile, List actualGherkinDocumentEvent, List expectedGherkinDocumentEvent, TestFile testFile) - { - actualGherkinDocumentEvent.Should().BeEquivalentTo(expectedGherkinDocumentEvent, - config => config - .AllowingInfiniteRecursion() - .IgnoringCyclicReferences() - .Excluding(ghe => ghe.Path.EndsWith("Uri")) - .Using(ctx => - { - var replacedSubject = NormalizeNewLines(ctx.Subject); - var expectedSubject = NormalizeNewLines(ctx.Expectation); - replacedSubject.Should().Be(expectedSubject); - }) - .WhenTypeIs(), - $"{testFeatureFile} is not generating the same content as {testFile.ExpectedFileFullPath}"); - } + actualGherkinDocumentEvent.Should().BeEquivalentTo(expectedGherkinDocumentEvent, + config => config + .AllowingInfiniteRecursion() + .IgnoringCyclicReferences() + .Excluding(ghe => ghe.Path.EndsWith("Uri")) + .Using(ctx => + { + var replacedSubject = NormalizeNewLines(ctx.Subject); + var expectedSubject = NormalizeNewLines(ctx.Expectation); + replacedSubject.Should().Be(expectedSubject); + }) + .WhenTypeIs(), + $"{testFeatureFile} is not generating the same content as {testFile.ExpectedFileFullPath}"); + } - private string NormalizeNewLines(string value) - { - return value?.Replace("\r\n", "\n").Replace("\n", Environment.NewLine); - } + private string NormalizeNewLines(string value) + { + return value?.Replace("\r\n", "\n").Replace("\n", Environment.NewLine); + } - protected class TestFile - { - public string FullPath { get; set; } - public string ExpectedFileFullPath { get; set; } - } + protected class TestFile + { + public string FullPath { get; set; } + public string ExpectedFileFullPath { get; set; } + } - protected TestFile GetFullPathToTestFeatureFile(string testFeatureFile, string category, string filePostfix) + protected TestFile GetFullPathToTestFeatureFile(string testFeatureFile, string category, string filePostfix) + { + var fullPathToTestFeatureFile = Path.Combine(TestFileProvider.GetTestFileFolder(category), testFeatureFile); + + var featureFileFolder = Path.GetDirectoryName(fullPathToTestFeatureFile); + Debug.Assert(featureFileFolder != null); + var expectedAstFile = fullPathToTestFeatureFile + filePostfix; + return new TestFile() { - var fullPathToTestFeatureFile = Path.Combine(TestFileProvider.GetTestFileFolder(category), testFeatureFile); + FullPath = fullPathToTestFeatureFile, + ExpectedFileFullPath = expectedAstFile + }; + } - var featureFileFolder = Path.GetDirectoryName(fullPathToTestFeatureFile); - Debug.Assert(featureFileFolder != null); - var expectedAstFile = fullPathToTestFeatureFile + filePostfix; - return new TestFile() - { - FullPath = fullPathToTestFeatureFile, - ExpectedFileFullPath = expectedAstFile - }; - } + protected List ProcessGherkinEvents(string fullPathToTestFeatureFile, bool printSource, bool printAst, bool printPickles) + { + var raisedEvents = new List(); - protected List ProcessGherkinEvents(string fullPathToTestFeatureFile, bool printSource, bool printAst, bool printPickles) + var sourceProvider = new SourceProvider(); + var sources = sourceProvider.GetSources(new List {fullPathToTestFeatureFile}); + var gherkinEventsProvider = new GherkinEventsProvider(printSource, printAst, printPickles, idGenerator); + foreach (var source in sources) { - var raisedEvents = new List(); - - var sourceProvider = new SourceProvider(); - var sources = sourceProvider.GetSources(new List {fullPathToTestFeatureFile}); - var gherkinEventsProvider = new GherkinEventsProvider(printSource, printAst, printPickles, idGenerator); - foreach (var source in sources) + foreach (var evt in gherkinEventsProvider.GetEvents(source)) { - foreach (var evt in gherkinEventsProvider.GetEvents(source)) - { - raisedEvents.Add(evt); - } + raisedEvents.Add(evt); } - - return raisedEvents; } - protected string GetExpectedContent(string expectedAstFile) - { - return File.ReadAllText(expectedAstFile, Encoding.UTF8); - } + return raisedEvents; + } + + protected string GetExpectedContent(string expectedAstFile) + { + return File.ReadAllText(expectedAstFile, Encoding.UTF8); } } \ No newline at end of file diff --git a/dotnet/Gherkin.Specs/GherkinDialectTests.cs b/dotnet/Gherkin.Specs/GherkinDialectTests.cs index 85740c543..818e8a723 100644 --- a/dotnet/Gherkin.Specs/GherkinDialectTests.cs +++ b/dotnet/Gherkin.Specs/GherkinDialectTests.cs @@ -1,40 +1,39 @@ using FluentAssertions; using Xunit; -namespace Gherkin.Specs +namespace Gherkin.Specs; + +public class GherkinDialectTests { - public class GherkinDialectTests + [Fact] + public void ShouldParseSpecialCharacters() { - [Fact] - public void ShouldParseSpecialCharacters() - { - var dialectProvider = new GherkinDialectProvider(); - var dialect = dialectProvider.GetDialect("hu", new Ast.Location(1, 2)); + var dialectProvider = new GherkinDialectProvider(); + var dialect = dialectProvider.GetDialect("hu", new Ast.Location(1, 2)); - dialect.FeatureKeywords.Should().Contain("Jellemző"); - } + dialect.FeatureKeywords.Should().Contain("Jellemző"); + } - [Fact] - public void ShouldThrowNoSuchLanguageExceptionForInvalidLanguage() - { - var x = new GherkinDialectProvider(); - - Assert.Throws(() => x.GetDialect("nosuchlang", new Ast.Location(1, 2))); - } + [Fact] + public void ShouldThrowNoSuchLanguageExceptionForInvalidLanguage() + { + var x = new GherkinDialectProvider(); + + Assert.Throws(() => x.GetDialect("nosuchlang", new Ast.Location(1, 2))); + } - [Fact] - public void ShouldThrowNoSuchLanguageExceptionForInvalidDefaultLanguage() - { - var x = new GherkinDialectProvider("nosuchlang"); - - Assert.Throws(() => { var dialect = x.DefaultDialect;}); - } + [Fact] + public void ShouldThrowNoSuchLanguageExceptionForInvalidDefaultLanguage() + { + var x = new GherkinDialectProvider("nosuchlang"); + + Assert.Throws(() => { var dialect = x.DefaultDialect;}); + } - [Fact] - public void ShouldThrowNoSuchLanguageExceptionForInvalidLanguageWithoutLocation() - { - var x = new GherkinDialectProvider(); - Assert.Throws(() => x.GetDialect("nosuchlang", null)); - } + [Fact] + public void ShouldThrowNoSuchLanguageExceptionForInvalidLanguageWithoutLocation() + { + var x = new GherkinDialectProvider(); + Assert.Throws(() => x.GetDialect("nosuchlang", null)); } } diff --git a/dotnet/Gherkin.Specs/Helper/LineEndingHelper.cs b/dotnet/Gherkin.Specs/Helper/LineEndingHelper.cs index 9b1b68806..bd86c84eb 100644 --- a/dotnet/Gherkin.Specs/Helper/LineEndingHelper.cs +++ b/dotnet/Gherkin.Specs/Helper/LineEndingHelper.cs @@ -1,15 +1,14 @@ -namespace Gherkin.Specs.Helper +namespace Gherkin.Specs.Helper; + +public static class LineEndingHelper { - public static class LineEndingHelper + public static string NormalizeLineEndings(string text) { - public static string NormalizeLineEndings(string text) - { - return text.Replace("\r\n", "\n").TrimEnd('\n'); - } + return text.Replace("\r\n", "\n").TrimEnd('\n'); + } - public static string StripLineEndings(string text) - { - return text.Replace("\r", "").Replace("\n", "").Trim(); - } + public static string StripLineEndings(string text) + { + return text.Replace("\r", "").Replace("\n", "").Trim(); } } diff --git a/dotnet/Gherkin.Specs/Helper/NDJsonParser.cs b/dotnet/Gherkin.Specs/Helper/NDJsonParser.cs index 07ec155e2..9636e63a4 100644 --- a/dotnet/Gherkin.Specs/Helper/NDJsonParser.cs +++ b/dotnet/Gherkin.Specs/Helper/NDJsonParser.cs @@ -2,23 +2,22 @@ using System.Collections.Generic; using Utf8Json; -namespace Gherkin.Specs.Helper +namespace Gherkin.Specs.Helper; + +public class NDJsonParser { - public class NDJsonParser + public static List Deserialize(string ndjson) { - public static List Deserialize(string ndjson) - { - var lines = ndjson.Split(new char[]{ '\n' }, StringSplitOptions.RemoveEmptyEntries); - - var result = new List(); + var lines = ndjson.Split(new char[]{ '\n' }, StringSplitOptions.RemoveEmptyEntries); - foreach (var line in lines) - { - var deserializedObject = JsonSerializer.Deserialize(line); - result.Add(deserializedObject); - } + var result = new List(); - return result; + foreach (var line in lines) + { + var deserializedObject = JsonSerializer.Deserialize(line); + result.Add(deserializedObject); } + + return result; } } \ No newline at end of file diff --git a/dotnet/Gherkin.Specs/Helper/TestFileProvider.cs b/dotnet/Gherkin.Specs/Helper/TestFileProvider.cs index 1ebf5aec9..1cb271047 100644 --- a/dotnet/Gherkin.Specs/Helper/TestFileProvider.cs +++ b/dotnet/Gherkin.Specs/Helper/TestFileProvider.cs @@ -2,32 +2,31 @@ using System.IO; using System.Linq; -namespace Gherkin.Specs.Helper +namespace Gherkin.Specs.Helper; + +public class TestFileProvider { - public class TestFileProvider + public static IEnumerable GetValidTestFiles() { - public static IEnumerable GetValidTestFiles() - { - return GetTestFiles("good"); - } + return GetTestFiles("good"); + } - public static IEnumerable GetInvalidTestFiles() - { - return GetTestFiles("bad"); - } + public static IEnumerable GetInvalidTestFiles() + { + return GetTestFiles("bad"); + } - private static IEnumerable GetTestFiles(string category) - { - string testFileFolder = GetTestFileFolder(category); + private static IEnumerable GetTestFiles(string category) + { + string testFileFolder = GetTestFileFolder(category); - return Directory.GetFiles(testFileFolder, "*.feature") - .Where(f => Path.GetFileName(f) != "escaped_pipes.feature") //currently failing, because of https://github.com/neuecc/Utf8Json/pull/96 - .Select(f => new object[]{Path.GetFileName(f)}); - } + return Directory.GetFiles(testFileFolder, "*.feature") + .Where(f => Path.GetFileName(f) != "escaped_pipes.feature") //currently failing, because of https://github.com/neuecc/Utf8Json/pull/96 + .Select(f => new object[]{Path.GetFileName(f)}); + } - public static string GetTestFileFolder(string category) - { - return Path.GetFullPath(Path.Combine(TestFolders.InputFolder, "..", "..", "..", "..", @"testdata", category)); - } + public static string GetTestFileFolder(string category) + { + return Path.GetFullPath(Path.Combine(TestFolders.InputFolder, "..", "..", "..", "..", @"testdata", category)); } } diff --git a/dotnet/Gherkin.Specs/Helper/TestFolders.cs b/dotnet/Gherkin.Specs/Helper/TestFolders.cs index 00f637884..3883c59e8 100644 --- a/dotnet/Gherkin.Specs/Helper/TestFolders.cs +++ b/dotnet/Gherkin.Specs/Helper/TestFolders.cs @@ -2,20 +2,19 @@ using System.IO; using System.Reflection; -namespace Gherkin.Specs.Helper +namespace Gherkin.Specs.Helper; + +internal static class TestFolders { - internal static class TestFolders + public static string InputFolder { - public static string InputFolder - { - get - { - var inputFolder = Path.GetDirectoryName(typeof(TestFolders).GetTypeInfo().Assembly.Location); + get + { + var inputFolder = Path.GetDirectoryName(typeof(TestFolders).GetTypeInfo().Assembly.Location); - inputFolder = Path.Combine(inputFolder, ".."); + inputFolder = Path.Combine(inputFolder, ".."); - return inputFolder; - } + return inputFolder; } } } diff --git a/dotnet/Gherkin.Specs/PicklesTests.cs b/dotnet/Gherkin.Specs/PicklesTests.cs index 3e6e11b7d..5f8f2238c 100644 --- a/dotnet/Gherkin.Specs/PicklesTests.cs +++ b/dotnet/Gherkin.Specs/PicklesTests.cs @@ -4,23 +4,22 @@ using Gherkin.Specs.Helper; using Xunit; -namespace Gherkin.Specs +namespace Gherkin.Specs; + +public class PicklesTests : EventTestBase { - public class PicklesTests : EventTestBase + [Theory, MemberData(nameof(TestFileProvider.GetValidTestFiles), MemberType = typeof(TestFileProvider))] + public void TestPickleCompilation(string testFeatureFile) { - [Theory, MemberData(nameof(TestFileProvider.GetValidTestFiles), MemberType = typeof(TestFileProvider))] - public void TestPickleCompilation(string testFeatureFile) - { - var testFile = GetFullPathToTestFeatureFile(testFeatureFile, "good", ".pickles.ndjson"); + var testFile = GetFullPathToTestFeatureFile(testFeatureFile, "good", ".pickles.ndjson"); - var expectedContent = GetExpectedContent(testFile.ExpectedFileFullPath); + var expectedContent = GetExpectedContent(testFile.ExpectedFileFullPath); - var expectedEvents = NDJsonParser.Deserialize(expectedContent); + var expectedEvents = NDJsonParser.Deserialize(expectedContent); - var raisedEvents = ProcessGherkinEvents(testFile.FullPath, false, false, true); + var raisedEvents = ProcessGherkinEvents(testFile.FullPath, false, false, true); - raisedEvents.Should().Match(list => list.All(e => e.Pickle != null)); - AssertEvents(testFeatureFile, raisedEvents, expectedEvents, testFile); - } + raisedEvents.Should().Match(list => list.All(e => e.Pickle != null)); + AssertEvents(testFeatureFile, raisedEvents, expectedEvents, testFile); } } diff --git a/dotnet/Gherkin.Specs/SourceTests.cs b/dotnet/Gherkin.Specs/SourceTests.cs index 89b8186d4..2f48ce17d 100644 --- a/dotnet/Gherkin.Specs/SourceTests.cs +++ b/dotnet/Gherkin.Specs/SourceTests.cs @@ -4,23 +4,22 @@ using Gherkin.Specs.Helper; using Xunit; -namespace Gherkin.Specs +namespace Gherkin.Specs; + +public class SourceTests : EventTestBase { - public class SourceTests : EventTestBase + [Theory, MemberData(nameof(TestFileProvider.GetValidTestFiles), MemberType = typeof(TestFileProvider))] + public void TestSourceMessage(string testFeatureFile) { - [Theory, MemberData(nameof(TestFileProvider.GetValidTestFiles), MemberType = typeof(TestFileProvider))] - public void TestSourceMessage(string testFeatureFile) - { - var testFile = GetFullPathToTestFeatureFile(testFeatureFile, "good", ".source.ndjson"); + var testFile = GetFullPathToTestFeatureFile(testFeatureFile, "good", ".source.ndjson"); - var expectedAstContent = GetExpectedContent(testFile.ExpectedFileFullPath); + var expectedAstContent = GetExpectedContent(testFile.ExpectedFileFullPath); - var expectedGherkinDocumentEvent = NDJsonParser.Deserialize(expectedAstContent); + var expectedGherkinDocumentEvent = NDJsonParser.Deserialize(expectedAstContent); - var raisedEvents = ProcessGherkinEvents(testFile.FullPath, true, false, false); + var raisedEvents = ProcessGherkinEvents(testFile.FullPath, true, false, false); - raisedEvents.Should().Match(list => list.All(e => e.Source != null)); - AssertEvents(testFeatureFile, raisedEvents, expectedGherkinDocumentEvent, testFile); - } + raisedEvents.Should().Match(list => list.All(e => e.Source != null)); + AssertEvents(testFeatureFile, raisedEvents, expectedGherkinDocumentEvent, testFile); } } diff --git a/dotnet/Gherkin.Specs/StringUtilsTests.cs b/dotnet/Gherkin.Specs/StringUtilsTests.cs index a8ad35fe0..1aa8fe23a 100644 --- a/dotnet/Gherkin.Specs/StringUtilsTests.cs +++ b/dotnet/Gherkin.Specs/StringUtilsTests.cs @@ -1,25 +1,24 @@ using System; using Xunit; -namespace Gherkin.Specs +namespace Gherkin.Specs; + +public class StringUtilsTests { - public class StringUtilsTests + [Fact] + public void StartsWithWorks() { - [Fact] - public void StartsWithWorks() - { - var bookEmoji = "\ud83d\udcd5"; - var zzzzEmoji = "\ud83d\udca4"; + var bookEmoji = "\ud83d\udcd5"; + var zzzzEmoji = "\ud83d\udca4"; - Assert.True(StringUtils.StartsWith(bookEmoji+"abc", bookEmoji)); - Assert.False(StringUtils.StartsWith(bookEmoji+"abc", zzzzEmoji)); - } + Assert.True(StringUtils.StartsWith(bookEmoji+"abc", bookEmoji)); + Assert.False(StringUtils.StartsWith(bookEmoji+"abc", zzzzEmoji)); + } - [Fact] - public void StartsWithTitleLineWorks() - { - var bookEmoji = "\ud83d\udcd5"; - Assert.Equal(1, StringUtils.CountSymbols(bookEmoji)); - } + [Fact] + public void StartsWithTitleLineWorks() + { + var bookEmoji = "\ud83d\udcd5"; + Assert.Equal(1, StringUtils.CountSymbols(bookEmoji)); } } diff --git a/dotnet/Gherkin.Specs/SuccessfulParsingTests.cs b/dotnet/Gherkin.Specs/SuccessfulParsingTests.cs index 3bcaa1713..432c640df 100644 --- a/dotnet/Gherkin.Specs/SuccessfulParsingTests.cs +++ b/dotnet/Gherkin.Specs/SuccessfulParsingTests.cs @@ -2,18 +2,17 @@ using Gherkin.Specs.Helper; using Xunit; -namespace Gherkin.Specs +namespace Gherkin.Specs; + +public class SuccessfulParsingTests { - public class SuccessfulParsingTests + [Theory, MemberData(nameof(TestFileProvider.GetValidTestFiles), MemberType = typeof(TestFileProvider))] + public void TestSuccessfulParsing(string testFeatureFile) { - [Theory, MemberData(nameof(TestFileProvider.GetValidTestFiles), MemberType = typeof(TestFileProvider))] - public void TestSuccessfulParsing(string testFeatureFile) - { - var fullPathToTestFeatureFile = Path.Combine(TestFileProvider.GetTestFileFolder("good"), testFeatureFile); + var fullPathToTestFeatureFile = Path.Combine(TestFileProvider.GetTestFileFolder("good"), testFeatureFile); - var parser = new Parser(); - var parsingResult = parser.Parse(fullPathToTestFeatureFile); - Assert.NotNull(parsingResult); - } + var parser = new Parser(); + var parsingResult = parser.Parse(fullPathToTestFeatureFile); + Assert.NotNull(parsingResult); } } diff --git a/dotnet/Gherkin.Specs/TokenizationTests.cs b/dotnet/Gherkin.Specs/TokenizationTests.cs index 5cf9be3a2..ea96db810 100644 --- a/dotnet/Gherkin.Specs/TokenizationTests.cs +++ b/dotnet/Gherkin.Specs/TokenizationTests.cs @@ -3,22 +3,21 @@ using Gherkin.Specs.Helper; using Xunit; -namespace Gherkin.Specs +namespace Gherkin.Specs; + +public class TokenizationTests { - public class TokenizationTests + [Theory, MemberData(nameof(TestFileProvider.GetValidTestFiles), MemberType = typeof(TestFileProvider))] + public void TestSuccessfulTokenMatching(string testFeatureFile) { - [Theory, MemberData(nameof(TestFileProvider.GetValidTestFiles), MemberType = typeof(TestFileProvider))] - public void TestSuccessfulTokenMatching(string testFeatureFile) - { - var fullPathToTestFeatureFile = Path.Combine(TestFileProvider.GetTestFileFolder("good"), testFeatureFile); - var featureFileFolder = Path.GetDirectoryName(fullPathToTestFeatureFile); - Debug.Assert(featureFileFolder != null); - var expectedTokensFile = fullPathToTestFeatureFile + ".tokens"; + var fullPathToTestFeatureFile = Path.Combine(TestFileProvider.GetTestFileFolder("good"), testFeatureFile); + var featureFileFolder = Path.GetDirectoryName(fullPathToTestFeatureFile); + Debug.Assert(featureFileFolder != null); + var expectedTokensFile = fullPathToTestFeatureFile + ".tokens"; - var tokensText = Tokens.TokensGenerator.GenerateTokens(fullPathToTestFeatureFile); - var expectedTokensText = LineEndingHelper.NormalizeLineEndings(File.ReadAllText(expectedTokensFile)); + var tokensText = Tokens.TokensGenerator.GenerateTokens(fullPathToTestFeatureFile); + var expectedTokensText = LineEndingHelper.NormalizeLineEndings(File.ReadAllText(expectedTokensFile)); - Assert.Equal(expectedTokensText, tokensText); - } + Assert.Equal(expectedTokensText, tokensText); } } diff --git a/dotnet/Gherkin.Specs/Tokens/TestTokenFormatter.cs b/dotnet/Gherkin.Specs/Tokens/TestTokenFormatter.cs index d1787bbe7..b241c224a 100644 --- a/dotnet/Gherkin.Specs/Tokens/TestTokenFormatter.cs +++ b/dotnet/Gherkin.Specs/Tokens/TestTokenFormatter.cs @@ -1,38 +1,37 @@ using System; using System.Linq; -namespace Gherkin.Specs.Tokens +namespace Gherkin.Specs.Tokens; + +class TestTokenFormatter { - class TestTokenFormatter + public string FormatToken(Token token) { - public string FormatToken(Token token) - { - if (token.IsEOF) - return "EOF"; + if (token.IsEOF) + return "EOF"; - string stepTypeText; - switch (token.MatchedType) - { - case TokenType.FeatureLine: - case TokenType.ScenarioLine: - case TokenType.ExamplesLine: - case TokenType.DocStringSeparator: - case TokenType.BackgroundLine: - case TokenType.RuleLine: - stepTypeText = "()"; - break; - case TokenType.StepLine: - var tokenType = token.MatchedGherkinDialect.GetStepKeywordType(token.MatchedKeyword); - stepTypeText = $"({tokenType})"; - break; - default: - stepTypeText = ""; - break; - } + string stepTypeText; + switch (token.MatchedType) + { + case TokenType.FeatureLine: + case TokenType.ScenarioLine: + case TokenType.ExamplesLine: + case TokenType.DocStringSeparator: + case TokenType.BackgroundLine: + case TokenType.RuleLine: + stepTypeText = "()"; + break; + case TokenType.StepLine: + var tokenType = token.MatchedGherkinDialect.GetStepKeywordType(token.MatchedKeyword); + stepTypeText = $"({tokenType})"; + break; + default: + stepTypeText = ""; + break; + } - var matchedItemsText = token.MatchedItems == null ? "" : string.Join(",", token.MatchedItems.Select(i => i.Column + ":" + i.Text)); + var matchedItemsText = token.MatchedItems == null ? "" : string.Join(",", token.MatchedItems.Select(i => i.Column + ":" + i.Text)); - return $"({token.Location.Line}:{token.Location.Column}){token.MatchedType}:{stepTypeText}{token.MatchedKeyword}/{token.MatchedText}/{matchedItemsText}"; - } + return $"({token.Location.Line}:{token.Location.Column}){token.MatchedType}:{stepTypeText}{token.MatchedKeyword}/{token.MatchedText}/{matchedItemsText}"; } } diff --git a/dotnet/Gherkin.Specs/Tokens/TokenFormatterBuilder.cs b/dotnet/Gherkin.Specs/Tokens/TokenFormatterBuilder.cs index 6092bb5d8..ee23a45fc 100644 --- a/dotnet/Gherkin.Specs/Tokens/TokenFormatterBuilder.cs +++ b/dotnet/Gherkin.Specs/Tokens/TokenFormatterBuilder.cs @@ -1,42 +1,41 @@ using System; using System.Text; -namespace Gherkin.Specs.Tokens +namespace Gherkin.Specs.Tokens; + +class TokenFormatterBuilder : IAstBuilder { - class TokenFormatterBuilder : IAstBuilder + private readonly TestTokenFormatter formatter = new TestTokenFormatter(); + private readonly StringBuilder tokensTextBuilder = new StringBuilder(); + + public string GetTokensText() { - private readonly TestTokenFormatter formatter = new TestTokenFormatter(); - private readonly StringBuilder tokensTextBuilder = new StringBuilder(); - - public string GetTokensText() - { - return tokensTextBuilder.ToString(); - } - - public void Build(Token token) - { - tokensTextBuilder.AppendLine(formatter.FormatToken(token)); - } - - public void StartRule(RuleType ruleType) - { - //nop - } - - public void EndRule(RuleType ruleType) - { - //nop - } - - public object GetResult() - { - return new object(); - } - - public void Reset() - { - //nop - } + return tokensTextBuilder.ToString(); + } + public void Build(Token token) + { + tokensTextBuilder.AppendLine(formatter.FormatToken(token)); } + + public void StartRule(RuleType ruleType) + { + //nop + } + + public void EndRule(RuleType ruleType) + { + //nop + } + + public object GetResult() + { + return new object(); + } + + public void Reset() + { + //nop + } + } \ No newline at end of file diff --git a/dotnet/Gherkin.Specs/Tokens/TokensGenerator.cs b/dotnet/Gherkin.Specs/Tokens/TokensGenerator.cs index bb9a31e55..bfb9049cd 100644 --- a/dotnet/Gherkin.Specs/Tokens/TokensGenerator.cs +++ b/dotnet/Gherkin.Specs/Tokens/TokensGenerator.cs @@ -1,31 +1,30 @@ using System; using System.IO; -namespace Gherkin.Specs.Tokens +namespace Gherkin.Specs.Tokens; + +public class TokensGenerator { - public class TokensGenerator + public static string GenerateTokens(string featureFilePath) { - public static string GenerateTokens(string featureFilePath) + var tokenFormatterBuilder = new TokenFormatterBuilder(); + var parser = new Parser(tokenFormatterBuilder); + + using (var stream = new FileStream(featureFilePath, FileMode.Open)) { - var tokenFormatterBuilder = new TokenFormatterBuilder(); - var parser = new Parser(tokenFormatterBuilder); - - using (var stream = new FileStream(featureFilePath, FileMode.Open)) + using (var reader = new StreamReader(stream)) { - using (var reader = new StreamReader(stream)) - { - parser.Parse(new TokenScanner(reader), new TokenMatcher()); - } + parser.Parse(new TokenScanner(reader), new TokenMatcher()); } + } - var tokensText = tokenFormatterBuilder.GetTokensText(); + var tokensText = tokenFormatterBuilder.GetTokensText(); - return NormalizeLineEndings(tokensText); - } + return NormalizeLineEndings(tokensText); + } - public static string NormalizeLineEndings(string text) - { - return text.Replace("\r\n", "\n").TrimEnd('\n'); - } + public static string NormalizeLineEndings(string text) + { + return text.Replace("\r\n", "\n").TrimEnd('\n'); } } diff --git a/dotnet/Gherkin/Ast/Background.cs b/dotnet/Gherkin/Ast/Background.cs index f2fc398e1..246069403 100644 --- a/dotnet/Gherkin/Ast/Background.cs +++ b/dotnet/Gherkin/Ast/Background.cs @@ -1,10 +1,9 @@ -namespace Gherkin.Ast +namespace Gherkin.Ast; + +public class Background : StepsContainer { - public class Background : StepsContainer + public Background(Location location, string keyword, string name, string description, Step[] steps) + : base(location, keyword, name, description, steps) { - public Background(Location location, string keyword, string name, string description, Step[] steps) - : base(location, keyword, name, description, steps) - { - } } } \ No newline at end of file diff --git a/dotnet/Gherkin/Ast/Comment.cs b/dotnet/Gherkin/Ast/Comment.cs index 37ace8d93..40db3f2fe 100644 --- a/dotnet/Gherkin/Ast/Comment.cs +++ b/dotnet/Gherkin/Ast/Comment.cs @@ -1,14 +1,13 @@ -namespace Gherkin.Ast +namespace Gherkin.Ast; + +public class Comment : IHasLocation { - public class Comment : IHasLocation - { - public Location Location { get; private set; } - public string Text { get; private set; } + public Location Location { get; private set; } + public string Text { get; private set; } - public Comment(Location location, string text) - { - Text = text; - Location = location; - } + public Comment(Location location, string text) + { + Text = text; + Location = location; } } \ No newline at end of file diff --git a/dotnet/Gherkin/Ast/DataTable.cs b/dotnet/Gherkin/Ast/DataTable.cs index a9c123d73..c3a797ce1 100644 --- a/dotnet/Gherkin/Ast/DataTable.cs +++ b/dotnet/Gherkin/Ast/DataTable.cs @@ -1,20 +1,19 @@ using System; using System.Collections.Generic; -namespace Gherkin.Ast +namespace Gherkin.Ast; + +public class DataTable : StepArgument, IHasRows, IHasLocation { - public class DataTable : StepArgument, IHasRows, IHasLocation - { - public Location Location { get; private set; } - public IEnumerable Rows { get; private set; } + public Location Location { get; private set; } + public IEnumerable Rows { get; private set; } - public DataTable(TableRow[] rows) - { - if (rows == null) throw new ArgumentNullException("rows"); - if (rows.Length == 0) throw new ArgumentException("DataTable must have at least one row", "rows"); + public DataTable(TableRow[] rows) + { + if (rows == null) throw new ArgumentNullException("rows"); + if (rows.Length == 0) throw new ArgumentException("DataTable must have at least one row", "rows"); - Location = rows[0].Location; - Rows = rows; - } + Location = rows[0].Location; + Rows = rows; } } \ No newline at end of file diff --git a/dotnet/Gherkin/Ast/DocString.cs b/dotnet/Gherkin/Ast/DocString.cs index b1d7af5d3..2376a4bed 100644 --- a/dotnet/Gherkin/Ast/DocString.cs +++ b/dotnet/Gherkin/Ast/DocString.cs @@ -1,18 +1,17 @@ -namespace Gherkin.Ast +namespace Gherkin.Ast; + +public class DocString : StepArgument, IHasLocation { - public class DocString : StepArgument, IHasLocation - { - public Location Location { get; private set; } - public string ContentType { get; private set; } - public string Content { get; private set; } - public string Delimiter { get; private set; } + public Location Location { get; private set; } + public string ContentType { get; private set; } + public string Content { get; private set; } + public string Delimiter { get; private set; } - public DocString(Location location, string contentType, string content, string delimiter = null) - { - Location = location; - ContentType = contentType; - Content = content; - Delimiter = delimiter; - } + public DocString(Location location, string contentType, string content, string delimiter = null) + { + Location = location; + ContentType = contentType; + Content = content; + Delimiter = delimiter; } } \ No newline at end of file diff --git a/dotnet/Gherkin/Ast/Examples.cs b/dotnet/Gherkin/Ast/Examples.cs index 61de29954..af0c0c7a7 100644 --- a/dotnet/Gherkin/Ast/Examples.cs +++ b/dotnet/Gherkin/Ast/Examples.cs @@ -1,32 +1,31 @@ using System.Collections.Generic; using System.Linq; -namespace Gherkin.Ast +namespace Gherkin.Ast; + +public class Examples : IHasLocation, IHasDescription, IHasRows, IHasTags { - public class Examples : IHasLocation, IHasDescription, IHasRows, IHasTags - { - public IEnumerable Tags { get; private set; } - 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 TableRow TableHeader { get; private set; } - public IEnumerable TableBody { get; private set; } + public IEnumerable Tags { get; private set; } + 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 TableRow TableHeader { get; private set; } + public IEnumerable TableBody { get; private set; } - public Examples(Tag[] tags, Location location, string keyword, string name, string description, TableRow header, TableRow[] body) - { - Tags = tags; - Location = location; - Keyword = keyword; - Name = name; - Description = description; - TableHeader = header; - TableBody = body; - } + public Examples(Tag[] tags, Location location, string keyword, string name, string description, TableRow header, TableRow[] body) + { + Tags = tags; + Location = location; + Keyword = keyword; + Name = name; + Description = description; + TableHeader = header; + TableBody = body; + } - IEnumerable IHasRows.Rows - { - get { return new TableRow[] {TableHeader}.Concat(TableBody); } - } + IEnumerable IHasRows.Rows + { + get { return new TableRow[] {TableHeader}.Concat(TableBody); } } } \ No newline at end of file diff --git a/dotnet/Gherkin/Ast/Feature.cs b/dotnet/Gherkin/Ast/Feature.cs index 1dafd1d44..ca8353050 100644 --- a/dotnet/Gherkin/Ast/Feature.cs +++ b/dotnet/Gherkin/Ast/Feature.cs @@ -1,26 +1,25 @@ using System.Collections.Generic; -namespace Gherkin.Ast +namespace Gherkin.Ast; + +public class Feature : IHasLocation, IHasDescription, IHasTags, IHasChildren { - public class Feature : IHasLocation, IHasDescription, IHasTags, IHasChildren - { - public IEnumerable 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 Children { get; private set; } + public IEnumerable 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 Children { get; private set; } - public Feature(Tag[] tags, Location location, string language, string keyword, string name, string description, IHasLocation[] children) - { - Tags = tags; - Location = location; - Language = language; - Keyword = keyword; - Name = name; - Description = description; - Children = children; - } + public Feature(Tag[] tags, Location location, string language, string keyword, string name, string description, IHasLocation[] children) + { + Tags = tags; + Location = location; + Language = language; + Keyword = keyword; + Name = name; + Description = description; + Children = children; } } diff --git a/dotnet/Gherkin/Ast/GherkinDocument.cs b/dotnet/Gherkin/Ast/GherkinDocument.cs index 1a34f2167..0893f7456 100644 --- a/dotnet/Gherkin/Ast/GherkinDocument.cs +++ b/dotnet/Gherkin/Ast/GherkinDocument.cs @@ -1,16 +1,15 @@ using System.Collections.Generic; -namespace Gherkin.Ast +namespace Gherkin.Ast; + +public class GherkinDocument { - public class GherkinDocument - { - public Feature Feature { get; private set; } - public IEnumerable Comments { get; private set; } + public Feature Feature { get; private set; } + public IEnumerable Comments { get; private set; } - public GherkinDocument(Feature feature, Comment[] comments) - { - Feature = feature; - Comments = comments; - } + public GherkinDocument(Feature feature, Comment[] comments) + { + Feature = feature; + Comments = comments; } } diff --git a/dotnet/Gherkin/Ast/IHasChildren.cs b/dotnet/Gherkin/Ast/IHasChildren.cs index 468f8a00d..0c66f8826 100644 --- a/dotnet/Gherkin/Ast/IHasChildren.cs +++ b/dotnet/Gherkin/Ast/IHasChildren.cs @@ -1,9 +1,8 @@ using System.Collections.Generic; -namespace Gherkin.Ast +namespace Gherkin.Ast; + +public interface IHasChildren { - public interface IHasChildren - { - IEnumerable Children { get; } - } + IEnumerable Children { get; } } \ No newline at end of file diff --git a/dotnet/Gherkin/Ast/IHasDescription.cs b/dotnet/Gherkin/Ast/IHasDescription.cs index 2c2de20a5..569f58006 100644 --- a/dotnet/Gherkin/Ast/IHasDescription.cs +++ b/dotnet/Gherkin/Ast/IHasDescription.cs @@ -1,9 +1,8 @@ -namespace Gherkin.Ast +namespace Gherkin.Ast; + +public interface IHasDescription { - public interface IHasDescription - { - string Keyword { get; } - string Name { get; } - string Description { get; } - } + string Keyword { get; } + string Name { get; } + string Description { get; } } \ No newline at end of file diff --git a/dotnet/Gherkin/Ast/IHasLocation.cs b/dotnet/Gherkin/Ast/IHasLocation.cs index 943a63abe..d4dd4047a 100644 --- a/dotnet/Gherkin/Ast/IHasLocation.cs +++ b/dotnet/Gherkin/Ast/IHasLocation.cs @@ -1,7 +1,6 @@ -namespace Gherkin.Ast +namespace Gherkin.Ast; + +public interface IHasLocation { - public interface IHasLocation - { - Location Location { get; } - } + Location Location { get; } } \ No newline at end of file diff --git a/dotnet/Gherkin/Ast/IHasRows.cs b/dotnet/Gherkin/Ast/IHasRows.cs index 84fa9d644..802f014e6 100644 --- a/dotnet/Gherkin/Ast/IHasRows.cs +++ b/dotnet/Gherkin/Ast/IHasRows.cs @@ -1,9 +1,8 @@ using System.Collections.Generic; -namespace Gherkin.Ast +namespace Gherkin.Ast; + +public interface IHasRows { - public interface IHasRows - { - IEnumerable Rows { get; } - } + IEnumerable Rows { get; } } \ No newline at end of file diff --git a/dotnet/Gherkin/Ast/IHasSteps.cs b/dotnet/Gherkin/Ast/IHasSteps.cs index de2139128..5f052f751 100644 --- a/dotnet/Gherkin/Ast/IHasSteps.cs +++ b/dotnet/Gherkin/Ast/IHasSteps.cs @@ -1,9 +1,8 @@ using System.Collections.Generic; -namespace Gherkin.Ast +namespace Gherkin.Ast; + +public interface IHasSteps { - public interface IHasSteps - { - IEnumerable Steps { get; } - } + IEnumerable Steps { get; } } \ No newline at end of file diff --git a/dotnet/Gherkin/Ast/IHasTags.cs b/dotnet/Gherkin/Ast/IHasTags.cs index ee9efcd09..34f652066 100644 --- a/dotnet/Gherkin/Ast/IHasTags.cs +++ b/dotnet/Gherkin/Ast/IHasTags.cs @@ -1,9 +1,8 @@ using System.Collections.Generic; -namespace Gherkin.Ast +namespace Gherkin.Ast; + +public interface IHasTags { - public interface IHasTags - { - IEnumerable Tags { get; } - } + IEnumerable Tags { get; } } \ No newline at end of file diff --git a/dotnet/Gherkin/Ast/Location.cs b/dotnet/Gherkin/Ast/Location.cs index 2c7af14b7..1ff2de30b 100644 --- a/dotnet/Gherkin/Ast/Location.cs +++ b/dotnet/Gherkin/Ast/Location.cs @@ -1,16 +1,15 @@ using System; -namespace Gherkin.Ast +namespace Gherkin.Ast; + +public class Location { - public class Location - { - public int Line { get; private set; } - public int Column { get; private set; } + public int Line { get; private set; } + public int Column { get; private set; } - public Location(int line = 0, int column = 0) - { - Line = line; - Column = column; - } + public Location(int line = 0, int column = 0) + { + Line = line; + Column = column; } } \ No newline at end of file diff --git a/dotnet/Gherkin/Ast/Node.cs b/dotnet/Gherkin/Ast/Node.cs index 4bad4561d..86ee9e66d 100644 --- a/dotnet/Gherkin/Ast/Node.cs +++ b/dotnet/Gherkin/Ast/Node.cs @@ -1,6 +1,5 @@ -namespace Gherkin.Ast +namespace Gherkin.Ast; + +public abstract class Node { - public abstract class Node - { - } } diff --git a/dotnet/Gherkin/Ast/Rule.cs b/dotnet/Gherkin/Ast/Rule.cs index abef56827..0d83802be 100644 --- a/dotnet/Gherkin/Ast/Rule.cs +++ b/dotnet/Gherkin/Ast/Rule.cs @@ -1,24 +1,23 @@ using System.Collections.Generic; -namespace Gherkin.Ast +namespace Gherkin.Ast; + +public class Rule : IHasLocation, IHasDescription, IHasChildren, IHasTags { - public class Rule : IHasLocation, IHasDescription, IHasChildren, IHasTags - { - 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 Tags { get; private set; } - public IEnumerable Children { get; private set; } + 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 Tags { get; private set; } + public IEnumerable Children { get; private set; } - public Rule(Tag[] tags, Location location, string keyword, string name, string description, IHasLocation[] children) - { - Location = location; - Keyword = keyword; - Name = name; - Description = description; - Children = children; - Tags = tags; - } + public Rule(Tag[] tags, Location location, string keyword, string name, string description, IHasLocation[] children) + { + Location = location; + Keyword = keyword; + Name = name; + Description = description; + Children = children; + Tags = tags; } } diff --git a/dotnet/Gherkin/Ast/Scenario.cs b/dotnet/Gherkin/Ast/Scenario.cs index 20b43f2f9..632cedfb5 100644 --- a/dotnet/Gherkin/Ast/Scenario.cs +++ b/dotnet/Gherkin/Ast/Scenario.cs @@ -1,17 +1,16 @@ using System.Collections.Generic; -namespace Gherkin.Ast +namespace Gherkin.Ast; + +public class Scenario : StepsContainer, IHasTags { - public class Scenario : StepsContainer, IHasTags - { - public IEnumerable Tags { get; private set; } - public IEnumerable Examples { get; private set; } + public IEnumerable Tags { get; private set; } + public IEnumerable Examples { get; private set; } - public Scenario(Tag[] tags, Location location, string keyword, string name, string description, Step[] steps, Examples[] examples) - : base(location, keyword, name, description, steps) - { - Tags = tags; - Examples = examples; - } + public Scenario(Tag[] tags, Location location, string keyword, string name, string description, Step[] steps, Examples[] examples) + : base(location, keyword, name, description, steps) + { + Tags = tags; + Examples = examples; } } \ No newline at end of file diff --git a/dotnet/Gherkin/Ast/Step.cs b/dotnet/Gherkin/Ast/Step.cs index 3177e6576..e52a746b5 100644 --- a/dotnet/Gherkin/Ast/Step.cs +++ b/dotnet/Gherkin/Ast/Step.cs @@ -1,21 +1,20 @@ -namespace Gherkin.Ast +namespace Gherkin.Ast; + +public class Step : IHasLocation { - public class Step : IHasLocation - { - public Location Location { get; private set; } - public string Keyword { get; private set; } - public StepKeywordType KeywordType { get; } + public Location Location { get; private set; } + public string Keyword { get; private set; } + public StepKeywordType KeywordType { get; } - public string Text { get; private set; } - public StepArgument Argument { get; private set; } + public string Text { get; private set; } + public StepArgument Argument { get; private set; } - public Step(Location location, string keyword, StepKeywordType keywordType, string text, StepArgument argument) - { - Location = location; - Keyword = keyword; - KeywordType = keywordType; - Text = text; - Argument = argument; - } + public Step(Location location, string keyword, StepKeywordType keywordType, string text, StepArgument argument) + { + Location = location; + Keyword = keyword; + KeywordType = keywordType; + Text = text; + Argument = argument; } } \ No newline at end of file diff --git a/dotnet/Gherkin/Ast/StepArgument.cs b/dotnet/Gherkin/Ast/StepArgument.cs index dc0f0fdf1..ea2b31c11 100644 --- a/dotnet/Gherkin/Ast/StepArgument.cs +++ b/dotnet/Gherkin/Ast/StepArgument.cs @@ -1,7 +1,6 @@ -namespace Gherkin.Ast +namespace Gherkin.Ast; + +public abstract class StepArgument { - public abstract class StepArgument - { - - } + } \ No newline at end of file diff --git a/dotnet/Gherkin/Ast/StepsContainer.cs b/dotnet/Gherkin/Ast/StepsContainer.cs index f7eb2a975..74aeedd6a 100644 --- a/dotnet/Gherkin/Ast/StepsContainer.cs +++ b/dotnet/Gherkin/Ast/StepsContainer.cs @@ -1,22 +1,21 @@ using System.Collections.Generic; -namespace Gherkin.Ast +namespace Gherkin.Ast; + +public abstract class StepsContainer : IHasLocation, IHasDescription, IHasSteps { - public abstract class StepsContainer : IHasLocation, IHasDescription, IHasSteps - { - 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 Steps { get; private set; } + 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 Steps { get; private set; } - protected StepsContainer(Location location, string keyword, string name, string description, Step[] steps) - { - Location = location; - Keyword = keyword; - Name = name; - Description = description; - Steps = steps; - } + protected StepsContainer(Location location, string keyword, string name, string description, Step[] steps) + { + Location = location; + Keyword = keyword; + Name = name; + Description = description; + Steps = steps; } } \ No newline at end of file diff --git a/dotnet/Gherkin/Ast/TableCell.cs b/dotnet/Gherkin/Ast/TableCell.cs index eca49769f..c21cf7981 100644 --- a/dotnet/Gherkin/Ast/TableCell.cs +++ b/dotnet/Gherkin/Ast/TableCell.cs @@ -1,14 +1,13 @@ -namespace Gherkin.Ast +namespace Gherkin.Ast; + +public class TableCell : IHasLocation { - public class TableCell : IHasLocation - { - public Location Location { get; private set; } - public string Value { get; private set; } + public Location Location { get; private set; } + public string Value { get; private set; } - public TableCell(Location location, string value) - { - Location = location; - Value = value; - } + public TableCell(Location location, string value) + { + Location = location; + Value = value; } } \ No newline at end of file diff --git a/dotnet/Gherkin/Ast/TableRow.cs b/dotnet/Gherkin/Ast/TableRow.cs index 2f79514c5..cf864254d 100644 --- a/dotnet/Gherkin/Ast/TableRow.cs +++ b/dotnet/Gherkin/Ast/TableRow.cs @@ -1,16 +1,15 @@ using System.Collections.Generic; -namespace Gherkin.Ast +namespace Gherkin.Ast; + +public class TableRow : IHasLocation { - public class TableRow : IHasLocation - { - public Location Location { get; private set; } - public IEnumerable Cells { get; private set; } + public Location Location { get; private set; } + public IEnumerable Cells { get; private set; } - public TableRow(Location location, TableCell[] cells) - { - Location = location; - Cells = cells; - } + public TableRow(Location location, TableCell[] cells) + { + Location = location; + Cells = cells; } } \ No newline at end of file diff --git a/dotnet/Gherkin/Ast/Tag.cs b/dotnet/Gherkin/Ast/Tag.cs index cece407c9..c97e8919d 100644 --- a/dotnet/Gherkin/Ast/Tag.cs +++ b/dotnet/Gherkin/Ast/Tag.cs @@ -1,14 +1,13 @@ -namespace Gherkin.Ast +namespace Gherkin.Ast; + +public class Tag : IHasLocation { - public class Tag : IHasLocation - { - public Location Location { get; private set; } - public string Name { get; private set; } + public Location Location { get; private set; } + public string Name { get; private set; } - public Tag(Location location, string name) - { - Name = name; - Location = location; - } + public Tag(Location location, string name) + { + Name = name; + Location = location; } } \ No newline at end of file diff --git a/dotnet/Gherkin/AstBuilder.cs b/dotnet/Gherkin/AstBuilder.cs index 98ecdfe4c..84f86c2d8 100644 --- a/dotnet/Gherkin/AstBuilder.cs +++ b/dotnet/Gherkin/AstBuilder.cs @@ -3,313 +3,312 @@ using System.Linq; using Gherkin.Ast; -namespace Gherkin +namespace Gherkin; + +public class AstBuilder : IAstBuilder { - public class AstBuilder : IAstBuilder + private readonly Stack _stack = new(); + private AstNode CurrentNode => _stack.Peek(); + private readonly List _comments = new(); + + public AstBuilder() { - private readonly Stack _stack = new(); - private AstNode CurrentNode => _stack.Peek(); - private readonly List _comments = new(); + Reset(); + } - public AstBuilder() - { - Reset(); - } + public void Reset() + { + _stack.Clear(); + _stack.Push(new AstNode(RuleType.None)); + _comments.Clear(); + } - public void Reset() + public void Build(Token token) + { + if (token.MatchedType == TokenType.Comment) { - _stack.Clear(); - _stack.Push(new AstNode(RuleType.None)); - _comments.Clear(); + _comments.Add(CreateComment(GetLocation(token), token.MatchedText)); } - - public void Build(Token token) + else { - if (token.MatchedType == TokenType.Comment) - { - _comments.Add(CreateComment(GetLocation(token), token.MatchedText)); - } - else - { - CurrentNode.Add((RuleType) token.MatchedType, token); - } + CurrentNode.Add((RuleType) token.MatchedType, token); } + } - public void StartRule(RuleType ruleType) - { - _stack.Push(new AstNode(ruleType)); - } + public void StartRule(RuleType ruleType) + { + _stack.Push(new AstNode(ruleType)); + } - public void EndRule(RuleType ruleType) - { - var node = _stack.Pop(); - object transformedNode = GetTransformedNode(node); - CurrentNode.Add(node.RuleType, transformedNode); - } + public void EndRule(RuleType ruleType) + { + var node = _stack.Pop(); + object transformedNode = GetTransformedNode(node); + CurrentNode.Add(node.RuleType, transformedNode); + } - public T GetResult() - { - return CurrentNode.GetSingle(RuleType.GherkinDocument); - } + public T GetResult() + { + return CurrentNode.GetSingle(RuleType.GherkinDocument); + } - private object GetTransformedNode(AstNode node) + private object GetTransformedNode(AstNode node) + { + switch (node.RuleType) { - switch (node.RuleType) + case RuleType.Step: { - case RuleType.Step: - { - var stepLine = node.GetToken(TokenType.StepLine); - var stepArg = node.GetSingle(RuleType.DataTable) ?? - node.GetSingle(RuleType.DocString); - var keywordType = GetKeywordType(stepLine); - return CreateStep(GetLocation(stepLine), stepLine.MatchedKeyword, keywordType, stepLine.MatchedText, stepArg, node); - } - case RuleType.DocString: - { - var separatorToken = node.GetTokens(TokenType.DocStringSeparator).First(); - var contentType = separatorToken.MatchedText.Length == 0 ? null : separatorToken.MatchedText; - var lineTokens = node.GetTokens(TokenType.Other); - var content = string.Join(Environment.NewLine, lineTokens.Select(lt => lt.MatchedText)); - var delimiter = separatorToken.MatchedKeyword.Length == 0 ? null : separatorToken.MatchedKeyword; + var stepLine = node.GetToken(TokenType.StepLine); + var stepArg = node.GetSingle(RuleType.DataTable) ?? + node.GetSingle(RuleType.DocString); + var keywordType = GetKeywordType(stepLine); + return CreateStep(GetLocation(stepLine), stepLine.MatchedKeyword, keywordType, stepLine.MatchedText, stepArg, node); + } + case RuleType.DocString: + { + var separatorToken = node.GetTokens(TokenType.DocStringSeparator).First(); + var contentType = separatorToken.MatchedText.Length == 0 ? null : separatorToken.MatchedText; + var lineTokens = node.GetTokens(TokenType.Other); + var content = string.Join(Environment.NewLine, lineTokens.Select(lt => lt.MatchedText)); + var delimiter = separatorToken.MatchedKeyword.Length == 0 ? null : separatorToken.MatchedKeyword; - return CreateDocString(GetLocation(separatorToken), contentType, content, delimiter, node); - } - case RuleType.DataTable: - { - var rows = GetTableRows(node); - return CreateDataTable(rows, node); - } - case RuleType.Background: - { - var backgroundLine = node.GetToken(TokenType.BackgroundLine); - var description = GetDescription(node); - var steps = GetSteps(node); - return CreateBackground(GetLocation(backgroundLine), backgroundLine.MatchedKeyword, backgroundLine.MatchedText, description, steps, node); - } - case RuleType.ScenarioDefinition: - { - var tags = GetTags(node); + return CreateDocString(GetLocation(separatorToken), contentType, content, delimiter, node); + } + case RuleType.DataTable: + { + var rows = GetTableRows(node); + return CreateDataTable(rows, node); + } + case RuleType.Background: + { + var backgroundLine = node.GetToken(TokenType.BackgroundLine); + var description = GetDescription(node); + var steps = GetSteps(node); + return CreateBackground(GetLocation(backgroundLine), backgroundLine.MatchedKeyword, backgroundLine.MatchedText, description, steps, node); + } + case RuleType.ScenarioDefinition: + { + var tags = GetTags(node); - var scenarioNode = node.GetSingle(RuleType.Scenario); - var scenarioLine = scenarioNode.GetToken(TokenType.ScenarioLine); + var scenarioNode = node.GetSingle(RuleType.Scenario); + var scenarioLine = scenarioNode.GetToken(TokenType.ScenarioLine); - var description = GetDescription(scenarioNode); - var steps = GetSteps(scenarioNode); - var examples = scenarioNode.GetItems(RuleType.ExamplesDefinition).ToArray(); - return CreateScenario(tags, GetLocation(scenarioLine), scenarioLine.MatchedKeyword, scenarioLine.MatchedText, description, steps, examples, node); - } - case RuleType.ExamplesDefinition: - { - var tags = GetTags(node); - var examplesNode = node.GetSingle(RuleType.Examples); - var examplesLine = examplesNode.GetToken(TokenType.ExamplesLine); - var description = GetDescription(examplesNode); - - var allRows = examplesNode.GetSingle(RuleType.ExamplesTable); - var header = allRows != null ? allRows.First() : null; - var rows = allRows != null ? allRows.Skip(1).ToArray() : null; - return CreateExamples(tags, GetLocation(examplesLine), examplesLine.MatchedKeyword, examplesLine.MatchedText, description, header, rows, node); - } - case RuleType.ExamplesTable: - { - return GetTableRows(node); - } - case RuleType.Description: - { - var lineTokens = node.GetTokens(TokenType.Other); + var description = GetDescription(scenarioNode); + var steps = GetSteps(scenarioNode); + var examples = scenarioNode.GetItems(RuleType.ExamplesDefinition).ToArray(); + return CreateScenario(tags, GetLocation(scenarioLine), scenarioLine.MatchedKeyword, scenarioLine.MatchedText, description, steps, examples, node); + } + case RuleType.ExamplesDefinition: + { + var tags = GetTags(node); + var examplesNode = node.GetSingle(RuleType.Examples); + var examplesLine = examplesNode.GetToken(TokenType.ExamplesLine); + var description = GetDescription(examplesNode); + + var allRows = examplesNode.GetSingle(RuleType.ExamplesTable); + var header = allRows != null ? allRows.First() : null; + var rows = allRows != null ? allRows.Skip(1).ToArray() : null; + return CreateExamples(tags, GetLocation(examplesLine), examplesLine.MatchedKeyword, examplesLine.MatchedText, description, header, rows, node); + } + case RuleType.ExamplesTable: + { + return GetTableRows(node); + } + case RuleType.Description: + { + var lineTokens = node.GetTokens(TokenType.Other); - // Trim trailing empty lines - lineTokens = lineTokens.Reverse().SkipWhile(t => string.IsNullOrWhiteSpace(t.MatchedText)).Reverse(); + // Trim trailing empty lines + lineTokens = lineTokens.Reverse().SkipWhile(t => string.IsNullOrWhiteSpace(t.MatchedText)).Reverse(); - return string.Join(Environment.NewLine, lineTokens.Select(lt => lt.MatchedText)); - } - case RuleType.Feature: + return string.Join(Environment.NewLine, lineTokens.Select(lt => lt.MatchedText)); + } + case RuleType.Feature: + { + var header = node.GetSingle(RuleType.FeatureHeader); + if(header == null) return null; + var tags = GetTags(header); + var featureLine = header.GetToken(TokenType.FeatureLine); + if(featureLine == null) return null; + var children = new List (); + var background = node.GetSingle(RuleType.Background); + if (background != null) { - var header = node.GetSingle(RuleType.FeatureHeader); - if(header == null) return null; - var tags = GetTags(header); - var featureLine = header.GetToken(TokenType.FeatureLine); - if(featureLine == null) return null; - var children = new List (); - var background = node.GetSingle(RuleType.Background); - if (background != null) - { - children.Add (background); - } - var childrenEnumerable = children.Concat(node.GetItems(RuleType.ScenarioDefinition)) - .Concat(node.GetItems(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); + children.Add (background); } - case RuleType.Rule: + var childrenEnumerable = children.Concat(node.GetItems(RuleType.ScenarioDefinition)) + .Concat(node.GetItems(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(RuleType.RuleHeader); + if (header == null) return null; + var tags = GetTags(header); + var ruleLine = header.GetToken(TokenType.RuleLine); + if (ruleLine == null) return null; + var children = new List(); + var background = node.GetSingle(RuleType.Background); + if (background != null) { - var header = node.GetSingle(RuleType.RuleHeader); - if (header == null) return null; - var tags = GetTags(header); - var ruleLine = header.GetToken(TokenType.RuleLine); - if (ruleLine == null) return null; - var children = new List(); - var background = node.GetSingle(RuleType.Background); - if (background != null) - { - children.Add(background); - } - var childrenEnumerable = children.Concat(node.GetItems(RuleType.ScenarioDefinition)); - var description = GetDescription(header); - if (ruleLine.MatchedGherkinDialect == null) return null; - - return CreateRule(tags, GetLocation(ruleLine), ruleLine.MatchedKeyword, ruleLine.MatchedText, description, childrenEnumerable.ToArray(), node); + children.Add(background); } - case RuleType.GherkinDocument: - { - var feature = node.GetSingle(RuleType.Feature); + var childrenEnumerable = children.Concat(node.GetItems(RuleType.ScenarioDefinition)); + var description = GetDescription(header); + if (ruleLine.MatchedGherkinDialect == null) return null; - return CreateGherkinDocument(feature, _comments.ToArray(), node); - } + return CreateRule(tags, GetLocation(ruleLine), ruleLine.MatchedKeyword, ruleLine.MatchedText, description, childrenEnumerable.ToArray(), node); } + case RuleType.GherkinDocument: + { + var feature = node.GetSingle(RuleType.Feature); - return node; + return CreateGherkinDocument(feature, _comments.ToArray(), node); + } } - protected virtual StepKeywordType GetKeywordType(Token stepLine) - { - var stepKeywordType = stepLine.MatchedGherkinDialect.GetStepKeywordType(stepLine.MatchedKeyword); - if (stepKeywordType == null || stepKeywordType == StepKeywordType.Unspecified) - return StepKeywordType.Unspecified; - return stepKeywordType.Value; - } + return node; + } - protected virtual Background CreateBackground(Location location, string keyword, string name, string description, Step[] steps, AstNode node) - { - return new Background(location, keyword, name, description, steps); - } + protected virtual StepKeywordType GetKeywordType(Token stepLine) + { + var stepKeywordType = stepLine.MatchedGherkinDialect.GetStepKeywordType(stepLine.MatchedKeyword); + if (stepKeywordType == null || stepKeywordType == StepKeywordType.Unspecified) + return StepKeywordType.Unspecified; + return stepKeywordType.Value; + } - protected virtual DataTable CreateDataTable(TableRow[] rows, AstNode node) - { - return new DataTable(rows); - } + protected virtual Background CreateBackground(Location location, string keyword, string name, string description, Step[] steps, AstNode node) + { + return new Background(location, keyword, name, description, steps); + } - protected virtual Comment CreateComment(Location location, string text) - { - return new Comment(location, text); - } + protected virtual DataTable CreateDataTable(TableRow[] rows, AstNode node) + { + return new DataTable(rows); + } - protected virtual Examples CreateExamples(Tag[] tags, Location location, string keyword, string name, string description, TableRow header, TableRow[] body, AstNode node) - { - return new Examples(tags, location, keyword, name, description, header, body); - } + protected virtual Comment CreateComment(Location location, string text) + { + return new Comment(location, text); + } - protected virtual Scenario CreateScenario(Tag[] tags, Location location, string keyword, string name, string description, Step[] steps, Examples[] examples, AstNode node) - { - return new Scenario(tags, location, keyword, name, description, steps, examples); - } + protected virtual Examples CreateExamples(Tag[] tags, Location location, string keyword, string name, string description, TableRow header, TableRow[] body, AstNode node) + { + return new Examples(tags, location, keyword, name, description, header, body); + } - protected virtual DocString CreateDocString(Location location, string contentType, string content, string delimiter, AstNode node) - { - return new DocString(location, contentType, content, delimiter); - } + protected virtual Scenario CreateScenario(Tag[] tags, Location location, string keyword, string name, string description, Step[] steps, Examples[] examples, AstNode node) + { + return new Scenario(tags, location, keyword, name, description, steps, examples); + } - protected virtual Step CreateStep(Location location, string keyword, StepKeywordType keywordType, string text, StepArgument argument, AstNode node) - { - return new Step(location, keyword, keywordType, text, argument); - } + protected virtual DocString CreateDocString(Location location, string contentType, string content, string delimiter, AstNode node) + { + return new DocString(location, contentType, content, delimiter); + } - protected virtual GherkinDocument CreateGherkinDocument(Feature feature, Comment[] gherkinDocumentComments, AstNode node) { - return new GherkinDocument(feature, gherkinDocumentComments); - } + protected virtual Step CreateStep(Location location, string keyword, StepKeywordType keywordType, string text, StepArgument argument, AstNode node) + { + return new Step(location, keyword, keywordType, text, argument); + } - 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 GherkinDocument CreateGherkinDocument(Feature feature, Comment[] gherkinDocumentComments, AstNode node) { + return new GherkinDocument(feature, gherkinDocumentComments); + } - protected virtual Rule CreateRule(Tag[] tags, Location location, string keyword, string name, string description, IHasLocation[] children, AstNode node) - { - return new Rule(tags, location, keyword, name, description, children); - } + 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 Tag CreateTag(Location location, string name, AstNode node) - { - return new Tag(location, name); - } + protected virtual Rule CreateRule(Tag[] tags, Location location, string keyword, string name, string description, IHasLocation[] children, AstNode node) + { + return new Rule(tags, location, keyword, name, description, children); + } - protected virtual Location CreateLocation(int line, int column) - { - return new Location(line, column); - } + protected virtual Tag CreateTag(Location location, string name, AstNode node) + { + return new Tag(location, name); + } - protected virtual TableRow CreateTableRow(Location location, TableCell[] cells, AstNode node) - { - return new TableRow(location, cells); - } + protected virtual Location CreateLocation(int line, int column) + { + return new Location(line, column); + } - protected virtual TableCell CreateTableCell(Location location, string value) - { - return new TableCell(location, value); - } + protected virtual TableRow CreateTableRow(Location location, TableCell[] cells, AstNode node) + { + return new TableRow(location, cells); + } - private Location GetLocation(Token token, int column = 0) - { - return column == 0 ? token.Location : CreateLocation(token.Location.Line, column); - } + protected virtual TableCell CreateTableCell(Location location, string value) + { + return new TableCell(location, value); + } - private Tag[] GetTags(AstNode node) - { - var tagsNode = node.GetSingle(RuleType.Tags); - if (tagsNode == null) - return new Tag[0]; - - return tagsNode.GetTokens(TokenType.TagLine) - .SelectMany(t => t.MatchedItems, (t, tagItem) => - CreateTag(GetLocation(t, tagItem.Column), tagItem.Text, tagsNode)) - .ToArray(); - } + private Location GetLocation(Token token, int column = 0) + { + return column == 0 ? token.Location : CreateLocation(token.Location.Line, column); + } - private TableRow[] GetTableRows(AstNode node) - { - var rows = node.GetTokens(TokenType.TableRow).Select(token => CreateTableRow(GetLocation(token), GetCells(token), node)).ToArray(); - CheckCellCountConsistency(rows); - return rows; - } + private Tag[] GetTags(AstNode node) + { + var tagsNode = node.GetSingle(RuleType.Tags); + if (tagsNode == null) + return new Tag[0]; + + return tagsNode.GetTokens(TokenType.TagLine) + .SelectMany(t => t.MatchedItems, (t, tagItem) => + CreateTag(GetLocation(t, tagItem.Column), tagItem.Text, tagsNode)) + .ToArray(); + } - protected virtual void CheckCellCountConsistency(TableRow[] rows) - { - if (rows.Length == 0) - return; + private TableRow[] GetTableRows(AstNode node) + { + var rows = node.GetTokens(TokenType.TableRow).Select(token => CreateTableRow(GetLocation(token), GetCells(token), node)).ToArray(); + CheckCellCountConsistency(rows); + return rows; + } + + protected virtual void CheckCellCountConsistency(TableRow[] rows) + { + if (rows.Length == 0) + return; - int cellCount = rows[0].Cells.Count(); - foreach (var row in rows) + int cellCount = rows[0].Cells.Count(); + foreach (var row in rows) + { + if (row.Cells.Count() != cellCount) { - if (row.Cells.Count() != cellCount) - { - HandleAstError("inconsistent cell count within the table", row.Location); - } + HandleAstError("inconsistent cell count within the table", row.Location); } } + } - protected virtual void HandleAstError(string message, Location location) - { - throw new AstBuilderException(message, location); - } + protected virtual void HandleAstError(string message, Location location) + { + throw new AstBuilderException(message, location); + } - private TableCell[] GetCells(Token tableRowToken) - { - return tableRowToken.MatchedItems - .Select(cellItem => CreateTableCell(GetLocation(tableRowToken, cellItem.Column), cellItem.Text)) - .ToArray(); - } + private TableCell[] GetCells(Token tableRowToken) + { + return tableRowToken.MatchedItems + .Select(cellItem => CreateTableCell(GetLocation(tableRowToken, cellItem.Column), cellItem.Text)) + .ToArray(); + } - private static Step[] GetSteps(AstNode scenarioDefinitionNode) - { - return scenarioDefinitionNode.GetItems(RuleType.Step).ToArray(); - } + private static Step[] GetSteps(AstNode scenarioDefinitionNode) + { + return scenarioDefinitionNode.GetItems(RuleType.Step).ToArray(); + } - private static string GetDescription(AstNode scenarioDefinitionNode) - { - return scenarioDefinitionNode.GetSingle(RuleType.Description); - } + private static string GetDescription(AstNode scenarioDefinitionNode) + { + return scenarioDefinitionNode.GetSingle(RuleType.Description); } } diff --git a/dotnet/Gherkin/AstNode.cs b/dotnet/Gherkin/AstNode.cs index c6a089ff4..75f8b1438 100644 --- a/dotnet/Gherkin/AstNode.cs +++ b/dotnet/Gherkin/AstNode.cs @@ -1,65 +1,64 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; -namespace Gherkin +namespace Gherkin; + +public class AstNode { - public class AstNode - { - private readonly Dictionary> subItems = new Dictionary>(); - public RuleType RuleType { get; private set; } + private readonly Dictionary> subItems = new Dictionary>(); + public RuleType RuleType { get; private set; } - public AstNode(RuleType ruleType) - { - this.RuleType = ruleType; - } + public AstNode(RuleType ruleType) + { + this.RuleType = ruleType; + } - public Token GetToken(TokenType tokenType) - { - return GetSingle((RuleType)tokenType); - } + public Token GetToken(TokenType tokenType) + { + return GetSingle((RuleType)tokenType); + } - public IEnumerable GetTokens(TokenType tokenType) - { - return GetItems((RuleType)tokenType); - } + public IEnumerable GetTokens(TokenType tokenType) + { + return GetItems((RuleType)tokenType); + } - public T GetSingle(RuleType ruleType) - { - return GetItems(ruleType).SingleOrDefault(); - } + public T GetSingle(RuleType ruleType) + { + return GetItems(ruleType).SingleOrDefault(); + } - public IEnumerable GetItems(RuleType ruleType) + public IEnumerable GetItems(RuleType ruleType) + { + IList items; + if (!subItems.TryGetValue(ruleType, out items)) { - IList items; - if (!subItems.TryGetValue(ruleType, out items)) - { - return Enumerable.Empty(); - } - return items.Cast(); + return Enumerable.Empty(); } + return items.Cast(); + } - public void SetSingle(RuleType ruleType, T value) - { - subItems[ruleType] = new object[] { value }; - } + public void SetSingle(RuleType ruleType, T value) + { + subItems[ruleType] = new object[] { value }; + } - public void AddRange(RuleType ruleType, IEnumerable values) + public void AddRange(RuleType ruleType, IEnumerable values) + { + foreach (var value in values) { - foreach (var value in values) - { - Add(ruleType, value); - } + Add(ruleType, value); } + } - public void Add(RuleType ruleType, T obj) + public void Add(RuleType ruleType, T obj) + { + IList items; + if (!subItems.TryGetValue(ruleType, out items)) { - IList items; - if (!subItems.TryGetValue(ruleType, out items)) - { - items = new List(); - subItems.Add(ruleType, items); - } - items.Add(obj); + items = new List(); + subItems.Add(ruleType, items); } + items.Add(obj); } } diff --git a/dotnet/Gherkin/CucumberMessages/AstMessagesConverter.cs b/dotnet/Gherkin/CucumberMessages/AstMessagesConverter.cs index ca96cdc12..97edb4fad 100644 --- a/dotnet/Gherkin/CucumberMessages/AstMessagesConverter.cs +++ b/dotnet/Gherkin/CucumberMessages/AstMessagesConverter.cs @@ -18,235 +18,234 @@ using TableRow = Gherkin.CucumberMessages.Types.TableRow; using Tag = Gherkin.CucumberMessages.Types.Tag; -namespace Gherkin.CucumberMessages +namespace Gherkin.CucumberMessages; + +public class AstMessagesConverter { - public class AstMessagesConverter + private readonly IIdGenerator _idGenerator; + + public AstMessagesConverter(IIdGenerator idGenerator) { - private readonly IIdGenerator _idGenerator; + _idGenerator = idGenerator; + } - public AstMessagesConverter(IIdGenerator idGenerator) + public GherkinDocument ConvertGherkinDocumentToEventArgs(Ast.GherkinDocument gherkinDocument, string sourceEventUri) + { + return new GherkinDocument() { - _idGenerator = idGenerator; - } + Uri = sourceEventUri, + Feature = ConvertFeature(gherkinDocument), + Comments = ConvertComments(gherkinDocument) + }; + } - public GherkinDocument ConvertGherkinDocumentToEventArgs(Ast.GherkinDocument gherkinDocument, string sourceEventUri) - { - return new GherkinDocument() + private IReadOnlyCollection ConvertComments(Ast.GherkinDocument gherkinDocument) + { + return gherkinDocument.Comments.Select(c => + new Comment() { - Uri = sourceEventUri, - Feature = ConvertFeature(gherkinDocument), - Comments = ConvertComments(gherkinDocument) - }; - } + Text = c.Text, + Location = ConvertLocation(c.Location) + }).ToReadOnlyCollection(); + } - private IReadOnlyCollection ConvertComments(Ast.GherkinDocument gherkinDocument) + private Feature ConvertFeature(Ast.GherkinDocument gherkinDocument) + { + var feature = gherkinDocument.Feature; + if (feature == null) { - return gherkinDocument.Comments.Select(c => - new Comment() - { - Text = c.Text, - Location = ConvertLocation(c.Location) - }).ToReadOnlyCollection(); + return null; } - private Feature ConvertFeature(Ast.GherkinDocument gherkinDocument) - { - var feature = gherkinDocument.Feature; - if (feature == null) - { - return null; - } - - var children = feature.Children.Select(ConvertToFeatureChild).ToReadOnlyCollection(); - var tags = feature.Tags.Select(ConvertTag).ToReadOnlyCollection(); - - return new Feature() - { - Name = CucumberMessagesDefaults.UseDefault(feature.Name, CucumberMessagesDefaults.DefaultName), - Description = CucumberMessagesDefaults.UseDefault(feature.Description, CucumberMessagesDefaults.DefaultDescription), - Keyword = feature.Keyword, - Language = feature.Language, - Location = ConvertLocation(feature.Location), - Children = children, - Tags = tags - }; - } + var children = feature.Children.Select(ConvertToFeatureChild).ToReadOnlyCollection(); + var tags = feature.Tags.Select(ConvertTag).ToReadOnlyCollection(); - private static Location ConvertLocation(Ast.Location location) + return new Feature() { - return new Location(location.Column, location.Line); - } + Name = CucumberMessagesDefaults.UseDefault(feature.Name, CucumberMessagesDefaults.DefaultName), + Description = CucumberMessagesDefaults.UseDefault(feature.Description, CucumberMessagesDefaults.DefaultDescription), + Keyword = feature.Keyword, + Language = feature.Language, + Location = ConvertLocation(feature.Location), + Children = children, + Tags = tags + }; + } - private FeatureChild ConvertToFeatureChild(IHasLocation hasLocation) - { - var tuple = ConvertToChild(hasLocation); - return new FeatureChild(tuple.Item3, tuple.Item1, tuple.Item2); - } - - private RuleChild ConvertToRuleChild(IHasLocation hasLocation) - { - var tuple = ConvertToChild(hasLocation); - return new RuleChild(tuple.Item1, tuple.Item3); - } - - private Tuple ConvertToChild(IHasLocation hasLocation) + private static Location ConvertLocation(Ast.Location location) + { + return new Location(location.Column, location.Line); + } + + private FeatureChild ConvertToFeatureChild(IHasLocation hasLocation) + { + var tuple = ConvertToChild(hasLocation); + return new FeatureChild(tuple.Item3, tuple.Item1, tuple.Item2); + } + + private RuleChild ConvertToRuleChild(IHasLocation hasLocation) + { + var tuple = ConvertToChild(hasLocation); + return new RuleChild(tuple.Item1, tuple.Item3); + } + + private Tuple ConvertToChild(IHasLocation hasLocation) + { + switch (hasLocation) { - switch (hasLocation) - { - case Gherkin.Ast.Background background: - var backgroundSteps = background.Steps.Select(ConvertStep).ToList(); - return new Tuple(new Background + case Gherkin.Ast.Background background: + var backgroundSteps = background.Steps.Select(ConvertStep).ToList(); + return new Tuple(new Background + { + Id = _idGenerator.GetNewId(), + Location = ConvertLocation(background.Location), + Name = CucumberMessagesDefaults.UseDefault(background.Name, CucumberMessagesDefaults.DefaultName), + Description = CucumberMessagesDefaults.UseDefault(background.Description, CucumberMessagesDefaults.DefaultDescription), + Keyword = background.Keyword, + Steps = backgroundSteps + }, null, null); + case Ast.Scenario scenario: + var steps = scenario.Steps.Select(ConvertStep).ToList(); + var examples = scenario.Examples.Select(ConvertExamples).ToReadOnlyCollection(); + var tags = scenario.Tags.Select(ConvertTag).ToReadOnlyCollection(); + return new Tuple(null, null, new Scenario() + { + Id = _idGenerator.GetNewId(), + Keyword = scenario.Keyword, + Location = ConvertLocation(scenario.Location), + Name = CucumberMessagesDefaults.UseDefault(scenario.Name, CucumberMessagesDefaults.DefaultName), + Description = CucumberMessagesDefaults.UseDefault(scenario.Description, CucumberMessagesDefaults.DefaultDescription), + Steps = steps, + Examples = examples, + Tags = tags + }); + case Ast.Rule rule: + { + var ruleChildren = rule.Children.Select(ConvertToRuleChild).ToReadOnlyCollection(); + var ruleTags = rule.Tags.Select(ConvertTag).ToReadOnlyCollection(); + return new Tuple(null, new Rule { Id = _idGenerator.GetNewId(), - Location = ConvertLocation(background.Location), - Name = CucumberMessagesDefaults.UseDefault(background.Name, CucumberMessagesDefaults.DefaultName), - Description = CucumberMessagesDefaults.UseDefault(background.Description, CucumberMessagesDefaults.DefaultDescription), - Keyword = background.Keyword, - Steps = backgroundSteps - }, null, null); - case Ast.Scenario scenario: - var steps = scenario.Steps.Select(ConvertStep).ToList(); - var examples = scenario.Examples.Select(ConvertExamples).ToReadOnlyCollection(); - var tags = scenario.Tags.Select(ConvertTag).ToReadOnlyCollection(); - return new Tuple(null, null, new Scenario() - { - Id = _idGenerator.GetNewId(), - Keyword = scenario.Keyword, - Location = ConvertLocation(scenario.Location), - Name = CucumberMessagesDefaults.UseDefault(scenario.Name, CucumberMessagesDefaults.DefaultName), - Description = CucumberMessagesDefaults.UseDefault(scenario.Description, CucumberMessagesDefaults.DefaultDescription), - Steps = steps, - Examples = examples, - Tags = tags - }); - case Ast.Rule rule: - { - var ruleChildren = rule.Children.Select(ConvertToRuleChild).ToReadOnlyCollection(); - var ruleTags = rule.Tags.Select(ConvertTag).ToReadOnlyCollection(); - return new Tuple(null, new Rule - { - Id = _idGenerator.GetNewId(), - Name = CucumberMessagesDefaults.UseDefault(rule.Name, CucumberMessagesDefaults.DefaultName), - Description = CucumberMessagesDefaults.UseDefault(rule.Description, CucumberMessagesDefaults.DefaultDescription), - Keyword = rule.Keyword, - Children = ruleChildren, - Location = ConvertLocation(rule.Location), - Tags = ruleTags - }, null); - } - - - - default: - throw new NotImplementedException(); - } + Name = CucumberMessagesDefaults.UseDefault(rule.Name, CucumberMessagesDefaults.DefaultName), + Description = CucumberMessagesDefaults.UseDefault(rule.Description, CucumberMessagesDefaults.DefaultDescription), + Keyword = rule.Keyword, + Children = ruleChildren, + Location = ConvertLocation(rule.Location), + Tags = ruleTags + }, null); + } + + + default: + throw new NotImplementedException(); } - private Examples ConvertExamples(Ast.Examples examples) + } + + private Examples ConvertExamples(Ast.Examples examples) + { + var header = ConvertTableHeader(examples); + var body = ConvertToTableBody(examples); + var tags = examples.Tags.Select(ConvertTag).ToReadOnlyCollection(); + return new Examples() { - var header = ConvertTableHeader(examples); - var body = ConvertToTableBody(examples); - var tags = examples.Tags.Select(ConvertTag).ToReadOnlyCollection(); - return new Examples() + Id = _idGenerator.GetNewId(), + Name = CucumberMessagesDefaults.UseDefault(examples.Name, CucumberMessagesDefaults.DefaultName), + Keyword = examples.Keyword, + Description = CucumberMessagesDefaults.UseDefault(examples.Description, CucumberMessagesDefaults.DefaultDescription), + Location = ConvertLocation(examples.Location), + TableHeader = header, + TableBody = body, + Tags = tags + }; + } + + private IReadOnlyCollection ConvertToTableBody(Ast.Examples examples) + { + if (examples.TableBody == null) + return new List(); + + return ConvertToTableRow(examples.TableBody); + } + + private IReadOnlyCollection ConvertToTableRow(IEnumerable rows) + { + return rows.Select(b => + new TableRow { Id = _idGenerator.GetNewId(), - Name = CucumberMessagesDefaults.UseDefault(examples.Name, CucumberMessagesDefaults.DefaultName), - Keyword = examples.Keyword, - Description = CucumberMessagesDefaults.UseDefault(examples.Description, CucumberMessagesDefaults.DefaultDescription), - Location = ConvertLocation(examples.Location), - TableHeader = header, - TableBody = body, - Tags = tags - }; - } - - private IReadOnlyCollection ConvertToTableBody(Ast.Examples examples) - { - if (examples.TableBody == null) - return new List(); + Location = ConvertLocation(b.Location), + Cells = b.Cells.Select(ConvertCell).ToReadOnlyCollection() + }).ToReadOnlyCollection(); + } - return ConvertToTableRow(examples.TableBody); - } + private TableRow ConvertTableHeader(Ast.Examples examples) + { + if (examples.TableHeader == null) + return null; - private IReadOnlyCollection ConvertToTableRow(IEnumerable rows) + return new TableRow { - return rows.Select(b => - new TableRow - { - Id = _idGenerator.GetNewId(), - Location = ConvertLocation(b.Location), - Cells = b.Cells.Select(ConvertCell).ToReadOnlyCollection() - }).ToReadOnlyCollection(); - } + Id = _idGenerator.GetNewId(), + Location = ConvertLocation(examples.TableHeader.Location), + Cells = examples.TableHeader.Cells.Select(ConvertCell).ToReadOnlyCollection() + }; + } - private TableRow ConvertTableHeader(Ast.Examples examples) + private Tag ConvertTag(Ast.Tag tag) + { + return new Tag { - if (examples.TableHeader == null) - return null; + Id = _idGenerator.GetNewId(), + Location = ConvertLocation(tag.Location), + Name = tag.Name + }; + } - return new TableRow - { - Id = _idGenerator.GetNewId(), - Location = ConvertLocation(examples.TableHeader.Location), - Cells = examples.TableHeader.Cells.Select(ConvertCell).ToReadOnlyCollection() - }; - } + private TableCell ConvertCell(Ast.TableCell c) + { + return new TableCell() + { + Value = CucumberMessagesDefaults.UseDefault(c.Value, CucumberMessagesDefaults.DefaultCellValue), + Location = ConvertLocation(c.Location) + }; + } - private Tag ConvertTag(Ast.Tag tag) + private Step ConvertStep(Ast.Step step) + { + DataTable dataTable = null; + if (step.Argument is Gherkin.Ast.DataTable astDataTable) { - return new Tag + var rows = ConvertToTableRow(astDataTable.Rows); + dataTable = new DataTable { - Id = _idGenerator.GetNewId(), - Location = ConvertLocation(tag.Location), - Name = tag.Name + Rows = rows, + Location = ConvertLocation(astDataTable.Location) }; } - private TableCell ConvertCell(Ast.TableCell c) + DocString docString = null; + if (step.Argument is Gherkin.Ast.DocString astDocString) { - return new TableCell() + docString = new DocString { - Value = CucumberMessagesDefaults.UseDefault(c.Value, CucumberMessagesDefaults.DefaultCellValue), - Location = ConvertLocation(c.Location) + Content = astDocString.Content, + MediaType = astDocString.ContentType, + Delimiter = astDocString.Delimiter ?? "\"\"\"", //TODO: store DocString delimiter in Gherkin AST + Location = ConvertLocation(astDocString.Location) }; } - private Step ConvertStep(Ast.Step step) + return new Step() { - DataTable dataTable = null; - if (step.Argument is Gherkin.Ast.DataTable astDataTable) - { - var rows = ConvertToTableRow(astDataTable.Rows); - dataTable = new DataTable - { - Rows = rows, - Location = ConvertLocation(astDataTable.Location) - }; - } - - DocString docString = null; - if (step.Argument is Gherkin.Ast.DocString astDocString) - { - docString = new DocString - { - Content = astDocString.Content, - MediaType = astDocString.ContentType, - Delimiter = astDocString.Delimiter ?? "\"\"\"", //TODO: store DocString delimiter in Gherkin AST - Location = ConvertLocation(astDocString.Location) - }; - } - - return new Step() - { - Id = _idGenerator.GetNewId(), - Keyword = step.Keyword, - KeywordType = step.KeywordType, - Text = step.Text, - DataTable = dataTable, - DocString = docString, - Location = ConvertLocation(step.Location) - }; - } + Id = _idGenerator.GetNewId(), + Keyword = step.Keyword, + KeywordType = step.KeywordType, + Text = step.Text, + DataTable = dataTable, + DocString = docString, + Location = ConvertLocation(step.Location) + }; } } \ No newline at end of file diff --git a/dotnet/Gherkin/CucumberMessages/CucumberMessagesDefaults.cs b/dotnet/Gherkin/CucumberMessages/CucumberMessagesDefaults.cs index fb3e5782b..5afce56af 100644 --- a/dotnet/Gherkin/CucumberMessages/CucumberMessagesDefaults.cs +++ b/dotnet/Gherkin/CucumberMessages/CucumberMessagesDefaults.cs @@ -1,15 +1,14 @@ -namespace Gherkin.CucumberMessages +namespace Gherkin.CucumberMessages; + +public static class CucumberMessagesDefaults { - public static class CucumberMessagesDefaults - { - public const string DefaultDescription = ""; - public const string DefaultName = ""; - public const string DefaultCellValue = ""; - public const string DefaultSourceData = ""; + public const string DefaultDescription = ""; + public const string DefaultName = ""; + public const string DefaultCellValue = ""; + public const string DefaultSourceData = ""; - public static string UseDefault(string value, string defaultValue) - { - return string.IsNullOrEmpty(value) ? defaultValue : value; - } + public static string UseDefault(string value, string defaultValue) + { + return string.IsNullOrEmpty(value) ? defaultValue : value; } } diff --git a/dotnet/Gherkin/CucumberMessages/EnumerableExtensions.cs b/dotnet/Gherkin/CucumberMessages/EnumerableExtensions.cs index da5b7e442..1a31c66b1 100644 --- a/dotnet/Gherkin/CucumberMessages/EnumerableExtensions.cs +++ b/dotnet/Gherkin/CucumberMessages/EnumerableExtensions.cs @@ -2,13 +2,12 @@ using System.Collections.ObjectModel; using System.Linq; -namespace Gherkin.CucumberMessages +namespace Gherkin.CucumberMessages; + +internal static class EnumerableExtensions { - internal static class EnumerableExtensions + public static ReadOnlyCollection ToReadOnlyCollection(this IEnumerable enumerable) { - public static ReadOnlyCollection ToReadOnlyCollection(this IEnumerable enumerable) - { - return new ReadOnlyCollection(enumerable.ToList()); - } + return new ReadOnlyCollection(enumerable.ToList()); } } \ No newline at end of file diff --git a/dotnet/Gherkin/CucumberMessages/IdGenerator.cs b/dotnet/Gherkin/CucumberMessages/IdGenerator.cs index 989dba94c..6804f52d0 100644 --- a/dotnet/Gherkin/CucumberMessages/IdGenerator.cs +++ b/dotnet/Gherkin/CucumberMessages/IdGenerator.cs @@ -1,33 +1,32 @@ using System; -namespace Gherkin.CucumberMessages +namespace Gherkin.CucumberMessages; + +public interface IIdGenerator +{ + string GetNewId(); +} + +public class GuidIdGenerator : IIdGenerator { - public interface IIdGenerator + public string GetNewId() { - string GetNewId(); + return Guid.NewGuid().ToString("N"); } +} - public class GuidIdGenerator : IIdGenerator +public class IncrementingIdGenerator : IIdGenerator +{ + private int _counter = 0; + + public string GetNewId() { - public string GetNewId() - { - return Guid.NewGuid().ToString("N"); - } + var nextId = _counter++; + return nextId.ToString(); } - public class IncrementingIdGenerator : IIdGenerator + public void Reset() { - private int _counter = 0; - - public string GetNewId() - { - var nextId = _counter++; - return nextId.ToString(); - } - - public void Reset() - { - _counter = 0; - } + _counter = 0; } } \ No newline at end of file diff --git a/dotnet/Gherkin/CucumberMessages/Pickles/PickleCompiler.cs b/dotnet/Gherkin/CucumberMessages/Pickles/PickleCompiler.cs index c2120a287..a1829447f 100644 --- a/dotnet/Gherkin/CucumberMessages/Pickles/PickleCompiler.cs +++ b/dotnet/Gherkin/CucumberMessages/Pickles/PickleCompiler.cs @@ -5,294 +5,293 @@ // ReSharper disable PossibleMultipleEnumeration -namespace Gherkin.CucumberMessages.Pickles +namespace Gherkin.CucumberMessages.Pickles; + +public class PickleCompiler { - public class PickleCompiler + private readonly IIdGenerator _idGenerator; + protected StepKeywordType CurrentStepKeywordType { get; set; } + + public PickleCompiler(IIdGenerator idGenerator) { - private readonly IIdGenerator _idGenerator; - protected StepKeywordType CurrentStepKeywordType { get; set; } + _idGenerator = idGenerator; + } - public PickleCompiler(IIdGenerator idGenerator) + public List Compile(GherkinDocument gherkinDocument) + { + var pickles = new List(); + var feature = gherkinDocument.Feature; + if (feature == null) { - _idGenerator = idGenerator; + return pickles; } - public List Compile(GherkinDocument gherkinDocument) - { - var pickles = new List(); - var feature = gherkinDocument.Feature; - if (feature == null) - { - return pickles; - } + var language = feature.Language; + var tags = feature.Tags; - var language = feature.Language; - var tags = feature.Tags; + BuildFeature(pickles, language, tags, Enumerable.Empty, feature.Children, gherkinDocument.Uri); - BuildFeature(pickles, language, tags, Enumerable.Empty, feature.Children, gherkinDocument.Uri); + return pickles; + } - return pickles; - } + protected virtual void BuildFeature(List pickles, string language, IEnumerable tags, + Func> backgroundStepsFactory, IEnumerable children, + string gherkinDocumentUri) + { + if (children == null) + return; - protected virtual void BuildFeature(List pickles, string language, IEnumerable tags, - Func> backgroundStepsFactory, IEnumerable children, - string gherkinDocumentUri) + foreach (var child in children) { - if (children == null) - return; - - foreach (var child in children) + if (child.Background != null) { - if (child.Background != null) - { - backgroundStepsFactory = BuildBackground(child.Background, backgroundStepsFactory); - } - else if (child.Rule != null) - { - var mergedRuleTags = tags.Concat(child.Rule.Tags); - BuildRule(pickles, language, mergedRuleTags, backgroundStepsFactory, child.Rule.Children, gherkinDocumentUri); - } - else if (child.Scenario != null) - { - BuildScenario(pickles, language, tags, backgroundStepsFactory, gherkinDocumentUri, child.Scenario); - } + backgroundStepsFactory = BuildBackground(child.Background, backgroundStepsFactory); } - } - - protected virtual void BuildRule(List pickles, string language, IEnumerable tags, - Func> backgroundStepsFactory, IEnumerable children, - string gherkinDocumentUri) - { - if (children == null) - return; - - foreach (var child in children) + else if (child.Rule != null) { - if (child.Background != null) - { - backgroundStepsFactory = BuildBackground(child.Background, backgroundStepsFactory); - } - else if (child.Scenario != null) - { - BuildScenario(pickles, language, tags, backgroundStepsFactory, gherkinDocumentUri, child.Scenario); - } + var mergedRuleTags = tags.Concat(child.Rule.Tags); + BuildRule(pickles, language, mergedRuleTags, backgroundStepsFactory, child.Rule.Children, gherkinDocumentUri); + } + else if (child.Scenario != null) + { + BuildScenario(pickles, language, tags, backgroundStepsFactory, gherkinDocumentUri, child.Scenario); } } + } - private Func> BuildBackground(Background background, Func> backgroundStepsFactory) - { - var previousFactory = backgroundStepsFactory; - backgroundStepsFactory = () => previousFactory().Concat(PickleSteps(background.Steps)); - return backgroundStepsFactory; - } + protected virtual void BuildRule(List pickles, string language, IEnumerable tags, + Func> backgroundStepsFactory, IEnumerable children, + string gherkinDocumentUri) + { + if (children == null) + return; - private void BuildScenario(List pickles, string language, IEnumerable tags, Func> backgroundStepsFactory, string gherkinDocumentUri, Scenario scenario) + foreach (var child in children) { - CurrentStepKeywordType = StepKeywordType.Unspecified; - if (!scenario.Examples.Any()) + if (child.Background != null) { - CompileScenario(pickles, backgroundStepsFactory, scenario, tags, language, gherkinDocumentUri); + backgroundStepsFactory = BuildBackground(child.Background, backgroundStepsFactory); } - else + else if (child.Scenario != null) { - CompileScenarioOutline(pickles, backgroundStepsFactory, scenario, tags, language, gherkinDocumentUri); + BuildScenario(pickles, language, tags, backgroundStepsFactory, gherkinDocumentUri, child.Scenario); } } + } - protected virtual void CompileScenario(List pickles, - Func> backgroundStepsFactory, Scenario scenario, IEnumerable featureTags, - string language, string gherkinDocumentUri) + private Func> BuildBackground(Background background, Func> backgroundStepsFactory) + { + var previousFactory = backgroundStepsFactory; + backgroundStepsFactory = () => previousFactory().Concat(PickleSteps(background.Steps)); + return backgroundStepsFactory; + } + + private void BuildScenario(List pickles, string language, IEnumerable tags, Func> backgroundStepsFactory, string gherkinDocumentUri, Scenario scenario) + { + CurrentStepKeywordType = StepKeywordType.Unspecified; + if (!scenario.Examples.Any()) { - var steps = new List(); - if (scenario.Steps.Any()) - steps.AddRange(backgroundStepsFactory()); - - var scenarioTags = new List(); - scenarioTags.AddRange(featureTags); - scenarioTags.AddRange(scenario.Tags); - - steps.AddRange(PickleSteps(scenario.Steps)); - - Pickle pickle = new Pickle( - _idGenerator.GetNewId(), - gherkinDocumentUri, - scenario.Name, - language, - steps, - PickleTags(scenarioTags), - new []{ scenario.Id } - ); - pickles.Add(pickle); + CompileScenario(pickles, backgroundStepsFactory, scenario, tags, language, gherkinDocumentUri); } + else + { + CompileScenarioOutline(pickles, backgroundStepsFactory, scenario, tags, language, gherkinDocumentUri); + } + } - protected virtual void CompileScenarioOutline(List pickles, - Func> backgroundStepsFactory, Scenario scenarioOutline, - IEnumerable featureTags, string language, string gherkinDocumentUri) + protected virtual void CompileScenario(List pickles, + Func> backgroundStepsFactory, Scenario scenario, IEnumerable featureTags, + string language, string gherkinDocumentUri) + { + var steps = new List(); + if (scenario.Steps.Any()) + steps.AddRange(backgroundStepsFactory()); + + var scenarioTags = new List(); + scenarioTags.AddRange(featureTags); + scenarioTags.AddRange(scenario.Tags); + + steps.AddRange(PickleSteps(scenario.Steps)); + + Pickle pickle = new Pickle( + _idGenerator.GetNewId(), + gherkinDocumentUri, + scenario.Name, + language, + steps, + PickleTags(scenarioTags), + new []{ scenario.Id } + ); + pickles.Add(pickle); + } + + protected virtual void CompileScenarioOutline(List pickles, + Func> backgroundStepsFactory, Scenario scenarioOutline, + IEnumerable featureTags, string language, string gherkinDocumentUri) + { + foreach (var examples in scenarioOutline.Examples) { - foreach (var examples in scenarioOutline.Examples) + if (examples.TableHeader == null) continue; + var variableCells = examples.TableHeader.Cells; + foreach (var values in examples.TableBody) { - if (examples.TableHeader == null) continue; - var variableCells = examples.TableHeader.Cells; - foreach (var values in examples.TableBody) + var valueCells = values.Cells; + + var steps = new List(); + if (scenarioOutline.Steps.Any()) + steps.AddRange(backgroundStepsFactory()); + + var tags = new List(); + tags.AddRange(featureTags); + tags.AddRange(scenarioOutline.Tags); + tags.AddRange(examples.Tags); + + foreach(var scenarioOutlineStep in scenarioOutline.Steps) { - var valueCells = values.Cells; - - var steps = new List(); - if (scenarioOutline.Steps.Any()) - steps.AddRange(backgroundStepsFactory()); - - var tags = new List(); - tags.AddRange(featureTags); - tags.AddRange(scenarioOutline.Tags); - tags.AddRange(examples.Tags); - - foreach(var scenarioOutlineStep in scenarioOutline.Steps) - { - string stepText = Interpolate(scenarioOutlineStep.Text, variableCells, valueCells); - - PickleStep pickleStep = CreatePickleStep( - scenarioOutlineStep, - stepText, - CreatePickleArgument(scenarioOutlineStep, variableCells, valueCells), - new[] { scenarioOutlineStep.Id, values.Id } - ); - steps.Add(pickleStep); - } - - Pickle pickle = new Pickle( - _idGenerator.GetNewId(), - gherkinDocumentUri, - Interpolate(scenarioOutline.Name, variableCells, valueCells), - language, - steps, - PickleTags(tags), - new[] { scenarioOutline.Id, values.Id } - ); + string stepText = Interpolate(scenarioOutlineStep.Text, variableCells, valueCells); - pickles.Add(pickle); + PickleStep pickleStep = CreatePickleStep( + scenarioOutlineStep, + stepText, + CreatePickleArgument(scenarioOutlineStep, variableCells, valueCells), + new[] { scenarioOutlineStep.Id, values.Id } + ); + steps.Add(pickleStep); } + + Pickle pickle = new Pickle( + _idGenerator.GetNewId(), + gherkinDocumentUri, + Interpolate(scenarioOutline.Name, variableCells, valueCells), + language, + steps, + PickleTags(tags), + new[] { scenarioOutline.Id, values.Id } + ); + + pickles.Add(pickle); } } + } - protected virtual PickleStep CreatePickleStep(Step step, string text, PickleStepArgument argument, IEnumerable astNodeIds) - { - CurrentStepKeywordType = GetKeywordType(step, CurrentStepKeywordType); - return new PickleStep(argument, astNodeIds, _idGenerator.GetNewId(), text, CurrentStepKeywordType); - } + protected virtual PickleStep CreatePickleStep(Step step, string text, PickleStepArgument argument, IEnumerable astNodeIds) + { + CurrentStepKeywordType = GetKeywordType(step, CurrentStepKeywordType); + return new PickleStep(argument, astNodeIds, _idGenerator.GetNewId(), text, CurrentStepKeywordType); + } - protected virtual StepKeywordType GetKeywordType(Step step, StepKeywordType lastStepKeywordType) + protected virtual StepKeywordType GetKeywordType(Step step, StepKeywordType lastStepKeywordType) + { + var stepKeywordType = step.KeywordType; + switch (stepKeywordType) { - var stepKeywordType = step.KeywordType; - switch (stepKeywordType) - { - case StepKeywordType.Context: - case StepKeywordType.Action: - case StepKeywordType.Outcome: - case StepKeywordType.Unknown: - return stepKeywordType; - case StepKeywordType.Conjunction: - return lastStepKeywordType == StepKeywordType.Unspecified || - lastStepKeywordType == StepKeywordType.Unknown - ? StepKeywordType.Context - : lastStepKeywordType; - default: - return StepKeywordType.Unspecified; - } + case StepKeywordType.Context: + case StepKeywordType.Action: + case StepKeywordType.Outcome: + case StepKeywordType.Unknown: + return stepKeywordType; + case StepKeywordType.Conjunction: + return lastStepKeywordType == StepKeywordType.Unspecified || + lastStepKeywordType == StepKeywordType.Unknown + ? StepKeywordType.Context + : lastStepKeywordType; + default: + return StepKeywordType.Unspecified; } + } - protected virtual PickleStepArgument CreatePickleArgument(Step argument) - { - var noCells = Enumerable.Empty(); - return CreatePickleArgument(argument, noCells, noCells); - } + protected virtual PickleStepArgument CreatePickleArgument(Step argument) + { + var noCells = Enumerable.Empty(); + return CreatePickleArgument(argument, noCells, noCells); + } - protected virtual PickleStepArgument CreatePickleArgument(Step step, IEnumerable variableCells, IEnumerable valueCells) - { - if (step.DataTable != null) { - var t = step.DataTable; - var rows = t.Rows; - var newRows = new List(rows.Count()); - foreach(var row in rows) + protected virtual PickleStepArgument CreatePickleArgument(Step step, IEnumerable variableCells, IEnumerable valueCells) + { + if (step.DataTable != null) { + var t = step.DataTable; + var rows = t.Rows; + var newRows = new List(rows.Count()); + foreach(var row in rows) + { + var cells = row.Cells; + var newCells = new List(); + foreach(var cell in cells) { - var cells = row.Cells; - var newCells = new List(); - foreach(var cell in cells) - { - newCells.Add( - new PickleTableCell( - Interpolate(cell.Value, variableCells, valueCells) - ) - ); - } - newRows.Add(new PickleTableRow(newCells)); + newCells.Add( + new PickleTableCell( + Interpolate(cell.Value, variableCells, valueCells) + ) + ); } - return new PickleStepArgument - { - DataTable = new PickleTable(newRows) - }; + newRows.Add(new PickleTableRow(newCells)); } - - if (step.DocString != null) { - var ds = step.DocString; - return - new PickleStepArgument - { - DocString = new PickleDocString( - Interpolate(ds.Content, variableCells, valueCells), - ds.MediaType == null ? null : Interpolate(ds.MediaType, variableCells, valueCells)) - }; - } - - return null; + return new PickleStepArgument + { + DataTable = new PickleTable(newRows) + }; } - protected virtual PickleStep[] PickleSteps(IEnumerable steps) - { - var result = new List(); - foreach(var step in steps) - { - result.Add(PickleStep(step)); - } - return result.ToArray(); - } + if (step.DocString != null) { + var ds = step.DocString; + return + new PickleStepArgument + { + DocString = new PickleDocString( + Interpolate(ds.Content, variableCells, valueCells), + ds.MediaType == null ? null : Interpolate(ds.MediaType, variableCells, valueCells)) + }; + } + + return null; + } - protected virtual PickleStep PickleStep(Step step) + protected virtual PickleStep[] PickleSteps(IEnumerable steps) + { + var result = new List(); + foreach(var step in steps) { - return CreatePickleStep( - step, - step.Text, - CreatePickleArgument(step), - new []{ step.Id } - ); + result.Add(PickleStep(step)); } + return result.ToArray(); + } - protected virtual string Interpolate(string name, IEnumerable variableCells, IEnumerable valueCells) - { - int col = 0; - foreach (var variableCell in variableCells) - { - var valueCell = valueCells.ElementAt(col++); - string header = variableCell.Value; - string value = valueCell.Value; - name = name.Replace("<" + header + ">", value); - } - return name; - } + protected virtual PickleStep PickleStep(Step step) + { + return CreatePickleStep( + step, + step.Text, + CreatePickleArgument(step), + new []{ step.Id } + ); + } - protected virtual List PickleTags(List tags) + protected virtual string Interpolate(string name, IEnumerable variableCells, IEnumerable valueCells) + { + int col = 0; + foreach (var variableCell in variableCells) { - var result = new List(); - foreach(var tag in tags) - { - result.Add(PickleTag(tag)); - } - return result; + var valueCell = valueCells.ElementAt(col++); + string header = variableCell.Value; + string value = valueCell.Value; + name = name.Replace("<" + header + ">", value); } + return name; + } - protected virtual PickleTag PickleTag(Tag tag) + protected virtual List PickleTags(List tags) + { + var result = new List(); + foreach(var tag in tags) { - return new PickleTag(tag.Name, tag.Id); + result.Add(PickleTag(tag)); } + return result; + } + + protected virtual PickleTag PickleTag(Tag tag) + { + return new PickleTag(tag.Name, tag.Id); } } diff --git a/dotnet/Gherkin/CucumberMessages/Types/Background.cs b/dotnet/Gherkin/CucumberMessages/Types/Background.cs index 35db9e1c8..32b053f52 100644 --- a/dotnet/Gherkin/CucumberMessages/Types/Background.cs +++ b/dotnet/Gherkin/CucumberMessages/Types/Background.cs @@ -1,26 +1,25 @@ using System.Collections.Generic; using System.Runtime.Serialization; -namespace Gherkin.CucumberMessages.Types +namespace Gherkin.CucumberMessages.Types; + +public class Background { - public class Background - { - [DataMember(Name = "location")] - public Location Location { get; set; } + [DataMember(Name = "location")] + public Location Location { get; set; } - [DataMember(Name = "keyword")] - public string Keyword { get; set; } + [DataMember(Name = "keyword")] + public string Keyword { get; set; } - [DataMember(Name = "name")] - public string Name { get; set; } + [DataMember(Name = "name")] + public string Name { get; set; } - [DataMember(Name = "description")] - public string Description { get; set; } + [DataMember(Name = "description")] + public string Description { get; set; } - [DataMember(Name = "steps")] - public IReadOnlyCollection Steps { get; set; } + [DataMember(Name = "steps")] + public IReadOnlyCollection Steps { get; set; } - [DataMember(Name = "id")] - public string Id { get; set; } - } + [DataMember(Name = "id")] + public string Id { get; set; } } diff --git a/dotnet/Gherkin/CucumberMessages/Types/Comment.cs b/dotnet/Gherkin/CucumberMessages/Types/Comment.cs index a0bd2115e..a6802c994 100644 --- a/dotnet/Gherkin/CucumberMessages/Types/Comment.cs +++ b/dotnet/Gherkin/CucumberMessages/Types/Comment.cs @@ -1,13 +1,12 @@ using System.Runtime.Serialization; -namespace Gherkin.CucumberMessages.Types +namespace Gherkin.CucumberMessages.Types; + +public class Comment { - public class Comment - { - [DataMember(Name = "location")] - public Location Location { get; set; } + [DataMember(Name = "location")] + public Location Location { get; set; } - [DataMember(Name="text")] - public string Text { get; set; } - } + [DataMember(Name="text")] + public string Text { get; set; } } \ No newline at end of file diff --git a/dotnet/Gherkin/CucumberMessages/Types/DataTable.cs b/dotnet/Gherkin/CucumberMessages/Types/DataTable.cs index 23c6dbd13..daa43b684 100644 --- a/dotnet/Gherkin/CucumberMessages/Types/DataTable.cs +++ b/dotnet/Gherkin/CucumberMessages/Types/DataTable.cs @@ -1,14 +1,13 @@ using System.Collections.Generic; using System.Runtime.Serialization; -namespace Gherkin.CucumberMessages.Types +namespace Gherkin.CucumberMessages.Types; + +public class DataTable { - public class DataTable - { - [DataMember(Name = "location")] - public Location Location { get; set; } + [DataMember(Name = "location")] + public Location Location { get; set; } - [DataMember(Name = "rows")] - public IReadOnlyCollection Rows { get; set; } - } + [DataMember(Name = "rows")] + public IReadOnlyCollection Rows { get; set; } } \ No newline at end of file diff --git a/dotnet/Gherkin/CucumberMessages/Types/DocString.cs b/dotnet/Gherkin/CucumberMessages/Types/DocString.cs index 3b6574872..f224983a9 100644 --- a/dotnet/Gherkin/CucumberMessages/Types/DocString.cs +++ b/dotnet/Gherkin/CucumberMessages/Types/DocString.cs @@ -1,19 +1,18 @@ using System.Runtime.Serialization; -namespace Gherkin.CucumberMessages.Types +namespace Gherkin.CucumberMessages.Types; + +public class DocString { - public class DocString - { - [DataMember(Name = "location")] - public Location Location { get; set; } + [DataMember(Name = "location")] + public Location Location { get; set; } - [DataMember(Name = "mediaType")] - public string MediaType { get; set; } + [DataMember(Name = "mediaType")] + public string MediaType { get; set; } - [DataMember(Name = "content")] - public string Content { get; set; } + [DataMember(Name = "content")] + public string Content { get; set; } - [DataMember(Name = "delimiter")] - public string Delimiter { get; set; } - } + [DataMember(Name = "delimiter")] + public string Delimiter { get; set; } } \ No newline at end of file diff --git a/dotnet/Gherkin/CucumberMessages/Types/Envelope.cs b/dotnet/Gherkin/CucumberMessages/Types/Envelope.cs index cbed1f00b..4591f5062 100644 --- a/dotnet/Gherkin/CucumberMessages/Types/Envelope.cs +++ b/dotnet/Gherkin/CucumberMessages/Types/Envelope.cs @@ -1,20 +1,19 @@ using System; using System.Runtime.Serialization; -namespace Gherkin.CucumberMessages.Types +namespace Gherkin.CucumberMessages.Types; + +public class Envelope { - public class Envelope - { - [DataMember(Name = "gherkinDocument")] - public GherkinDocument GherkinDocument { get; set; } + [DataMember(Name = "gherkinDocument")] + public GherkinDocument GherkinDocument { get; set; } - [DataMember(Name = "source")] - public Source Source { get; set; } + [DataMember(Name = "source")] + public Source Source { get; set; } - [DataMember(Name = "pickle")] - public Pickle Pickle { get; set; } + [DataMember(Name = "pickle")] + public Pickle Pickle { get; set; } - [DataMember(Name = "parseError")] - public ParseError ParseError { get; set; } - } + [DataMember(Name = "parseError")] + public ParseError ParseError { get; set; } } diff --git a/dotnet/Gherkin/CucumberMessages/Types/Examples.cs b/dotnet/Gherkin/CucumberMessages/Types/Examples.cs index 4f48817b6..24b0f8137 100644 --- a/dotnet/Gherkin/CucumberMessages/Types/Examples.cs +++ b/dotnet/Gherkin/CucumberMessages/Types/Examples.cs @@ -1,32 +1,31 @@ using System.Collections.Generic; using System.Runtime.Serialization; -namespace Gherkin.CucumberMessages.Types +namespace Gherkin.CucumberMessages.Types; + +public class Examples { - public class Examples - { - [DataMember(Name = "location")] - public Location Location { get; set; } + [DataMember(Name = "location")] + public Location Location { get; set; } - [DataMember(Name = "tags")] - public IReadOnlyCollection Tags { get; set; } + [DataMember(Name = "tags")] + public IReadOnlyCollection Tags { get; set; } - [DataMember(Name = "keyword")] - public string Keyword { get; set; } + [DataMember(Name = "keyword")] + public string Keyword { get; set; } - [DataMember(Name = "name")] - public string Name { get; set; } + [DataMember(Name = "name")] + public string Name { get; set; } - [DataMember(Name = "description")] - public string Description { get; set; } + [DataMember(Name = "description")] + public string Description { get; set; } - [DataMember(Name = "tableHeader")] - public TableRow TableHeader { get; set; } + [DataMember(Name = "tableHeader")] + public TableRow TableHeader { get; set; } - [DataMember(Name = "tableBody")] - public IReadOnlyCollection TableBody { get; set; } + [DataMember(Name = "tableBody")] + public IReadOnlyCollection TableBody { get; set; } - [DataMember(Name = "id")] - public string Id { get; set; } - } + [DataMember(Name = "id")] + public string Id { get; set; } } \ No newline at end of file diff --git a/dotnet/Gherkin/CucumberMessages/Types/Feature.cs b/dotnet/Gherkin/CucumberMessages/Types/Feature.cs index db5dbab29..8452acfc7 100644 --- a/dotnet/Gherkin/CucumberMessages/Types/Feature.cs +++ b/dotnet/Gherkin/CucumberMessages/Types/Feature.cs @@ -1,29 +1,28 @@ using System.Collections.Generic; using System.Runtime.Serialization; -namespace Gherkin.CucumberMessages.Types +namespace Gherkin.CucumberMessages.Types; + +public class Feature { - public class Feature - { - [DataMember(Name = "location")] - public Location Location { get; set; } + [DataMember(Name = "location")] + public Location Location { get; set; } - [DataMember(Name = "tags")] - public IReadOnlyCollection Tags { get; set; } + [DataMember(Name = "tags")] + public IReadOnlyCollection Tags { get; set; } - [DataMember(Name = "language")] - public string Language { get; set; } + [DataMember(Name = "language")] + public string Language { get; set; } - [DataMember(Name = "keyword")] - public string Keyword { get; set; } + [DataMember(Name = "keyword")] + public string Keyword { get; set; } - [DataMember(Name = "name")] - public string Name { get; set; } - - [DataMember(Name = "description")] - public string Description { get; set; } - - [DataMember(Name = "children")] - public IReadOnlyCollection Children { get; set; } - } + [DataMember(Name = "name")] + public string Name { get; set; } + + [DataMember(Name = "description")] + public string Description { get; set; } + + [DataMember(Name = "children")] + public IReadOnlyCollection Children { get; set; } } \ No newline at end of file diff --git a/dotnet/Gherkin/CucumberMessages/Types/FeatureChild.cs b/dotnet/Gherkin/CucumberMessages/Types/FeatureChild.cs index 882e54526..5c5dd0b07 100644 --- a/dotnet/Gherkin/CucumberMessages/Types/FeatureChild.cs +++ b/dotnet/Gherkin/CucumberMessages/Types/FeatureChild.cs @@ -1,27 +1,26 @@ using System.Runtime.Serialization; -namespace Gherkin.CucumberMessages.Types +namespace Gherkin.CucumberMessages.Types; + +public class FeatureChild { - public class FeatureChild - { - [DataMember(Name = "scenario")] - public Scenario Scenario { get; set; } + [DataMember(Name = "scenario")] + public Scenario Scenario { get; set; } - [DataMember(Name = "background")] - public Background Background { get; set; } + [DataMember(Name = "background")] + public Background Background { get; set; } - [DataMember(Name = "rule")] - public Rule Rule { get; set; } + [DataMember(Name = "rule")] + public Rule Rule { get; set; } - public FeatureChild() - { - } + public FeatureChild() + { + } - public FeatureChild(Scenario scenario, Background background, Rule rule) - { - Scenario = scenario; - Background = background; - Rule = rule; - } + public FeatureChild(Scenario scenario, Background background, Rule rule) + { + Scenario = scenario; + Background = background; + Rule = rule; } } \ No newline at end of file diff --git a/dotnet/Gherkin/CucumberMessages/Types/GherkinDocument.cs b/dotnet/Gherkin/CucumberMessages/Types/GherkinDocument.cs index b110ab5b2..dadee0063 100644 --- a/dotnet/Gherkin/CucumberMessages/Types/GherkinDocument.cs +++ b/dotnet/Gherkin/CucumberMessages/Types/GherkinDocument.cs @@ -1,17 +1,16 @@ using System.Collections.Generic; using System.Runtime.Serialization; -namespace Gherkin.CucumberMessages.Types +namespace Gherkin.CucumberMessages.Types; + +public class GherkinDocument { - public class GherkinDocument - { - [DataMember(Name = "uri")] - public string Uri { get; set; } + [DataMember(Name = "uri")] + public string Uri { get; set; } - [DataMember(Name = "feature")] - public Feature Feature { get; set; } + [DataMember(Name = "feature")] + public Feature Feature { get; set; } - [DataMember(Name = "comments")] - public IReadOnlyCollection Comments { get; set; } - } + [DataMember(Name = "comments")] + public IReadOnlyCollection Comments { get; set; } } \ No newline at end of file diff --git a/dotnet/Gherkin/CucumberMessages/Types/Location.cs b/dotnet/Gherkin/CucumberMessages/Types/Location.cs index 72daa42a4..3d9cf3de1 100644 --- a/dotnet/Gherkin/CucumberMessages/Types/Location.cs +++ b/dotnet/Gherkin/CucumberMessages/Types/Location.cs @@ -1,23 +1,22 @@ using System.Runtime.Serialization; -namespace Gherkin.CucumberMessages.Types +namespace Gherkin.CucumberMessages.Types; + +public class Location { - public class Location - { - [DataMember(Name = "line")] - public int Line { get; set; } + [DataMember(Name = "line")] + public int Line { get; set; } - [DataMember(Name = "column")] - public int? Column { get; set; } + [DataMember(Name = "column")] + public int? Column { get; set; } - public Location() - { - } + public Location() + { + } - public Location(int column, int line) - { - Column = column == 0 ? (int?)null : column; - Line = line; - } + public Location(int column, int line) + { + Column = column == 0 ? (int?)null : column; + Line = line; } } \ No newline at end of file diff --git a/dotnet/Gherkin/CucumberMessages/Types/ParseError.cs b/dotnet/Gherkin/CucumberMessages/Types/ParseError.cs index 78f181ed8..655eca018 100644 --- a/dotnet/Gherkin/CucumberMessages/Types/ParseError.cs +++ b/dotnet/Gherkin/CucumberMessages/Types/ParseError.cs @@ -1,13 +1,12 @@ using System.Runtime.Serialization; -namespace Gherkin.CucumberMessages.Types +namespace Gherkin.CucumberMessages.Types; + +public class ParseError { - public class ParseError - { - [DataMember(Name = "source")] - public SourceReference Source { get; set; } + [DataMember(Name = "source")] + public SourceReference Source { get; set; } - [DataMember(Name = "message")] - public string Message { get; set; } - } + [DataMember(Name = "message")] + public string Message { get; set; } } \ No newline at end of file diff --git a/dotnet/Gherkin/CucumberMessages/Types/Pickle.cs b/dotnet/Gherkin/CucumberMessages/Types/Pickle.cs index 3e03de527..30d817e95 100644 --- a/dotnet/Gherkin/CucumberMessages/Types/Pickle.cs +++ b/dotnet/Gherkin/CucumberMessages/Types/Pickle.cs @@ -1,44 +1,43 @@ using System.Collections.Generic; using System.Runtime.Serialization; -namespace Gherkin.CucumberMessages.Types +namespace Gherkin.CucumberMessages.Types; + +public class Pickle { - public class Pickle + [DataMember(Name = "id")] + public string Id { get; set; } + + [DataMember(Name = "uri")] + public string Uri { get; set; } + + [DataMember(Name = "name")] + public string Name { get; set; } + + [DataMember(Name = "language")] + public string Language { get; set; } + + [DataMember(Name = "steps")] + public IReadOnlyCollection Steps { get; set; } + + [DataMember(Name = "tags")] + public IReadOnlyCollection Tags { get; set; } + + [DataMember(Name = "astNodeIds")] + public IReadOnlyCollection AstNodeIds { get; set; } + + public Pickle() + { + } + + public Pickle(string id, string uri, string name, string language, IEnumerable steps, IEnumerable tags, IEnumerable astNodeIds) { - [DataMember(Name = "id")] - public string Id { get; set; } - - [DataMember(Name = "uri")] - public string Uri { get; set; } - - [DataMember(Name = "name")] - public string Name { get; set; } - - [DataMember(Name = "language")] - public string Language { get; set; } - - [DataMember(Name = "steps")] - public IReadOnlyCollection Steps { get; set; } - - [DataMember(Name = "tags")] - public IReadOnlyCollection Tags { get; set; } - - [DataMember(Name = "astNodeIds")] - public IReadOnlyCollection AstNodeIds { get; set; } - - public Pickle() - { - } - - public Pickle(string id, string uri, string name, string language, IEnumerable steps, IEnumerable tags, IEnumerable astNodeIds) - { - Id = id; - Uri = uri; - Name = name; - Language = language; - Steps = steps.ToReadOnlyCollection(); - Tags = tags.ToReadOnlyCollection(); - AstNodeIds = astNodeIds.ToReadOnlyCollection(); - } + Id = id; + Uri = uri; + Name = name; + Language = language; + Steps = steps.ToReadOnlyCollection(); + Tags = tags.ToReadOnlyCollection(); + AstNodeIds = astNodeIds.ToReadOnlyCollection(); } } diff --git a/dotnet/Gherkin/CucumberMessages/Types/PickleDocString.cs b/dotnet/Gherkin/CucumberMessages/Types/PickleDocString.cs index 10c12912b..69a62d2ea 100644 --- a/dotnet/Gherkin/CucumberMessages/Types/PickleDocString.cs +++ b/dotnet/Gherkin/CucumberMessages/Types/PickleDocString.cs @@ -1,23 +1,22 @@ using System.Runtime.Serialization; -namespace Gherkin.CucumberMessages.Types +namespace Gherkin.CucumberMessages.Types; + +public class PickleDocString { - public class PickleDocString - { - [DataMember(Name = "mediaType")] - public string MediaType { get; set; } + [DataMember(Name = "mediaType")] + public string MediaType { get; set; } - [DataMember(Name = "content")] - public string Content { get; set; } + [DataMember(Name = "content")] + public string Content { get; set; } - public PickleDocString() - { - } - - public PickleDocString(string content, string mediaType = null) - { - Content = content; - MediaType = mediaType; - } + public PickleDocString() + { + } + + public PickleDocString(string content, string mediaType = null) + { + Content = content; + MediaType = mediaType; } } diff --git a/dotnet/Gherkin/CucumberMessages/Types/PickleStep.cs b/dotnet/Gherkin/CucumberMessages/Types/PickleStep.cs index f405f88b0..019e608a8 100644 --- a/dotnet/Gherkin/CucumberMessages/Types/PickleStep.cs +++ b/dotnet/Gherkin/CucumberMessages/Types/PickleStep.cs @@ -1,35 +1,34 @@ using System.Collections.Generic; using System.Runtime.Serialization; -namespace Gherkin.CucumberMessages.Types +namespace Gherkin.CucumberMessages.Types; + +public class PickleStep { - public class PickleStep - { - [DataMember(Name = "argument")] - public PickleStepArgument Argument { get; set; } + [DataMember(Name = "argument")] + public PickleStepArgument Argument { get; set; } - [DataMember(Name = "astNodeIds")] - public IReadOnlyCollection AstNodeIds { get; set; } + [DataMember(Name = "astNodeIds")] + public IReadOnlyCollection AstNodeIds { get; set; } - [DataMember(Name = "id")] - public string Id { get; set; } + [DataMember(Name = "id")] + public string Id { get; set; } - [DataMember(Name = "text")] - public string Text { get; set; } + [DataMember(Name = "text")] + public string Text { get; set; } - [DataMember(Name = "type")] - public StepKeywordType Type { get; set; } + [DataMember(Name = "type")] + public StepKeywordType Type { get; set; } - public PickleStep() - { - } - public PickleStep(PickleStepArgument argument, IEnumerable astNodeIds, string id, string text, StepKeywordType type) - { - Id = id; - Text = text; - Argument = argument; - AstNodeIds = astNodeIds.ToReadOnlyCollection(); - Type = type; - } + public PickleStep() + { + } + public PickleStep(PickleStepArgument argument, IEnumerable astNodeIds, string id, string text, StepKeywordType type) + { + Id = id; + Text = text; + Argument = argument; + AstNodeIds = astNodeIds.ToReadOnlyCollection(); + Type = type; } } diff --git a/dotnet/Gherkin/CucumberMessages/Types/PickleStepArgument.cs b/dotnet/Gherkin/CucumberMessages/Types/PickleStepArgument.cs index 1e50967e3..d0adadb9c 100644 --- a/dotnet/Gherkin/CucumberMessages/Types/PickleStepArgument.cs +++ b/dotnet/Gherkin/CucumberMessages/Types/PickleStepArgument.cs @@ -1,13 +1,12 @@ using System.Runtime.Serialization; -namespace Gherkin.CucumberMessages.Types +namespace Gherkin.CucumberMessages.Types; + +public class PickleStepArgument { - public class PickleStepArgument - { - [DataMember(Name = "docString")] - public PickleDocString DocString { get; set; } + [DataMember(Name = "docString")] + public PickleDocString DocString { get; set; } - [DataMember(Name = "dataTable")] - public PickleTable DataTable { get; set; } - } + [DataMember(Name = "dataTable")] + public PickleTable DataTable { get; set; } } diff --git a/dotnet/Gherkin/CucumberMessages/Types/PickleTable.cs b/dotnet/Gherkin/CucumberMessages/Types/PickleTable.cs index c80044a31..cfac8ece7 100644 --- a/dotnet/Gherkin/CucumberMessages/Types/PickleTable.cs +++ b/dotnet/Gherkin/CucumberMessages/Types/PickleTable.cs @@ -1,20 +1,19 @@ using System.Collections.Generic; using System.Runtime.Serialization; -namespace Gherkin.CucumberMessages.Types +namespace Gherkin.CucumberMessages.Types; + +public class PickleTable { - public class PickleTable - { - [DataMember(Name = "rows")] - public IEnumerable Rows { get; set; } + [DataMember(Name = "rows")] + public IEnumerable Rows { get; set; } - public PickleTable() - { - } - - public PickleTable(IEnumerable rows) - { - Rows = rows; - } + public PickleTable() + { + } + + public PickleTable(IEnumerable rows) + { + Rows = rows; } } diff --git a/dotnet/Gherkin/CucumberMessages/Types/PickleTableCell.cs b/dotnet/Gherkin/CucumberMessages/Types/PickleTableCell.cs index 1176ac533..369a54756 100644 --- a/dotnet/Gherkin/CucumberMessages/Types/PickleTableCell.cs +++ b/dotnet/Gherkin/CucumberMessages/Types/PickleTableCell.cs @@ -1,19 +1,18 @@ using System.Runtime.Serialization; -namespace Gherkin.CucumberMessages.Types +namespace Gherkin.CucumberMessages.Types; + +public class PickleTableCell { - public class PickleTableCell - { - [DataMember(Name = "value")] - public string Value { get; set; } + [DataMember(Name = "value")] + public string Value { get; set; } - public PickleTableCell() - { - } - - public PickleTableCell(string value) - { - Value = value; - } + public PickleTableCell() + { + } + + public PickleTableCell(string value) + { + Value = value; } } diff --git a/dotnet/Gherkin/CucumberMessages/Types/PickleTableRow.cs b/dotnet/Gherkin/CucumberMessages/Types/PickleTableRow.cs index 79f8f8beb..3ff98752a 100644 --- a/dotnet/Gherkin/CucumberMessages/Types/PickleTableRow.cs +++ b/dotnet/Gherkin/CucumberMessages/Types/PickleTableRow.cs @@ -1,20 +1,19 @@ using System.Collections.Generic; using System.Runtime.Serialization; -namespace Gherkin.CucumberMessages.Types +namespace Gherkin.CucumberMessages.Types; + +public class PickleTableRow { - public class PickleTableRow - { - [DataMember(Name = "cells")] - public IEnumerable Cells { get; set; } + [DataMember(Name = "cells")] + public IEnumerable Cells { get; set; } - public PickleTableRow() - { - } - - public PickleTableRow(IEnumerable cells) - { - Cells = cells; - } + public PickleTableRow() + { + } + + public PickleTableRow(IEnumerable cells) + { + Cells = cells; } } diff --git a/dotnet/Gherkin/CucumberMessages/Types/PickleTag.cs b/dotnet/Gherkin/CucumberMessages/Types/PickleTag.cs index 3cc46272b..110e4147d 100644 --- a/dotnet/Gherkin/CucumberMessages/Types/PickleTag.cs +++ b/dotnet/Gherkin/CucumberMessages/Types/PickleTag.cs @@ -1,23 +1,22 @@ using System.Runtime.Serialization; -namespace Gherkin.CucumberMessages.Types +namespace Gherkin.CucumberMessages.Types; + +public class PickleTag { - public class PickleTag - { - [DataMember(Name = "name")] - public string Name { get; set; } + [DataMember(Name = "name")] + public string Name { get; set; } - [DataMember(Name = "astNodeId")] - public string AstNodeId { get; set; } + [DataMember(Name = "astNodeId")] + public string AstNodeId { get; set; } - public PickleTag() - { - } + public PickleTag() + { + } - public PickleTag(string name, string astNodeId) - { - AstNodeId = astNodeId; - Name = name; - } + public PickleTag(string name, string astNodeId) + { + AstNodeId = astNodeId; + Name = name; } } diff --git a/dotnet/Gherkin/CucumberMessages/Types/Rule.cs b/dotnet/Gherkin/CucumberMessages/Types/Rule.cs index cc54ee3d2..c60333601 100644 --- a/dotnet/Gherkin/CucumberMessages/Types/Rule.cs +++ b/dotnet/Gherkin/CucumberMessages/Types/Rule.cs @@ -1,29 +1,28 @@ using System.Collections.Generic; using System.Runtime.Serialization; -namespace Gherkin.CucumberMessages.Types +namespace Gherkin.CucumberMessages.Types; + +public class Rule { - public class Rule - { - [DataMember(Name = "location")] - public Location Location { get; set; } + [DataMember(Name = "location")] + public Location Location { get; set; } - [DataMember(Name = "tags")] - public IReadOnlyCollection Tags { get; set; } + [DataMember(Name = "tags")] + public IReadOnlyCollection Tags { get; set; } - [DataMember(Name = "keyword")] - public string Keyword { get; set; } + [DataMember(Name = "keyword")] + public string Keyword { get; set; } - [DataMember(Name = "name")] - public string Name { get; set; } + [DataMember(Name = "name")] + public string Name { get; set; } - [DataMember(Name = "description")] - public string Description { get; set; } + [DataMember(Name = "description")] + public string Description { get; set; } - [DataMember(Name = "children")] - public IReadOnlyCollection Children { get; set; } + [DataMember(Name = "children")] + public IReadOnlyCollection Children { get; set; } - [DataMember(Name = "id")] - public string Id { get; set; } - } + [DataMember(Name = "id")] + public string Id { get; set; } } \ No newline at end of file diff --git a/dotnet/Gherkin/CucumberMessages/Types/RuleChild.cs b/dotnet/Gherkin/CucumberMessages/Types/RuleChild.cs index eedca0c53..8958094d9 100644 --- a/dotnet/Gherkin/CucumberMessages/Types/RuleChild.cs +++ b/dotnet/Gherkin/CucumberMessages/Types/RuleChild.cs @@ -1,23 +1,22 @@ using System.Runtime.Serialization; -namespace Gherkin.CucumberMessages.Types +namespace Gherkin.CucumberMessages.Types; + +public class RuleChild { - public class RuleChild - { - [DataMember(Name = "background")] - public Background Background { get; set; } + [DataMember(Name = "background")] + public Background Background { get; set; } - [DataMember(Name = "scenario")] - public Scenario Scenario { get; set; } + [DataMember(Name = "scenario")] + public Scenario Scenario { get; set; } - public RuleChild() - { - } + public RuleChild() + { + } - public RuleChild(Background background, Scenario scenario) - { - Background = background; - Scenario = scenario; - } + public RuleChild(Background background, Scenario scenario) + { + Background = background; + Scenario = scenario; } } \ No newline at end of file diff --git a/dotnet/Gherkin/CucumberMessages/Types/Scenario.cs b/dotnet/Gherkin/CucumberMessages/Types/Scenario.cs index 2bad0f002..573629ec9 100644 --- a/dotnet/Gherkin/CucumberMessages/Types/Scenario.cs +++ b/dotnet/Gherkin/CucumberMessages/Types/Scenario.cs @@ -1,32 +1,31 @@ using System.Collections.Generic; using System.Runtime.Serialization; -namespace Gherkin.CucumberMessages.Types +namespace Gherkin.CucumberMessages.Types; + +public class Scenario { - public class Scenario - { - [DataMember(Name = "location")] - public Location Location { get; set; } + [DataMember(Name = "location")] + public Location Location { get; set; } - [DataMember(Name = "tags")] - public IReadOnlyCollection Tags { get; set; } + [DataMember(Name = "tags")] + public IReadOnlyCollection Tags { get; set; } - [DataMember(Name = "keyword")] - public string Keyword { get; set; } + [DataMember(Name = "keyword")] + public string Keyword { get; set; } - [DataMember(Name = "name")] - public string Name { get; set; } + [DataMember(Name = "name")] + public string Name { get; set; } - [DataMember(Name = "description")] - public string Description { get; set; } + [DataMember(Name = "description")] + public string Description { get; set; } - [DataMember(Name = "steps")] - public IReadOnlyCollection Steps { get; set; } + [DataMember(Name = "steps")] + public IReadOnlyCollection Steps { get; set; } - [DataMember(Name = "examples")] - public IReadOnlyCollection Examples { get; set; } + [DataMember(Name = "examples")] + public IReadOnlyCollection Examples { get; set; } - [DataMember(Name = "id")] - public string Id { get; set; } - } + [DataMember(Name = "id")] + public string Id { get; set; } } \ No newline at end of file diff --git a/dotnet/Gherkin/CucumberMessages/Types/Source.cs b/dotnet/Gherkin/CucumberMessages/Types/Source.cs index 71a996b6f..dbfc887f7 100644 --- a/dotnet/Gherkin/CucumberMessages/Types/Source.cs +++ b/dotnet/Gherkin/CucumberMessages/Types/Source.cs @@ -1,16 +1,15 @@ using System.Runtime.Serialization; -namespace Gherkin.CucumberMessages.Types +namespace Gherkin.CucumberMessages.Types; + +public class Source { - public class Source - { - [DataMember(Name = "uri")] - public string Uri { get; set; } + [DataMember(Name = "uri")] + public string Uri { get; set; } - [DataMember(Name = "data")] - public string Data { get; set; } + [DataMember(Name = "data")] + public string Data { get; set; } - [DataMember(Name = "mediaType")] - public string MediaType { get; set; } - } + [DataMember(Name = "mediaType")] + public string MediaType { get; set; } } \ No newline at end of file diff --git a/dotnet/Gherkin/CucumberMessages/Types/SourceReference.cs b/dotnet/Gherkin/CucumberMessages/Types/SourceReference.cs index f71d9f363..8bee318be 100644 --- a/dotnet/Gherkin/CucumberMessages/Types/SourceReference.cs +++ b/dotnet/Gherkin/CucumberMessages/Types/SourceReference.cs @@ -1,15 +1,14 @@ using System.Runtime.Serialization; -namespace Gherkin.CucumberMessages.Types +namespace Gherkin.CucumberMessages.Types; + +public class SourceReference { - public class SourceReference - { - [DataMember(Name = "location")] - public Location Location { get; set; } + [DataMember(Name = "location")] + public Location Location { get; set; } - [DataMember(Name = "uri")] - public string Uri { get; set; } + [DataMember(Name = "uri")] + public string Uri { get; set; } - //TODO: javaMethod, javaStackTraceElement - } + //TODO: javaMethod, javaStackTraceElement } \ No newline at end of file diff --git a/dotnet/Gherkin/CucumberMessages/Types/Step.cs b/dotnet/Gherkin/CucumberMessages/Types/Step.cs index 2f5e04503..48d79b308 100644 --- a/dotnet/Gherkin/CucumberMessages/Types/Step.cs +++ b/dotnet/Gherkin/CucumberMessages/Types/Step.cs @@ -1,28 +1,27 @@ using System.Runtime.Serialization; -namespace Gherkin.CucumberMessages.Types +namespace Gherkin.CucumberMessages.Types; + +public class Step { - public class Step - { - [DataMember(Name = "location")] - public Location Location { get; set; } + [DataMember(Name = "location")] + public Location Location { get; set; } - [DataMember(Name = "keyword")] - public string Keyword { get; set; } + [DataMember(Name = "keyword")] + public string Keyword { get; set; } - [DataMember(Name = "keywordType")] - public StepKeywordType KeywordType { get; set; } + [DataMember(Name = "keywordType")] + public StepKeywordType KeywordType { get; set; } - [DataMember(Name = "text")] - public string Text { get; set; } + [DataMember(Name = "text")] + public string Text { get; set; } - [DataMember(Name = "docString")] - public DocString DocString { get; set; } + [DataMember(Name = "docString")] + public DocString DocString { get; set; } - [DataMember(Name = "dataTable")] - public DataTable DataTable { get; set; } + [DataMember(Name = "dataTable")] + public DataTable DataTable { get; set; } - [DataMember(Name = "id")] - public string Id { get; set; } - } + [DataMember(Name = "id")] + public string Id { get; set; } } \ No newline at end of file diff --git a/dotnet/Gherkin/CucumberMessages/Types/TableCell.cs b/dotnet/Gherkin/CucumberMessages/Types/TableCell.cs index ccac3d741..49452efe2 100644 --- a/dotnet/Gherkin/CucumberMessages/Types/TableCell.cs +++ b/dotnet/Gherkin/CucumberMessages/Types/TableCell.cs @@ -1,13 +1,12 @@ using System.Runtime.Serialization; -namespace Gherkin.CucumberMessages.Types +namespace Gherkin.CucumberMessages.Types; + +public class TableCell { - public class TableCell - { - [DataMember(Name = "location")] - public Location Location { get; set; } - - [DataMember(Name = "value")] - public string Value { get; set; } - } + [DataMember(Name = "location")] + public Location Location { get; set; } + + [DataMember(Name = "value")] + public string Value { get; set; } } \ No newline at end of file diff --git a/dotnet/Gherkin/CucumberMessages/Types/TableRow.cs b/dotnet/Gherkin/CucumberMessages/Types/TableRow.cs index f2573e5d6..1c78f33ff 100644 --- a/dotnet/Gherkin/CucumberMessages/Types/TableRow.cs +++ b/dotnet/Gherkin/CucumberMessages/Types/TableRow.cs @@ -1,17 +1,16 @@ using System.Collections.Generic; using System.Runtime.Serialization; -namespace Gherkin.CucumberMessages.Types +namespace Gherkin.CucumberMessages.Types; + +public class TableRow { - public class TableRow - { - [DataMember(Name = "location")] - public Location Location { get; set; } + [DataMember(Name = "location")] + public Location Location { get; set; } - [DataMember(Name = "cells")] - public IReadOnlyCollection Cells { get; set; } + [DataMember(Name = "cells")] + public IReadOnlyCollection Cells { get; set; } - [DataMember(Name = "id")] - public string Id { get; set; } - } + [DataMember(Name = "id")] + public string Id { get; set; } } \ No newline at end of file diff --git a/dotnet/Gherkin/CucumberMessages/Types/Tag.cs b/dotnet/Gherkin/CucumberMessages/Types/Tag.cs index 594b37acc..34974e463 100644 --- a/dotnet/Gherkin/CucumberMessages/Types/Tag.cs +++ b/dotnet/Gherkin/CucumberMessages/Types/Tag.cs @@ -1,16 +1,15 @@ using System.Runtime.Serialization; -namespace Gherkin.CucumberMessages.Types +namespace Gherkin.CucumberMessages.Types; + +public class Tag { - public class Tag - { - [DataMember(Name = "location")] - public Location Location { get; set; } + [DataMember(Name = "location")] + public Location Location { get; set; } - [DataMember(Name = "name")] - public string Name { get; set; } + [DataMember(Name = "name")] + public string Name { get; set; } - [DataMember(Name = "id")] - public string Id { get; set; } - } + [DataMember(Name = "id")] + public string Id { get; set; } } \ No newline at end of file diff --git a/dotnet/Gherkin/GherkinDialect.cs b/dotnet/Gherkin/GherkinDialect.cs index 0dbab24a9..8f32609a6 100644 --- a/dotnet/Gherkin/GherkinDialect.cs +++ b/dotnet/Gherkin/GherkinDialect.cs @@ -1,76 +1,75 @@ using System.Collections.Generic; using System.Linq; -namespace Gherkin -{ - public class GherkinDialect - { - public const string AsteriskKeyword = "* "; - public string Language { get; } +namespace Gherkin; - public string[] FeatureKeywords { get; } - public string[] RuleKeywords { get; } - public string[] BackgroundKeywords { get; } - public string[] ScenarioKeywords { get; } - public string[] ScenarioOutlineKeywords { get; } - public string[] ExamplesKeywords { get; } - public string[] GivenStepKeywords { get; } - public string[] WhenStepKeywords { get; } - public string[] ThenStepKeywords { get; } - public string[] AndStepKeywords { get; } - public string[] ButStepKeywords { get; } +public class GherkinDialect +{ + public const string AsteriskKeyword = "* "; + public string Language { get; } + public string[] FeatureKeywords { get; } + public string[] RuleKeywords { get; } + public string[] BackgroundKeywords { get; } + public string[] ScenarioKeywords { get; } + public string[] ScenarioOutlineKeywords { get; } + public string[] ExamplesKeywords { get; } + public string[] GivenStepKeywords { get; } + public string[] WhenStepKeywords { get; } + public string[] ThenStepKeywords { get; } + public string[] AndStepKeywords { get; } + public string[] ButStepKeywords { get; } - public string[] StepKeywords { get; } - public IDictionary StepKeywordTypes { get; } - public GherkinDialect( - string language, - string[] featureKeywords, - string[] ruleKeywords, - string[] backgroundKeywords, - string[] scenarioKeywords, - string[] scenarioOutlineKeywords, - string[] examplesKeywords, - string[] givenStepKeywords, - string[] whenStepKeywords, - string[] thenStepKeywords, - string[] andStepKeywords, - string[] butStepKeywords) - { - Language = language; - FeatureKeywords = featureKeywords; - RuleKeywords = ruleKeywords; - BackgroundKeywords = backgroundKeywords; - ScenarioKeywords = scenarioKeywords; - ScenarioOutlineKeywords = scenarioOutlineKeywords; - ExamplesKeywords = examplesKeywords; - GivenStepKeywords = givenStepKeywords; - WhenStepKeywords = whenStepKeywords; - ThenStepKeywords = thenStepKeywords; - AndStepKeywords = andStepKeywords; - ButStepKeywords = butStepKeywords; + public string[] StepKeywords { get; } + public IDictionary StepKeywordTypes { get; } - StepKeywords = givenStepKeywords - .Concat(whenStepKeywords) - .Concat(thenStepKeywords) - .Concat(andStepKeywords) - .Concat(butStepKeywords) - .Distinct() - .ToArray(); + public GherkinDialect( + string language, + string[] featureKeywords, + string[] ruleKeywords, + string[] backgroundKeywords, + string[] scenarioKeywords, + string[] scenarioOutlineKeywords, + string[] examplesKeywords, + string[] givenStepKeywords, + string[] whenStepKeywords, + string[] thenStepKeywords, + string[] andStepKeywords, + string[] butStepKeywords) + { + Language = language; + FeatureKeywords = featureKeywords; + RuleKeywords = ruleKeywords; + BackgroundKeywords = backgroundKeywords; + ScenarioKeywords = scenarioKeywords; + ScenarioOutlineKeywords = scenarioOutlineKeywords; + ExamplesKeywords = examplesKeywords; + GivenStepKeywords = givenStepKeywords; + WhenStepKeywords = whenStepKeywords; + ThenStepKeywords = thenStepKeywords; + AndStepKeywords = andStepKeywords; + ButStepKeywords = butStepKeywords; - StepKeywordTypes = - new[] { new { Keyword = AsteriskKeyword, Type = StepKeywordType.Unknown } } - .Concat(GivenStepKeywords.Select(kw => new { Keyword = kw, Type = StepKeywordType.Context })) - .Concat(WhenStepKeywords.Select(kw => new { Keyword = kw, Type = StepKeywordType.Action })) - .Concat(ThenStepKeywords.Select(kw => new { Keyword = kw, Type = StepKeywordType.Outcome })) - .Concat(AndStepKeywords.Select(kw => new { Keyword = kw, Type = StepKeywordType.Conjunction })) - .Concat(ButStepKeywords.Select(kw => new { Keyword = kw, Type = StepKeywordType.Conjunction })) - .GroupBy(item => item.Keyword, item => item.Type) - .ToDictionary(item => item.Key, item => item.First()); - } + StepKeywords = givenStepKeywords + .Concat(whenStepKeywords) + .Concat(thenStepKeywords) + .Concat(andStepKeywords) + .Concat(butStepKeywords) + .Distinct() + .ToArray(); - public StepKeywordType? GetStepKeywordType(string keyword) - => StepKeywordTypes.TryGetValue(keyword, out var tokenType) ? tokenType : null; + StepKeywordTypes = + new[] { new { Keyword = AsteriskKeyword, Type = StepKeywordType.Unknown } } + .Concat(GivenStepKeywords.Select(kw => new { Keyword = kw, Type = StepKeywordType.Context })) + .Concat(WhenStepKeywords.Select(kw => new { Keyword = kw, Type = StepKeywordType.Action })) + .Concat(ThenStepKeywords.Select(kw => new { Keyword = kw, Type = StepKeywordType.Outcome })) + .Concat(AndStepKeywords.Select(kw => new { Keyword = kw, Type = StepKeywordType.Conjunction })) + .Concat(ButStepKeywords.Select(kw => new { Keyword = kw, Type = StepKeywordType.Conjunction })) + .GroupBy(item => item.Keyword, item => item.Type) + .ToDictionary(item => item.Key, item => item.First()); } + + public StepKeywordType? GetStepKeywordType(string keyword) + => StepKeywordTypes.TryGetValue(keyword, out var tokenType) ? tokenType : null; } diff --git a/dotnet/Gherkin/GherkinDialectProvider.cs b/dotnet/Gherkin/GherkinDialectProvider.cs index a7d47b085..e592d18d0 100644 --- a/dotnet/Gherkin/GherkinDialectProvider.cs +++ b/dotnet/Gherkin/GherkinDialectProvider.cs @@ -6,135 +6,134 @@ using System.Reflection; using TinyJson; -namespace Gherkin +namespace Gherkin; + +public interface IGherkinDialectProvider +{ + GherkinDialect DefaultDialect { get; } + GherkinDialect GetDialect(string language, Ast.Location location); +} + +public class GherkinDialectProvider : IGherkinDialectProvider { - public interface IGherkinDialectProvider + private readonly Lazy defaultDialect; + + public GherkinDialect DefaultDialect { - GherkinDialect DefaultDialect { get; } - GherkinDialect GetDialect(string language, Ast.Location location); + get { return defaultDialect.Value; } } - public class GherkinDialectProvider : IGherkinDialectProvider + public GherkinDialectProvider(string defaultLanguage = "en") { - private readonly Lazy defaultDialect; - - public GherkinDialect DefaultDialect - { - get { return defaultDialect.Value; } - } - - public GherkinDialectProvider(string defaultLanguage = "en") - { - defaultDialect = new Lazy(() => GetDialect(defaultLanguage, null)); - } + defaultDialect = new Lazy(() => GetDialect(defaultLanguage, null)); + } - protected virtual bool TryGetDialect(string language, Ast.Location location, out GherkinDialect dialect) - { - var gherkinLanguageSettings = LoadLanguageSettings(); - return TryGetDialect(language, gherkinLanguageSettings, location, out dialect); - } + protected virtual bool TryGetDialect(string language, Ast.Location location, out GherkinDialect dialect) + { + var gherkinLanguageSettings = LoadLanguageSettings(); + return TryGetDialect(language, gherkinLanguageSettings, location, out dialect); + } - public virtual GherkinDialect GetDialect(string language, Ast.Location location) - { - if (!TryGetDialect(language, location, out var dialect)) - throw new NoSuchLanguageException(language, location); - return dialect; - } + public virtual GherkinDialect GetDialect(string language, Ast.Location location) + { + if (!TryGetDialect(language, location, out var dialect)) + throw new NoSuchLanguageException(language, location); + return dialect; + } - protected virtual Dictionary LoadLanguageSettings() - { - const string languageFileName = "gherkin-languages.json"; - - var assembly = typeof(GherkinDialectProvider).Assembly; - var resourceStream = assembly.GetManifestResourceStream("Gherkin." + languageFileName); - - if (resourceStream == null) - throw new InvalidOperationException("Gherkin language resource not found: " + languageFileName); - var languagesFileContent = new StreamReader(resourceStream).ReadToEnd(); - - return ParseJsonContent(languagesFileContent); - } + protected virtual Dictionary LoadLanguageSettings() + { + const string languageFileName = "gherkin-languages.json"; + + var assembly = typeof(GherkinDialectProvider).Assembly; + var resourceStream = assembly.GetManifestResourceStream("Gherkin." + languageFileName); + + if (resourceStream == null) + throw new InvalidOperationException("Gherkin language resource not found: " + languageFileName); + var languagesFileContent = new StreamReader(resourceStream).ReadToEnd(); + + return ParseJsonContent(languagesFileContent); + } - protected virtual Dictionary ParseJsonContent(string languagesFileContent) - { - // ReSharper disable once InvokeAsExtensionMethod - return JSONParser.FromJson>(languagesFileContent); - } + protected virtual Dictionary ParseJsonContent(string languagesFileContent) + { + // ReSharper disable once InvokeAsExtensionMethod + return JSONParser.FromJson>(languagesFileContent); + } - protected virtual bool TryGetDialect(string language, Dictionary gherkinLanguageSettings, Ast.Location location, out GherkinDialect dialect) + protected virtual bool TryGetDialect(string language, Dictionary gherkinLanguageSettings, Ast.Location location, out GherkinDialect dialect) + { + if (!gherkinLanguageSettings.TryGetValue(language, out var languageSettings)) { - if (!gherkinLanguageSettings.TryGetValue(language, out var languageSettings)) - { - dialect = null; - return false; - } - - dialect = CreateGherkinDialect(language, languageSettings); - return true; + dialect = null; + return false; } - protected GherkinDialect CreateGherkinDialect(string language, GherkinLanguageSetting languageSettings) - { - return new GherkinDialect( - language, - ParseTitleKeywords(languageSettings.feature), - ParseTitleKeywords(languageSettings.rule), - ParseTitleKeywords(languageSettings.background), - ParseTitleKeywords(languageSettings.scenario), - ParseTitleKeywords(languageSettings.scenarioOutline), - ParseTitleKeywords(languageSettings.examples), - ParseStepKeywords(languageSettings.given), - ParseStepKeywords(languageSettings.when), - ParseStepKeywords(languageSettings.then), - ParseStepKeywords(languageSettings.and), - ParseStepKeywords(languageSettings.but) - ); - } + dialect = CreateGherkinDialect(language, languageSettings); + return true; + } - private string[] ParseStepKeywords(string[] stepKeywords) - { - return stepKeywords; - } + protected GherkinDialect CreateGherkinDialect(string language, GherkinLanguageSetting languageSettings) + { + return new GherkinDialect( + language, + ParseTitleKeywords(languageSettings.feature), + ParseTitleKeywords(languageSettings.rule), + ParseTitleKeywords(languageSettings.background), + ParseTitleKeywords(languageSettings.scenario), + ParseTitleKeywords(languageSettings.scenarioOutline), + ParseTitleKeywords(languageSettings.examples), + ParseStepKeywords(languageSettings.given), + ParseStepKeywords(languageSettings.when), + ParseStepKeywords(languageSettings.then), + ParseStepKeywords(languageSettings.and), + ParseStepKeywords(languageSettings.but) + ); + } - private string[] ParseTitleKeywords(string[] keywords) - { - return keywords; - } + private string[] ParseStepKeywords(string[] stepKeywords) + { + return stepKeywords; + } - protected static GherkinDialect GetFactoryDefault() - { - return new GherkinDialect( - "en", - new[] {"Feature"}, - new[] {"Rule"}, - new[] {"Background"}, - new[] {"Scenario"}, - new[] {"Scenario Outline", "Scenario Template"}, - new[] {"Examples", "Scenarios"}, - new[] {"* ", "Given "}, - new[] {"* ", "When " }, - new[] {"* ", "Then " }, - new[] {"* ", "And " }, - new[] {"* ", "But " }); - } + private string[] ParseTitleKeywords(string[] keywords) + { + return keywords; } - public class GherkinLanguageSetting + protected static GherkinDialect GetFactoryDefault() { - // ReSharper disable InconsistentNaming - public string name; - public string native; - public string[] feature; - public string[] rule; - public string[] background; - public string[] scenario; - public string[] scenarioOutline; - public string[] examples; - public string[] given; - public string[] when; - public string[] then; - public string[] and; - public string[] but; - // ReSharper restore InconsistentNaming + return new GherkinDialect( + "en", + new[] {"Feature"}, + new[] {"Rule"}, + new[] {"Background"}, + new[] {"Scenario"}, + new[] {"Scenario Outline", "Scenario Template"}, + new[] {"Examples", "Scenarios"}, + new[] {"* ", "Given "}, + new[] {"* ", "When " }, + new[] {"* ", "Then " }, + new[] {"* ", "And " }, + new[] {"* ", "But " }); } } + +public class GherkinLanguageSetting +{ + // ReSharper disable InconsistentNaming + public string name; + public string native; + public string[] feature; + public string[] rule; + public string[] background; + public string[] scenario; + public string[] scenarioOutline; + public string[] examples; + public string[] given; + public string[] when; + public string[] then; + public string[] and; + public string[] but; + // ReSharper restore InconsistentNaming +} diff --git a/dotnet/Gherkin/GherkinLanguageConstants.cs b/dotnet/Gherkin/GherkinLanguageConstants.cs index 0a2309167..ec1726597 100644 --- a/dotnet/Gherkin/GherkinLanguageConstants.cs +++ b/dotnet/Gherkin/GherkinLanguageConstants.cs @@ -1,14 +1,13 @@ -namespace Gherkin +namespace Gherkin; + +public static class GherkinLanguageConstants { - public static class GherkinLanguageConstants - { - public const string TAG_PREFIX = "@"; - public const string COMMENT_PREFIX = "#"; - public const string TITLE_KEYWORD_SEPARATOR = ":"; - public const string TABLE_CELL_SEPARATOR = "|"; - public const char TABLE_CELL_ESCAPE_CHAR = '\\'; - public const char TABLE_CELL_NEWLINE_ESCAPE = 'n'; - public const string DOCSTRING_SEPARATOR = "\"\"\""; - public const string DOCSTRING_ALTERNATIVE_SEPARATOR = "```"; - } + public const string TAG_PREFIX = "@"; + public const string COMMENT_PREFIX = "#"; + public const string TITLE_KEYWORD_SEPARATOR = ":"; + public const string TABLE_CELL_SEPARATOR = "|"; + public const char TABLE_CELL_ESCAPE_CHAR = '\\'; + public const char TABLE_CELL_NEWLINE_ESCAPE = 'n'; + public const string DOCSTRING_SEPARATOR = "\"\"\""; + public const string DOCSTRING_ALTERNATIVE_SEPARATOR = "```"; } diff --git a/dotnet/Gherkin/GherkinLine.cs b/dotnet/Gherkin/GherkinLine.cs index 60922ed32..d67195574 100644 --- a/dotnet/Gherkin/GherkinLine.cs +++ b/dotnet/Gherkin/GherkinLine.cs @@ -1,158 +1,170 @@ -using System; -using System.Text.RegularExpressions; +using Gherkin.Ast; +using System; using System.Collections.Generic; using System.Linq; -using Gherkin.Ast; +using System.Text.RegularExpressions; + +namespace Gherkin; -namespace Gherkin +public class GherkinLine : IGherkinLine { - public class GherkinLine : IGherkinLine - { - private static char[] inlineWhitespaceChars = new char[] { ' ', '\t', '\u00A0'}; + private static char[] inlineWhitespaceChars = new char[] { ' ', '\t', '\u00A0' }; - private readonly string lineText; - private readonly string trimmedLineText; - public int LineNumber { get; private set; } + private readonly string lineText; + private readonly string trimmedLineText; + public int LineNumber { get; private set; } - public GherkinLine(string line, int lineNumber) - { - this.LineNumber = lineNumber; + public GherkinLine(string line, int lineNumber) + { + this.LineNumber = lineNumber; - this.lineText = line; - this.trimmedLineText = this.lineText.TrimStart(); - } + this.lineText = line; + this.trimmedLineText = this.lineText.TrimStart(); + } - public void Detach() - { - //nop - } + public void Detach() + { + //nop + } - public int Indent - { - get { return lineText.Length - trimmedLineText.Length; } - } + public int Indent + { + get { return lineText.Length - trimmedLineText.Length; } + } - public bool IsEmpty() - { - return trimmedLineText.Length == 0; - } + public bool IsEmpty() + { + return trimmedLineText.Length == 0; + } - public bool StartsWith(string text) - { - return trimmedLineText.StartsWith(text); - } + public bool StartsWith(string text) + { + return trimmedLineText.StartsWith(text); + } - public bool StartsWithTitleKeyword(string text) - { - return StringUtils.StartsWith(trimmedLineText, text) && - StartsWithFrom(trimmedLineText, text.Length, GherkinLanguageConstants.TITLE_KEYWORD_SEPARATOR); - } + public bool StartsWithTitleKeyword(string text) + { + return StringUtils.StartsWith(trimmedLineText, text) && + StartsWithFrom(trimmedLineText, text.Length, GherkinLanguageConstants.TITLE_KEYWORD_SEPARATOR); + } - private static bool StartsWithFrom(string text, int textIndex, string value) - { - return string.CompareOrdinal(text, textIndex, value, 0, value.Length) == 0; - } + private static bool StartsWithFrom(string text, int textIndex, string value) + { + return string.CompareOrdinal(text, textIndex, value, 0, value.Length) == 0; + } - public string GetLineText(int indentToRemove) - { - if (indentToRemove < 0 || indentToRemove > Indent) - return trimmedLineText; + public string GetLineText(int indentToRemove) + { + if (indentToRemove < 0 || indentToRemove > Indent) + return trimmedLineText; - return lineText.Substring(indentToRemove); - } + return lineText.Substring(indentToRemove); + } - public string GetRestTrimmed(int length) - { - return trimmedLineText.Substring(length).Trim(); - } + public string GetRestTrimmed(int length) + { + return trimmedLineText.Substring(length).Trim(); + } - public IEnumerable GetTags() + public IEnumerable GetTags() + { + var uncommentedLine = Regex.Split(trimmedLineText, @"\s" + GherkinLanguageConstants.COMMENT_PREFIX)[0]; + int position = Indent; + foreach (string item in uncommentedLine.Split(GherkinLanguageConstants.TAG_PREFIX[0])) { - var uncommentedLine = Regex.Split(trimmedLineText, @"\s" + GherkinLanguageConstants.COMMENT_PREFIX)[0]; - int position = Indent; - foreach (string item in uncommentedLine.Split(GherkinLanguageConstants.TAG_PREFIX[0])) + if (item.Length > 0) { - if (item.Length > 0) - { - var tagName = GherkinLanguageConstants.TAG_PREFIX + item.TrimEnd(inlineWhitespaceChars); - if (tagName.Length == 1) - continue; + var tagName = GherkinLanguageConstants.TAG_PREFIX + item.TrimEnd(inlineWhitespaceChars); + if (tagName.Length == 1) + continue; - if (tagName.IndexOfAny(inlineWhitespaceChars) >= 0) - throw new InvalidTagException("A tag may not contain whitespace", new Location(LineNumber, position)); + if (tagName.IndexOfAny(inlineWhitespaceChars) >= 0) + throw new InvalidTagException("A tag may not contain whitespace", new Location(LineNumber, position)); - yield return new GherkinLineSpan(position, tagName); - position += item.Length; - } - position++; // separator + yield return new GherkinLineSpan(position, tagName); + position += item.Length; } + position++; // separator } - - public IEnumerable GetTableCells() + } + + public IEnumerable GetTableCells() + { + var items = SplitCells(trimmedLineText).ToList(); + bool isBeforeFirst = true; + foreach (var item in items.Take(items.Count - 1)) // skipping the one after last { - var items = SplitCells(trimmedLineText).ToList(); - bool isBeforeFirst = true; - foreach (var item in items.Take(items.Count - 1)) // skipping the one after last + if (!isBeforeFirst) { - if (!isBeforeFirst) - { - int trimmedStart; - var cellText = Trim(item.Item1, out trimmedStart); - var cellPosition = item.Item2 + trimmedStart; + int trimmedStart; + var cellText = Trim(item.Item1, out trimmedStart); + var cellPosition = item.Item2 + trimmedStart; - if (cellText.Length == 0) - cellPosition = item.Item2; - - yield return new GherkinLineSpan(Indent + cellPosition + 1, cellText); - } + if (cellText.Length == 0) + cellPosition = item.Item2; - isBeforeFirst = false; + yield return new GherkinLineSpan(Indent + cellPosition + 1, cellText); } + + isBeforeFirst = false; } + } - private IEnumerable> SplitCells(string row) + private IEnumerable> SplitCells(string row) + { + var rowEnum = row.GetEnumerator(); + + string cell = ""; + int pos = 0; + int startPos = 0; + while (rowEnum.MoveNext()) { - var rowEnum = row.GetEnumerator(); - - string cell = ""; - int pos = 0; - int startPos = 0; - while (rowEnum.MoveNext()) { - pos++; - char c = rowEnum.Current; - if (c.ToString() == GherkinLanguageConstants.TABLE_CELL_SEPARATOR) { - yield return Tuple.Create(cell, startPos); - cell = ""; - startPos = pos; - } else if (c == GherkinLanguageConstants.TABLE_CELL_ESCAPE_CHAR) { - if(rowEnum.MoveNext()) { - pos++; - c = rowEnum.Current; - if (c == GherkinLanguageConstants.TABLE_CELL_NEWLINE_ESCAPE) { - cell += "\n"; - } else { - if (c.ToString() != GherkinLanguageConstants.TABLE_CELL_SEPARATOR && c != GherkinLanguageConstants.TABLE_CELL_ESCAPE_CHAR) { - cell += GherkinLanguageConstants.TABLE_CELL_ESCAPE_CHAR; - } - cell += c; + pos++; + char c = rowEnum.Current; + if (c.ToString() == GherkinLanguageConstants.TABLE_CELL_SEPARATOR) + { + yield return Tuple.Create(cell, startPos); + cell = ""; + startPos = pos; + } + else if (c == GherkinLanguageConstants.TABLE_CELL_ESCAPE_CHAR) + { + if (rowEnum.MoveNext()) + { + pos++; + c = rowEnum.Current; + if (c == GherkinLanguageConstants.TABLE_CELL_NEWLINE_ESCAPE) + { + cell += "\n"; + } + else + { + if (c.ToString() != GherkinLanguageConstants.TABLE_CELL_SEPARATOR && c != GherkinLanguageConstants.TABLE_CELL_ESCAPE_CHAR) + { + cell += GherkinLanguageConstants.TABLE_CELL_ESCAPE_CHAR; } - } else { - cell += GherkinLanguageConstants.TABLE_CELL_ESCAPE_CHAR; + cell += c; } - } else { - cell += c; } + else + { + cell += GherkinLanguageConstants.TABLE_CELL_ESCAPE_CHAR; + } + } + else + { + cell += c; } - yield return Tuple.Create(cell, startPos); } + yield return Tuple.Create(cell, startPos); + } - private string Trim(string s, out int trimmedStart) - { - trimmedStart = 0; - while (trimmedStart < s.Length && inlineWhitespaceChars.Contains(s[trimmedStart])) - trimmedStart++; + private string Trim(string s, out int trimmedStart) + { + trimmedStart = 0; + while (trimmedStart < s.Length && inlineWhitespaceChars.Contains(s[trimmedStart])) + trimmedStart++; - return s.Trim(inlineWhitespaceChars); - } + return s.Trim(inlineWhitespaceChars); } } diff --git a/dotnet/Gherkin/GherkinLineSpan.cs b/dotnet/Gherkin/GherkinLineSpan.cs index 5da039b58..15fab7e59 100644 --- a/dotnet/Gherkin/GherkinLineSpan.cs +++ b/dotnet/Gherkin/GherkinLineSpan.cs @@ -1,21 +1,20 @@ -namespace Gherkin +namespace Gherkin; + +public struct GherkinLineSpan { - public struct GherkinLineSpan - { - /// - /// One-based line position - /// - public int Column { get; private set; } + /// + /// One-based line position + /// + public int Column { get; private set; } - /// - /// Text part of the line - /// - public string Text { get; private set; } + /// + /// Text part of the line + /// + public string Text { get; private set; } - public GherkinLineSpan(int column, string text) : this() - { - Column = column; - Text = text; - } + public GherkinLineSpan(int column, string text) : this() + { + Column = column; + Text = text; } } diff --git a/dotnet/Gherkin/IGherkinLine.cs b/dotnet/Gherkin/IGherkinLine.cs index 1e9c4ac9b..f61cc9770 100644 --- a/dotnet/Gherkin/IGherkinLine.cs +++ b/dotnet/Gherkin/IGherkinLine.cs @@ -1,72 +1,71 @@ -using System.Collections.Generic; +using System.Collections.Generic; -namespace Gherkin +namespace Gherkin; + +/// +/// Represents a line of a Gherkin file +/// +public interface IGherkinLine { /// - /// Represents a line of a Gherkin file + /// One-based line number /// - public interface IGherkinLine - { - /// - /// One-based line number - /// - int LineNumber { get; } + int LineNumber { get; } - /// - /// Called by the parser to indicate non-streamed reading (e.g. during look-ahead). - /// - /// - /// If the implementation depends on streamed reading behavior, with this method, it can clone itself, so that it will be detached. - /// - void Detach(); + /// + /// Called by the parser to indicate non-streamed reading (e.g. during look-ahead). + /// + /// + /// If the implementation depends on streamed reading behavior, with this method, it can clone itself, so that it will be detached. + /// + void Detach(); - /// - /// The number of whitespace characters in the beginning of the line. - /// - int Indent { get; } + /// + /// The number of whitespace characters in the beginning of the line. + /// + int Indent { get; } - /// - /// Gets if the line is empty or contains whitespaces only. - /// - /// true, if empty or contains whitespaces only; otherwise, false. - bool IsEmpty(); + /// + /// Gets if the line is empty or contains whitespaces only. + /// + /// true, if empty or contains whitespaces only; otherwise, false. + bool IsEmpty(); - /// - /// Determines whether the beginning of the line (wihtout whitespaces) matches a specified string. - /// - /// The string to compare. - /// true if text matches the beginning of this line; otherwise, false. - bool StartsWith(string text); + /// + /// Determines whether the beginning of the line (wihtout whitespaces) matches a specified string. + /// + /// The string to compare. + /// true if text matches the beginning of this line; otherwise, false. + bool StartsWith(string text); - /// - /// Determines whether the beginning of the line (wihtout whitespaces) matches a specified title keyword (ie. a keyword followed by a ':' character). - /// - /// The keyword to compare. - /// true if keyword matches the beginning of this line and followed by a ':' character; otherwise, false. - bool StartsWithTitleKeyword(string keyword); - /// - /// Returns the line text - /// - /// The maximum number of whitespace characters to remove. -1 removes all leading whitespaces. - /// The line text. - string GetLineText(int indentToRemove = 0); - /// - /// Returns the remaining part of the line. - /// - /// - /// - string GetRestTrimmed(int length); + /// + /// Determines whether the beginning of the line (wihtout whitespaces) matches a specified title keyword (ie. a keyword followed by a ':' character). + /// + /// The keyword to compare. + /// true if keyword matches the beginning of this line and followed by a ':' character; otherwise, false. + bool StartsWithTitleKeyword(string keyword); + /// + /// Returns the line text + /// + /// The maximum number of whitespace characters to remove. -1 removes all leading whitespaces. + /// The line text. + string GetLineText(int indentToRemove = 0); + /// + /// Returns the remaining part of the line. + /// + /// + /// + string GetRestTrimmed(int length); - /// - /// Tries parsing the line as a tag list, and returns the tags wihtout the leading '@' characters. - /// - /// (position,text) pairs, position is 0-based index - IEnumerable GetTags(); + /// + /// Tries parsing the line as a tag list, and returns the tags wihtout the leading '@' characters. + /// + /// (position,text) pairs, position is 0-based index + IEnumerable GetTags(); - /// - /// Tries parsing the line as table row and returns the trimmed cell values. - /// - /// (position,text) pairs, position is 0-based index - IEnumerable GetTableCells(); - } + /// + /// Tries parsing the line as table row and returns the trimmed cell values. + /// + /// (position,text) pairs, position is 0-based index + IEnumerable GetTableCells(); } diff --git a/dotnet/Gherkin/Parser.Extensions.cs b/dotnet/Gherkin/Parser.Extensions.cs index a2adba985..d7f86a752 100644 --- a/dotnet/Gherkin/Parser.Extensions.cs +++ b/dotnet/Gherkin/Parser.Extensions.cs @@ -1,32 +1,31 @@ using System.IO; using Gherkin.Ast; -namespace Gherkin +namespace Gherkin; + +public class Parser : Parser { - public class Parser : Parser + public Parser() { - public Parser() - { - } + } - public Parser(IAstBuilder astBuilder) - : base(astBuilder) - { - } + public Parser(IAstBuilder astBuilder) + : base(astBuilder) + { + } - public GherkinDocument Parse(TextReader reader) - { - return Parse(new TokenScanner(reader)); - } + public GherkinDocument Parse(TextReader reader) + { + return Parse(new TokenScanner(reader)); + } - public GherkinDocument Parse(string sourceFile) + public GherkinDocument Parse(string sourceFile) + { + using (var stream = new FileStream(sourceFile, FileMode.Open, FileAccess.Read)) { - using (var stream = new FileStream(sourceFile, FileMode.Open, FileAccess.Read)) + using (var reader = new StreamReader(stream)) { - using (var reader = new StreamReader(stream)) - { - return Parse(new TokenScanner(reader)); - } + return Parse(new TokenScanner(reader)); } } } diff --git a/dotnet/Gherkin/ParserException.cs b/dotnet/Gherkin/ParserException.cs index 39cb96d82..921400fac 100644 --- a/dotnet/Gherkin/ParserException.cs +++ b/dotnet/Gherkin/ParserException.cs @@ -3,133 +3,132 @@ using System.Linq; using Gherkin.Ast; -namespace Gherkin +namespace Gherkin; + +public abstract class ParserException : Exception { - public abstract class ParserException : Exception + public Ast.Location Location { get; private set; } + + protected ParserException(string message, Ast.Location location = null) : base(GetMessage(message, location)) { - public Ast.Location Location { get; private set; } + Location = location; + } - protected ParserException(string message, Ast.Location location = null) : base(GetMessage(message, location)) - { - Location = location; - } + private static string GetMessage(string message, Ast.Location location) + { + if (location == null) + return message; - private static string GetMessage(string message, Ast.Location location) - { - if (location == null) - return message; + return string.Format("({0}:{1}): {2}", location.Line, location.Column, message); + } - return string.Format("({0}:{1}): {2}", location.Line, location.Column, message); - } +} +public class AstBuilderException : ParserException +{ + public AstBuilderException(string message, Ast.Location location) : base(message, location) + { } - public class AstBuilderException : ParserException - { - public AstBuilderException(string message, Ast.Location location) : base(message, location) - { - } +} +public class NoSuchLanguageException : ParserException +{ + public NoSuchLanguageException(string language, Ast.Location location = null) : + base("Language not supported: " + language, location) + { + if (language == null) throw new ArgumentNullException("language"); } - public class NoSuchLanguageException : ParserException - { - public NoSuchLanguageException(string language, Ast.Location location = null) : - base("Language not supported: " + language, location) - { - if (language == null) throw new ArgumentNullException("language"); - } +} +public class InvalidTagException : ParserException +{ + public InvalidTagException(string message, Ast.Location location = null) : + base(message, location) + { } +} - public class InvalidTagException : ParserException +public abstract class TokenParserException : ParserException +{ + protected TokenParserException(string message, Token receivedToken) + : base(message, GetLocation(receivedToken)) { - public InvalidTagException(string message, Ast.Location location = null) : - base(message, location) - { - } + if (receivedToken == null) throw new ArgumentNullException("receivedToken"); } - public abstract class TokenParserException : ParserException + private static Ast.Location GetLocation(Token receivedToken) { - protected TokenParserException(string message, Token receivedToken) - : base(message, GetLocation(receivedToken)) - { - if (receivedToken == null) throw new ArgumentNullException("receivedToken"); - } - - private static Ast.Location GetLocation(Token receivedToken) - { - return receivedToken.IsEOF || receivedToken.Location.Column > 1 - ? receivedToken.Location - : new Ast.Location(receivedToken.Location.Line, receivedToken.Line.Indent + 1); - } - + return receivedToken.IsEOF || receivedToken.Location.Column > 1 + ? receivedToken.Location + : new Ast.Location(receivedToken.Location.Line, receivedToken.Line.Indent + 1); } - public class UnexpectedTokenException : TokenParserException - { - public string StateComment { get; private set; } +} - public Token ReceivedToken { get; private set; } - public string[] ExpectedTokenTypes { get; private set; } +public class UnexpectedTokenException : TokenParserException +{ + public string StateComment { get; private set; } - public UnexpectedTokenException(Token receivedToken, string[] expectedTokenTypes, string stateComment) - : base(GetMessage(receivedToken, expectedTokenTypes), receivedToken) - { - if (receivedToken == null) throw new ArgumentNullException("receivedToken"); - if (expectedTokenTypes == null) throw new ArgumentNullException("expectedTokenTypes"); + public Token ReceivedToken { get; private set; } + public string[] ExpectedTokenTypes { get; private set; } - ReceivedToken = receivedToken; - ExpectedTokenTypes = expectedTokenTypes; - StateComment = stateComment; - } + public UnexpectedTokenException(Token receivedToken, string[] expectedTokenTypes, string stateComment) + : base(GetMessage(receivedToken, expectedTokenTypes), receivedToken) + { + if (receivedToken == null) throw new ArgumentNullException("receivedToken"); + if (expectedTokenTypes == null) throw new ArgumentNullException("expectedTokenTypes"); - private static string GetMessage(Token receivedToken, string[] expectedTokenTypes) - { - return string.Format("expected: {0}, got '{1}'", - string.Join(", ", expectedTokenTypes), - receivedToken.GetTokenValue().Trim()); - } + ReceivedToken = receivedToken; + ExpectedTokenTypes = expectedTokenTypes; + StateComment = stateComment; + } + private static string GetMessage(Token receivedToken, string[] expectedTokenTypes) + { + return string.Format("expected: {0}, got '{1}'", + string.Join(", ", expectedTokenTypes), + receivedToken.GetTokenValue().Trim()); } - public class UnexpectedEOFException : TokenParserException +} + +public class UnexpectedEOFException : TokenParserException +{ + public string StateComment { get; private set; } + public string[] ExpectedTokenTypes { get; private set; } + public UnexpectedEOFException(Token receivedToken, string[] expectedTokenTypes, string stateComment) + : base(GetMessage(expectedTokenTypes), receivedToken) { - public string StateComment { get; private set; } - public string[] ExpectedTokenTypes { get; private set; } - public UnexpectedEOFException(Token receivedToken, string[] expectedTokenTypes, string stateComment) - : base(GetMessage(expectedTokenTypes), receivedToken) - { - if (receivedToken == null) throw new ArgumentNullException("receivedToken"); - if (expectedTokenTypes == null) throw new ArgumentNullException("expectedTokenTypes"); - - ExpectedTokenTypes = expectedTokenTypes; - StateComment = stateComment; - } - - private static string GetMessage(string[] expectedTokenTypes) - { - return string.Format("unexpected end of file, expected: {0}", - string.Join(", ", expectedTokenTypes)); - } + if (receivedToken == null) throw new ArgumentNullException("receivedToken"); + if (expectedTokenTypes == null) throw new ArgumentNullException("expectedTokenTypes"); + + ExpectedTokenTypes = expectedTokenTypes; + StateComment = stateComment; } - public class CompositeParserException : ParserException + private static string GetMessage(string[] expectedTokenTypes) { - public IEnumerable Errors { get; private set; } + return string.Format("unexpected end of file, expected: {0}", + string.Join(", ", expectedTokenTypes)); + } +} - public CompositeParserException(ParserException[] errors) - : base(GetMessage(errors)) - { - if (errors == null) throw new ArgumentNullException("errors"); +public class CompositeParserException : ParserException +{ + public IEnumerable Errors { get; private set; } - Errors = errors; - } + public CompositeParserException(ParserException[] errors) + : base(GetMessage(errors)) + { + if (errors == null) throw new ArgumentNullException("errors"); - private static string GetMessage(ParserException[] errors) - { - return "Parser errors:" + Environment.NewLine + string.Join(Environment.NewLine, errors.Select(e => e.Message)); - } + Errors = errors; + } + + private static string GetMessage(ParserException[] errors) + { + return "Parser errors:" + Environment.NewLine + string.Join(Environment.NewLine, errors.Select(e => e.Message)); } } \ No newline at end of file diff --git a/dotnet/Gherkin/StepKeywordType.cs b/dotnet/Gherkin/StepKeywordType.cs index 6fac8d4c4..5cdf9925b 100644 --- a/dotnet/Gherkin/StepKeywordType.cs +++ b/dotnet/Gherkin/StepKeywordType.cs @@ -1,12 +1,11 @@ -namespace Gherkin +namespace Gherkin; + +public enum StepKeywordType { - public enum StepKeywordType - { - Unspecified, - Context, - Action, - Outcome, - Conjunction, - Unknown - } + Unspecified, + Context, + Action, + Outcome, + Conjunction, + Unknown } \ No newline at end of file diff --git a/dotnet/Gherkin/StringUtils.cs b/dotnet/Gherkin/StringUtils.cs index ab184775d..5fcbf9b35 100644 --- a/dotnet/Gherkin/StringUtils.cs +++ b/dotnet/Gherkin/StringUtils.cs @@ -1,33 +1,32 @@ using System.Globalization; -namespace Gherkin +namespace Gherkin; + +public class StringUtils { - public class StringUtils + // string.StartsWith(string) is broken on Mono for strings outside + // the Basic Multilingual Plane (BMP). We have to roll our own so + // it works with Emoji characters. + public static bool StartsWith(string a, string b) { - // string.StartsWith(string) is broken on Mono for strings outside - // the Basic Multilingual Plane (BMP). We have to roll our own so - // it works with Emoji characters. - public static bool StartsWith(string a, string b) - { - return StartsWith (a.ToCharArray(), b.ToCharArray()); - } + return StartsWith (a.ToCharArray(), b.ToCharArray()); + } - private static bool StartsWith(char[] a, char[] b) + private static bool StartsWith(char[] a, char[] b) + { + if (a.Length < b.Length) + return false; + for (int i = 0; i < b.Length; i++) { - if (a.Length < b.Length) + if (a [i] != b [i]) return false; - for (int i = 0; i < b.Length; i++) - { - if (a [i] != b [i]) - return false; - } - return true; } + return true; + } - public static int CountSymbols(string s) - { - return new StringInfo (s).LengthInTextElements; - } + public static int CountSymbols(string s) + { + return new StringInfo (s).LengthInTextElements; } } diff --git a/dotnet/Gherkin/TinyJson/JSONParser.cs b/dotnet/Gherkin/TinyJson/JSONParser.cs index 1f619ea5a..b2572cd55 100644 --- a/dotnet/Gherkin/TinyJson/JSONParser.cs +++ b/dotnet/Gherkin/TinyJson/JSONParser.cs @@ -7,367 +7,366 @@ using System.Runtime.Serialization; using System.Text; -namespace TinyJson +namespace TinyJson; + +// Really simple JSON parser in ~300 lines +// - Attempts to parse JSON files with minimal GC allocation +// - Nice and simple "[1,2,3]".FromJson>() API +// - Classes and structs can be parsed too! +// class Foo { public int Value; } +// "{\"Value\":10}".FromJson() +// - Can parse JSON without type information into Dictionary and List e.g. +// "[1,2,3]".FromJson().GetType() == typeof(List) +// "{\"Value\":10}".FromJson().GetType() == typeof(Dictionary) +// - No JIT Emit support to support AOT compilation on iOS +// - Attempts are made to NOT throw an exception if the JSON is corrupted or invalid: returns null instead. +// - Only public fields and property setters on classes/structs will be written to +// +// Limitations: +// - No JIT Emit support to parse structures quickly +// - Limited to parsing <2GB JSON files (due to int.MaxValue) +// - Parsing of abstract classes or interfaces is NOT supported and will throw an exception. +internal static class JSONParser { - // Really simple JSON parser in ~300 lines - // - Attempts to parse JSON files with minimal GC allocation - // - Nice and simple "[1,2,3]".FromJson>() API - // - Classes and structs can be parsed too! - // class Foo { public int Value; } - // "{\"Value\":10}".FromJson() - // - Can parse JSON without type information into Dictionary and List e.g. - // "[1,2,3]".FromJson().GetType() == typeof(List) - // "{\"Value\":10}".FromJson().GetType() == typeof(Dictionary) - // - No JIT Emit support to support AOT compilation on iOS - // - Attempts are made to NOT throw an exception if the JSON is corrupted or invalid: returns null instead. - // - Only public fields and property setters on classes/structs will be written to - // - // Limitations: - // - No JIT Emit support to parse structures quickly - // - Limited to parsing <2GB JSON files (due to int.MaxValue) - // - Parsing of abstract classes or interfaces is NOT supported and will throw an exception. - internal static class JSONParser + [ThreadStatic] static Stack> splitArrayPool; + [ThreadStatic] static StringBuilder stringBuilder; + [ThreadStatic] static Dictionary> fieldInfoCache; + [ThreadStatic] static Dictionary> propertyInfoCache; + + public static T FromJson(this string json) { - [ThreadStatic] static Stack> splitArrayPool; - [ThreadStatic] static StringBuilder stringBuilder; - [ThreadStatic] static Dictionary> fieldInfoCache; - [ThreadStatic] static Dictionary> propertyInfoCache; + // Initialize, if needed, the ThreadStatic variables + if (propertyInfoCache == null) propertyInfoCache = new Dictionary>(); + if (fieldInfoCache == null) fieldInfoCache = new Dictionary>(); + if (stringBuilder == null) stringBuilder = new StringBuilder(); + if (splitArrayPool == null) splitArrayPool = new Stack>(); - public static T FromJson(this string json) + //Remove all whitespace not within strings to make parsing simpler + stringBuilder.Length = 0; + for (int i = 0; i < json.Length; i++) { - // Initialize, if needed, the ThreadStatic variables - if (propertyInfoCache == null) propertyInfoCache = new Dictionary>(); - if (fieldInfoCache == null) fieldInfoCache = new Dictionary>(); - if (stringBuilder == null) stringBuilder = new StringBuilder(); - if (splitArrayPool == null) splitArrayPool = new Stack>(); - - //Remove all whitespace not within strings to make parsing simpler - stringBuilder.Length = 0; - for (int i = 0; i < json.Length; i++) + char c = json[i]; + if (c == '"') { - char c = json[i]; - if (c == '"') - { - i = AppendUntilStringEnd(true, i, json); - continue; - } - if (char.IsWhiteSpace(c)) - continue; - - stringBuilder.Append(c); + i = AppendUntilStringEnd(true, i, json); + continue; } + if (char.IsWhiteSpace(c)) + continue; - //Parse the thing! - return (T)ParseValue(typeof(T), stringBuilder.ToString()); + stringBuilder.Append(c); } - static int AppendUntilStringEnd(bool appendEscapeCharacter, int startIdx, string json) + //Parse the thing! + return (T)ParseValue(typeof(T), stringBuilder.ToString()); + } + + static int AppendUntilStringEnd(bool appendEscapeCharacter, int startIdx, string json) + { + stringBuilder.Append(json[startIdx]); + for (int i = startIdx + 1; i < json.Length; i++) { - stringBuilder.Append(json[startIdx]); - for (int i = startIdx + 1; i < json.Length; i++) + if (json[i] == '\\') { - if (json[i] == '\\') - { - if (appendEscapeCharacter) - stringBuilder.Append(json[i]); - stringBuilder.Append(json[i + 1]); - i++;//Skip next character as it is escaped - } - else if (json[i] == '"') - { - stringBuilder.Append(json[i]); - return i; - } - else + if (appendEscapeCharacter) stringBuilder.Append(json[i]); + stringBuilder.Append(json[i + 1]); + i++;//Skip next character as it is escaped + } + else if (json[i] == '"') + { + stringBuilder.Append(json[i]); + return i; } - return json.Length - 1; + else + stringBuilder.Append(json[i]); } + return json.Length - 1; + } - //Splits { :, : } and [ , ] into a list of strings - static List Split(string json) + //Splits { :, : } and [ , ] into a list of strings + static List Split(string json) + { + List splitArray = splitArrayPool.Count > 0 ? splitArrayPool.Pop() : new List(); + splitArray.Clear(); + if (json.Length == 2) + return splitArray; + int parseDepth = 0; + stringBuilder.Length = 0; + for (int i = 1; i < json.Length - 1; i++) { - List splitArray = splitArrayPool.Count > 0 ? splitArrayPool.Pop() : new List(); - splitArray.Clear(); - if (json.Length == 2) - return splitArray; - int parseDepth = 0; - stringBuilder.Length = 0; - for (int i = 1; i < json.Length - 1; i++) + switch (json[i]) { - switch (json[i]) - { - case '[': - case '{': - parseDepth++; - break; - case ']': - case '}': - parseDepth--; - break; - case '"': - i = AppendUntilStringEnd(true, i, json); + case '[': + case '{': + parseDepth++; + break; + case ']': + case '}': + parseDepth--; + break; + case '"': + i = AppendUntilStringEnd(true, i, json); + continue; + case ',': + case ':': + if (parseDepth == 0) + { + splitArray.Add(stringBuilder.ToString()); + stringBuilder.Length = 0; continue; - case ',': - case ':': - if (parseDepth == 0) - { - splitArray.Add(stringBuilder.ToString()); - stringBuilder.Length = 0; - continue; - } - break; - } - - stringBuilder.Append(json[i]); + } + break; } - splitArray.Add(stringBuilder.ToString()); - - return splitArray; + stringBuilder.Append(json[i]); } - internal static object ParseValue(Type type, string json) + splitArray.Add(stringBuilder.ToString()); + + return splitArray; + } + + internal static object ParseValue(Type type, string json) + { + if (type == typeof(string)) { - if (type == typeof(string)) + if (json.Length <= 2) + return string.Empty; + StringBuilder parseStringBuilder = new StringBuilder(json.Length); + for (int i = 1; i < json.Length - 1; ++i) { - if (json.Length <= 2) - return string.Empty; - StringBuilder parseStringBuilder = new StringBuilder(json.Length); - for (int i = 1; i < json.Length - 1; ++i) + if (json[i] == '\\' && i + 1 < json.Length - 1) { - if (json[i] == '\\' && i + 1 < json.Length - 1) + int j = "\"\\nrtbf/".IndexOf(json[i + 1]); + if (j >= 0) { - int j = "\"\\nrtbf/".IndexOf(json[i + 1]); - if (j >= 0) + parseStringBuilder.Append("\"\\\n\r\t\b\f/"[j]); + ++i; + continue; + } + if (json[i + 1] == 'u' && i + 5 < json.Length - 1) + { + UInt32 c = 0; + if (UInt32.TryParse(json.Substring(i + 2, 4), System.Globalization.NumberStyles.AllowHexSpecifier, null, out c)) { - parseStringBuilder.Append("\"\\\n\r\t\b\f/"[j]); - ++i; + parseStringBuilder.Append((char)c); + i += 5; continue; } - if (json[i + 1] == 'u' && i + 5 < json.Length - 1) - { - UInt32 c = 0; - if (UInt32.TryParse(json.Substring(i + 2, 4), System.Globalization.NumberStyles.AllowHexSpecifier, null, out c)) - { - parseStringBuilder.Append((char)c); - i += 5; - continue; - } - } } - parseStringBuilder.Append(json[i]); } - return parseStringBuilder.ToString(); + parseStringBuilder.Append(json[i]); } - if (type.IsPrimitive) + return parseStringBuilder.ToString(); + } + if (type.IsPrimitive) + { + var result = Convert.ChangeType(json, type, System.Globalization.CultureInfo.InvariantCulture); + return result; + } + if (type == typeof(decimal)) + { + decimal result; + decimal.TryParse(json, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out result); + return result; + } + if (json == "null") + { + return null; + } + if (type.IsEnum) + { + if (json[0] == '"') + json = json.Substring(1, json.Length - 2); + try { - var result = Convert.ChangeType(json, type, System.Globalization.CultureInfo.InvariantCulture); - return result; + return Enum.Parse(type, json, false); } - if (type == typeof(decimal)) + catch { - decimal result; - decimal.TryParse(json, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out result); - return result; + return 0; } - if (json == "null") - { + } + if (type.IsArray) + { + Type arrayType = type.GetElementType(); + if (json[0] != '[' || json[json.Length - 1] != ']') return null; - } - if (type.IsEnum) - { - if (json[0] == '"') - json = json.Substring(1, json.Length - 2); - try - { - return Enum.Parse(type, json, false); - } - catch - { - return 0; - } - } - if (type.IsArray) - { - Type arrayType = type.GetElementType(); - if (json[0] != '[' || json[json.Length - 1] != ']') - return null; - List elems = Split(json); - Array newArray = Array.CreateInstance(arrayType, elems.Count); - for (int i = 0; i < elems.Count; i++) - newArray.SetValue(ParseValue(arrayType, elems[i]), i); - splitArrayPool.Push(elems); - return newArray; - } - if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>)) - { - Type listType = type.GetGenericArguments()[0]; - if (json[0] != '[' || json[json.Length - 1] != ']') - return null; + List elems = Split(json); + Array newArray = Array.CreateInstance(arrayType, elems.Count); + for (int i = 0; i < elems.Count; i++) + newArray.SetValue(ParseValue(arrayType, elems[i]), i); + splitArrayPool.Push(elems); + return newArray; + } + if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>)) + { + Type listType = type.GetGenericArguments()[0]; + if (json[0] != '[' || json[json.Length - 1] != ']') + return null; - List elems = Split(json); - var list = (IList)type.GetConstructor(new Type[] { typeof(int) }).Invoke(new object[] { elems.Count }); - for (int i = 0; i < elems.Count; i++) - list.Add(ParseValue(listType, elems[i])); - splitArrayPool.Push(elems); - return list; - } - if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<,>)) + List elems = Split(json); + var list = (IList)type.GetConstructor(new Type[] { typeof(int) }).Invoke(new object[] { elems.Count }); + for (int i = 0; i < elems.Count; i++) + list.Add(ParseValue(listType, elems[i])); + splitArrayPool.Push(elems); + return list; + } + if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<,>)) + { + Type keyType, valueType; { - Type keyType, valueType; - { - Type[] args = type.GetGenericArguments(); - keyType = args[0]; - valueType = args[1]; - } + Type[] args = type.GetGenericArguments(); + keyType = args[0]; + valueType = args[1]; + } - //Refuse to parse dictionary keys that aren't of type string - if (keyType != typeof(string)) - return null; - //Must be a valid dictionary element - if (json[0] != '{' || json[json.Length - 1] != '}') - return null; - //The list is split into key/value pairs only, this means the split must be divisible by 2 to be valid JSON - List elems = Split(json); - if (elems.Count % 2 != 0) - return null; + //Refuse to parse dictionary keys that aren't of type string + if (keyType != typeof(string)) + return null; + //Must be a valid dictionary element + if (json[0] != '{' || json[json.Length - 1] != '}') + return null; + //The list is split into key/value pairs only, this means the split must be divisible by 2 to be valid JSON + List elems = Split(json); + if (elems.Count % 2 != 0) + return null; - var dictionary = (IDictionary)type.GetConstructor(new Type[] { typeof(int) }).Invoke(new object[] { elems.Count / 2 }); - for (int i = 0; i < elems.Count; i += 2) - { - if (elems[i].Length <= 2) - continue; - string keyValue = elems[i].Substring(1, elems[i].Length - 2); - object val = ParseValue(valueType, elems[i + 1]); - dictionary[keyValue] = val; - } - return dictionary; - } - if (type == typeof(object)) - { - return ParseAnonymousValue(json); - } - if (json[0] == '{' && json[json.Length - 1] == '}') + var dictionary = (IDictionary)type.GetConstructor(new Type[] { typeof(int) }).Invoke(new object[] { elems.Count / 2 }); + for (int i = 0; i < elems.Count; i += 2) { - return ParseObject(type, json); + if (elems[i].Length <= 2) + continue; + string keyValue = elems[i].Substring(1, elems[i].Length - 2); + object val = ParseValue(valueType, elems[i + 1]); + dictionary[keyValue] = val; } - - return null; + return dictionary; } + if (type == typeof(object)) + { + return ParseAnonymousValue(json); + } + if (json[0] == '{' && json[json.Length - 1] == '}') + { + return ParseObject(type, json); + } + + return null; + } - static object ParseAnonymousValue(string json) + static object ParseAnonymousValue(string json) + { + if (json.Length == 0) + return null; + if (json[0] == '{' && json[json.Length - 1] == '}') { - if (json.Length == 0) + List elems = Split(json); + if (elems.Count % 2 != 0) return null; - if (json[0] == '{' && json[json.Length - 1] == '}') - { - List elems = Split(json); - if (elems.Count % 2 != 0) - return null; - var dict = new Dictionary(elems.Count / 2); - for (int i = 0; i < elems.Count; i += 2) - dict[elems[i].Substring(1, elems[i].Length - 2)] = ParseAnonymousValue(elems[i + 1]); - return dict; - } - if (json[0] == '[' && json[json.Length - 1] == ']') - { - List items = Split(json); - var finalList = new List(items.Count); - for (int i = 0; i < items.Count; i++) - finalList.Add(ParseAnonymousValue(items[i])); - return finalList; - } - if (json[0] == '"' && json[json.Length - 1] == '"') + var dict = new Dictionary(elems.Count / 2); + for (int i = 0; i < elems.Count; i += 2) + dict[elems[i].Substring(1, elems[i].Length - 2)] = ParseAnonymousValue(elems[i + 1]); + return dict; + } + if (json[0] == '[' && json[json.Length - 1] == ']') + { + List items = Split(json); + var finalList = new List(items.Count); + for (int i = 0; i < items.Count; i++) + finalList.Add(ParseAnonymousValue(items[i])); + return finalList; + } + if (json[0] == '"' && json[json.Length - 1] == '"') + { + string str = json.Substring(1, json.Length - 2); + return str.Replace("\\", string.Empty); + } + if (char.IsDigit(json[0]) || json[0] == '-') + { + if (json.Contains(".")) { - string str = json.Substring(1, json.Length - 2); - return str.Replace("\\", string.Empty); + double result; + double.TryParse(json, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out result); + return result; } - if (char.IsDigit(json[0]) || json[0] == '-') + else { - if (json.Contains(".")) - { - double result; - double.TryParse(json, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out result); - return result; - } - else - { - int result; - int.TryParse(json, out result); - return result; - } + int result; + int.TryParse(json, out result); + return result; } - if (json == "true") - return true; - if (json == "false") - return false; - // handles json == "null" as well as invalid JSON - return null; } + if (json == "true") + return true; + if (json == "false") + return false; + // handles json == "null" as well as invalid JSON + return null; + } - static Dictionary CreateMemberNameDictionary(T[] members) where T : MemberInfo + static Dictionary CreateMemberNameDictionary(T[] members) where T : MemberInfo + { + Dictionary nameToMember = new Dictionary(StringComparer.OrdinalIgnoreCase); + for (int i = 0; i < members.Length; i++) { - Dictionary nameToMember = new Dictionary(StringComparer.OrdinalIgnoreCase); - for (int i = 0; i < members.Length; i++) - { - T member = members[i]; - if (member.IsDefined(typeof(IgnoreDataMemberAttribute), true)) - continue; - - string name = member.Name; - if (member.IsDefined(typeof(DataMemberAttribute), true)) - { - DataMemberAttribute dataMemberAttribute = (DataMemberAttribute)Attribute.GetCustomAttribute(member, typeof(DataMemberAttribute), true); - if (!string.IsNullOrEmpty(dataMemberAttribute.Name)) - name = dataMemberAttribute.Name; - } + T member = members[i]; + if (member.IsDefined(typeof(IgnoreDataMemberAttribute), true)) + continue; - nameToMember.Add(name, member); + string name = member.Name; + if (member.IsDefined(typeof(DataMemberAttribute), true)) + { + DataMemberAttribute dataMemberAttribute = (DataMemberAttribute)Attribute.GetCustomAttribute(member, typeof(DataMemberAttribute), true); + if (!string.IsNullOrEmpty(dataMemberAttribute.Name)) + name = dataMemberAttribute.Name; } - return nameToMember; + nameToMember.Add(name, member); } - static object ParseObject(Type type, string json) - { - object instance = FormatterServices.GetUninitializedObject(type); + return nameToMember; + } - //The list is split into key/value pairs only, this means the split must be divisible by 2 to be valid JSON - List elems = Split(json); - if (elems.Count % 2 != 0) - return instance; + static object ParseObject(Type type, string json) + { + object instance = FormatterServices.GetUninitializedObject(type); - Dictionary nameToField; - Dictionary nameToProperty; - if (!fieldInfoCache.TryGetValue(type, out nameToField)) - { - nameToField = CreateMemberNameDictionary(type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy)); - fieldInfoCache.Add(type, nameToField); - } - if (!propertyInfoCache.TryGetValue(type, out nameToProperty)) - { - nameToProperty = CreateMemberNameDictionary(type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy)); - propertyInfoCache.Add(type, nameToProperty); - } + //The list is split into key/value pairs only, this means the split must be divisible by 2 to be valid JSON + List elems = Split(json); + if (elems.Count % 2 != 0) + return instance; - for (int i = 0; i < elems.Count; i += 2) - { - if (elems[i].Length <= 2) - continue; - string key = elems[i].Substring(1, elems[i].Length - 2); - string value = elems[i + 1]; + Dictionary nameToField; + Dictionary nameToProperty; + if (!fieldInfoCache.TryGetValue(type, out nameToField)) + { + nameToField = CreateMemberNameDictionary(type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy)); + fieldInfoCache.Add(type, nameToField); + } + if (!propertyInfoCache.TryGetValue(type, out nameToProperty)) + { + nameToProperty = CreateMemberNameDictionary(type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy)); + propertyInfoCache.Add(type, nameToProperty); + } - FieldInfo fieldInfo; - PropertyInfo propertyInfo; - if (nameToField.TryGetValue(key, out fieldInfo)) - fieldInfo.SetValue(instance, ParseValue(fieldInfo.FieldType, value)); - else if (nameToProperty.TryGetValue(key, out propertyInfo)) - propertyInfo.SetValue(instance, ParseValue(propertyInfo.PropertyType, value), null); - } + for (int i = 0; i < elems.Count; i += 2) + { + if (elems[i].Length <= 2) + continue; + string key = elems[i].Substring(1, elems[i].Length - 2); + string value = elems[i + 1]; - return instance; + FieldInfo fieldInfo; + PropertyInfo propertyInfo; + if (nameToField.TryGetValue(key, out fieldInfo)) + fieldInfo.SetValue(instance, ParseValue(fieldInfo.FieldType, value)); + else if (nameToProperty.TryGetValue(key, out propertyInfo)) + propertyInfo.SetValue(instance, ParseValue(propertyInfo.PropertyType, value), null); } + + return instance; } } diff --git a/dotnet/Gherkin/Token.cs b/dotnet/Gherkin/Token.cs index 6e0d616d0..709115b52 100644 --- a/dotnet/Gherkin/Token.cs +++ b/dotnet/Gherkin/Token.cs @@ -1,39 +1,38 @@ using Gherkin.Ast; -namespace Gherkin +namespace Gherkin; + +public class Token { - public class Token - { - public bool IsEOF { get { return Line == null; } } - public IGherkinLine Line { get; set; } - public TokenType MatchedType { get; set; } - public string MatchedKeyword { get; set; } - public string MatchedText { get; set; } - public GherkinLineSpan[] MatchedItems { get; set; } - public int MatchedIndent { get; set; } - public GherkinDialect MatchedGherkinDialect { get; set; } - public Ast.Location Location { get; set; } + public bool IsEOF { get { return Line == null; } } + public IGherkinLine Line { get; set; } + public TokenType MatchedType { get; set; } + public string MatchedKeyword { get; set; } + public string MatchedText { get; set; } + public GherkinLineSpan[] MatchedItems { get; set; } + public int MatchedIndent { get; set; } + public GherkinDialect MatchedGherkinDialect { get; set; } + public Ast.Location Location { get; set; } - public Token(IGherkinLine line, Ast.Location location) - { - Line = line; - Location = location; - } + public Token(IGherkinLine line, Ast.Location location) + { + Line = line; + Location = location; + } - public void Detach() - { - if (Line != null) - Line.Detach(); - } + public void Detach() + { + if (Line != null) + Line.Detach(); + } - public string GetTokenValue() - { - return IsEOF ? "EOF" : Line.GetLineText(-1); - } + public string GetTokenValue() + { + return IsEOF ? "EOF" : Line.GetLineText(-1); + } - public override string ToString() - { - return string.Format("{0}: {1}/{2}", MatchedType, MatchedKeyword, MatchedText); - } + public override string ToString() + { + return string.Format("{0}: {1}/{2}", MatchedType, MatchedKeyword, MatchedText); } } \ No newline at end of file diff --git a/dotnet/Gherkin/TokenMatcher.cs b/dotnet/Gherkin/TokenMatcher.cs index bf639e85a..d616ac2fb 100644 --- a/dotnet/Gherkin/TokenMatcher.cs +++ b/dotnet/Gherkin/TokenMatcher.cs @@ -3,231 +3,230 @@ using System.Linq; using Gherkin.Ast; -namespace Gherkin +namespace Gherkin; + +public class TokenMatcher : ITokenMatcher { - public class TokenMatcher : ITokenMatcher - { private readonly Regex LANGUAGE_PATTERN = new Regex ("^\\s*#\\s*language\\s*:\\s*([a-zA-Z\\-_]+)\\s*$"); - private readonly IGherkinDialectProvider dialectProvider; - private GherkinDialect currentDialect; - private string activeDocStringSeparator = null; - private int indentToRemove = 0; + private readonly IGherkinDialectProvider dialectProvider; + private GherkinDialect currentDialect; + private string activeDocStringSeparator = null; + private int indentToRemove = 0; - public GherkinDialect CurrentDialect + public GherkinDialect CurrentDialect + { + get { - get - { - if (currentDialect == null) - currentDialect = dialectProvider.DefaultDialect; - return currentDialect; - } + if (currentDialect == null) + currentDialect = dialectProvider.DefaultDialect; + return currentDialect; } + } - public TokenMatcher(IGherkinDialectProvider dialectProvider = null) - { - this.dialectProvider = dialectProvider ?? new GherkinDialectProvider(); - } + public TokenMatcher(IGherkinDialectProvider dialectProvider = null) + { + this.dialectProvider = dialectProvider ?? new GherkinDialectProvider(); + } - public TokenMatcher(string defaultLanguage) : this(new GherkinDialectProvider(defaultLanguage)) { - } + public TokenMatcher(string defaultLanguage) : this(new GherkinDialectProvider(defaultLanguage)) { + } - public void Reset() - { - activeDocStringSeparator = null; - indentToRemove = 0; - if (currentDialect != dialectProvider.DefaultDialect) - currentDialect = dialectProvider.DefaultDialect; - } + public void Reset() + { + activeDocStringSeparator = null; + indentToRemove = 0; + if (currentDialect != dialectProvider.DefaultDialect) + currentDialect = dialectProvider.DefaultDialect; + } - protected virtual void SetTokenMatched(Token token, TokenType matchedType, string text = null, string keyword = null, int? indent = null, GherkinLineSpan[] items = null) - { - token.MatchedType = matchedType; - token.MatchedKeyword = keyword; - token.MatchedText = text; - token.MatchedItems = items; - token.MatchedGherkinDialect = CurrentDialect; - token.MatchedIndent = indent ?? (token.Line == null ? 0 : token.Line.Indent); - token.Location = new Ast.Location(token.Location.Line, token.MatchedIndent + 1); - } + protected virtual void SetTokenMatched(Token token, TokenType matchedType, string text = null, string keyword = null, int? indent = null, GherkinLineSpan[] items = null) + { + token.MatchedType = matchedType; + token.MatchedKeyword = keyword; + token.MatchedText = text; + token.MatchedItems = items; + token.MatchedGherkinDialect = CurrentDialect; + token.MatchedIndent = indent ?? (token.Line == null ? 0 : token.Line.Indent); + token.Location = new Ast.Location(token.Location.Line, token.MatchedIndent + 1); + } - public bool Match_EOF(Token token) + public bool Match_EOF(Token token) + { + if (token.IsEOF) { - if (token.IsEOF) - { - SetTokenMatched(token, TokenType.EOF); - return true; - } - return false; + SetTokenMatched(token, TokenType.EOF); + return true; } + return false; + } - public bool Match_Other(Token token) + public bool Match_Other(Token token) + { + var text = token.Line.GetLineText(indentToRemove); //take the entire line, except removing DocString indents + SetTokenMatched(token, TokenType.Other, UnescapeDocString(text), indent: 0); + return true; + } + + public bool Match_Empty(Token token) + { + if (token.Line.IsEmpty()) { - var text = token.Line.GetLineText(indentToRemove); //take the entire line, except removing DocString indents - SetTokenMatched(token, TokenType.Other, UnescapeDocString(text), indent: 0); + SetTokenMatched(token, TokenType.Empty); return true; } + return false; + } - public bool Match_Empty(Token token) + public bool Match_Comment(Token token) + { + if (token.Line.StartsWith(GherkinLanguageConstants.COMMENT_PREFIX)) { - if (token.Line.IsEmpty()) - { - SetTokenMatched(token, TokenType.Empty); - return true; - } - return false; + var text = token.Line.GetLineText(); //take the entire line + SetTokenMatched(token, TokenType.Comment, text, indent: 0); + return true; } + return false; + } - public bool Match_Comment(Token token) - { - if (token.Line.StartsWith(GherkinLanguageConstants.COMMENT_PREFIX)) - { - var text = token.Line.GetLineText(); //take the entire line - SetTokenMatched(token, TokenType.Comment, text, indent: 0); - return true; - } - return false; - } + private ParserException CreateTokenMatcherException(Token token, string message) + { + return new AstBuilderException(message, new Ast.Location(token.Location.Line, token.Line.Indent + 1)); + } - private ParserException CreateTokenMatcherException(Token token, string message) - { - return new AstBuilderException(message, new Ast.Location(token.Location.Line, token.Line.Indent + 1)); - } + public bool Match_Language(Token token) + { + var match = LANGUAGE_PATTERN.Match(token.Line.GetLineText()); - public bool Match_Language(Token token) + if (match.Success) { - var match = LANGUAGE_PATTERN.Match(token.Line.GetLineText()); + var language = match.Groups[1].Value; + SetTokenMatched(token, TokenType.Language, language); - if (match.Success) + try { - var language = match.Groups[1].Value; - SetTokenMatched(token, TokenType.Language, language); - - try - { - currentDialect = dialectProvider.GetDialect(language, token.Location); - } - catch (NotSupportedException ex) - { - throw CreateTokenMatcherException(token, ex.Message); - } - - return true; + currentDialect = dialectProvider.GetDialect(language, token.Location); } - return false; - } - - public bool Match_TagLine(Token token) - { - if (token.Line.StartsWith(GherkinLanguageConstants.TAG_PREFIX)) + catch (NotSupportedException ex) { - SetTokenMatched(token, TokenType.TagLine, items: token.Line.GetTags().ToArray()); - return true; + throw CreateTokenMatcherException(token, ex.Message); } - return false; - } - public bool Match_FeatureLine(Token token) - { - return MatchTitleLine(token, TokenType.FeatureLine, CurrentDialect.FeatureKeywords); + return true; } + return false; + } - public bool Match_RuleLine(Token token) + public bool Match_TagLine(Token token) + { + if (token.Line.StartsWith(GherkinLanguageConstants.TAG_PREFIX)) { - return MatchTitleLine(token, TokenType.RuleLine, CurrentDialect.RuleKeywords); + SetTokenMatched(token, TokenType.TagLine, items: token.Line.GetTags().ToArray()); + return true; } + return false; + } - public bool Match_BackgroundLine(Token token) - { - return MatchTitleLine(token, TokenType.BackgroundLine, CurrentDialect.BackgroundKeywords); - } + public bool Match_FeatureLine(Token token) + { + return MatchTitleLine(token, TokenType.FeatureLine, CurrentDialect.FeatureKeywords); + } - public bool Match_ScenarioLine(Token token) - { - return MatchTitleLine(token, TokenType.ScenarioLine, CurrentDialect.ScenarioKeywords) - || MatchTitleLine(token, TokenType.ScenarioLine, CurrentDialect.ScenarioOutlineKeywords); - } + public bool Match_RuleLine(Token token) + { + return MatchTitleLine(token, TokenType.RuleLine, CurrentDialect.RuleKeywords); + } - public bool Match_ExamplesLine(Token token) - { - return MatchTitleLine(token, TokenType.ExamplesLine, CurrentDialect.ExamplesKeywords); - } + public bool Match_BackgroundLine(Token token) + { + return MatchTitleLine(token, TokenType.BackgroundLine, CurrentDialect.BackgroundKeywords); + } - private bool MatchTitleLine(Token token, TokenType tokenType, string[] keywords) - { - foreach (var keyword in keywords) - { - if (token.Line.StartsWithTitleKeyword(keyword)) - { - var title = token.Line.GetRestTrimmed(keyword.Length + GherkinLanguageConstants.TITLE_KEYWORD_SEPARATOR.Length); - SetTokenMatched(token, tokenType, keyword: keyword, text: title); - return true; - } - } - return false; - } + public bool Match_ScenarioLine(Token token) + { + return MatchTitleLine(token, TokenType.ScenarioLine, CurrentDialect.ScenarioKeywords) + || MatchTitleLine(token, TokenType.ScenarioLine, CurrentDialect.ScenarioOutlineKeywords); + } - public bool Match_DocStringSeparator(Token token) - { - return activeDocStringSeparator == null - // open - ? Match_DocStringSeparator(token, GherkinLanguageConstants.DOCSTRING_SEPARATOR, true) || - Match_DocStringSeparator(token, GherkinLanguageConstants.DOCSTRING_ALTERNATIVE_SEPARATOR, true) - // close - : Match_DocStringSeparator(token, activeDocStringSeparator, false); - } + public bool Match_ExamplesLine(Token token) + { + return MatchTitleLine(token, TokenType.ExamplesLine, CurrentDialect.ExamplesKeywords); + } - private bool Match_DocStringSeparator(Token token, string separator, bool isOpen) + private bool MatchTitleLine(Token token, TokenType tokenType, string[] keywords) + { + foreach (var keyword in keywords) { - if (token.Line.StartsWith(separator)) + if (token.Line.StartsWithTitleKeyword(keyword)) { - string contentType = null; - if (isOpen) - { - contentType = token.Line.GetRestTrimmed(separator.Length); - activeDocStringSeparator = separator; - indentToRemove = token.Line.Indent; - } - else - { - activeDocStringSeparator = null; - indentToRemove = 0; - } - - SetTokenMatched(token, TokenType.DocStringSeparator, contentType, separator); + var title = token.Line.GetRestTrimmed(keyword.Length + GherkinLanguageConstants.TITLE_KEYWORD_SEPARATOR.Length); + SetTokenMatched(token, tokenType, keyword: keyword, text: title); return true; } - return false; } + return false; + } + public bool Match_DocStringSeparator(Token token) + { + return activeDocStringSeparator == null + // open + ? Match_DocStringSeparator(token, GherkinLanguageConstants.DOCSTRING_SEPARATOR, true) || + Match_DocStringSeparator(token, GherkinLanguageConstants.DOCSTRING_ALTERNATIVE_SEPARATOR, true) + // close + : Match_DocStringSeparator(token, activeDocStringSeparator, false); + } - public bool Match_StepLine(Token token) + private bool Match_DocStringSeparator(Token token, string separator, bool isOpen) + { + if (token.Line.StartsWith(separator)) { - var keywords = CurrentDialect.StepKeywords; - foreach (var keyword in keywords) + string contentType = null; + if (isOpen) { - if (token.Line.StartsWith(keyword)) - { - var stepText = token.Line.GetRestTrimmed(keyword.Length); - SetTokenMatched(token, TokenType.StepLine, keyword: keyword, text: stepText); - return true; - } + contentType = token.Line.GetRestTrimmed(separator.Length); + activeDocStringSeparator = separator; + indentToRemove = token.Line.Indent; } - return false; + else + { + activeDocStringSeparator = null; + indentToRemove = 0; + } + + SetTokenMatched(token, TokenType.DocStringSeparator, contentType, separator); + return true; } + return false; + } + - public bool Match_TableRow(Token token) + public bool Match_StepLine(Token token) + { + var keywords = CurrentDialect.StepKeywords; + foreach (var keyword in keywords) { - if (token.Line.StartsWith(GherkinLanguageConstants.TABLE_CELL_SEPARATOR)) + if (token.Line.StartsWith(keyword)) { - SetTokenMatched(token, TokenType.TableRow, items: token.Line.GetTableCells().ToArray()); + var stepText = token.Line.GetRestTrimmed(keyword.Length); + SetTokenMatched(token, TokenType.StepLine, keyword: keyword, text: stepText); return true; } - return false; } + return false; + } - private string UnescapeDocString(string text) + public bool Match_TableRow(Token token) + { + if (token.Line.StartsWith(GherkinLanguageConstants.TABLE_CELL_SEPARATOR)) { - return activeDocStringSeparator != null ? text.Replace("\\\"\\\"\\\"", "\"\"\"").Replace("\\`\\`\\`", "```") : text; + SetTokenMatched(token, TokenType.TableRow, items: token.Line.GetTableCells().ToArray()); + return true; } + return false; + } + + private string UnescapeDocString(string text) + { + return activeDocStringSeparator != null ? text.Replace("\\\"\\\"\\\"", "\"\"\"").Replace("\\`\\`\\`", "```") : text; } } diff --git a/dotnet/Gherkin/TokenScanner.cs b/dotnet/Gherkin/TokenScanner.cs index 55460a38e..8b418a26e 100644 --- a/dotnet/Gherkin/TokenScanner.cs +++ b/dotnet/Gherkin/TokenScanner.cs @@ -1,33 +1,32 @@ using System.IO; using Gherkin.Ast; -namespace Gherkin +namespace Gherkin; + +/// +/// The scanner reads a gherkin doc (typically read from a .feature file) and creates a token +/// for each line. +/// +/// The tokens are passed to the parser, which outputs an AST (Abstract Syntax Tree). +/// +/// If the scanner sees a `#` language header, it will reconfigure itself dynamically to look +/// for Gherkin keywords for the associated language. The keywords are defined in +/// gherkin-languages.json. +/// +public class TokenScanner : ITokenScanner { - /// - /// The scanner reads a gherkin doc (typically read from a .feature file) and creates a token - /// for each line. - /// - /// The tokens are passed to the parser, which outputs an AST (Abstract Syntax Tree). - /// - /// If the scanner sees a `#` language header, it will reconfigure itself dynamically to look - /// for Gherkin keywords for the associated language. The keywords are defined in - /// gherkin-languages.json. - /// - public class TokenScanner : ITokenScanner - { - protected int lineNumber = 0; - protected readonly TextReader reader; + protected int lineNumber = 0; + protected readonly TextReader reader; - public TokenScanner(TextReader reader) - { - this.reader = reader; - } + public TokenScanner(TextReader reader) + { + this.reader = reader; + } - public virtual Token Read() - { - var line = reader.ReadLine(); - var location = new Ast.Location(++lineNumber); - return line == null ? new Token(null, location) : new Token(new GherkinLine(line, lineNumber), location); - } + public virtual Token Read() + { + var line = reader.ReadLine(); + var location = new Ast.Location(++lineNumber); + return line == null ? new Token(null, location) : new Token(new GherkinLine(line, lineNumber), location); } } \ No newline at end of file