Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
c5840f4
Initial Commit of using erb to generate dotnet
clrudolphi Jun 27, 2024
b90e60e
fixup syntax errors
clrudolphi Jun 27, 2024
4b9f301
fixup mistake with enums
clrudolphi Jun 27, 2024
24685ba
added using statement for System.ComponentModel so that Description a…
clrudolphi Jun 27, 2024
ea833bf
added using statement for System.ComponentModel so that Description a…
clrudolphi Jun 27, 2024
792de3e
Merge branch 'RefactorDotnetCodeGen' of https://github.com/clrudolphi…
clrudolphi Jun 27, 2024
213fba6
added using statement for System.Reflection to the enum generator
clrudolphi Jun 27, 2024
8b652ea
regenerated the enums with the previous fix
clrudolphi Jun 27, 2024
1521062
Fixed enums by creating Extensions class for each enum
clrudolphi Jun 27, 2024
7044cb3
Fixup nullable value types,
clrudolphi Jun 28, 2024
3cdf56a
Setup Make, make build fail
mpkorstanje Jun 29, 2024
e4aa561
Moved Generated Files to the /generated folder. Added support classes…
clrudolphi Jun 30, 2024
8e274b3
Modified github workflow test-dotnet.yml to invoke dotnet test during…
clrudolphi Jun 30, 2024
b99f54b
Revisions based upon PR comments. All resolved except for decisions o…
clrudolphi Jul 1, 2024
4cf2841
Downgraded dependency on System.Text.JSON to v6.0.0 per comments in t…
clrudolphi Jul 2, 2024
2e6bd7c
Revised JsonOptions initializer from a lock sequence to Lazy<T>
clrudolphi Jul 2, 2024
97f4da6
Remove unused default.mk
mpkorstanje Jul 5, 2024
e4925a2
Remove unused update-versions script
mpkorstanje Jul 5, 2024
6061002
Remove unused default.mk
mpkorstanje Jul 5, 2024
579edce
Clean-ups from review comments.
clrudolphi Jul 5, 2024
8b5849f
Merge branch 'RefactorDotnetCodeGen' of https://github.com/clrudolphi…
clrudolphi Jul 5, 2024
d605e39
Changes per review comments
clrudolphi Jul 9, 2024
cbfd326
Remove dependabot config
mpkorstanje Jul 11, 2024
49b45ad
Merge branch 'main' into RefactorDotnetCodeGen
mpkorstanje Jul 11, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/test-dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ jobs:
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v4
with:
dotnet-version: '5.0.x'
dotnet-version: '8.0.x'

- name: run tests
run: |
make
dotnet test
working-directory: dotnet
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased]

