@@ -602,6 +602,128 @@ public void CreateNavigationPropertyPathItemAddsCustomAttributeValuesToPathExten
602602 Assert . Equal ( "true" , isHiddenValue ) ;
603603 }
604604
605+ [ Theory ]
606+ [ InlineData ( false , new string [ ] { "get" , "patch" , "delete" } ) ]
607+ [ InlineData ( true , new string [ ] { "get" , "put" , "delete" } ) ]
608+ public void CreateSingleNavigationPropertyPathItemUsesHttpPutForUpdateWhenSettingIsEnabled ( bool useHttpPutForUpdate , string [ ] expected )
609+ {
610+ // Arrange
611+ IEdmModel model = GetEdmModel ( "" ) ;
612+ OpenApiConvertSettings settings = new OpenApiConvertSettings
613+ {
614+ UseHttpPutForUpdate = useHttpPutForUpdate
615+ } ;
616+ ODataContext context = new ODataContext ( model , settings ) ;
617+ IEdmEntitySet entitySet = model . EntityContainer . FindEntitySet ( "Customers" ) ;
618+ Assert . NotNull ( entitySet ) ; // guard
619+ IEdmEntityType entityType = entitySet . EntityType ;
620+
621+ IEdmNavigationProperty property = entityType . DeclaredNavigationProperties ( )
622+ . FirstOrDefault ( c => c . ContainsTarget == true && c . TargetMultiplicity ( ) != EdmMultiplicity . Many ) ;
623+ Assert . NotNull ( property ) ;
624+
625+ ODataPath path = new ODataPath ( new ODataNavigationSourceSegment ( entitySet ) ,
626+ new ODataKeySegment ( entityType ) ,
627+ new ODataNavigationPropertySegment ( property ) ) ;
628+
629+ // Act
630+ var pathItem = _pathItemHandler . CreatePathItem ( context , path ) ;
631+
632+ // Assert
633+ Assert . NotNull ( pathItem ) ;
634+ Assert . NotNull ( pathItem . Operations ) ;
635+ Assert . NotEmpty ( pathItem . Operations ) ;
636+ Assert . Equal ( expected , pathItem . Operations . Select ( o => o . Key . ToString ( ) . ToLowerInvariant ( ) ) ) ;
637+ }
638+
639+ [ Theory ]
640+ [ InlineData ( false , new string [ ] { "get" , "patch" , "delete" } ) ]
641+ [ InlineData ( true , new string [ ] { "get" , "put" , "delete" } ) ]
642+ public void CreateCollectionNavigationPropertyPathItemUsesHttpPutForUpdateWhenSettingIsEnabled ( bool useHttpPutForUpdate , string [ ] expected )
643+ {
644+ // Arrange
645+ IEdmModel model = GetEdmModel ( "" ) ;
646+ OpenApiConvertSettings settings = new OpenApiConvertSettings
647+ {
648+ UseHttpPutForUpdate = useHttpPutForUpdate
649+ } ;
650+ ODataContext context = new ODataContext ( model , settings ) ;
651+ IEdmEntitySet entitySet = model . EntityContainer . FindEntitySet ( "Customers" ) ;
652+ Assert . NotNull ( entitySet ) ; // guard
653+ IEdmEntityType entityType = entitySet . EntityType ;
654+
655+ IEdmNavigationProperty property = entityType . DeclaredNavigationProperties ( )
656+ . FirstOrDefault ( c => c . ContainsTarget == true && c . TargetMultiplicity ( ) == EdmMultiplicity . Many ) ;
657+ Assert . NotNull ( property ) ;
658+
659+ ODataPath path = new ODataPath ( new ODataNavigationSourceSegment ( entitySet ) ,
660+ new ODataKeySegment ( entityType ) ,
661+ new ODataNavigationPropertySegment ( property ) ,
662+ new ODataKeySegment ( property . ToEntityType ( ) ) ) ;
663+
664+ // Act
665+ var pathItem = _pathItemHandler . CreatePathItem ( context , path ) ;
666+
667+ // Assert
668+ Assert . NotNull ( pathItem ) ;
669+ Assert . NotNull ( pathItem . Operations ) ;
670+ Assert . NotEmpty ( pathItem . Operations ) ;
671+ Assert . Equal ( expected , pathItem . Operations . Select ( o => o . Key . ToString ( ) . ToLowerInvariant ( ) ) ) ;
672+ }
673+
674+ [ Fact ]
675+ public void CreateNavigationPropertyPathItemPrefersUpdateMethodAnnotationOverUseHttpPutForUpdateSetting ( )
676+ {
677+ // Arrange - annotation specifies PUT explicitly, setting is disabled (default PATCH)
678+ string annotation = @"
679+ <Annotation Term=""Org.OData.Capabilities.V1.NavigationRestrictions"">
680+ <Record>
681+ <PropertyValue Property=""RestrictedProperties"" >
682+ <Collection>
683+ <Record>
684+ <PropertyValue Property=""NavigationProperty"" NavigationPropertyPath=""ContainedMyOrder"" />
685+ <PropertyValue Property=""UpdateRestrictions"" >
686+ <Record>
687+ <PropertyValue Property=""UpdateMethod"">
688+ <EnumMember>Org.OData.Capabilities.V1.HttpMethod/PUT</EnumMember>
689+ </PropertyValue>
690+ </Record>
691+ </PropertyValue>
692+ </Record>
693+ </Collection>
694+ </PropertyValue>
695+ </Record>
696+ </Annotation>" ;
697+
698+ IEdmModel model = GetEdmModel ( annotation ) ;
699+ OpenApiConvertSettings settings = new OpenApiConvertSettings
700+ {
701+ UseHttpPutForUpdate = false // Setting says use PATCH (default)
702+ } ;
703+ ODataContext context = new ODataContext ( model , settings ) ;
704+ IEdmEntitySet entitySet = model . EntityContainer . FindEntitySet ( "Customers" ) ;
705+ Assert . NotNull ( entitySet ) ; // guard
706+ IEdmEntityType entityType = entitySet . EntityType ;
707+
708+ IEdmNavigationProperty property = entityType . DeclaredNavigationProperties ( )
709+ . FirstOrDefault ( c => c . ContainsTarget == true && c . Name == "ContainedMyOrder" ) ;
710+ Assert . NotNull ( property ) ;
711+
712+ ODataPath path = new ODataPath ( new ODataNavigationSourceSegment ( entitySet ) ,
713+ new ODataKeySegment ( entityType ) ,
714+ new ODataNavigationPropertySegment ( property ) ) ;
715+
716+ // Act
717+ var pathItem = _pathItemHandler . CreatePathItem ( context , path ) ;
718+
719+ // Assert
720+ Assert . NotNull ( pathItem ) ;
721+ Assert . NotNull ( pathItem . Operations ) ;
722+ Assert . NotEmpty ( pathItem . Operations ) ;
723+ // Should use PUT from annotation, not PATCH from setting
724+ Assert . Equal ( new string [ ] { "get" , "put" , "delete" } , pathItem . Operations . Select ( o => o . Key . ToString ( ) . ToLowerInvariant ( ) ) ) ;
725+ }
726+
605727 public static IEdmModel GetEdmModel ( string annotation , string annotation2 = "" )
606728 {
607729 const string template = @"<edmx:Edmx Version=""4.0"" xmlns:edmx=""http://docs.oasis-open.org/odata/ns/edmx"" xmlns:ags=""http://aggregator.microsoft.com/internal"">
0 commit comments