11using System . Reflection ;
2+ using System . Runtime . CompilerServices ;
23using AwesomeAssertions ;
34using Spillgebees . SIRI . Models . V2_2 ;
45using Spillgebees . SIRI . Models . V2_2 . SIRI ;
@@ -12,9 +13,22 @@ namespace Spillgebees.SIRI.Models.Tests;
1213/// </summary>
1314public 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