diff --git a/.github/workflows/build-test-publish.yml b/.github/workflows/build-test-publish.yml index 0b914e8..57b59f7 100644 --- a/.github/workflows/build-test-publish.yml +++ b/.github/workflows/build-test-publish.yml @@ -43,10 +43,13 @@ jobs: dotnet pack src/netex/Spillgebees.NeTEx.Models.V1_2_3/Spillgebees.NeTEx.Models.V1_2_3.csproj --configuration Release --no-build --output package dotnet pack src/netex/Spillgebees.NeTEx.Models.V1_3_0/Spillgebees.NeTEx.Models.V1_3_0.csproj --configuration Release --no-build --output package dotnet pack src/netex/Spillgebees.NeTEx.Models.V1_3_1/Spillgebees.NeTEx.Models.V1_3_1.csproj --configuration Release --no-build --output package + dotnet pack src/netex/Spillgebees.NeTEx.Models.V1_3_2/Spillgebees.NeTEx.Models.V1_3_2.csproj --configuration Release --no-build --output package dotnet pack src/netex/Spillgebees.NeTEx.Models.V2_0_0/Spillgebees.NeTEx.Models.V2_0_0.csproj --configuration Release --no-build --output package dotnet pack src/netex/Spillgebees.NeTEx.Models/Spillgebees.NeTEx.Models.csproj --configuration Release --no-build --output package dotnet pack src/siri/Spillgebees.SIRI.Models.V2_1/Spillgebees.SIRI.Models.V2_1.csproj --configuration Release --no-build --output package dotnet pack src/siri/Spillgebees.SIRI.Models.V2_2/Spillgebees.SIRI.Models.V2_2.csproj --configuration Release --no-build --output package + dotnet pack src/siri/Spillgebees.SIRI.Models.V2_2_1/Spillgebees.SIRI.Models.V2_2_1.csproj --configuration Release --no-build --output package + dotnet pack src/siri/Spillgebees.SIRI.Models.V2_3/Spillgebees.SIRI.Models.V2_3.csproj --configuration Release --no-build --output package dotnet pack src/siri/Spillgebees.SIRI.Models/Spillgebees.SIRI.Models.csproj --configuration Release --no-build --output package dotnet pack src/generator/Spillgebees.Transmodel.Generator/Spillgebees.Transmodel.Generator.csproj --configuration Release --no-build --output package diff --git a/Spillgebees.Transmodel.slnx b/Spillgebees.Transmodel.slnx index ea20df6..54888ad 100644 --- a/Spillgebees.Transmodel.slnx +++ b/Spillgebees.Transmodel.slnx @@ -22,6 +22,7 @@ + @@ -30,6 +31,8 @@ + + diff --git a/src/generator/Spillgebees.Transmodel.Generator/Configuration/NetexDefaults.cs b/src/generator/Spillgebees.Transmodel.Generator/Configuration/NetexDefaults.cs index 5519f55..a2114d0 100644 --- a/src/generator/Spillgebees.Transmodel.Generator/Configuration/NetexDefaults.cs +++ b/src/generator/Spillgebees.Transmodel.Generator/Configuration/NetexDefaults.cs @@ -2,7 +2,7 @@ namespace Spillgebees.Transmodel.Generator.Configuration; public static class NetexDefaults { - public const string DefaultVersion = "v1.3.1"; + public const string DefaultVersion = "v2.0.0"; public const string DefaultNamespace = "NeTEx.Models"; public const string NetexXmlNamespace = "http://www.netex.org.uk/netex"; diff --git a/src/generator/Spillgebees.Transmodel.Generator/Configuration/SiriDefaults.cs b/src/generator/Spillgebees.Transmodel.Generator/Configuration/SiriDefaults.cs index dc3bb3e..5f4bfd2 100644 --- a/src/generator/Spillgebees.Transmodel.Generator/Configuration/SiriDefaults.cs +++ b/src/generator/Spillgebees.Transmodel.Generator/Configuration/SiriDefaults.cs @@ -2,7 +2,7 @@ namespace Spillgebees.Transmodel.Generator.Configuration; public static class SiriDefaults { - public const string DefaultVersion = "v2.2"; + public const string DefaultVersion = "v2.3"; public const string DefaultNamespace = "SIRI.Models"; public const string SiriXmlNamespace = "http://www.siri.org.uk/siri"; diff --git a/src/netex/Spillgebees.NeTEx.Models.Tests/Serialization/Netex/ReleaseRegressionTests.cs b/src/netex/Spillgebees.NeTEx.Models.Tests/Serialization/Netex/ReleaseRegressionTests.cs new file mode 100644 index 0000000..c26f080 --- /dev/null +++ b/src/netex/Spillgebees.NeTEx.Models.Tests/Serialization/Netex/ReleaseRegressionTests.cs @@ -0,0 +1,93 @@ +using System.Xml.Linq; +using System.Xml.Serialization; +using AwesomeAssertions; +using Netex132 = Spillgebees.NeTEx.Models.V1_3_2.NeTEx; + +namespace Spillgebees.NeTEx.Models.Tests.Serialization.Netex; + +public class ReleaseRegressionTests +{ + [Test] + public void Should_keep_the_netex_namespace_for_v1_3_2() + { + // arrange + var type = typeof(Netex132.StopPlace); + + // act + var xmlType = type.GetCustomAttributes(typeof(XmlTypeAttribute), false) + .Cast().Single(); + + // assert + xmlType.Namespace.Should().Be("http://www.netex.org.uk/netex"); + } + [Test] + public void Should_round_trip_type_of_frame_reference_attributes() + { + // arrange + var original = new Netex132.ClassInFrameStructure + { + TypeOfFrameRef = new Netex132.TypeOfFrameRefStructure { Ref = "frame-type:1", Version = "1" }, + }; + var serializer = new XmlSerializer(typeof(Netex132.ClassInFrameStructure)); + + // act + using var writer = new StringWriter(); + serializer.Serialize(writer, original); + using var reader = new StringReader(writer.ToString()); + var result = (Netex132.ClassInFrameStructure)serializer.Deserialize(reader)!; + + // assert + result.TypeOfFrameRef.Should().NotBeNull(); + result.TypeOfFrameRef.Ref.Should().Be("frame-type:1"); + result.TypeOfFrameRef.Version.Should().Be("1"); + XDocument.Parse(writer.ToString()).Descendants() + .Single(element => element.Name.LocalName == "TypeOfFrameRef") + .Attribute("ref")!.Value.Should().Be("frame-type:1"); + } + + [Test] + public void Should_round_trip_route_instruction_references() + { + // arrange + var original = new Netex132.RouteInstructionsRelStructure + { + RouteInstructionRef = + [ + new Netex132.RouteInstructionRefStructure { Ref = "instruction:1", Version = "1" }, + new Netex132.RouteInstructionRefStructure { Ref = "instruction:2", Version = "1" }, + ], + }; + var serializer = new XmlSerializer(typeof(Netex132.RouteInstructionsRelStructure)); + + // act + using var writer = new StringWriter(); + serializer.Serialize(writer, original); + using var reader = new StringReader(writer.ToString()); + var result = (Netex132.RouteInstructionsRelStructure)serializer.Deserialize(reader)!; + + // assert + result.RouteInstructionRef.Should().HaveCount(2); + result.RouteInstructionRef!.Select(reference => reference.Ref) + .Should().Equal("instruction:1", "instruction:2"); + result.RouteInstruction.Should().BeNullOrEmpty(); + } + + [Test] + public void Should_deserialize_concrete_luggage_locker_equipment() + { + // arrange + const string xml = """ + + """; + var serializer = new XmlSerializer(typeof(Netex132.LuggageLockerEquipment)); + + // act + using var reader = new StringReader(xml); + var result = (Netex132.LuggageLockerEquipment)serializer.Deserialize(reader)!; + + // assert + result.Id.Should().Be("locker:1"); + result.Version.Should().Be("1"); + typeof(Netex132.LuggageLockerEquipment).IsAbstract.Should().BeFalse(); + } +} diff --git a/src/netex/Spillgebees.NeTEx.Models.Tests/Spillgebees.NeTEx.Models.Tests.csproj b/src/netex/Spillgebees.NeTEx.Models.Tests/Spillgebees.NeTEx.Models.Tests.csproj index 97a3dfa..a5c5250 100644 --- a/src/netex/Spillgebees.NeTEx.Models.Tests/Spillgebees.NeTEx.Models.Tests.csproj +++ b/src/netex/Spillgebees.NeTEx.Models.Tests/Spillgebees.NeTEx.Models.Tests.csproj @@ -17,6 +17,7 @@ + diff --git a/src/netex/Spillgebees.NeTEx.Models.V1_3_2/Spillgebees.NeTEx.Models.V1_3_2.csproj b/src/netex/Spillgebees.NeTEx.Models.V1_3_2/Spillgebees.NeTEx.Models.V1_3_2.csproj new file mode 100644 index 0000000..7bab17f --- /dev/null +++ b/src/netex/Spillgebees.NeTEx.Models.V1_3_2/Spillgebees.NeTEx.Models.V1_3_2.csproj @@ -0,0 +1,9 @@ + + + + + + v1.3.2 + Pre-generated C# XML bindings for NeTEx (Network Timetable Exchange) $(NetexVersion) and associated SIRI/GML schemas. + + diff --git a/src/netex/Spillgebees.NeTEx.Models/Spillgebees.NeTEx.Models.csproj b/src/netex/Spillgebees.NeTEx.Models/Spillgebees.NeTEx.Models.csproj index 36ab411..c5af0a4 100644 --- a/src/netex/Spillgebees.NeTEx.Models/Spillgebees.NeTEx.Models.csproj +++ b/src/netex/Spillgebees.NeTEx.Models/Spillgebees.NeTEx.Models.csproj @@ -12,6 +12,7 @@ + diff --git a/src/siri/Spillgebees.SIRI.Models.Tests/Serialization/ReleaseRegressionTests.cs b/src/siri/Spillgebees.SIRI.Models.Tests/Serialization/ReleaseRegressionTests.cs new file mode 100644 index 0000000..148de38 --- /dev/null +++ b/src/siri/Spillgebees.SIRI.Models.Tests/Serialization/ReleaseRegressionTests.cs @@ -0,0 +1,138 @@ +using System.Xml; +using System.Xml.Linq; +using System.Xml.Schema; +using System.Xml.Serialization; +using AwesomeAssertions; +using Siri221 = Spillgebees.SIRI.Models.V2_2_1.SIRI; +using Siri23 = Spillgebees.SIRI.Models.V2_3.SIRI; + +namespace Spillgebees.SIRI.Models.Tests.Serialization; + +public class ReleaseRegressionTests +{ + [Test] + public void Should_keep_the_siri_namespace_for_new_releases() + { + // arrange + var types = new[] { typeof(Siri221.Siri), typeof(Siri23.Siri) }; + + // act + var namespaces = types.Select(type => type.GetCustomAttributes(typeof(XmlTypeAttribute), false) + .Cast().Single().Namespace); + + // assert + namespaces.Should().OnlyContain(value => value == "http://www.siri.org.uk/siri"); + } + [Test] + public void Should_round_trip_corrected_driver_scope_in_v2_2_1() + { + // arrange + const string xml = """ + + message:1 + driver:1 + + """; + var serializer = new XmlSerializer(typeof(Siri221.DriverMessageStructure), "http://www.siri.org.uk/siri"); + + // act + using var reader = new StringReader(xml); + var message = (Siri221.DriverMessageStructure)serializer.Deserialize(reader)!; + using var writer = new StringWriter(); + serializer.Serialize(writer, message); + + // assert + message.DriverScope.EmployeeRef.Should().Be("driver:1"); + writer.ToString().Should().Contain("").And.NotContain("DiverScope"); + } + + [Test] + [Arguments(true)] + [Arguments(false)] + public void Should_round_trip_dead_run_flag_in_v2_3(bool isDeadRun) + { + // arrange + var original = new Siri23.TargetedVehicleJourneyStructure + { + LineRef = new Siri23.LineRefStructure { Value = "line:1" }, + DirectionRef = new Siri23.DirectionRefStructure { Value = "outbound" }, + IsDeadRun = isDeadRun, + }; + var serializer = new XmlSerializer(typeof(Siri23.TargetedVehicleJourneyStructure)); + + // act + using var writer = new StringWriter(); + serializer.Serialize(writer, original); + using var reader = new StringReader(writer.ToString()); + var result = (Siri23.TargetedVehicleJourneyStructure)serializer.Deserialize(reader)!; + + // assert + result.IsDeadRun.Should().Be(isDeadRun); + XDocument.Parse(writer.ToString()).Descendants() + .Single(element => element.Name.LocalName == "IsDeadRun").Value + .Should().Be(XmlConvert.ToString(isDeadRun)); + } + + [Test] + public void Should_serialize_action_keywords_as_one_schema_valid_token_list() + { + // arrange + var original = new Siri23.ParameterisedActionStructure { Keywords = ["delay", "rail"] }; + var serializer = new XmlSerializer(typeof(Siri23.ParameterisedActionStructure)); + const string schema = """ + + + + """; + var schemas = new XmlSchemaSet(); + using var schemaReader = new StringReader(schema); + schemas.Add("http://www.siri.org.uk/siri", XmlReader.Create(schemaReader)); + + // act + using var writer = new StringWriter(); + serializer.Serialize(writer, original); + var keywords = XDocument.Parse(writer.ToString()).Descendants() + .Where(element => element.Name.LocalName == "Keywords").ToList(); + + // assert + keywords.Should().ContainSingle(); + keywords[0].Value.Should().Be("delay rail"); + var validationErrors = new List(); + new XDocument(new XElement(keywords[0])).Validate(schemas, (_, error) => validationErrors.Add(error.Message)); + validationErrors.Should().BeEmpty(); + using var reader = new StringReader(writer.ToString()); + var result = (Siri23.ParameterisedActionStructure)serializer.Deserialize(reader)!; + result.Keywords.Should().Equal("delay", "rail"); + } + [Test] + public void Should_round_trip_passenger_information_periods_in_v2_3() + { + // arrange + var start = new DateTimeOffset(2026, 10, 3, 8, 0, 0, TimeSpan.Zero); + var original = new Siri23.PassengerInformationActionStructure + { + ActionRef = new Siri23.EntryQualifierStructure { Value = "action:1" }, + RecordedAtTime = start, + Period = + [ + new Siri23.HalfOpenTimestampOutputRangeStructure { StartTime = start, EndTime = start.AddHours(2) }, + new Siri23.HalfOpenTimestampOutputRangeStructure { StartTime = start.AddDays(1) }, + ], + }; + var serializer = new XmlSerializer(typeof(Siri23.PassengerInformationActionStructure)); + + // act + using var writer = new StringWriter(); + serializer.Serialize(writer, original); + using var reader = new StringReader(writer.ToString()); + var result = (Siri23.PassengerInformationActionStructure)serializer.Deserialize(reader)!; + + // assert + result.Period.Should().HaveCount(2); + result.Period![0].StartTime.Should().Be(start); + result.Period[0].EndTime.Should().Be(start.AddHours(2)); + result.Period[1].StartTime.Should().Be(start.AddDays(1)); + result.Period[1].EndTime.Should().BeNull(); + } +} diff --git a/src/siri/Spillgebees.SIRI.Models.Tests/Spillgebees.SIRI.Models.Tests.csproj b/src/siri/Spillgebees.SIRI.Models.Tests/Spillgebees.SIRI.Models.Tests.csproj index 79eadc2..dcbe706 100644 --- a/src/siri/Spillgebees.SIRI.Models.Tests/Spillgebees.SIRI.Models.Tests.csproj +++ b/src/siri/Spillgebees.SIRI.Models.Tests/Spillgebees.SIRI.Models.Tests.csproj @@ -14,5 +14,7 @@ + + diff --git a/src/siri/Spillgebees.SIRI.Models.V2_2_1/Spillgebees.SIRI.Models.V2_2_1.csproj b/src/siri/Spillgebees.SIRI.Models.V2_2_1/Spillgebees.SIRI.Models.V2_2_1.csproj new file mode 100644 index 0000000..6a89f91 --- /dev/null +++ b/src/siri/Spillgebees.SIRI.Models.V2_2_1/Spillgebees.SIRI.Models.V2_2_1.csproj @@ -0,0 +1,9 @@ + + + + + + v2.2.1 + Pre-generated C# XML bindings for SIRI (Service Interface for Real-time Information) $(SiriVersion) including IFOPT, ACSB, DATEX2, and WSDL schemas. + + diff --git a/src/siri/Spillgebees.SIRI.Models.V2_3/Spillgebees.SIRI.Models.V2_3.csproj b/src/siri/Spillgebees.SIRI.Models.V2_3/Spillgebees.SIRI.Models.V2_3.csproj new file mode 100644 index 0000000..e64c017 --- /dev/null +++ b/src/siri/Spillgebees.SIRI.Models.V2_3/Spillgebees.SIRI.Models.V2_3.csproj @@ -0,0 +1,9 @@ + + + + + + v2.3 + Pre-generated C# XML bindings for SIRI (Service Interface for Real-time Information) $(SiriVersion) including IFOPT, ACSB, DATEX2, and WSDL schemas. + + diff --git a/src/siri/Spillgebees.SIRI.Models/Spillgebees.SIRI.Models.csproj b/src/siri/Spillgebees.SIRI.Models/Spillgebees.SIRI.Models.csproj index 069ad19..87701fc 100644 --- a/src/siri/Spillgebees.SIRI.Models/Spillgebees.SIRI.Models.csproj +++ b/src/siri/Spillgebees.SIRI.Models/Spillgebees.SIRI.Models.csproj @@ -9,5 +9,7 @@ + +