- [Dotnet] **Breaking Change** Rewritten to align with the code generation techniques used for the other languages. Added support classes aligned with what is provided for the Java implementation. Upgraded from .NET 5 to .NET 8. Dropped .NET Framework 4.x as a target (but did retain .NET Standard 2.0 as the primary target framework). (https://github.com/cucumber/messages/pull/233) [clrudolphi](https://github.com/clrudolphi)
## [25.0.1] - 2024-06-13
### Fixed
- [Php] Fixed a workflow issue with publishing the package
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ schemas = \
./jsonschema/UndefinedParameterType.json \
./jsonschema/Envelope.json

languages = cpp go java javascript perl php ruby
languages = cpp go java javascript perl php ruby dotnet

.DEFAULT_GOAL = help

Expand Down
21 changes: 21 additions & 0 deletions dotnet/.devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/ruby
{
"name": "Ruby",
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
"image": "mcr.microsoft.com/devcontainers/ruby:1-3.3-bullseye",
"features": {
"ghcr.io/jungaretti/features/make:1": {},
"ghcr.io/devcontainers/features/dotnet:2": {
"version": "8.0"
}
}
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
// Use 'postCreateCommand' to run commands after the container is created.
// "postCreateCommand": "ruby --version",
// Configure tool-specific properties.
// "customizations": {},
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
// "remoteUser": "root"
}
36 changes: 36 additions & 0 deletions dotnet/Cucumber.Messages.Specs/BasicMessageSerializationTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using Xunit;
using System.IO;
using Io.Cucumber.Messages.Types;
using System.Text.Json;
using System.Collections.Generic;
using System.Reflection;
using System.Text.Json.Serialization;
using System;
using System.ComponentModel;
using Cucumber.Messages;

namespace Cucumber.Messages.Specs
{
public class BasicMessageSerializationTests
{

[Fact]
public void SerializesAnEnvelopeToNDJSONCorrectly()
{
var stepDefinitionNDJSON = @"{""stepDefinition"":{""id"":""0"",""pattern"":{""source"":""I have {int} cukes in my belly"",""type"":""CUCUMBER_EXPRESSION""},""sourceReference"":{""location"":{""line"":3},""uri"":""samples/minimal/minimal.feature.ts""}}}
";
var sourceReference = new SourceReference("samples/minimal/minimal.feature.ts",
null, null, new Location(3, null));
var stepDefPattern = new StepDefinitionPattern("I have {int} cukes in my belly", StepDefinitionPatternType.CUCUMBER_EXPRESSION);
var stepDefinition = new StepDefinition("0", stepDefPattern, sourceReference);
var env = new Envelope(null, null, null, null, null, null, null, null, stepDefinition, null, null, null, null, null, null, null, null);

var serializedStepDefinition = NdjsonSerializer.Serialize(env);
var reconstructedStepDefinition = NdjsonSerializer.Deserialize(serializedStepDefinition);

var expectedStepDefinition = NdjsonSerializer.Deserialize(stepDefinitionNDJSON);
Assert.Equal(expectedStepDefinition, reconstructedStepDefinition);
}

}
}
35 changes: 35 additions & 0 deletions dotnet/Cucumber.Messages.Specs/ConvertersTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xunit;

namespace Cucumber.Messages.Specs
{
public class ConvertersTests
{

[Fact]
public void ConvertsToAndFromTimestamp()
{
var current = DateTime.Parse("2024-06-29T17:29:47.1537257Z", null, System.Globalization.DateTimeStyles.RoundtripKind);
var timestamp = Converters.ToTimestamp(current);

var dt = Converters.ToDateTime(timestamp);

Assert.Equal(current, dt);
}

[Fact]
public void ConvertsToAndFromDuration()
{
var current = TimeSpan.FromSeconds(3.000161);
var duration = Converters.ToDuration(current);

var ts = Converters.ToTimeSpan(duration);

Assert.Equal(current, ts);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<IsPackable>False</IsPackable>
</PropertyGroup>

Expand Down
31 changes: 0 additions & 31 deletions dotnet/Cucumber.Messages.Specs/MessagesSpec.cs

This file was deleted.

27 changes: 27 additions & 0 deletions dotnet/Cucumber.Messages.Specs/MessagesTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using Io.Cucumber.Messages.Types;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xunit;

namespace Cucumber.Messages.Specs
{
public class MessagesTest
{

[Fact]
public void ThrowsWhenRequiredFieldsAreMissing()
{
Assert.Throws<ArgumentNullException>(() => new Background(null, null, null, null, null, null));
}

[Fact]
public void IsValidWhenNoRequiredFieldsAreMissing()
{
// This should succeed as no constructor arguments to an Envelope are required.
var env = new Envelope(null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null);
}
}
}
91 changes: 91 additions & 0 deletions dotnet/Cucumber.Messages.Specs/NdjsonStreamSerializationTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xunit;

using Cucumber.Messages;
using Io.Cucumber.Messages.Types;

namespace Cucumber.Messages.Specs
{
public class NdjsonStreamSerializationTests
{

[Fact]
public void WritesSourceEnvelope()
{
MemoryStream memoryStream = new MemoryStream();
var writer = new MessageToNdjsonWriter(memoryStream);
writer.Write(Envelope.Create(new Source("hello.feature", "Feature: Hello", SourceMediaType.TEXT_X_CUCUMBER_GHERKIN_PLAIN)));

var json = Encoding.UTF8.GetString(memoryStream.ToArray());
Assert.Equal(@"{""source"":{""uri"":""hello.feature"",""data"":""Feature: Hello"",""mediaType"":""text/x.cucumber.gherkin+plain""}}"+Environment.NewLine, json);
}

[Fact]
public void DoesNotSerializeNullFields()
{
MemoryStream memoryStream = new MemoryStream();
var writer = new MessageToNdjsonWriter(memoryStream);
writer.Write(new Envelope(null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null));

var json = Encoding.UTF8.GetString(memoryStream.ToArray());
Assert.Equal("{}"+Environment.NewLine, json);
}

[Fact]
public void IgnoresEmptyLines()
{
MemoryStream memoryStream = new MemoryStream(Encoding.UTF8.GetBytes("{}\n{}\n\n{}\n"));
var enumerator = new NdjsonMessageReader(memoryStream).GetEnumerator();

var expectedEnvelope = new Envelope(null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null);
for (int i = 0; i < 3; i++)
{
Assert.True(enumerator.MoveNext());
Assert.Equal(expectedEnvelope, enumerator.Current);
}

Assert.False(enumerator.MoveNext());
}

[Fact]
public void Handles_Enums()
{
MemoryStream memoryStream = new MemoryStream(Encoding.UTF8.GetBytes("{\"attachment\":{\"contentEncoding\":\"BASE64\", \"body\":\"the-body\", \"mediaType\":\"text/plain\"}}\n"));
var enumerator = new NdjsonMessageReader(memoryStream).GetEnumerator();
Assert.True(enumerator.MoveNext());
Envelope envelope = enumerator.Current;

Assert.Equal(AttachmentContentEncoding.BASE64, envelope.Attachment.ContentEncoding);
Assert.Equal("the-body", envelope.Attachment.Body);
Assert.Equal("text/plain", envelope.Attachment.MediaType);
Assert.False(enumerator.MoveNext());
}

[Fact]
public void Handles_Single_Argument_Constructor()
{
MemoryStream memoryStream = new MemoryStream(Encoding.UTF8.GetBytes("{\"testRunStarted\": {\"timestamp\":{\"nanos\":0,\"seconds\":0}}}\n"));
var enumerator = new NdjsonMessageReader(memoryStream).GetEnumerator();
Assert.True(enumerator.MoveNext());
Envelope envelope = enumerator.Current;
Envelope expected = Envelope.Create(new TestRunStarted(new Timestamp(0, 0)));

Assert.Equal(expected, envelope);
Assert.False(enumerator.MoveNext());
}

[Fact]
public void Includes_Offending_Line_In_Error_Message()
{
MemoryStream memoryStream = new MemoryStream(Encoding.UTF8.GetBytes("BLA BLA"));
var enumerator = new NdjsonMessageReader(memoryStream).GetEnumerator();
var exception = Assert.Throws<InvalidOperationException>( () => enumerator.MoveNext());
Assert.Equal("Could not parse JSON: BLA BLA", exception.Message);
}
}
}
19 changes: 19 additions & 0 deletions dotnet/Cucumber.Messages.Specs/ProtocolVersionTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Xunit;

namespace Cucumber.Messages.Specs
{
public class ProtocolVersionTest
{
[Fact]
public void ProtocolVersionIsCorrect()
{
Assert.Matches(@"\d+\.\d+\.\d+(-[0-9A-Za-z-](\.[0-9A-Za-z-])*)?", Cucumber.Messages.ProtocolVersion.Version);
}
}
}
5 changes: 2 additions & 3 deletions dotnet/Cucumber.Messages.sln
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.28803.156
# Visual Studio Version 17
VisualStudioVersion = 17.10.35013.160
MinimumVisualStudioVersion = 15.0.26124.0
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cucumber.Messages", "Cucumber.Messages\Cucumber.Messages.csproj", "{E90670B3-6B40-4844-9D8F-0C19F89A9B45}"
EndProject
Expand All @@ -10,7 +10,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
ProjectSection(SolutionItems) = preProject
.gitignore = .gitignore
..\..\LICENSE = ..\..\LICENSE
..\messages.proto = ..\messages.proto
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{A0B27547-2117-480F-9572-BF004AC570A1}"
Expand Down
48 changes: 48 additions & 0 deletions dotnet/Cucumber.Messages/Converters.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using Io.Cucumber.Messages.Types;
using System;
using System.Collections.Generic;
using System.Data;
using System.Text;

namespace Cucumber.Messages
{
public class Converters
{
private static DateTime EpochStart = new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc);
private static long NanoSecondsPerTick = 100L;

public static Timestamp ToTimestamp(DateTime dateTime)
{
var timeSpan = (dateTime.Subtract(EpochStart));
long seconds = timeSpan.Ticks / TimeSpan.TicksPerSecond;
long nanos = (timeSpan.Ticks % TimeSpan.TicksPerSecond) * NanoSecondsPerTick;
return new Timestamp(
seconds,
nanos);
}

public static Duration ToDuration(TimeSpan timeSpan)
{
return new Duration(
(long) timeSpan.TotalSeconds,
(timeSpan.Ticks % TimeSpan.TicksPerSecond) * NanoSecondsPerTick);
}

public static DateTime ToDateTime(Timestamp timestamp)
{
var seconds = timestamp.Seconds;
var time = EpochStart.AddSeconds(seconds).ToUniversalTime();
time = time.AddTicks(timestamp.Nanos / NanoSecondsPerTick);

return time;
}

public static TimeSpan ToTimeSpan(Duration duration)
{
var ts = new TimeSpan(0, 0, 0, (int)duration.Seconds);
ts = ts.Add(TimeSpan.FromTicks(duration.Nanos / NanoSecondsPerTick));

return ts;
}
}
}
Loading