Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
4 changes: 2 additions & 2 deletions src/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
<PackageVersion Include="MinVer" Version="7.0.0" />

<!-- Generator dependencies -->
<PackageVersion Include="XmlSchemaClassGenerator-beta" Version="99.0.11-local" />
<PackageVersion Include="XmlSchemaClassGenerator.Analyzer" Version="99.0.11-local" />
<PackageVersion Include="XmlSchemaClassGenerator-beta" Version="99.0.14-local" />
<PackageVersion Include="XmlSchemaClassGenerator.Analyzer" Version="99.0.14-local" />
<PackageVersion Include="System.CommandLine" Version="2.0.7" />

<!-- Test dependencies -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ private static XscGenerator CreateBaseGenerator(
EnableNullableDirective = true,
GenerateRequiredModifier = true,
UseShouldSerializePattern = true,
UseShouldSerializeForDefaultValues = true,
GenerateChoiceGroupAttributes = true,
ChoiceGroupAttributeNamespace = rootNamespace,
GenerateStrictFixedValues = true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,31 @@ public void Should_serialize_and_deserialize_optional_element_with_default_value
deserialized.Note.Value.Should().Be("false.");
}

[Test]
[Arguments("changed")]
[Arguments("false.")]
public void Should_preserve_edits_to_the_contents_of_a_default_object(string text)
{
// arrange
var serializer = new XmlSerializer(typeof(AccessVehicleEquipment));
var equipment = new AccessVehicleEquipment
{
Id = "NSR:AccessVehicleEquipment:1",
Version = "1",
};

// act
equipment.Note!.Value = text;
using var writer = new StringWriter();
serializer.Serialize(writer, equipment);
using var reader = new StringReader(writer.ToString());
var result = (AccessVehicleEquipment)serializer.Deserialize(reader)!;

// assert
writer.ToString().Should().Contain($"<Note>{text}</Note>");
result.Note!.Value.Should().Be(text);
}

[Test]
public void Should_serialize_simple_content_ref_as_self_closing_element_when_value_is_null()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ public void Should_not_have_default_value_attribute_on_nullable_string_property_
}

[Test]
public void Should_still_have_default_value_attribute_on_value_type_property_with_xsd_default()
public void Should_track_assignment_instead_of_omitting_explicit_default_values()
{
// arrange
var property = typeof(DayTypeAssignmentVersionStructure)
Expand All @@ -128,8 +128,8 @@ public void Should_still_have_default_value_attribute_on_value_type_property_wit
var attr = property.GetCustomAttribute<DefaultValueAttribute>();

// assert
attr.Should().NotBeNull();
attr!.Value.Should().Be(true);
attr.Should().BeNull();
property.DeclaringType!.GetMethod("ShouldSerialize" + property.Name).Should().NotBeNull();
}

[Test]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using System.Reflection;
using AwesomeAssertions;

namespace Spillgebees.SIRI.Models.Tests;

