Skip to content

Commit c2a241d

Browse files
authored
✨ handle choice groups that require at least one element (#48)
1 parent 8afed16 commit c2a241d

6 files changed

Lines changed: 112 additions & 9 deletions
-160 KB
Binary file not shown.
161 KB
Binary file not shown.
-10.1 KB
Binary file not shown.
12.9 KB
Binary file not shown.

src/Directory.Packages.props

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
<PackageVersion Include="MinVer" Version="7.0.0" />
99

1010
<!-- Generator dependencies -->
11-
<PackageVersion Include="XmlSchemaClassGenerator-beta" Version="99.0.10-local" />
12-
<PackageVersion Include="XmlSchemaClassGenerator.Analyzer" Version="99.0.10-local" />
11+
<PackageVersion Include="XmlSchemaClassGenerator-beta" Version="99.0.11-local" />
12+
<PackageVersion Include="XmlSchemaClassGenerator.Analyzer" Version="99.0.11-local" />
1313
<PackageVersion Include="System.CommandLine" Version="2.0.5" />
1414

1515
<!-- Test dependencies -->

src/siri/Spillgebees.SIRI.Models.Tests/ChoiceGroupAttributeTests.cs

Lines changed: 110 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Reflection;
2+
using System.Runtime.CompilerServices;
23
using AwesomeAssertions;
34
using Spillgebees.SIRI.Models.V2_2;
45
using Spillgebees.SIRI.Models.V2_2.SIRI;
@@ -12,9 +13,22 @@ namespace Spillgebees.SIRI.Models.Tests;
1213
/// </summary>
1314
public class ChoiceGroupAttributeTests
1415
{
15-
private static XmlChoiceGroupAttribute? GetChoiceGroupAttribute<T>(string propertyName) =>
16+
private static XmlChoiceGroupAttribute? GetChoiceGroupAttribute<T>(string propertyName)
17+
{
18+
var attributes = typeof(T).GetProperty(propertyName)?
19+
.GetCustomAttributes<XmlChoiceGroupAttribute>()
20+
.ToList();
21+
22+
attributes?.Should().HaveCountLessThanOrEqualTo(1,
23+
$"property {typeof(T).Name}.{propertyName} should not have multiple [XmlChoiceGroupAttribute] annotations");
24+
25+
return attributes?.SingleOrDefault();
26+
}
27+
28+
private static IReadOnlyList<XmlChoiceGroupAttribute> GetChoiceGroupAttributes<T>(string propertyName) =>
1629
typeof(T).GetProperty(propertyName)?
17-
.GetCustomAttribute<XmlChoiceGroupAttribute>();
30+
.GetCustomAttributes<XmlChoiceGroupAttribute>()
31+
.ToList() ?? [];
1832

1933
private static XmlChoiceGroupAttribute GetRequiredChoiceGroupAttribute<T>(string propertyName)
2034
{
@@ -175,14 +189,103 @@ public void Should_not_have_choice_group_attribute_on_location_id()
175189
[Test]
176190
public void Should_have_multiple_distinct_choice_groups_on_control_action_structure()
177191
{
178-
// ControlActionStructure has 5 choice groups — verify at least 2 are distinct
192+
// arrange
179193
var properties = typeof(ControlActionStructure).GetProperties();
194+
195+
// act
180196
var choiceGroupIds = properties
181-
.Select(p => p.GetCustomAttribute<XmlChoiceGroupAttribute>())
182-
.Where(a => a is not null)
183-
.Select(a => a!.GroupId)
197+
.SelectMany(p => p.GetCustomAttributes<XmlChoiceGroupAttribute>())
198+
.Select(a => a.GroupId)
184199
.Distinct()
185200
.ToList();
186-
choiceGroupIds.Count.Should().BeGreaterThanOrEqualTo(2);
201+
202+
// assert
203+
choiceGroupIds.Should().HaveCount(5);
204+
}
205+
206+
[Test]
207+
public void Should_mark_tpeg_reason_arms_as_required_choice_group_without_required_members()
208+
{
209+
// arrange
210+
var propertyNames = new[]
211+
{
212+
nameof(PtSituationBodyGroupSecondaryReasonsReason.AlertCause),
213+
nameof(PtSituationBodyGroupSecondaryReasonsReason.UnknownReason),
214+
nameof(PtSituationBodyGroupSecondaryReasonsReason.MiscellaneousReason),
215+
nameof(PtSituationBodyGroupSecondaryReasonsReason.PersonnelReason),
216+
nameof(PtSituationBodyGroupSecondaryReasonsReason.EquipmentReason),
217+
nameof(PtSituationBodyGroupSecondaryReasonsReason.EnvironmentReason),
218+
nameof(PtSituationBodyGroupSecondaryReasonsReason.UndefinedReason),
219+
};
220+
221+
// act
222+
var properties = propertyNames
223+
.Select(name => typeof(PtSituationBodyGroupSecondaryReasonsReason).GetProperty(name)!)
224+
.ToList();
225+
var attributes = properties
226+
.Select(property => property.GetCustomAttributes<XmlChoiceGroupAttribute>().Single())
227+
.ToList();
228+
229+
// assert
230+
properties.Should().AllSatisfy(property =>
231+
property.IsDefined(typeof(RequiredMemberAttribute), inherit: false).Should().BeFalse());
232+
attributes.Select(attribute => attribute.GroupId).Distinct().Should().ContainSingle();
233+
attributes.Should().AllSatisfy(attribute => attribute.IsRequired.Should().BeTrue());
234+
attributes.Select(attribute => attribute.ArmId).Distinct().Should().HaveCount(propertyNames.Length);
235+
}
236+
237+
[Test]
238+
public void Should_mark_optional_tpeg_sub_reason_choice_group_as_not_required()
239+
{
240+
// arrange
241+
var propertyNames = new[]
242+
{
243+
nameof(PtSituationBodyGroupSecondaryReasonsReason.MiscellaneousSubReason),
244+
nameof(PtSituationBodyGroupSecondaryReasonsReason.PersonnelSubReason),
245+
nameof(PtSituationBodyGroupSecondaryReasonsReason.EquipmentSubReason),
246+
nameof(PtSituationBodyGroupSecondaryReasonsReason.EnvironmentSubReason),
247+
};
248+
249+
// act
250+
var attributes = propertyNames
251+
.Select(name => typeof(PtSituationBodyGroupSecondaryReasonsReason).GetProperty(name)!)
252+
.Select(property => property.GetCustomAttributes<XmlChoiceGroupAttribute>().Single())
253+
.ToList();
254+
255+
// assert
256+
attributes.Select(attribute => attribute.GroupId).Distinct().Should().ContainSingle();
257+
attributes.Should().AllSatisfy(attribute => attribute.IsRequired.Should().BeFalse());
258+
}
259+
260+
[Test]
261+
public void Should_keep_outer_and_inner_memberships_for_nested_service_delivery_choice()
262+
{
263+
// arrange
264+
var included = GetChoiceGroupAttributes<ServiceDeliveryBodyStructure>(
265+
nameof(ServiceDeliveryBodyStructure.IncludedSituationExchangeDelivery));
266+
var production = GetChoiceGroupAttributes<ServiceDeliveryBodyStructure>(
267+
nameof(ServiceDeliveryBodyStructure.ProductionTimetableDelivery));
268+
var estimated = GetChoiceGroupAttributes<ServiceDeliveryBodyStructure>(
269+
nameof(ServiceDeliveryBodyStructure.EstimatedTimetableDelivery));
270+
var situationExchange = GetChoiceGroupAttributes<ServiceDeliveryBodyStructure>(
271+
nameof(ServiceDeliveryBodyStructure.SituationExchangeDelivery));
272+
273+
// act
274+
var outerGroupId = included.Single().GroupId;
275+
var productionOuter = production.Single(attribute => attribute.GroupId == outerGroupId);
276+
var productionInner = production.Single(attribute => attribute.GroupId != outerGroupId);
277+
var estimatedInner = estimated.Single(attribute => attribute.GroupId != outerGroupId);
278+
279+
// assert
280+
production.Should().HaveCount(2);
281+
estimated.Should().HaveCount(2);
282+
situationExchange.Should().ContainSingle();
283+
productionOuter.ArmId.Should().Be(included.Single().ArmId);
284+
situationExchange.Single().GroupId.Should().Be(outerGroupId);
285+
situationExchange.Single().ArmId.Should().NotBe(included.Single().ArmId);
286+
estimatedInner.GroupId.Should().Be(productionInner.GroupId);
287+
estimatedInner.ArmId.Should().NotBe(productionInner.ArmId);
288+
included.Concat(production).Concat(estimated).Concat(situationExchange).Should().AllSatisfy(attribute =>
289+
attribute.IsRequired.Should().BeTrue());
187290
}
188291
}

0 commit comments

Comments
 (0)