public class ChoiceSchemaRegressionTests
{
[Test]
[Arguments(typeof(V2_1.SIRI.AffectedSectionStructureIndirectSectionRef))]
[Arguments(typeof(V2_2.SIRI.AffectedSectionStructureIndirectSectionRef))]
public void Should_allow_mixed_references_in_repeated_situation_exchange_choice(Type sectionType)
{
// arrange
var properties = new[] { "IntermediateStopPointRef", "IntermediateStopPlaceRef", "IntermediateQuayRef" };

// act
var attributes = properties.SelectMany(name => sectionType.GetProperty(name)!.GetCustomAttributesData())
.Where(attribute => attribute.AttributeType.Name == "XmlChoiceGroupAttribute")
.ToList();

// assert
attributes.Should().BeEmpty("each repetition can select a different reference type");
}

[Test]
[Arguments(typeof(V2_1.SIRI.VehicleMonitoringSubscriptionStructure), "ChangeBeforeUpdates", "UpdateInterval")]
[Arguments(typeof(V2_2.SIRI.VehicleMonitoringSubscriptionStructure), "ChangeBeforeUpdates", "UpdateInterval")]
[Arguments(typeof(V2_1.SIRI.SituationExchangeRequestStructure), "LineRef", "Lines")]
[Arguments(typeof(V2_2.SIRI.SituationExchangeRequestStructure), "LineRef", "Lines")]
public void Should_allow_omitting_choices_with_optional_alternatives(Type modelType, string first, string second)
{
// arrange
var properties = new[] { first, second };

// act
var attributes = properties.Select(name => modelType.GetProperty(name)!.GetCustomAttributesData()
.Single(attribute => attribute.AttributeType.Name == "XmlChoiceGroupAttribute")).ToList();

// assert
attributes[0].ConstructorArguments[0].Value.Should().Be(attributes[1].ConstructorArguments[0].Value);
attributes[0].ConstructorArguments[1].Value.Should().NotBe(attributes[1].ConstructorArguments[1].Value);
attributes.Should().AllSatisfy(attribute =>
attribute.NamedArguments.Single(argument => argument.MemberName == "IsRequired")
.TypedValue.Value.Should().Be(false));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
using System.Xml.Linq;
using System.Xml.Serialization;
using AwesomeAssertions;
using Spillgebees.SIRI.Models.V2_2.SIRI;

namespace Spillgebees.SIRI.Models.Tests.Serialization;

public class DefaultPresenceTests
{
[Test]
[Arguments(null)]
[Arguments(true)]
[Arguments(false)]
public void Should_preserve_assignment_of_defaulted_monitored_value(bool? assignedValue)
{
// arrange
var original = new MonitoredVehicleJourneyStructure();
if (assignedValue.HasValue)
{
original.Monitored = assignedValue.Value;
}

// act
var xml = Serialize(original);
var monitored = xml.Root!.Element(XName.Get("Monitored", "http://www.siri.org.uk/siri"));

// assert
original.Monitored.Should().Be(assignedValue ?? true);
if (assignedValue.HasValue)
{
monitored.Should().NotBeNull();
monitored!.Value.Should().Be(assignedValue.Value ? "true" : "false");
}
else
{
monitored.Should().BeNull();
}
}

[Test]
[Arguments("")]
[Arguments("<Monitored xmlns=\"http://www.siri.org.uk/siri\">true</Monitored>")]
[Arguments("<Monitored xmlns=\"http://www.siri.org.uk/siri\">false</Monitored>")]
public void Should_preserve_default_presence_after_deserialization(string element)
{
// arrange
var serializer = new XmlSerializer(typeof(MonitoredVehicleJourneyStructure));
using var reader = new StringReader($"<MonitoredVehicleJourneyStructure>{element}</MonitoredVehicleJourneyStructure>");

// act
var model = (MonitoredVehicleJourneyStructure)serializer.Deserialize(reader)!;
var xml = Serialize(model);

// assert
var monitored = xml.Root!.Element(XName.Get("Monitored", "http://www.siri.org.uk/siri"));
(monitored is not null).Should().Be(element.Length != 0);
if (monitored is not null)
{
monitored.Value.Should().Be(model.Monitored ? "true" : "false");
}
}

private static XDocument Serialize(MonitoredVehicleJourneyStructure model)
{
var serializer = new XmlSerializer(typeof(MonitoredVehicleJourneyStructure));
using var writer = new StringWriter();
serializer.Serialize(writer, model);
return XDocument.Parse(writer.ToString());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
using System.Xml.Linq;
using System.Xml.Serialization;
using AwesomeAssertions;
using Spillgebees.SIRI.Models.V2_2.SIRI;

namespace Spillgebees.SIRI.Models.Tests.Serialization;

public class FixedValueSerializationTests
{
[Test]
public void Should_serialize_required_fixed_discovery_version()
{
// arrange
var original = new ConnectionLinksDiscoveryRequestStructure
{
RequestTimestamp = DateTimeOffset.UnixEpoch,
RequestorRef = new ParticipantRefStructure { Value = "test:requestor" },
};
var serializer = new XmlSerializer(original.GetType());

// act
using var writer = new StringWriter();
serializer.Serialize(writer, original);
var xml = XDocument.Parse(writer.ToString());

// assert
var version = xml.Root!.Attribute("version");
version.Should().NotBeNull();
version!.Value.Should().Be("2.1");
typeof(ConnectionLinksDiscoveryRequestStructure).GetProperty(nameof(original.Version))!.CanWrite.Should().BeFalse();
}

[Test]
public void Should_include_optional_fixed_capability_only_when_requested()
{
// arrange
var original = new SituationExchangeServiceCapabilitiesStructureTopicFiltering
{
DefaultPreviewInterval = TimeSpan.FromHours(1),
};
var serializer = new XmlSerializer(original.GetType());
using var untouchedWriter = new StringWriter();
serializer.Serialize(untouchedWriter, original);

// act
original.IncludeFilterByLocationRef();
using var writer = new StringWriter();
serializer.Serialize(writer, original);
var xml = XDocument.Parse(writer.ToString());
using var reader = new StringReader(writer.ToString());
var result = (SituationExchangeServiceCapabilitiesStructureTopicFiltering)serializer.Deserialize(reader)!;
using var roundTripWriter = new StringWriter();
serializer.Serialize(roundTripWriter, result);

// assert
XDocument.Parse(untouchedWriter.ToString()).Descendants()
.Should().NotContain(element => element.Name.LocalName == "FilterByLocationRef");
xml.Descendants().Single(element => element.Name.LocalName == "FilterByLocationRef").Value.Should().Be("true");
XDocument.Parse(roundTripWriter.ToString()).Descendants()
.Single(element => element.Name.LocalName == "FilterByLocationRef").Value.Should().Be("true");
}

[Test]
public void Should_serialize_required_fixed_vehicle_monitoring_capability()
{
// arrange
var original = new VehicleMonitoringServiceCapabilitiesStructureTopicFiltering
{
DefaultPreviewInterval = TimeSpan.FromHours(1),
};
var serializer = new XmlSerializer(original.GetType());

// act
using var writer = new StringWriter();
serializer.Serialize(writer, original);
var xml = XDocument.Parse(writer.ToString());

// assert
var capability = xml.Root!.Element(XName.Get("FilterByVehicleMonitoringRef", "http://www.siri.org.uk/siri"));
capability.Should().NotBeNull();
capability!.Value.Should().Be("true");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -153,13 +153,8 @@ public void Should_have_correct_xml_type_namespace_on_siri_types()
xmlTypeAttr.Namespace.Should().Be("http://www.siri.org.uk/siri");
}

/// <summary>
/// Siri.Version defaults to "2.1" via backing field initialization.
/// With <c>[DefaultValueAttribute]</c> suppressed on <c>string?</c> properties,
/// <c>XmlSerializer</c> must include the default value in the serialized XML.
/// </summary>
[Test]
public void Should_serialize_default_string_value_when_property_is_left_as_default()
public void Should_omit_untouched_default_string_value()
{
// arrange
var serializer = new XmlSerializer(typeof(Siri));
Expand All @@ -174,7 +169,7 @@ public void Should_serialize_default_string_value_when_property_is_left_as_defau
var deserialized = serializer.Deserialize(reader) as Siri;

// assert
xml.Should().Contain("version=\"2.1\"");
xml.Should().NotContain("version=\"2.1\"");
deserialized.Should().NotBeNull();
deserialized.Version.Should().Be("2.1");
}
Expand Down
6 changes: 3 additions & 3 deletions src/siri/Spillgebees.SIRI.Models.Tests/XsdTypeMappingTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ public void Should_not_have_default_value_attribute_on_nullable_string_property_
}

[Test]
public void Should_still_have_default_value_attribute_on_value_type_property_with_xsd_default()
public void Should_track_assignment_instead_of_omitting_explicit_default_values()
{
// arrange
var property = typeof(HalfOpenTimestampOutputRangeStructure)
Expand All @@ -120,8 +120,8 @@ public void Should_still_have_default_value_attribute_on_value_type_property_wit
var attr = property.GetCustomAttribute<DefaultValueAttribute>();

// assert
attr.Should().NotBeNull();
attr!.Value.Should().Be(EndTimeStatusEnumeration.Undefined);
attr.Should().BeNull();
property.DeclaringType!.GetMethod("ShouldSerialize" + property.Name).Should().NotBeNull();
}

[Test]
Expand Down
Loading