refactor for the capabilities and modify the test cases

This commit is contained in:
Sam Xu 2018-08-23 17:27:14 -07:00
parent 91f8fb371a
commit 13ca340cc0
54 changed files with 1570 additions and 1265 deletions

View file

@ -3,8 +3,6 @@
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using Microsoft.OData.Edm;
namespace Microsoft.OpenApi.OData.Capabilities
{
/// <summary>
@ -13,18 +11,8 @@ namespace Microsoft.OpenApi.OData.Capabilities
internal class BatchSupported : SupportedRestrictions
{
/// <summary>
/// The Term type name.
/// The Term type kind.
/// </summary>
public override string QualifiedName => CapabilitiesConstants.BatchSupported;
/// <summary>
/// Initializes a new instance of <see cref="BatchSupported"/> class.
/// </summary>
/// <param name="model">The Edm model.</param>
/// <param name="target">The annotation target <see cref="IEdmEntityContainer"/>.</param>
public BatchSupported(IEdmModel model, IEdmEntityContainer target)
: base(model, target)
{
}
public override CapabilitesTermKind Kind => CapabilitesTermKind.BatchSupported;
}
}

View file

@ -0,0 +1,318 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Vocabularies;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Properties;
namespace Microsoft.OpenApi.OData.Capabilities
{
/// <summary>
/// The class provides the functionality for the capabilities annotation.
/// </summary>
internal static class CapabilitiesExtensions
{
private static IDictionary<IEdmVocabularyAnnotatable, IDictionary<CapabilitesTermKind, ICapablitiesRestrictions>> _capabilitesRestrictions;
private static IEdmModel _savedModel = null;
private static object _objectLock = new object();
/// <summary>
/// Gets Org.OData.Capabilities.V1.SearchRestrictions.
/// </summary>
/// <param name="model">The Edm model.</param>
/// <param name="target">The target.</param>
/// <returns>The Org.OData.Capabilities.V1.SearchRestrictions or null.</returns>
public static SearchRestrictions GetSearchRestrictions(this IEdmModel model, IEdmVocabularyAnnotatable target)
{
return model.GetCapabilities(target, CapabilitesTermKind.SearchRestrictions) as SearchRestrictions;
}
/// <summary>
/// Gets Org.OData.Capabilities.V1.FilterRestrictions.
/// </summary>
/// <param name="model">The Edm model.</param>
/// <param name="target">The target.</param>
/// <returns>The Org.OData.Capabilities.V1.FilterRestrictions or null.</returns>
public static FilterRestrictions GetFilterRestrictions(this IEdmModel model, IEdmVocabularyAnnotatable target)
{
return model.GetCapabilities(target, CapabilitesTermKind.FilterRestrictions) as FilterRestrictions;
}
/// <summary>
/// Gets Org.OData.Capabilities.V1.NavigationRestrictions.
/// </summary>
/// <param name="model">The Edm model.</param>
/// <param name="target">The target.</param>
/// <returns>The Org.OData.Capabilities.V1.NavigationRestrictions or null.</returns>
public static NavigationRestrictions GetNavigationRestrictions(this IEdmModel model, IEdmVocabularyAnnotatable target)
{
return model.GetCapabilities(target, CapabilitesTermKind.NavigationRestrictions) as NavigationRestrictions;
}
/// <summary>
/// Gets Org.OData.Capabilities.V1.ExpandRestrictions.
/// </summary>
/// <param name="model">The Edm model.</param>
/// <param name="target">The target.</param>
/// <returns>The Org.OData.Capabilities.V1.ExpandRestrictions or null.</returns>
public static ExpandRestrictions GetExpandRestrictions(this IEdmModel model, IEdmVocabularyAnnotatable target)
{
return model.GetCapabilities(target, CapabilitesTermKind.ExpandRestrictions) as ExpandRestrictions;
}
/// <summary>
/// Gets Org.OData.Capabilities.V1.DeleteRestrictions.
/// </summary>
/// <param name="model">The Edm model.</param>
/// <param name="target">The target.</param>
/// <returns>The Org.OData.Capabilities.V1.DeleteRestrictions or null.</returns>
public static DeleteRestrictions GetDeleteRestrictions(this IEdmModel model, IEdmVocabularyAnnotatable target)
{
return model.GetCapabilities(target, CapabilitesTermKind.DeleteRestrictions) as DeleteRestrictions;
}
/// <summary>
/// Gets Org.OData.Capabilities.V1.UpdateRestrictions.
/// </summary>
/// <param name="model">The Edm model.</param>
/// <param name="target">The target.</param>
/// <returns>The Org.OData.Capabilities.V1.UpdateRestrictions or null.</returns>
public static UpdateRestrictions GetUpdateRestrictions(this IEdmModel model, IEdmVocabularyAnnotatable target)
{
return model.GetCapabilities(target, CapabilitesTermKind.UpdateRestrictions) as UpdateRestrictions;
}
/// <summary>
/// Gets Org.OData.Capabilities.V1.InsertRestrictions.
/// </summary>
/// <param name="model">The Edm model.</param>
/// <param name="target">The target.</param>
/// <returns>The Org.OData.Capabilities.V1.InsertRestrictions or null.</returns>
public static InsertRestrictions GetInsertRestrictions(this IEdmModel model, IEdmVocabularyAnnotatable target)
{
return model.GetCapabilities(target, CapabilitesTermKind.InsertRestrictions) as InsertRestrictions;
}
/// <summary>
/// Gets Org.OData.Capabilities.V1.SortRestrictions.
/// </summary>
/// <param name="model">The Edm model.</param>
/// <param name="target">The target.</param>
/// <returns>The Org.OData.Capabilities.V1.SortRestrictions or null.</returns>
public static SortRestrictions GetSortRestrictions(this IEdmModel model, IEdmVocabularyAnnotatable target)
{
return model.GetCapabilities(target, CapabilitesTermKind.SortRestrictions) as SortRestrictions;
}
/// <summary>
/// Gets Org.OData.Capabilities.V1.CountRestrictions.
/// </summary>
/// <param name="model">The Edm model.</param>
/// <param name="target">The target.</param>
/// <returns>The Org.OData.Capabilities.V1.CountRestrictions or null.</returns>
public static CountRestrictions GetCountRestrictions(this IEdmModel model, IEdmVocabularyAnnotatable target)
{
return model.GetCapabilities(target, CapabilitesTermKind.CountRestrictions) as CountRestrictions;
}
/// <summary>
/// Gets Org.OData.Capabilities.V1.BatchSupported.
/// </summary>
/// <param name="model">The Edm model.</param>
/// <param name="target">The target.</param>
/// <returns>The Org.OData.Capabilities.V1.BatchSupported or null.</returns>
public static BatchSupported GetBatchSupported(this IEdmModel model, IEdmVocabularyAnnotatable target)
{
return model.GetCapabilities(target, CapabilitesTermKind.BatchSupported) as BatchSupported;
}
/// <summary>
/// Gets Org.OData.Capabilities.V1.SkipSupported.
/// </summary>
/// <param name="model">The Edm model.</param>
/// <param name="target">The target.</param>
/// <returns>The Org.OData.Capabilities.V1.SkipSupported or null.</returns>
public static SkipSupported GetSkipSupported(this IEdmModel model, IEdmVocabularyAnnotatable target)
{
return model.GetCapabilities(target, CapabilitesTermKind.SkipSupported) as SkipSupported;
}
/// <summary>
/// Gets Org.OData.Capabilities.V1.TopSupported.
/// </summary>
/// <param name="model">The Edm model.</param>
/// <param name="target">The target.</param>
/// <returns>The Org.OData.Capabilities.V1.TopSupported or null.</returns>
public static TopSupported GetTopSupported(this IEdmModel model, IEdmVocabularyAnnotatable target)
{
return model.GetCapabilities(target, CapabilitesTermKind.TopSupported) as TopSupported;
}
/// <summary>
/// Gets Org.OData.Capabilities.V1.KeyAsSegmentSupported.
/// </summary>
/// <param name="model">The Edm model.</param>
/// <param name="target">The target.</param>
/// <returns>The Org.OData.Capabilities.V1.KeyAsSegmentSupported or null.</returns>
public static KeyAsSegmentSupported GetKeyAsSegmentSupported(this IEdmModel model, IEdmVocabularyAnnotatable target)
{
return model.GetCapabilities(target, CapabilitesTermKind.KeyAsSegmentSupported) as KeyAsSegmentSupported;
}
/// <summary>
/// Gets Org.OData.Capabilities.V1.IndexableByKey.
/// </summary>
/// <param name="model">The Edm model.</param>
/// <param name="target">The target.</param>
/// <returns>The Org.OData.Capabilities.V1.IndexableByKey or null.</returns>
public static IndexableByKey GetIndexableByKey(this IEdmModel model, IEdmVocabularyAnnotatable target)
{
return model.GetCapabilities(target, CapabilitesTermKind.IndexableByKey) as IndexableByKey;
}
/// <summary>
/// Gets the capablities from the <see cref="IEdmModel"/> for the given <see cref="IEdmVocabularyAnnotatable"/>.
/// </summary>
/// <param name="model">The Edm model.</param>
/// <param name="target">The target.</param>
/// <param name="kind">Thye Capabilites kind.</param>
/// <returns>The capabilities restrictions or null.</returns>
public static ICapablitiesRestrictions GetCapabilities(this IEdmModel model, IEdmVocabularyAnnotatable target, CapabilitesTermKind kind)
{
Utils.CheckArgumentNull(model, nameof(model));
Utils.CheckArgumentNull(target, nameof(target));
lock (_objectLock)
{
if (!ReferenceEquals(_savedModel, model))
{
if (_capabilitesRestrictions != null)
{
_capabilitesRestrictions.Clear();
}
_savedModel = model;
}
if (_capabilitesRestrictions == null)
{
_capabilitesRestrictions = new Dictionary<IEdmVocabularyAnnotatable, IDictionary<CapabilitesTermKind, ICapablitiesRestrictions>>();
}
ICapablitiesRestrictions restriction;
if (_capabilitesRestrictions.TryGetValue(target, out IDictionary<CapabilitesTermKind, ICapablitiesRestrictions> value))
{
// Here means we visited target before and we are sure that the value is not null.
if (value.TryGetValue(kind, out restriction))
{
return restriction;
}
else
{
restriction = CreateCapabilitesRestrictions(model, target, kind);
value[kind] = restriction;
return restriction;
}
}
// It's first time to query this target, create new dictionary and restriction.
value = new Dictionary<CapabilitesTermKind, ICapablitiesRestrictions>();
_capabilitesRestrictions[target] = value;
restriction = CreateCapabilitesRestrictions(model, target, kind);
value[kind] = restriction;
return restriction;
}
}
private static ICapablitiesRestrictions CreateCapabilitesRestrictions(this IEdmModel model, IEdmVocabularyAnnotatable target, CapabilitesTermKind kind)
{
Debug.Assert(model != null);
Debug.Assert(target != null);
ICapablitiesRestrictions capabilitiesRestrictions = null;
switch(kind)
{
case CapabilitesTermKind.DeleteRestrictions: // DeleteRestrictions
capabilitiesRestrictions = new DeleteRestrictions();
break;
case CapabilitesTermKind.UpdateRestrictions: // UpdateRestrictions
capabilitiesRestrictions = new UpdateRestrictions();
break;
case CapabilitesTermKind.InsertRestrictions: // InsertRestrictions
capabilitiesRestrictions = new InsertRestrictions();
break;
case CapabilitesTermKind.SearchRestrictions: // SearchRestrictions
capabilitiesRestrictions = new SearchRestrictions();
break;
case CapabilitesTermKind.ExpandRestrictions: // ExpandRestrictions
capabilitiesRestrictions = new ExpandRestrictions();
break;
case CapabilitesTermKind.SortRestrictions: // SortRestrictions
capabilitiesRestrictions = new SortRestrictions();
break;
case CapabilitesTermKind.FilterRestrictions: // FilterRestrictions
capabilitiesRestrictions = new FilterRestrictions();
break;
case CapabilitesTermKind.NavigationRestrictions: // NavigationRestrictions
capabilitiesRestrictions = new NavigationRestrictions();
break;
case CapabilitesTermKind.CountRestrictions: // CountRestrictions
capabilitiesRestrictions = new CountRestrictions();
break;
case CapabilitesTermKind.BatchSupported: // BatchSupported
capabilitiesRestrictions = new BatchSupported();
break;
case CapabilitesTermKind.SkipSupported: // SkipSupported
capabilitiesRestrictions = new SkipSupported();
break;
case CapabilitesTermKind.TopSupported: // TopSupported
capabilitiesRestrictions = new TopSupported();
break;
case CapabilitesTermKind.KeyAsSegmentSupported: // KeyAsSegmentSupported
capabilitiesRestrictions = new KeyAsSegmentSupported();
break;
case CapabilitesTermKind.IndexableByKey: // IndexableByKey
capabilitiesRestrictions = new IndexableByKey();
break;
case CapabilitesTermKind.ChangeTracking: // ChangeTracking
case CapabilitesTermKind.CrossJoinSupported: // CrossJoinSupported
case CapabilitesTermKind.CallbackSupported: // CallbackSupported
case CapabilitesTermKind.FilterFunctions: // FilterFunctions
case CapabilitesTermKind.BatchContinueOnErrorSupported: // BatchContinueOnErrorSupported
case CapabilitesTermKind.AsynchronousRequestsSupported: // AsynchronousRequestsSupported
case CapabilitesTermKind.Isolation: // Isolation
case CapabilitesTermKind.AcceptableEncodings: // AcceptableEncodings
case CapabilitesTermKind.SupportedFormats: // SupportedFormats
default:
throw Error.NotSupported(String.Format(SRResource.CapabilitiesKindNotSupported, kind));
}
// load the annotation value
if (!capabilitiesRestrictions.Load(model, target))
{
return null;
}
return capabilitiesRestrictions;
}
}
}

View file

@ -1,31 +0,0 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using Microsoft.OData.Edm;
using Microsoft.OpenApi.OData.Common;
namespace Microsoft.OpenApi.OData.Capabilities
{
internal static class CapabilitiesHelper
{
/// <summary>
/// Gets boolean value for term Org.OData.Core.V1.KeyAsSegmentSupported
/// </summary>
/// <param name="model">The model referenced to.</param>
/// <returns>Boolean for term Org.OData.Core.V1.KeyAsSegmentSupported</returns>
public static bool GetKeyAsSegmentSupported(this IEdmModel model)
{
Utils.CheckArgumentNull(model, nameof(model));
if (model.EntityContainer == null)
{
return false;
}
KeyAsSegmentSupported keyAsSegment = new KeyAsSegmentSupported(model, model.EntityContainer);
return keyAsSegment.Supported ?? false;
}
}
}

View file

@ -13,60 +13,44 @@ namespace Microsoft.OpenApi.OData.Capabilities
/// <summary>
/// The base class of Capabilities
/// </summary>
internal abstract class CapabilitiesRestrictions
internal abstract class CapabilitiesRestrictions : ICapablitiesRestrictions
{
/// <summary>
/// Gets the <see cref="IEdmModel"/>.
/// The Capablities Kind.
/// </summary>
public IEdmModel Model { get; }
public abstract CapabilitesTermKind Kind { get; }
/// <summary>
/// Gets the <see cref="IEdmVocabularyAnnotatable"/>.
/// </summary>
public IEdmVocabularyAnnotatable Target { get; }
/// <summary>
/// The Term qualified name.
/// </summary>
public virtual string QualifiedName { get; }
/// <summary>
/// Initializes a new instance of <see cref="CapabilitiesRestrictions"/> class.
/// Load the annotation value.
/// </summary>
/// <param name="model">The Edm model.</param>
/// <param name="target">The Edm vocabulary annotatable.</param>
public CapabilitiesRestrictions(IEdmModel model, IEdmVocabularyAnnotatable target)
/// <param name="target">The target.</param>
public virtual bool Load(IEdmModel model, IEdmVocabularyAnnotatable target)
{
Utils.CheckArgumentNull(model, nameof(model));
Utils.CheckArgumentNull(target, nameof(target));
Model = model;
Target = target;
Initialize();
}
protected void Initialize()
{
IEdmVocabularyAnnotation annotation = Model.GetVocabularyAnnotation(Target, QualifiedName);
string termQualifiedName = CapabilitiesConstants.Namespace + "." + Kind.ToString();
IEdmVocabularyAnnotation annotation = model.GetVocabularyAnnotation(target, termQualifiedName);
if (annotation == null)
{
IEdmNavigationSource navigationSource = Target as IEdmNavigationSource;
IEdmNavigationSource navigationSource = target as IEdmNavigationSource;
// if not, search the entity type.
if (navigationSource != null)
{
IEdmEntityType entityType = navigationSource.EntityType();
annotation = Model.GetVocabularyAnnotation(entityType, QualifiedName);
annotation = model.GetVocabularyAnnotation(entityType, termQualifiedName);
}
}
Initialize(annotation);
return Initialize(annotation);
}
/// <summary>
/// Initialize the capabilities with the vocabulary annotation.
/// </summary>
/// <param name="annotation">The input vocabulary annotation.</param>
protected abstract void Initialize(IEdmVocabularyAnnotation annotation);
protected abstract bool Initialize(IEdmVocabularyAnnotation annotation);
}
}

View file

@ -0,0 +1,128 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
namespace Microsoft.OpenApi.OData.Capabilities
{
/// <summary>
/// The Enum kind for Capabiliites annotation
/// </summary>
internal enum CapabilitesTermKind
{
/// <summary>
/// Media types of supported formats, including format parameters
/// </summary>
SupportedFormats,
/// <summary>
/// List of acceptable compression methods for ($batch) requests, e.g. gzip
/// </summary>
AcceptableEncodings,
/// <summary>
/// Supports key values according to OData URL conventions
/// </summary>
IndexableByKey,
/// <summary>
/// Supported odata.isolation levels
/// </summary>
Isolation,
/// <summary>
/// Supports key as segment
/// </summary>
KeyAsSegmentSupported,
/// <summary>
/// Supports $top
/// </summary>
TopSupported,
/// <summary>
/// Supports $skip
/// </summary>
SkipSupported,
/// <summary>
/// Service supports the asynchronous request preference
/// </summary>
AsynchronousRequestsSupported,
/// <summary>
/// Supports $batch requests
/// </summary>
BatchSupported,
/// <summary>
/// Service supports the continue on error preference
/// </summary>
BatchContinueOnErrorSupported,
/// <summary>
/// List of functions supported in $filter
/// </summary>
FilterFunctions,
/// <summary>
/// Supports callbacks for the specified protocols
/// </summary>
CallbackSupported,
/// <summary>
/// Supports cross joins for the entity sets in this container
/// </summary>
CrossJoinSupported,
/// <summary>
/// Change tracking capabilities of this service or entity set
/// </summary>
ChangeTracking,
/// <summary>
/// Restrictions on /$count path suffix and $count=true system query option
/// </summary>
CountRestrictions,
/// <summary>
/// Restrictions on navigating properties according to OData URL conventions
/// </summary>
NavigationRestrictions,
/// <summary>
/// Restrictions on $filter expressions
/// </summary>
FilterRestrictions,
/// <summary>
/// Restrictions on $orderby expressions
/// </summary>
SortRestrictions,
/// <summary>
/// Restrictions on $expand expressions
/// </summary>
ExpandRestrictions,
/// <summary>
/// Restrictions on $search expressions
/// </summary>
SearchRestrictions,
/// <summary>
/// Restrictions on insert operations
/// </summary>
InsertRestrictions,
/// <summary>
/// Restrictions on update operations
/// </summary>
UpdateRestrictions,
/// <summary>
/// Restrictions on delete operations
/// </summary>
DeleteRestrictions,
}
}

View file

@ -16,9 +16,9 @@ namespace Microsoft.OpenApi.OData.Capabilities
internal class CountRestrictions : CapabilitiesRestrictions
{
/// <summary>
/// The Term type name.
/// The Term type kind.
/// </summary>
public override string QualifiedName => CapabilitiesConstants.CountRestrictions;
public override CapabilitesTermKind Kind => CapabilitesTermKind.CountRestrictions;
/// <summary>
/// Gets the Countable value.
@ -35,16 +35,6 @@ namespace Microsoft.OpenApi.OData.Capabilities
/// </summary>
public IList<string> NonCountableNavigationProperties { get; private set; }
/// <summary>
/// Initializes a new instance of <see cref="CountRestrictions"/> class.
/// </summary>
/// <param name="model">The Edm model.</param>
/// <param name="target">The Edm annotation target.</param>
public CountRestrictions(IEdmModel model, IEdmVocabularyAnnotatable target)
: base(model, target)
{
}
/// <summary>
/// Test the target supports count.
/// </summary>
@ -52,36 +42,34 @@ namespace Microsoft.OpenApi.OData.Capabilities
public bool IsCountable => Countable == null || Countable.Value;
/// <summary>
/// Test the input property which do not allow /$count segments.
/// Test the input property path which do not allow /$count segments.
/// </summary>
/// <param name="property">The input property.</param>
/// <param name="propertyPath">The input property path. "property1/property2"</param>
/// <returns>True/False.</returns>
public bool IsNonCountableProperty(IEdmProperty property)
public bool IsNonCountableProperty(string propertyPath)
{
return NonCountableProperties != null ?
NonCountableProperties.Any(a => a == property.Name) :
false;
return NonCountableProperties != null ? NonCountableProperties.Any(a => a == propertyPath) : false;
}
/// <summary>
/// Test the input navigation property which do not allow /$count segments.
/// </summary>
/// <param name="property">The input navigation property.</param>
/// <param name="navigationPropertyPath">The input navigation property path.</param>
/// <returns>True/False.</returns>
public bool IsNonCountableNavigationProperty(IEdmNavigationProperty property)
public bool IsNonCountableNavigationProperty(string navigationPropertyPath)
{
return NonCountableNavigationProperties != null ?
NonCountableNavigationProperties.Any(a => a == property.Name) :
NonCountableNavigationProperties.Any(a => a == navigationPropertyPath) :
false;
}
protected override void Initialize(IEdmVocabularyAnnotation annotation)
protected override bool Initialize(IEdmVocabularyAnnotation annotation)
{
if (annotation == null ||
annotation.Value == null ||
annotation.Value.ExpressionKind != EdmExpressionKind.Record)
{
return;
return false;
}
IEdmRecordExpression record = (IEdmRecordExpression)annotation.Value;
@ -94,6 +82,8 @@ namespace Microsoft.OpenApi.OData.Capabilities
// NonCountableNavigationProperties
NonCountableNavigationProperties = record.GetCollectionPropertyPath("NonCountableNavigationProperties");
return true;
}
}
}

View file

@ -16,9 +16,9 @@ namespace Microsoft.OpenApi.OData.Capabilities
internal class DeleteRestrictions : CapabilitiesRestrictions
{
/// <summary>
/// The Term type name.
/// The Term type kind.
/// </summary>
public override string QualifiedName => CapabilitiesConstants.DeleteRestrictions;
public override CapabilitesTermKind Kind => CapabilitesTermKind.DeleteRestrictions;
/// <summary>
/// Gets the Deletable value.
@ -30,16 +30,6 @@ namespace Microsoft.OpenApi.OData.Capabilities
/// </summary>
public IList<string> NonDeletableNavigationProperties { get; private set; }
/// <summary>
/// Initializes a new instance of <see cref="DeleteRestrictions"/> class.
/// </summary>
/// <param name="model">The Edm model.</param>
/// <param name="target">The Edm annotation target.</param>
public DeleteRestrictions(IEdmModel model, IEdmVocabularyAnnotatable target)
: base(model, target)
{
}
/// <summary>
/// Test the target supports delete.
/// </summary>
@ -49,22 +39,22 @@ namespace Microsoft.OpenApi.OData.Capabilities
/// <summary>
/// Test the input navigation property do not allow DeleteLink requests.
/// </summary>
/// <param name="property">The input property.</param>
/// <param name="navigationPropertyPath">The input navigation property path.</param>
/// <returns>True/False.</returns>
public bool IsNonDeletableNavigationProperty(IEdmNavigationProperty property)
public bool IsNonDeletableNavigationProperty(string navigationPropertyPath)
{
return NonDeletableNavigationProperties != null ?
NonDeletableNavigationProperties.Any(a => a == property.Name) :
NonDeletableNavigationProperties.Any(a => a == navigationPropertyPath) :
false;
}
protected override void Initialize(IEdmVocabularyAnnotation annotation)
protected override bool Initialize(IEdmVocabularyAnnotation annotation)
{
if (annotation == null ||
annotation.Value == null ||
annotation.Value.ExpressionKind != EdmExpressionKind.Record)
{
return;
return false;
}
IEdmRecordExpression record = (IEdmRecordExpression)annotation.Value;
@ -74,6 +64,8 @@ namespace Microsoft.OpenApi.OData.Capabilities
// NonDeletableNavigationProperties
NonDeletableNavigationProperties = record.GetCollectionPropertyPath("NonDeletableNavigationProperties");
return true;
}
}
}

View file

@ -16,9 +16,9 @@ namespace Microsoft.OpenApi.OData.Capabilities
internal class ExpandRestrictions : CapabilitiesRestrictions
{
/// <summary>
/// The Term type name.
/// The Term type kind.
/// </summary>
public override string QualifiedName => CapabilitiesConstants.ExpandRestrictions;
public override CapabilitesTermKind Kind => CapabilitesTermKind.ExpandRestrictions;
/// <summary>
/// Gets the Expandable value.
@ -30,16 +30,6 @@ namespace Microsoft.OpenApi.OData.Capabilities
/// </summary>
public IList<string> NonExpandableProperties { get; private set; }
/// <summary>
/// Initializes a new instance of <see cref="ExpandRestrictions"/> class.
/// </summary>
/// <param name="model">The Edm model.</param>
/// <param name="entityStargetet">The Edm annotation target.</param>
public ExpandRestrictions(IEdmModel model, IEdmVocabularyAnnotatable target)
: base(model, target)
{
}
/// <summary>
/// Test the target supports $expand.
/// </summary>
@ -49,20 +39,20 @@ namespace Microsoft.OpenApi.OData.Capabilities
/// <summary>
/// Test the input property cannot be used in $orderby expressions.
/// </summary>
/// <param name="property">The input navigation property.</param>
/// <param name="navigationPropertyPath">The input navigation property path.</param>
/// <returns>True/False.</returns>
public bool IsNonExpandableProperty(IEdmNavigationProperty property)
public bool IsNonExpandableProperty(string navigationPropertyPath)
{
return NonExpandableProperties != null ? NonExpandableProperties.Any(a => a == property.Name) : false;
return NonExpandableProperties != null ? NonExpandableProperties.Any(a => a == navigationPropertyPath) : false;
}
protected override void Initialize(IEdmVocabularyAnnotation annotation)
protected override bool Initialize(IEdmVocabularyAnnotation annotation)
{
if (annotation == null ||
annotation.Value == null ||
annotation.Value.ExpressionKind != EdmExpressionKind.Record)
{
return;
return false;
}
IEdmRecordExpression record = (IEdmRecordExpression)annotation.Value;
@ -72,6 +62,8 @@ namespace Microsoft.OpenApi.OData.Capabilities
// NonExpandableProperties
NonExpandableProperties = record.GetCollectionPropertyPath("NonExpandableProperties");
return true;
}
}
}

View file

@ -16,9 +16,9 @@ namespace Microsoft.OpenApi.OData.Capabilities
internal class FilterRestrictions : CapabilitiesRestrictions
{
/// <summary>
/// The Term type name.
/// The Term type kind.
/// </summary>
public override string QualifiedName => CapabilitiesConstants.FilterRestrictions;
public override CapabilitesTermKind Kind => CapabilitesTermKind.FilterRestrictions;
/// <summary>
/// Gets the Filterable value.
@ -40,16 +40,6 @@ namespace Microsoft.OpenApi.OData.Capabilities
/// </summary>
public IList<string> NonFilterableProperties { get; private set; }
/// <summary>
/// Initializes a new instance of <see cref="FilterRestrictions"/> class.
/// </summary>
/// <param name="model">The Edm model.</param>
/// <param name="target">The Edm annotation target.</param>
public FilterRestrictions(IEdmModel model, IEdmVocabularyAnnotatable target)
: base(model, target)
{
}
/// <summary>
/// Test the target supports filter.
/// </summary>
@ -59,30 +49,30 @@ namespace Microsoft.OpenApi.OData.Capabilities
/// <summary>
/// Test the input property which must be specified in the $filter clause.
/// </summary>
/// <param name="property">The input property.</param>
/// <param name="propertyPath">The input property path.</param>
/// <returns>True/False.</returns>
public bool IsRequiredProperty(IEdmProperty property)
public bool IsRequiredProperty(string propertyPath)
{
return RequiredProperties != null ? RequiredProperties.Any(a => a == property.Name) : false;
return RequiredProperties != null ? RequiredProperties.Any(a => a == propertyPath) : false;
}
/// <summary>
/// Test the input property which cannot be used in $filter expressions.
/// </summary>
/// <param name="property">The input property.</param>
/// <param name="propertyPath">The input property path.</param>
/// <returns>True/False.</returns>
public bool IsNonFilterableProperty(IEdmProperty property)
public bool IsNonFilterableProperty(string propertyPath)
{
return NonFilterableProperties != null ? NonFilterableProperties.Any(a => a == property.Name) : false;
return NonFilterableProperties != null ? NonFilterableProperties.Any(a => a == propertyPath) : false;
}
protected override void Initialize(IEdmVocabularyAnnotation annotation)
protected override bool Initialize(IEdmVocabularyAnnotation annotation)
{
if (annotation == null ||
annotation.Value == null ||
annotation.Value.ExpressionKind != EdmExpressionKind.Record)
{
return;
return false;
}
IEdmRecordExpression record = (IEdmRecordExpression)annotation.Value;
@ -98,6 +88,8 @@ namespace Microsoft.OpenApi.OData.Capabilities
// NonFilterableProperties
NonFilterableProperties = record.GetCollectionPropertyPath("NonFilterableProperties");
return true;
}
}
}

View file

@ -0,0 +1,17 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Vocabularies;
namespace Microsoft.OpenApi.OData.Capabilities
{
internal interface ICapablitiesRestrictions
{
CapabilitesTermKind Kind { get; }
bool Load(IEdmModel model, IEdmVocabularyAnnotatable target);
}
}

View file

@ -14,18 +14,8 @@ namespace Microsoft.OpenApi.OData.Capabilities
internal class IndexableByKey : SupportedRestrictions
{
/// <summary>
/// The Term type name.
/// The Term type kind.
/// </summary>
public override string QualifiedName => CapabilitiesConstants.IndexableByKey;
/// <summary>
/// Initializes a new instance of <see cref="IndexableByKey"/> class.
/// </summary>
/// <param name="model">The Edm model.</param>
/// <param name="target">The Edm annotation target.</param>
public IndexableByKey(IEdmModel model, IEdmVocabularyAnnotatable target)
: base(model, target)
{
}
public override CapabilitesTermKind Kind => CapabilitesTermKind.IndexableByKey;
}
}

View file

@ -16,9 +16,9 @@ namespace Microsoft.OpenApi.OData.Capabilities
internal class InsertRestrictions : CapabilitiesRestrictions
{
/// <summary>
/// The Term type name.
/// The Term type kind.
/// </summary>
public override string QualifiedName => CapabilitiesConstants.InsertRestrictions;
public override CapabilitesTermKind Kind => CapabilitesTermKind.InsertRestrictions;
/// <summary>
/// Gets the Insertable value.
@ -30,16 +30,6 @@ namespace Microsoft.OpenApi.OData.Capabilities
/// </summary>
public IList<string> NonInsertableNavigationProperties { get; private set; }
/// <summary>
/// Initializes a new instance of <see cref="InsertRestrictions"/> class.
/// </summary>
/// <param name="model">The Edm model.</param>
/// <param name="target">The Edm annotation target.</param>
public InsertRestrictions(IEdmModel model, IEdmVocabularyAnnotatable target)
: base(model, target)
{
}
/// <summary>
/// Test the target supports insert.
/// </summary>
@ -49,22 +39,22 @@ namespace Microsoft.OpenApi.OData.Capabilities
/// <summary>
/// Test the input navigation property do not allow deep insert.
/// </summary>
/// <param name="property">The input property.</param>
/// <param name="navigationPropertyPath">The input navigation property path.</param>
/// <returns>True/False.</returns>
public bool IsNonINsertableNavigationProperty(IEdmNavigationProperty property)
public bool IsNonInsertableNavigationProperty(string navigationPropertyPath)
{
return NonInsertableNavigationProperties != null ?
NonInsertableNavigationProperties.Any(a => a == property.Name) :
NonInsertableNavigationProperties.Any(a => a == navigationPropertyPath) :
false;
}
protected override void Initialize(IEdmVocabularyAnnotation annotation)
protected override bool Initialize(IEdmVocabularyAnnotation annotation)
{
if (annotation == null ||
annotation.Value == null ||
annotation.Value.ExpressionKind != EdmExpressionKind.Record)
{
return;
return false;
}
IEdmRecordExpression record = (IEdmRecordExpression)annotation.Value;
@ -74,6 +64,8 @@ namespace Microsoft.OpenApi.OData.Capabilities
// NonInsertableNavigationProperties
NonInsertableNavigationProperties = record.GetCollectionPropertyPath("NonInsertableNavigationProperties");
return true;
}
}
}

View file

@ -3,8 +3,6 @@
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using Microsoft.OData.Edm;
namespace Microsoft.OpenApi.OData.Capabilities
{
/// <summary>
@ -13,18 +11,8 @@ namespace Microsoft.OpenApi.OData.Capabilities
internal class KeyAsSegmentSupported : SupportedRestrictions
{
/// <summary>
/// The Term type name.
/// The Term type kind.
/// </summary>
public override string QualifiedName => CapabilitiesConstants.KeyAsSegmentSupported;
/// <summary>
/// Initializes a new instance of <see cref="TopSupported"/> class.
/// </summary>
/// <param name="model">The Edm model.</param>
/// <param name="target">The Edm annotation target.</param>
public KeyAsSegmentSupported(IEdmModel model, IEdmEntityContainer target)
: base(model, target)
{
}
public override CapabilitesTermKind Kind => CapabilitesTermKind.KeyAsSegmentSupported;
}
}

View file

@ -55,7 +55,7 @@ namespace Microsoft.OpenApi.OData.Capabilities
/// <summary>
/// The Term type name.
/// </summary>
public override string QualifiedName => CapabilitiesConstants.NavigationRestrictions;
public override CapabilitesTermKind Kind => CapabilitesTermKind.NavigationRestrictions;
/// <summary>
/// Gets the Navigability value.
@ -67,16 +67,6 @@ namespace Microsoft.OpenApi.OData.Capabilities
/// </summary>
public IList<NavigationPropertyRestriction> RestrictedProperties { get; private set; }
/// <summary>
/// Initializes a new instance of <see cref="NavigationRestrictions"/> class.
/// </summary>
/// <param name="model">The Edm model.</param>
/// <param name="target">The Edm annotation target.</param>
public NavigationRestrictions(IEdmModel model, IEdmVocabularyAnnotatable target)
: base(model, target)
{
}
/// <summary>
/// Gets a value indicating the target is navigable or not.
/// </summary>
@ -85,23 +75,23 @@ namespace Microsoft.OpenApi.OData.Capabilities
/// <summary>
/// Test the input navigation property which has navigation restrictions.
/// </summary>
/// <param name="property">The input navigation property.</param>
/// <param name="navigationPropertyPath">The input navigation property path.</param>
/// <returns>True/False.</returns>
public bool IsRestrictedProperty(IEdmNavigationProperty property)
public bool IsRestrictedProperty(string navigationPropertyPath)
{
return RestrictedProperties != null ?
RestrictedProperties.Where(a => a.NavigationProperty == property.Name)
RestrictedProperties.Where(a => a.NavigationProperty == navigationPropertyPath)
.Any(a => a.Navigability != null && a.Navigability.Value == NavigationType.None) :
true;
false;
}
protected override void Initialize(IEdmVocabularyAnnotation annotation)
protected override bool Initialize(IEdmVocabularyAnnotation annotation)
{
if (annotation == null ||
annotation.Value == null ||
annotation.Value.ExpressionKind != EdmExpressionKind.Record)
{
return;
return false;
}
IEdmRecordExpression record = (IEdmRecordExpression)annotation.Value;
@ -111,6 +101,8 @@ namespace Microsoft.OpenApi.OData.Capabilities
// RestrictedProperties
RestrictedProperties = GetRestrictedProperties(record);
return true;
}
private static IList<NavigationPropertyRestriction> GetRestrictedProperties(IEdmRecordExpression record)

View file

@ -53,9 +53,9 @@ namespace Microsoft.OpenApi.OData.Capabilities
internal class SearchRestrictions : CapabilitiesRestrictions
{
/// <summary>
/// The Term type name.
/// The Term type kind.
/// </summary>
public override string QualifiedName => CapabilitiesConstants.SearchRestrictions;
public override CapabilitesTermKind Kind => CapabilitesTermKind.SearchRestrictions;
/// <summary>
/// Gets the Searchable value.
@ -67,29 +67,39 @@ namespace Microsoft.OpenApi.OData.Capabilities
/// </summary>
public SearchExpressions? UnsupportedExpressions { get; private set; }
/// <summary>
/// Initializes a new instance of <see cref="SearchRestrictions"/> class.
/// </summary>
/// <param name="model">The Edm model.</param>
/// <param name="target">The Edm annotation target.</param>
public SearchRestrictions(IEdmModel model, IEdmVocabularyAnnotatable target)
: base(model, target)
{
}
/// <summary>
/// Test the target supports search.
/// </summary>
/// <returns>True/false.</returns>
public bool IsSearchable => Searchable == null || Searchable.Value == true;
protected override void Initialize(IEdmVocabularyAnnotation annotation)
/// <summary>
/// Test the input expression supported or not.
/// </summary>
/// <param name="expression">The input expression</param>
/// <returns>True/false.</returns>
public bool IsUnsupportedExpressions(SearchExpressions expression)
{
if (UnsupportedExpressions == null || UnsupportedExpressions.Value == SearchExpressions.none)
{
return false;
}
if ((UnsupportedExpressions.Value & expression) == expression)
{
return true;
}
return false;
}
protected override bool Initialize(IEdmVocabularyAnnotation annotation)
{
if (annotation == null ||
annotation.Value == null ||
annotation.Value.ExpressionKind != EdmExpressionKind.Record)
{
return;
return false;
}
IEdmRecordExpression record = (IEdmRecordExpression)annotation.Value;
@ -121,6 +131,8 @@ namespace Microsoft.OpenApi.OData.Capabilities
}
}
}
return true;
}
}
}

View file

@ -3,9 +3,6 @@
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Vocabularies;
namespace Microsoft.OpenApi.OData.Capabilities
{
/// <summary>
@ -14,18 +11,8 @@ namespace Microsoft.OpenApi.OData.Capabilities
internal class SkipSupported : SupportedRestrictions
{
/// <summary>
/// The Term type name.
/// The Term type kind.
/// </summary>
public override string QualifiedName => CapabilitiesConstants.SkipSupported;
/// <summary>
/// Initializes a new instance of <see cref="SkipSupported"/> class.
/// </summary>
/// <param name="model">The Edm model.</param>
/// <param name="target">The Edm annotation target.</param>
public SkipSupported(IEdmModel model, IEdmVocabularyAnnotatable target)
: base(model, target)
{
}
public override CapabilitesTermKind Kind => CapabilitesTermKind.SkipSupported;
}
}

View file

@ -18,7 +18,7 @@ namespace Microsoft.OpenApi.OData.Capabilities
/// <summary>
/// The Term type name.
/// </summary>
public override string QualifiedName => CapabilitiesConstants.SortRestrictions;
public override CapabilitesTermKind Kind => CapabilitesTermKind.SortRestrictions;
/// <summary>
/// Gets the Sortable value.
@ -40,16 +40,6 @@ namespace Microsoft.OpenApi.OData.Capabilities
/// </summary>
public IList<string> NonSortableProperties { get; private set; }
/// <summary>
/// Initializes a new instance of <see cref="SortRestrictions"/> class.
/// </summary>
/// <param name="model">The Edm model.</param>
/// <param name="target">The Edm annotation target.</param>
public SortRestrictions(IEdmModel model, IEdmVocabularyAnnotatable target)
: base(model, target)
{
}
/// <summary>
/// Gets a boolean value indicating whether the target supports $orderby.
/// </summary>
@ -58,40 +48,40 @@ namespace Microsoft.OpenApi.OData.Capabilities
/// <summary>
/// Test the input property is Ascending only.
/// </summary>
/// <param name="property">The input property.</param>
/// <param name="propertyPath">The input property path.</param>
/// <returns>True/False.</returns>
public bool IsAscendingOnlyProperty(IEdmProperty property)
public bool IsAscendingOnlyProperty(string propertyPath)
{
return AscendingOnlyProperties != null ? AscendingOnlyProperties.Any(a => a == property.Name) : false;
return AscendingOnlyProperties != null ? AscendingOnlyProperties.Any(a => a == propertyPath) : false;
}
/// <summary>
/// Test the input property is Descending only.
/// </summary>
/// <param name="property">The input property.</param>
/// <param name="propertyPath">The input property path.</param>
/// <returns>True/False.</returns>
public bool IsDescendingOnlyProperty(IEdmProperty property)
public bool IsDescendingOnlyProperty(string propertyPath)
{
return DescendingOnlyProperties != null ? DescendingOnlyProperties.Any(a => a == property.Name) : false;
return DescendingOnlyProperties != null ? DescendingOnlyProperties.Any(a => a == propertyPath) : false;
}
/// <summary>
/// Test the input property cannot be used in $orderby expressions.
/// </summary>
/// <param name="property">The input property.</param>
/// <param name="propertyPath">The input property path.</param>
/// <returns>True/False.</returns>
public bool IsNonSortableProperty(IEdmProperty property)
public bool IsNonSortableProperty(string propertyPath)
{
return NonSortableProperties != null ? NonSortableProperties.Any(a => a == property.Name) : false;
return NonSortableProperties != null ? NonSortableProperties.Any(a => a == propertyPath) : false;
}
protected override void Initialize(IEdmVocabularyAnnotation annotation)
protected override bool Initialize(IEdmVocabularyAnnotation annotation)
{
if (annotation == null ||
annotation.Value == null ||
annotation.Value.ExpressionKind != EdmExpressionKind.Record)
{
return;
return false;
}
IEdmRecordExpression record = (IEdmRecordExpression)annotation.Value;
@ -107,6 +97,8 @@ namespace Microsoft.OpenApi.OData.Capabilities
// NonSortablePropeties
NonSortableProperties = record.GetCollectionPropertyPath("NonSortableProperties");
return true;
}
}
}

View file

@ -18,29 +18,19 @@ namespace Microsoft.OpenApi.OData.Capabilities
/// </summary>
public bool? Supported { get; private set; }
/// <summary>
/// Initializes a new instance of <see cref="SupportedRestrictions"/> class.
/// </summary>
/// <param name="model">The Edm model.</param>
/// <param name="target">The Edm annotation target.</param>
public SupportedRestrictions(IEdmModel model, IEdmVocabularyAnnotatable target)
: base(model, target)
{
}
/// <summary>
/// Test the target supports the corresponding restriction.
/// </summary>
/// <returns>True/false.</returns>
public bool IsSupported => Supported == null || Supported.Value == true;
protected override void Initialize(IEdmVocabularyAnnotation annotation)
protected override bool Initialize(IEdmVocabularyAnnotation annotation)
{
if (annotation == null ||
annotation.Value == null ||
annotation.Value.ExpressionKind != EdmExpressionKind.BooleanConstant)
{
return;
return false;
}
// supported
@ -49,6 +39,8 @@ namespace Microsoft.OpenApi.OData.Capabilities
{
Supported = boolConstant.Value;
}
return true;
}
}
}

View file

@ -3,9 +3,6 @@
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Vocabularies;
namespace Microsoft.OpenApi.OData.Capabilities
{
/// <summary>
@ -14,18 +11,8 @@ namespace Microsoft.OpenApi.OData.Capabilities
internal class TopSupported : SupportedRestrictions
{
/// <summary>
/// The Term type name.
/// The Term type Kind.
/// </summary>
public override string QualifiedName => CapabilitiesConstants.TopSupported;
/// <summary>
/// Initializes a new instance of <see cref="TopSupported"/> class.
/// </summary>
/// <param name="model">The Edm model.</param>
/// <param name="target">The Edm annotation target.</param>
public TopSupported(IEdmModel model, IEdmVocabularyAnnotatable target)
: base(model, target)
{
}
public override CapabilitesTermKind Kind => CapabilitesTermKind.TopSupported;
}
}

View file

@ -16,9 +16,9 @@ namespace Microsoft.OpenApi.OData.Capabilities
internal class UpdateRestrictions : CapabilitiesRestrictions
{
/// <summary>
/// The Term type name.
/// The Term type kind.
/// </summary>
public override string QualifiedName => CapabilitiesConstants.UpdateRestrictions;
public override CapabilitesTermKind Kind => CapabilitesTermKind.UpdateRestrictions;
/// <summary>
/// Gets the Updatable value.
@ -30,41 +30,31 @@ namespace Microsoft.OpenApi.OData.Capabilities
/// </summary>
public IList<string> NonUpdatableNavigationProperties { get; private set; }
/// <summary>
/// Initializes a new instance of <see cref="UpdateRestrictions"/> class.
/// </summary>
/// <param name="model">The Edm model.</param>
/// <param name="target">The Edm annotation target.</param>
public UpdateRestrictions(IEdmModel model, IEdmVocabularyAnnotatable target)
: base(model, target)
{
}
/// <summary>
/// Test the target supports update.
/// </summary>
/// <returns>True/false.</returns>
public bool IsUpdatable => Updatable == null || Updatable.Value == true;
public bool IsUpdatable => Updatable == null || Updatable.Value;
/// <summary>
/// Test the input navigation property do not allow rebinding.
/// </summary>
/// <param name="property">The input property.</param>
/// <param name="navigationPropertyPath">The input navigation property path.</param>
/// <returns>True/False.</returns>
public bool IsNonUpdatableNavigationProperty(IEdmNavigationProperty property)
public bool IsNonUpdatableNavigationProperty(string navigationPropertyPath)
{
return NonUpdatableNavigationProperties != null ?
NonUpdatableNavigationProperties.Any(a => a == property.Name) :
NonUpdatableNavigationProperties.Any(a => a == navigationPropertyPath) :
false;
}
protected override void Initialize(IEdmVocabularyAnnotation annotation)
protected override bool Initialize(IEdmVocabularyAnnotation annotation)
{
if (annotation == null ||
annotation.Value == null ||
annotation.Value.ExpressionKind != EdmExpressionKind.Record)
{
return;
return false;
}
IEdmRecordExpression record = (IEdmRecordExpression)annotation.Value;
@ -74,6 +64,8 @@ namespace Microsoft.OpenApi.OData.Capabilities
// NonUpdatableNavigationProperties
NonUpdatableNavigationProperties = record.GetCollectionPropertyPath("NonUpdatableNavigationProperties");
return true;
}
}
}

View file

@ -53,7 +53,6 @@ namespace Microsoft.OpenApi.OData.Edm
visitor.Visit(model);
IsSpatialTypeUsed = visitor.IsSpatialTypeUsed;
_keyAsSegmentSupported = settings.EnableKeyAsSegment ?? model.GetKeyAsSegmentSupported();
_pathHandler = new ODataPathHandler(this);
@ -61,6 +60,24 @@ namespace Microsoft.OpenApi.OData.Edm
PathItemHanderProvider = new PathItemHandlerProvider();
AuthorizationProvider = new AuthorizationProvider();
if (settings.EnableKeyAsSegment != null)
{
// We have the global setting, use the global setting
_keyAsSegmentSupported = settings.EnableKeyAsSegment.Value;
}
else
{
_keyAsSegmentSupported = false;
if (model.EntityContainer != null)
{
var keyAsSegment = model.GetKeyAsSegmentSupported(model.EntityContainer);
if (keyAsSegment != null)
{
_keyAsSegmentSupported = keyAsSegment.IsSupported;
}
}
}
}
public IPathItemHandlerProvider PathItemHanderProvider { get; }
@ -72,6 +89,8 @@ namespace Microsoft.OpenApi.OData.Edm
/// </summary>
public AuthorizationProvider AuthorizationProvider { get; }
//public CapabilitiesProvider CapabilitiesProvider { get; }
/// <summary>
/// Gets the Edm model.
/// </summary>

View file

@ -154,8 +154,8 @@ namespace Microsoft.OpenApi.OData.Generator
Utils.CheckArgumentNull(context, nameof(context));
Utils.CheckArgumentNull(target, nameof(target));
TopSupported top = new TopSupported(context.Model, target);
if (top.IsSupported)
TopSupported top = context.Model.GetTopSupported(target);
if (top == null || top.IsSupported)
{
return new OpenApiParameter
{
@ -177,8 +177,8 @@ namespace Microsoft.OpenApi.OData.Generator
Utils.CheckArgumentNull(context, nameof(context));
Utils.CheckArgumentNull(target, nameof(target));
SkipSupported skip = new SkipSupported(context.Model, target);
if (skip.IsSupported)
SkipSupported skip = context.Model.GetSkipSupported(target);
if (skip == null || skip.IsSupported)
{
return new OpenApiParameter
{
@ -200,8 +200,8 @@ namespace Microsoft.OpenApi.OData.Generator
Utils.CheckArgumentNull(context, nameof(context));
Utils.CheckArgumentNull(target, nameof(target));
SearchRestrictions search = new SearchRestrictions(context.Model, target);
if (search.IsSearchable)
SearchRestrictions search = context.Model.GetSearchRestrictions(target);
if (search == null || search.IsSearchable)
{
return new OpenApiParameter
{
@ -223,8 +223,8 @@ namespace Microsoft.OpenApi.OData.Generator
Utils.CheckArgumentNull(context, nameof(context));
Utils.CheckArgumentNull(target, nameof(target));
CountRestrictions count = new CountRestrictions(context.Model, target);
if (count.IsCountable)
CountRestrictions count = context.Model.GetCountRestrictions(target);
if (count == null || count.IsCountable)
{
return new OpenApiParameter
{
@ -246,8 +246,8 @@ namespace Microsoft.OpenApi.OData.Generator
Utils.CheckArgumentNull(context, nameof(context));
Utils.CheckArgumentNull(target, nameof(target));
FilterRestrictions filter = new FilterRestrictions(context.Model, target);
if (filter.IsFilterable)
FilterRestrictions filter = context.Model.GetFilterRestrictions(target);
if (filter == null || filter.IsFilterable)
{
return new OpenApiParameter
{
@ -294,8 +294,8 @@ namespace Microsoft.OpenApi.OData.Generator
Utils.CheckArgumentNull(target, nameof(target));
Utils.CheckArgumentNull(entityType, nameof(entityType));
SortRestrictions sort = new SortRestrictions(context.Model, target);
if (sort.Sortable != null && sort.Sortable.Value == false)
SortRestrictions sort = context.Model.GetSortRestrictions(target);
if (sort != null && !sort.IsSortable)
{
return null;
}
@ -303,13 +303,13 @@ namespace Microsoft.OpenApi.OData.Generator
IList<IOpenApiAny> orderByItems = new List<IOpenApiAny>();
foreach (var property in entityType.StructuralProperties())
{
if (sort.IsNonSortableProperty(property))
if (sort != null && sort.IsNonSortableProperty(property.Name))
{
continue;
}
bool isAscOnly = sort.IsAscendingOnlyProperty(property);
bool isDescOnly = sort.IsDescendingOnlyProperty(property);
bool isAscOnly = sort != null ? sort.IsAscendingOnlyProperty(property.Name) : false ;
bool isDescOnly = sort != null ? sort.IsDescendingOnlyProperty(property.Name) : false;
if (isAscOnly || isDescOnly)
{
if (isAscOnly)
@ -382,8 +382,8 @@ namespace Microsoft.OpenApi.OData.Generator
Utils.CheckArgumentNull(target, nameof(target));
Utils.CheckArgumentNull(entityType, nameof(entityType));
NavigationRestrictions navigation = new NavigationRestrictions(context.Model, target);
if (navigation.Navigability != null && navigation.Navigability.Value == NavigationType.None)
NavigationRestrictions navigation = context.Model.GetNavigationRestrictions(target);
if (navigation != null && !navigation.IsNavigable)
{
return null;
}
@ -397,7 +397,7 @@ namespace Microsoft.OpenApi.OData.Generator
foreach (var property in entityType.NavigationProperties())
{
if (navigation.IsRestrictedProperty(property))
if (navigation != null && navigation.IsRestrictedProperty(property.Name))
{
continue;
}
@ -460,8 +460,8 @@ namespace Microsoft.OpenApi.OData.Generator
Utils.CheckArgumentNull(target, nameof(target));
Utils.CheckArgumentNull(entityType, nameof(entityType));
ExpandRestrictions expand = new ExpandRestrictions(context.Model, target);
if (expand.Expandable != null && expand.Expandable.Value == false)
ExpandRestrictions expand = context.Model.GetExpandRestrictions(target);
if (expand != null && !expand.IsExpandable)
{
return null;
}
@ -473,7 +473,7 @@ namespace Microsoft.OpenApi.OData.Generator
foreach (var property in entityType.NavigationProperties())
{
if (expand.IsNonExpandableProperty(property))
if (expand != null && expand.IsNonExpandableProperty(property.Name))
{
continue;
}

View file

@ -19,6 +19,10 @@
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
</PropertyGroup>
<ItemGroup>
<None Remove="Capabilities\CapabilitiesTermKind.cs~RF91fb26a.TMP" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.OData.Edm" Version="7.5.0" />
<PackageReference Include="Microsoft.OpenApi" Version="1.1.0" />

View file

@ -5,6 +5,7 @@
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Capabilities;
using Microsoft.OpenApi.OData.Edm;
namespace Microsoft.OpenApi.OData.PathItem
{
@ -13,23 +14,26 @@ namespace Microsoft.OpenApi.OData.PathItem
/// </summary>
internal class EntityPathItemHandler : EntitySetPathItemHandler
{
/// <inheritdoc/>
protected override ODataPathKind HandleKind { get; } = ODataPathKind.Entity;
/// <inheritdoc/>
protected override void SetOperations(OpenApiPathItem item)
{
IndexableByKey index = new IndexableByKey(Context.Model, EntitySet);
if (index.IsSupported)
IndexableByKey index = Context.Model.GetIndexableByKey(EntitySet);
if (index == null || index.IsSupported)
{
AddOperation(item, OperationType.Get);
}
UpdateRestrictions update = new UpdateRestrictions(Context.Model, EntitySet);
if (update.IsUpdatable)
UpdateRestrictions update = Context.Model.GetUpdateRestrictions(EntitySet);
if (update == null || update.IsUpdatable)
{
AddOperation(item, OperationType.Patch);
}
DeleteRestrictions delete = new DeleteRestrictions(Context.Model, EntitySet);
if (delete.IsDeletable)
DeleteRestrictions delete = Context.Model.GetDeleteRestrictions(EntitySet);
if (delete == null || delete.IsDeletable)
{
AddOperation(item, OperationType.Delete);
}

View file

@ -15,6 +15,9 @@ namespace Microsoft.OpenApi.OData.PathItem
/// </summary>
internal class EntitySetPathItemHandler : PathItemHandler
{
/// <inheritdoc/>
protected override ODataPathKind HandleKind { get; } = ODataPathKind.EntitySet;
/// <summary>
/// Gets the entity set.
/// </summary>
@ -23,14 +26,14 @@ namespace Microsoft.OpenApi.OData.PathItem
/// <inheritdoc/>
protected override void SetOperations(OpenApiPathItem item)
{
NavigationRestrictions navigation = new NavigationRestrictions(Context.Model, EntitySet);
if (navigation.IsNavigable)
NavigationRestrictions navigation = Context.Model.GetNavigationRestrictions(EntitySet);
if (navigation == null || navigation.IsNavigable)
{
AddOperation(item, OperationType.Get);
}
InsertRestrictions insert = new InsertRestrictions(Context.Model, EntitySet);
if (insert.IsInsertable)
InsertRestrictions insert = Context.Model.GetInsertRestrictions(EntitySet);
if (insert == null || insert.IsInsertable)
{
AddOperation(item, OperationType.Post);
}
@ -39,11 +42,11 @@ namespace Microsoft.OpenApi.OData.PathItem
/// <inheritdoc/>
protected override void Initialize(ODataContext context, ODataPath path)
{
base.Initialize(context, path);
// The first segment should be the entity set segment.
ODataNavigationSourceSegment navigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment;
EntitySet = navigationSourceSegment.NavigationSource as IEdmEntitySet;
base.Initialize(context, path);
}
}
}

View file

@ -11,6 +11,7 @@ using Microsoft.OpenApi.OData.Capabilities;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Edm;
using Microsoft.OpenApi.Any;
using Microsoft.OData.Edm.Vocabularies;
namespace Microsoft.OpenApi.OData.PathItem
{
@ -19,6 +20,9 @@ namespace Microsoft.OpenApi.OData.PathItem
/// </summary>
internal class NavigationPropertyPathItemHandler : PathItemHandler
{
/// <inheritdoc/>
protected override ODataPathKind HandleKind { get; } = ODataPathKind.NavigationProperty;
/// <summary>
/// Gets the navigation property.
/// </summary>
@ -37,9 +41,20 @@ namespace Microsoft.OpenApi.OData.PathItem
/// <inheritdoc/>
protected override void SetOperations(OpenApiPathItem item)
{
IEdmEntitySet entitySet = NavigationSource as IEdmEntitySet;
IEdmVocabularyAnnotatable target = entitySet;
if (target == null)
{
target = NavigationSource as IEdmSingleton;
}
// contaiment: Get / (Post - Collection | Patch - Single)
// non-containment: only Get
AddOperation(item, OperationType.Get);
NavigationRestrictions navigation = Context.Model.GetNavigationRestrictions(target);
if (navigation == null || navigation.IsNavigable)
{
AddOperation(item, OperationType.Get);
}
if (NavigationProperty.ContainsTarget)
{
@ -47,16 +62,16 @@ namespace Microsoft.OpenApi.OData.PathItem
{
if (LastSegmentIsKeySegment)
{
UpdateRestrictions update = new UpdateRestrictions(Context.Model, NavigationProperty);
if (update.IsUpdatable)
UpdateRestrictions update = Context.Model.GetUpdateRestrictions(target);
if (update == null || update.IsUpdatable)
{
AddOperation(item, OperationType.Patch);
}
}
else
{
InsertRestrictions insert = new InsertRestrictions(Context.Model, NavigationProperty);
if (insert.IsInsertable)
InsertRestrictions insert = Context.Model.GetInsertRestrictions(target);
if (insert == null || insert.IsInsertable)
{
AddOperation(item, OperationType.Post);
}
@ -64,8 +79,8 @@ namespace Microsoft.OpenApi.OData.PathItem
}
else
{
UpdateRestrictions update = new UpdateRestrictions(Context.Model, NavigationProperty);
if (update.IsUpdatable)
UpdateRestrictions update = Context.Model.GetUpdateRestrictions(target);
if (update == null || update.IsUpdatable)
{
AddOperation(item, OperationType.Patch);
}
@ -76,6 +91,8 @@ namespace Microsoft.OpenApi.OData.PathItem
/// <inheritdoc/>
protected override void Initialize(ODataContext context, ODataPath path)
{
base.Initialize(context, path);
ODataNavigationSourceSegment navigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment;
NavigationSource = navigationSourceSegment.NavigationSource;
@ -86,8 +103,6 @@ namespace Microsoft.OpenApi.OData.PathItem
npSegment = path.Segments[path.Count - 2] as ODataNavigationPropertySegment;
}
NavigationProperty = npSegment.NavigationProperty;
base.Initialize(context, path);
}
/// <inheritdoc/>

View file

@ -14,6 +14,9 @@ namespace Microsoft.OpenApi.OData.PathItem
/// </summary>
internal class OperationImportPathItemHandler : PathItemHandler
{
/// <inheritdoc/>
protected override ODataPathKind HandleKind { get; } = ODataPathKind.OperationImport;
/// <summary>
/// Gets the operation import.
/// </summary>
@ -43,10 +46,10 @@ namespace Microsoft.OpenApi.OData.PathItem
/// <inheritdoc/>
protected override void Initialize(ODataContext context, ODataPath path)
{
base.Initialize(context, path);
ODataOperationImportSegment operationImportSegment = path.FirstSegment as ODataOperationImportSegment;
EdmOperationImport = operationImportSegment.OperationImport;
base.Initialize(context, path);
}
}
}

View file

@ -18,6 +18,9 @@ namespace Microsoft.OpenApi.OData.PathItem
/// </summary>
internal class OperationPathItemHandler : PathItemHandler
{
/// <inheritdoc/>
protected override ODataPathKind HandleKind { get; } = ODataPathKind.Operation;
/// <summary>
/// Gets the Edm operation.
/// </summary>
@ -43,9 +46,10 @@ namespace Microsoft.OpenApi.OData.PathItem
/// <inheritdoc/>
protected override void Initialize(ODataContext context, ODataPath path)
{
base.Initialize(context, path);
ODataOperationSegment operationSegment = path.LastSegment as ODataOperationSegment;
EdmOperation = operationSegment.Operation;
base.Initialize(context, path);
}
/// <inheritdoc/>

View file

@ -3,10 +3,12 @@
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Edm;
using Microsoft.OpenApi.OData.Operation;
using Microsoft.OpenApi.OData.Properties;
namespace Microsoft.OpenApi.OData.PathItem
{
@ -15,6 +17,11 @@ namespace Microsoft.OpenApi.OData.PathItem
/// </summary>
internal abstract class PathItemHandler : IPathItemHandler
{
/// <summary>
/// Gets the handler path kind.
/// </summary>
protected abstract ODataPathKind HandleKind { get; }
/// <summary>
/// Gets the OData Context.
/// </summary>
@ -55,7 +62,12 @@ namespace Microsoft.OpenApi.OData.PathItem
/// <param name="context">The context.</param>
/// <param name="path">The path.</param>
protected virtual void Initialize(ODataContext context, ODataPath path)
{ }
{
if (HandleKind != path.Kind)
{
throw Error.InvalidOperation(String.Format(SRResource.InvalidPathKindForPathItemHandler, GetType().Name, path.Kind));
}
}
/// <summary>
/// Set the extensions for the path item.

View file

@ -3,13 +3,10 @@
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System;
using Microsoft.OData.Edm;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Capabilities;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Edm;
using Microsoft.OpenApi.OData.Properties;
namespace Microsoft.OpenApi.OData.PathItem
{
@ -18,6 +15,9 @@ namespace Microsoft.OpenApi.OData.PathItem
/// </summary>
internal class SingletonPathItemHandler : PathItemHandler
{
/// <inheritdoc/>
protected override ODataPathKind HandleKind { get; } = ODataPathKind.Singleton;
/// <summary>
/// Gets the singleton.
/// </summary>
@ -27,15 +27,15 @@ namespace Microsoft.OpenApi.OData.PathItem
protected override void SetOperations(OpenApiPathItem item)
{
// Retrieve a singleton.
NavigationRestrictions navigation = new NavigationRestrictions(Context.Model, Singleton);
if (navigation.IsNavigable)
NavigationRestrictions navigation = Context.Model.GetNavigationRestrictions(Singleton);
if (navigation == null || navigation.IsNavigable)
{
AddOperation(item, OperationType.Get);
}
// Update a singleton
UpdateRestrictions update = new UpdateRestrictions(Context.Model, Singleton);
if (update.IsUpdatable)
UpdateRestrictions update = Context.Model.GetUpdateRestrictions(Singleton);
if (update == null || update.IsUpdatable)
{
AddOperation(item, OperationType.Patch);
}
@ -44,14 +44,10 @@ namespace Microsoft.OpenApi.OData.PathItem
/// <inheritdoc/>
protected override void Initialize(ODataContext context, ODataPath path)
{
if (path.Kind != ODataPathKind.Singleton)
{
throw Error.InvalidOperation(String.Format(SRResource.InvalidPathKindForPathItemHandler, nameof(SingletonPathItemHandler), path.Kind));
}
base.Initialize(context, path);
ODataNavigationSourceSegment navigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment;
Singleton = navigationSourceSegment.NavigationSource as IEdmSingleton;
base.Initialize(context, path);
}
}
}

View file

@ -78,6 +78,15 @@ namespace Microsoft.OpenApi.OData.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to The capabilities term kind &apos;{0}&apos; is not supported now..
/// </summary>
internal static string CapabilitiesKindNotSupported {
get {
return ResourceManager.GetString("CapabilitiesKindNotSupported", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to The filed name of extension doesn&apos;t begin with x-..
/// </summary>

View file

@ -123,6 +123,9 @@
<data name="AuthorizationRecordTypeNameNotCorrect" xml:space="preserve">
<value>The authorization record type name '{0}' is not correct.</value>
</data>
<data name="CapabilitiesKindNotSupported" xml:space="preserve">
<value>The capabilities term kind '{0}' is not supported now.</value>
</data>
<data name="ExtensionFieldNameMustBeginWithXMinus" xml:space="preserve">
<value>The filed name of extension doesn't begin with x-.</value>
</data>

View file

@ -13,17 +13,29 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
{
public class BatchSupportedTests
{
[Fact]
public void KindPropertyReturnsBatchSupportedEnumMember()
{
// Arrange & Act
BatchSupported batch = new BatchSupported();
// Assert
Assert.Equal(CapabilitesTermKind.BatchSupported, batch.Kind);
}
[Fact]
public void UnknownAnnotatableTargetReturnsDefaultBatchSupportedValues()
{
// Arrange
EdmEntityContainer container = new EdmEntityContainer("NS", "Default");
BatchSupported batch = new BatchSupported();
EdmEntityType entityType = new EdmEntityType("NS", "Entity");
// Act
BatchSupported batch = new BatchSupported(EdmCoreModel.Instance, container);
// Act
bool result = batch.Load(EdmCoreModel.Instance, entityType);
// Assert
Assert.Equal(CapabilitiesConstants.BatchSupported, batch.QualifiedName);
Assert.False(result);
Assert.True(batch.IsSupported);
Assert.Null(batch.Supported);
}
@ -39,11 +51,14 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
Assert.NotNull(model); // guard
// Act
BatchSupported batch = new BatchSupported(model, model.EntityContainer);
BatchSupported batch = new BatchSupported();
bool result = batch.Load(model, model.EntityContainer);
// Assert
Assert.True(result);
Assert.NotNull(batch.Supported);
Assert.Equal(support, batch.Supported.Value);
Assert.Equal(support, batch.IsSupported);
}
private static IEdmModel GetEdmModel(EdmVocabularyAnnotationSerializationLocation location, bool supported)

View file

@ -4,7 +4,6 @@
// ------------------------------------------------------------
using System;
using System.Linq;
using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Csdl;
using Microsoft.OpenApi.OData.Capabilities;
@ -15,16 +14,28 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
public class CountRestrictionsTests
{
[Fact]
public void UnknownAnnotatableTargetReturnsDefaultPropertyValues()
public void KindPropertyReturnsCountRestrictionEnumMember()
{
// Arrange
EdmEntityType entityType = new EdmEntityType("NS", "Entity");
// Act
CountRestrictions count = new CountRestrictions(EdmCoreModel.Instance, entityType);
// Arrange & Act
CountRestrictions count = new CountRestrictions();
// Assert
Assert.Equal(CapabilitiesConstants.CountRestrictions, count.QualifiedName);
Assert.Equal(CapabilitesTermKind.CountRestrictions, count.Kind);
}
[Fact]
public void UnknownAnnotatableTargetReturnsDefaultPropertyValues()
{
// Arrange & Act
CountRestrictions count = new CountRestrictions();
EdmEntityType entityType = new EdmEntityType("NS", "Entity");
// Act
bool result = count.Load(EdmCoreModel.Instance, entityType);
// Assert
Assert.False(result);
Assert.True(count.IsCountable);
Assert.Null(count.Countable);
Assert.Null(count.NonCountableProperties);
Assert.Null(count.NonCountableNavigationProperties);
@ -44,13 +55,15 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
IEdmModel model = GetEdmModel(template, location);
Assert.NotNull(model); // guard
IEdmEntityType calendar = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "Calendar");
Assert.NotNull(calendar); // guard
IEdmEntitySet calendars = model.EntityContainer.FindEntitySet("Calendars");
Assert.NotNull(calendars); // guard
// Act
CountRestrictions count = new CountRestrictions(model, calendar);
CountRestrictions count = new CountRestrictions();
bool result = count.Load(model, calendars);
// Assert
Assert.True(result);
VerifyCountRestrictions(count);
}
@ -72,77 +85,15 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
Assert.NotNull(calendars); // guard
// Act
CountRestrictions count = new CountRestrictions(model, calendars);
CountRestrictions count = new CountRestrictions();
bool result = count.Load(model, calendars);
// Assert
Assert.True(result);
VerifyCountRestrictions(count);
}
[Theory]
[InlineData(EdmVocabularyAnnotationSerializationLocation.Inline)]
[InlineData(EdmVocabularyAnnotationSerializationLocation.OutOfLine)]
public void TargetOnNavigationPropertyReturnsCorrectCountRestrictionsValue(EdmVocabularyAnnotationSerializationLocation location)
{
// Arrange
const string template = @"
<Annotations Target=""NS.Calendar/RelatedEvents"">
{0}
</Annotations>";
IEdmModel model = GetEdmModel(template, location, true);
Assert.NotNull(model); // guard
IEdmEntityType calendar = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "Calendar");
Assert.NotNull(calendar); // guard
IEdmNavigationProperty navigationProperty = calendar.DeclaredNavigationProperties().First(c => c.Name == "RelatedEvents");
Assert.NotNull(navigationProperty); // guard
// Act
CountRestrictions count = new CountRestrictions(model, navigationProperty);
// Assert
VerifyCountRestrictions(count);
}
[Theory]
[InlineData(EdmVocabularyAnnotationSerializationLocation.Inline)]
[InlineData(EdmVocabularyAnnotationSerializationLocation.OutOfLine)]
public void IsNonCountablePropertyReturnsCorrectForProperty(EdmVocabularyAnnotationSerializationLocation location)
{
// Arrange
const string template = @"
<Annotations Target=""NS.Calendar"">
{0}
</Annotations>";
IEdmModel model = GetEdmModel(template, location);
Assert.NotNull(model); // guard
IEdmEntityType calendar = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "Calendar");
Assert.NotNull(calendar); // Guard
IEdmProperty id = calendar.DeclaredStructuralProperties().First(c => c.Name == "Id");
Assert.NotNull(id); // Guard
IEdmProperty property = calendar.DeclaredStructuralProperties().First(c => c.Name == "Emails");
Assert.NotNull(property); // Guard
IEdmNavigationProperty navigationProperty = calendar.DeclaredNavigationProperties().First(c => c.Name == "RelatedEvents");
Assert.NotNull(navigationProperty); // Guard
// Act
CountRestrictions count = new CountRestrictions(model, calendar);
// Assert
Assert.NotNull(count.Countable);
Assert.False(count.Countable.Value);
Assert.False(count.IsNonCountableProperty(id));
Assert.True(count.IsNonCountableProperty(property));
Assert.True(count.IsNonCountableNavigationProperty(navigationProperty));
}
private static IEdmModel GetEdmModel(string template, EdmVocabularyAnnotationSerializationLocation location, bool navInLine = false)
private static IEdmModel GetEdmModel(string template, EdmVocabularyAnnotationSerializationLocation location)
{
string countAnnotation = @"
<Annotation Term=""Org.OData.Capabilities.V1.CountRestrictions"" >
@ -170,14 +121,7 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
}
else
{
if (navInLine)
{
return CapabilitiesModelHelper.GetEdmModelNavInline(countAnnotation);
}
else
{
return CapabilitiesModelHelper.GetEdmModelTypeInline(countAnnotation);
}
return CapabilitiesModelHelper.GetEdmModelTypeInline(countAnnotation);
}
}
@ -187,6 +131,7 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
Assert.NotNull(count.Countable);
Assert.False(count.Countable.Value);
Assert.False(count.IsCountable);
Assert.NotNull(count.NonCountableProperties);
Assert.Equal(2, count.NonCountableProperties.Count);
@ -195,6 +140,10 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
Assert.NotNull(count.NonCountableNavigationProperties);
Assert.Equal(2, count.NonCountableNavigationProperties.Count);
Assert.Equal("RelatedEvents,abc", String.Join(",", count.NonCountableNavigationProperties));
Assert.False(count.IsNonCountableProperty("id"));
Assert.True(count.IsNonCountableProperty("Emails"));
Assert.True(count.IsNonCountableNavigationProperty("RelatedEvents"));
}
}
}

View file

@ -14,17 +14,29 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
{
public class DeleteRestrictionsTests
{
[Fact]
public void KindPropertyReturnsDeleteRestrictionsEnumMember()
{
// Arrange & Act
DeleteRestrictions delete = new DeleteRestrictions();
// Assert
Assert.Equal(CapabilitesTermKind.DeleteRestrictions, delete.Kind);
}
[Fact]
public void UnknownAnnotatableTargetReturnsDefaultDeleteRestrictionsValues()
{
// Arrange
DeleteRestrictions delete = new DeleteRestrictions();
EdmEntityType entityType = new EdmEntityType("NS", "Entity");
// Act
DeleteRestrictions delete = new DeleteRestrictions(EdmCoreModel.Instance, entityType);
// Act
bool result = delete.Load(EdmCoreModel.Instance, entityType);
// Assert
Assert.Equal(CapabilitiesConstants.DeleteRestrictions, delete.QualifiedName);
Assert.False(result);
Assert.True(delete.IsDeletable);
Assert.Null(delete.Deletable);
Assert.Null(delete.NonDeletableNavigationProperties);
}
@ -43,13 +55,15 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
IEdmModel model = GetEdmModel(template, location);
Assert.NotNull(model); // guard
IEdmEntityType calendar = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "Calendar");
Assert.NotNull(calendar); // guard
IEdmEntitySet calendars = model.EntityContainer.FindEntitySet("Calendars");
Assert.NotNull(calendars); // guard
// Act
DeleteRestrictions delete = new DeleteRestrictions(model, calendar);
DeleteRestrictions delete = new DeleteRestrictions();
bool result = delete.Load(model, calendars);
// Assert
Assert.True(result);
VerifyDeleteRestrictions(delete);
}
@ -71,69 +85,15 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
Assert.NotNull(calendars); // guard
// Act
DeleteRestrictions delete = new DeleteRestrictions(model, calendars);
DeleteRestrictions delete = new DeleteRestrictions();
bool result = delete.Load(model, calendars);
// Assert
Assert.True(result);
VerifyDeleteRestrictions(delete);
}
[Theory]
[InlineData(EdmVocabularyAnnotationSerializationLocation.Inline)]
[InlineData(EdmVocabularyAnnotationSerializationLocation.OutOfLine)]
public void TargetOnNavigationPropertyReturnsCorrectDeleteRestrictionsValue(EdmVocabularyAnnotationSerializationLocation location)
{
// Arrange
const string template = @"
<Annotations Target=""NS.Calendar/RelatedEvents"">
{0}
</Annotations>";
IEdmModel model = GetEdmModel(template, location, true);
Assert.NotNull(model); // guard
IEdmEntityType calendar = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "Calendar");
Assert.NotNull(calendar); // guard
IEdmNavigationProperty navigationProperty = calendar.DeclaredNavigationProperties().First(c => c.Name == "RelatedEvents");
Assert.NotNull(navigationProperty); // guard
// Act
DeleteRestrictions delete = new DeleteRestrictions(model, navigationProperty);
// Assert
VerifyDeleteRestrictions(delete);
}
[Theory]
[InlineData(EdmVocabularyAnnotationSerializationLocation.Inline)]
[InlineData(EdmVocabularyAnnotationSerializationLocation.OutOfLine)]
public void IsNonDeletableNavigationPropertyReturnsCorrectForProperty(EdmVocabularyAnnotationSerializationLocation location)
{
// Arrange
const string template = @"
<Annotations Target=""NS.Calendar"">
{0}
</Annotations>";
IEdmModel model = GetEdmModel(template, location);
Assert.NotNull(model); // guard
IEdmEntityType calendar = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "Calendar");
Assert.NotNull(calendar); // Guard
IEdmNavigationProperty navigationProperty = calendar.DeclaredNavigationProperties().First(c => c.Name == "RelatedEvents");
Assert.NotNull(navigationProperty); // Guard
// Act
DeleteRestrictions delete = new DeleteRestrictions(model, calendar);
// Assert
Assert.NotNull(delete.Deletable);
Assert.False(delete.Deletable.Value);
Assert.True(delete.IsNonDeletableNavigationProperty(navigationProperty));
}
private static IEdmModel GetEdmModel(string template, EdmVocabularyAnnotationSerializationLocation location, bool navInLine = false)
private static IEdmModel GetEdmModel(string template, EdmVocabularyAnnotationSerializationLocation location)
{
string countAnnotation = @"
<Annotation Term=""Org.OData.Capabilities.V1.DeleteRestrictions"" >
@ -155,14 +115,7 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
}
else
{
if (navInLine)
{
return CapabilitiesModelHelper.GetEdmModelNavInline(countAnnotation);
}
else
{
return CapabilitiesModelHelper.GetEdmModelTypeInline(countAnnotation);
}
return CapabilitiesModelHelper.GetEdmModelTypeInline(countAnnotation);
}
}
@ -176,6 +129,8 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
Assert.NotNull(delete.NonDeletableNavigationProperties);
Assert.Equal(2, delete.NonDeletableNavigationProperties.Count);
Assert.Equal("abc|RelatedEvents", String.Join("|", delete.NonDeletableNavigationProperties));
Assert.True(delete.IsNonDeletableNavigationProperty("RelatedEvents"));
}
}
}

View file

@ -4,7 +4,6 @@
// ------------------------------------------------------------
using System;
using System.Linq;
using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Csdl;
using Microsoft.OpenApi.OData.Capabilities;
@ -14,17 +13,30 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
{
public class ExpandRestrictionsTests
{
[Fact]
public void KindPropertyReturnsExpandRestrictionsEnumMember()
{
// Arrange & Act
ExpandRestrictions expand = new ExpandRestrictions();
// Assert
Assert.Equal(CapabilitesTermKind.ExpandRestrictions, expand.Kind);
}
[Fact]
public void UnknownAnnotatableTargetReturnsDefaultExpandRestrictionsValues()
{
// Arrange
ExpandRestrictions expand = new ExpandRestrictions();
EdmEntityType entityType = new EdmEntityType("NS", "Entity");
// Act
ExpandRestrictions expand = new ExpandRestrictions(EdmCoreModel.Instance, entityType);
// Act
bool result = expand.Load(EdmCoreModel.Instance, entityType);
// Assert
Assert.Equal(CapabilitiesConstants.ExpandRestrictions, expand.QualifiedName);
Assert.False(result);
Assert.Equal(CapabilitesTermKind.ExpandRestrictions, expand.Kind);
Assert.True(expand.IsExpandable);
Assert.Null(expand.Expandable);
Assert.Null(expand.NonExpandableProperties);
}
@ -43,13 +55,15 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
IEdmModel model = GetEdmModel(template, location);
Assert.NotNull(model); // guard
IEdmEntityType calendar = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "Calendar");
Assert.NotNull(calendar); // guard
IEdmEntitySet calendars = model.EntityContainer.FindEntitySet("Calendars");
Assert.NotNull(calendars); // guard
// Act
ExpandRestrictions expand = new ExpandRestrictions(model, calendar);
ExpandRestrictions expand = new ExpandRestrictions();
bool result = expand.Load(model, calendars);
// Assert
Assert.True(result);
VerifyExpandRestrictions(expand);
}
@ -71,69 +85,16 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
Assert.NotNull(calendars); // guard
// Act
ExpandRestrictions expand = new ExpandRestrictions(model, calendars);
// Act
ExpandRestrictions expand = new ExpandRestrictions();
bool result = expand.Load(model, calendars);
// Assert
Assert.True(result);
VerifyExpandRestrictions(expand);
}
[Theory]
[InlineData(EdmVocabularyAnnotationSerializationLocation.Inline)]
[InlineData(EdmVocabularyAnnotationSerializationLocation.OutOfLine)]
public void TargetOnNavigationPropertyReturnsCorrectExpandRestrictionsValue(EdmVocabularyAnnotationSerializationLocation location)
{
// Arrange
const string template = @"
<Annotations Target=""NS.Calendar/RelatedEvents"">
{0}
</Annotations>";
IEdmModel model = GetEdmModel(template, location, true);
Assert.NotNull(model); // guard
IEdmEntityType calendar = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "Calendar");
Assert.NotNull(calendar); // guard
IEdmNavigationProperty navigationProperty = calendar.DeclaredNavigationProperties().First(c => c.Name == "RelatedEvents");
Assert.NotNull(navigationProperty); // guard
// Act
ExpandRestrictions expand = new ExpandRestrictions(model, navigationProperty);
// Assert
VerifyExpandRestrictions(expand);
}
[Theory]
[InlineData(EdmVocabularyAnnotationSerializationLocation.Inline)]
[InlineData(EdmVocabularyAnnotationSerializationLocation.OutOfLine)]
public void IsNonExpandablePropertyReturnsCorrectForProperty(EdmVocabularyAnnotationSerializationLocation location)
{
// Arrange
const string template = @"
<Annotations Target=""NS.Calendar"">
{0}
</Annotations>";
IEdmModel model = GetEdmModel(template, location);
Assert.NotNull(model); // guard
IEdmEntityType calendar = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "Calendar");
Assert.NotNull(calendar); // Guard
IEdmNavigationProperty navigationProperty = calendar.DeclaredNavigationProperties().First(c => c.Name == "RelatedEvents");
Assert.NotNull(navigationProperty); // Guard
// Act
ExpandRestrictions expand = new ExpandRestrictions(model, calendar);
// Assert
Assert.NotNull(expand.Expandable);
Assert.False(expand.Expandable.Value);
Assert.True(expand.IsNonExpandableProperty(navigationProperty));
}
private static IEdmModel GetEdmModel(string template, EdmVocabularyAnnotationSerializationLocation location, bool navInLine = false)
private static IEdmModel GetEdmModel(string template, EdmVocabularyAnnotationSerializationLocation location)
{
string countAnnotation = @"
<Annotation Term=""Org.OData.Capabilities.V1.ExpandRestrictions"" >
@ -155,14 +116,7 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
}
else
{
if (navInLine)
{
return CapabilitiesModelHelper.GetEdmModelNavInline(countAnnotation);
}
else
{
return CapabilitiesModelHelper.GetEdmModelTypeInline(countAnnotation);
}
return CapabilitiesModelHelper.GetEdmModelTypeInline(countAnnotation);
}
}
@ -176,6 +130,8 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
Assert.NotNull(expand.NonExpandableProperties);
Assert.Equal(2, expand.NonExpandableProperties.Count);
Assert.Equal("abc|RelatedEvents", String.Join("|", expand.NonExpandableProperties));
Assert.True(expand.IsNonExpandableProperty("RelatedEvents"));
}
}
}

View file

@ -13,17 +13,29 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
{
public class FilterRestrictionsTests
{
[Fact]
public void KindPropertyReturnsFilterRestrictionsEnumMember()
{
// Arrange & Act
FilterRestrictions filter = new FilterRestrictions();
// Assert
Assert.Equal(CapabilitesTermKind.FilterRestrictions, filter.Kind);
}
[Fact]
public void UnknownAnnotatableTargetReturnsDefaultFilterRestrictionsValues()
{
// Arrange
FilterRestrictions filter = new FilterRestrictions();
EdmEntityType entityType = new EdmEntityType("NS", "Entity");
// Act
FilterRestrictions filter = new FilterRestrictions(EdmCoreModel.Instance, entityType);
// Act
bool result = filter.Load(EdmCoreModel.Instance, entityType);
// Assert
Assert.Equal(CapabilitiesConstants.FilterRestrictions, filter.QualifiedName);
Assert.False(result);
Assert.True(filter.IsFilterable);
Assert.Null(filter.Filterable);
Assert.Null(filter.RequiresFilter);
Assert.Null(filter.RequiredProperties);
@ -44,13 +56,15 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
IEdmModel model = GetEdmModel(template, location);
Assert.NotNull(model); // guard
IEdmEntityType calendar = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "Calendar");
Assert.NotNull(calendar); // guard
IEdmEntitySet calendars = model.EntityContainer.FindEntitySet("Calendars");
Assert.NotNull(calendars); // guard
// Act
FilterRestrictions filter = new FilterRestrictions(model, calendar);
FilterRestrictions filter = new FilterRestrictions();
bool result = filter.Load(model, calendars);
// Assert
Assert.True(result);
VerifyFilterRestrictions(filter);
}
@ -72,76 +86,15 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
Assert.NotNull(calendars); // guard
// Act
FilterRestrictions filter = new FilterRestrictions(model, calendars);
FilterRestrictions filter = new FilterRestrictions();
bool result = filter.Load(model, calendars);
// Assert
Assert.True(result);
VerifyFilterRestrictions(filter);
}
[Theory]
[InlineData(EdmVocabularyAnnotationSerializationLocation.Inline)]
[InlineData(EdmVocabularyAnnotationSerializationLocation.OutOfLine)]
public void TargetOnNavigationPropertyReturnsCorrectFilterRestrictionsValue(EdmVocabularyAnnotationSerializationLocation location)
{
// Arrange
const string template = @"
<Annotations Target=""NS.Calendar/RelatedEvents"">
{0}
</Annotations>";
IEdmModel model = GetEdmModel(template, location, true);
Assert.NotNull(model); // guard
IEdmEntityType calendar = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "Calendar");
Assert.NotNull(calendar); // guard
IEdmNavigationProperty navigationProperty = calendar.DeclaredNavigationProperties().First(c => c.Name == "RelatedEvents");
Assert.NotNull(navigationProperty); // guard
// Act
FilterRestrictions filter = new FilterRestrictions(model, navigationProperty);
// Assert
VerifyFilterRestrictions(filter);
}
[Theory]
[InlineData(EdmVocabularyAnnotationSerializationLocation.Inline)]
[InlineData(EdmVocabularyAnnotationSerializationLocation.OutOfLine)]
public void IsNonExpandablePropertyReturnsCorrectForProperty(EdmVocabularyAnnotationSerializationLocation location)
{
// Arrange
const string template = @"
<Annotations Target=""NS.Calendar"">
{0}
</Annotations>";
IEdmModel model = GetEdmModel(template, location);
Assert.NotNull(model); // guard
IEdmEntityType calendar = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "Calendar");
Assert.NotNull(calendar); // Guard
IEdmProperty id = calendar.DeclaredStructuralProperties().First(c => c.Name == "Id");
Assert.NotNull(id); // Guard
IEdmProperty emails = calendar.DeclaredStructuralProperties().First(c => c.Name == "Emails");
Assert.NotNull(emails); // Guard
// Act
FilterRestrictions filter = new FilterRestrictions(model, calendar);
// Assert
Assert.NotNull(filter.Filterable);
Assert.False(filter.Filterable.Value);
Assert.NotNull(filter.RequiresFilter);
Assert.False(filter.RequiresFilter.Value);
Assert.True(filter.IsRequiredProperty(id));
Assert.True(filter.IsNonFilterableProperty(emails));
}
private static IEdmModel GetEdmModel(string template, EdmVocabularyAnnotationSerializationLocation location, bool navInLine = false)
private static IEdmModel GetEdmModel(string template, EdmVocabularyAnnotationSerializationLocation location)
{
string countAnnotation = @"
<Annotation Term=""Org.OData.Capabilities.V1.FilterRestrictions"" >
@ -168,14 +121,7 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
}
else
{
if (navInLine)
{
return CapabilitiesModelHelper.GetEdmModelNavInline(countAnnotation);
}
else
{
return CapabilitiesModelHelper.GetEdmModelTypeInline(countAnnotation);
}
return CapabilitiesModelHelper.GetEdmModelTypeInline(countAnnotation);
}
}
@ -196,6 +142,12 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
Assert.NotNull(filter.NonFilterableProperties);
Assert.Single(filter.NonFilterableProperties);
Assert.Equal("Emails", filter.NonFilterableProperties.First());
Assert.True(filter.IsRequiredProperty("Id"));
Assert.False(filter.IsRequiredProperty("ID"));
Assert.True(filter.IsNonFilterableProperty("Emails"));
Assert.False(filter.IsNonFilterableProperty("ID"));
}
}
}

View file

@ -3,7 +3,6 @@
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System.Linq;
using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Csdl;
using Microsoft.OpenApi.OData.Capabilities;
@ -13,17 +12,29 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
{
public class IndexableByKeyTests
{
[Fact]
public void KindPropertyReturnsIndexableByKeyEnumMember()
{
// Arrange & Act
IndexableByKey index = new IndexableByKey();
// Assert
Assert.Equal(CapabilitesTermKind.IndexableByKey, index.Kind);
}
[Fact]
public void UnknownAnnotatableTargetReturnsDefaultIndexableByKeyValues()
{
// Arrange
IndexableByKey index = new IndexableByKey();
EdmEntityType entityType = new EdmEntityType("NS", "Entity");
// Act
IndexableByKey index = new IndexableByKey(EdmCoreModel.Instance, entityType);
// Act
bool result = index.Load(EdmCoreModel.Instance, entityType);
// Assert
Assert.Equal(CapabilitiesConstants.IndexableByKey, index.QualifiedName);
Assert.False(result);
Assert.True(index.IsSupported);
Assert.Null(index.Supported);
}
@ -41,13 +52,15 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
IEdmModel model = GetEdmModel(template, location);
Assert.NotNull(model); // guard
IEdmEntityType calendar = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "Calendar");
Assert.NotNull(calendar); // guard
IEdmEntitySet calendars = model.EntityContainer.FindEntitySet("Calendars");
Assert.NotNull(calendars); // guard
// Act
IndexableByKey index = new IndexableByKey(model, calendar);
IndexableByKey index = new IndexableByKey();
bool result = index.Load(model, calendars);
// Assert
Assert.True(result);
Assert.NotNull(index.Supported);
Assert.False(index.Supported.Value);
}
@ -70,42 +83,16 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
Assert.NotNull(calendars); // guard
// Act
IndexableByKey index = new IndexableByKey(model, calendars);
IndexableByKey index = new IndexableByKey();
bool result = index.Load(model, calendars);
// Assert
Assert.True(result);
Assert.NotNull(index.Supported);
Assert.False(index.Supported.Value);
}
[Theory]
[InlineData(EdmVocabularyAnnotationSerializationLocation.Inline)]
[InlineData(EdmVocabularyAnnotationSerializationLocation.OutOfLine)]
public void TargetOnNavigationPropertyReturnsCorrectIndexableByKeyValue(EdmVocabularyAnnotationSerializationLocation location)
{
// Arrange
const string template = @"
<Annotations Target=""NS.Calendar/RelatedEvents"">
{0}
</Annotations>";
IEdmModel model = GetEdmModel(template, location, true);
Assert.NotNull(model); // guard
IEdmEntityType calendar = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "Calendar");
Assert.NotNull(calendar); // guard
IEdmNavigationProperty navigationProperty = calendar.DeclaredNavigationProperties().First(c => c.Name == "RelatedEvents");
Assert.NotNull(navigationProperty); // guard
// Act
IndexableByKey index = new IndexableByKey(model, navigationProperty);
// Assert
Assert.NotNull(index.Supported);
Assert.False(index.Supported.Value);
}
private static IEdmModel GetEdmModel(string template, EdmVocabularyAnnotationSerializationLocation location, bool navInLine = false)
private static IEdmModel GetEdmModel(string template, EdmVocabularyAnnotationSerializationLocation location)
{
string countAnnotation = @"<Annotation Term=""Org.OData.Capabilities.V1.IndexableByKey"" Bool=""false"" />";
@ -116,14 +103,7 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
}
else
{
if (navInLine)
{
return CapabilitiesModelHelper.GetEdmModelNavInline(countAnnotation);
}
else
{
return CapabilitiesModelHelper.GetEdmModelTypeInline(countAnnotation);
}
return CapabilitiesModelHelper.GetEdmModelTypeInline(countAnnotation);
}
}
}

View file

@ -4,7 +4,6 @@
// ------------------------------------------------------------
using System;
using System.Linq;
using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Csdl;
using Microsoft.OpenApi.OData.Capabilities;
@ -14,17 +13,29 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
{
public class InsertRestrictionsTests
{
[Fact]
public void KindPropertyReturnsInsertRestrictionsEnumMember()
{
// Arrange & Act
InsertRestrictions insert = new InsertRestrictions();
// Assert
Assert.Equal(CapabilitesTermKind.InsertRestrictions, insert.Kind);
}
[Fact]
public void UnknownAnnotatableTargetReturnsDefaultInsertRestrictionsValues()
{
// Arrange
InsertRestrictions insert = new InsertRestrictions();
EdmEntityType entityType = new EdmEntityType("NS", "Entity");
// Act
InsertRestrictions insert = new InsertRestrictions(EdmCoreModel.Instance, entityType);
// Act
bool result = insert.Load(EdmCoreModel.Instance, entityType);
// Assert
Assert.Equal(CapabilitiesConstants.InsertRestrictions, insert.QualifiedName);
Assert.False(result);
Assert.True(insert.IsInsertable);
Assert.Null(insert.Insertable);
Assert.Null(insert.NonInsertableNavigationProperties);
}
@ -43,13 +54,15 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
IEdmModel model = GetEdmModel(template, location);
Assert.NotNull(model); // guard
IEdmEntityType calendar = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "Calendar");
Assert.NotNull(calendar); // guard
IEdmEntitySet calendars = model.EntityContainer.FindEntitySet("Calendars");
Assert.NotNull(calendars); // guard
// Act
InsertRestrictions insert = new InsertRestrictions(model, calendar);
InsertRestrictions insert = new InsertRestrictions();
bool result = insert.Load(model, calendars);
// Assert
Assert.True(result);
VerifyInsertRestrictions(insert);
}
@ -71,69 +84,15 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
Assert.NotNull(calendars); // guard
// Act
InsertRestrictions insert = new InsertRestrictions(model, calendars);
InsertRestrictions insert = new InsertRestrictions();
bool result = insert.Load(model, calendars);
// Assert
Assert.True(result);
VerifyInsertRestrictions(insert);
}
[Theory]
[InlineData(EdmVocabularyAnnotationSerializationLocation.Inline)]
[InlineData(EdmVocabularyAnnotationSerializationLocation.OutOfLine)]
public void TargetOnNavigationPropertyReturnsCorrectInsertRestrictionsValue(EdmVocabularyAnnotationSerializationLocation location)
{
// Arrange
const string template = @"
<Annotations Target=""NS.Calendar/RelatedEvents"">
{0}
</Annotations>";
IEdmModel model = GetEdmModel(template, location, true);
Assert.NotNull(model); // guard
IEdmEntityType calendar = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "Calendar");
Assert.NotNull(calendar); // guard
IEdmNavigationProperty navigationProperty = calendar.DeclaredNavigationProperties().First(c => c.Name == "RelatedEvents");
Assert.NotNull(navigationProperty); // guard
// Act
InsertRestrictions insert = new InsertRestrictions(model, navigationProperty);
// Assert
VerifyInsertRestrictions(insert);
}
[Theory]
[InlineData(EdmVocabularyAnnotationSerializationLocation.Inline)]
[InlineData(EdmVocabularyAnnotationSerializationLocation.OutOfLine)]
public void IsNonINsertableNavigationPropertyReturnsCorrectForProperty(EdmVocabularyAnnotationSerializationLocation location)
{
// Arrange
const string template = @"
<Annotations Target=""NS.Calendar"">
{0}
</Annotations>";
IEdmModel model = GetEdmModel(template, location);
Assert.NotNull(model); // guard
IEdmEntityType calendar = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "Calendar");
Assert.NotNull(calendar); // Guard
IEdmNavigationProperty navigationProperty = calendar.DeclaredNavigationProperties().First(c => c.Name == "RelatedEvents");
Assert.NotNull(navigationProperty); // Guard
// Act
InsertRestrictions insert = new InsertRestrictions(model, calendar);
// Assert
Assert.NotNull(insert.Insertable);
Assert.False(insert.Insertable.Value);
Assert.True(insert.IsNonINsertableNavigationProperty(navigationProperty));
}
private static IEdmModel GetEdmModel(string template, EdmVocabularyAnnotationSerializationLocation location, bool navInLine = false)
private static IEdmModel GetEdmModel(string template, EdmVocabularyAnnotationSerializationLocation location)
{
string countAnnotation = @"
<Annotation Term=""Org.OData.Capabilities.V1.InsertRestrictions"" >
@ -155,14 +114,7 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
}
else
{
if (navInLine)
{
return CapabilitiesModelHelper.GetEdmModelNavInline(countAnnotation);
}
else
{
return CapabilitiesModelHelper.GetEdmModelTypeInline(countAnnotation);
}
return CapabilitiesModelHelper.GetEdmModelTypeInline(countAnnotation);
}
}
@ -176,6 +128,9 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
Assert.NotNull(insert.NonInsertableNavigationProperties);
Assert.Equal(2, insert.NonInsertableNavigationProperties.Count);
Assert.Equal("abc|RelatedEvents", String.Join("|", insert.NonInsertableNavigationProperties));
Assert.True(insert.IsNonInsertableNavigationProperty("RelatedEvents"));
Assert.False(insert.IsNonInsertableNavigationProperty("MyUnknownNavigationProperty"));
}
}
}

View file

@ -3,28 +3,39 @@
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System.Linq;
using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Csdl;
using Microsoft.OpenApi.OData.Capabilities;
using Xunit;
using Microsoft.OData.Edm.Vocabularies;
using Xunit;
namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
{
public class KeyAsSegmentSupportedTests
{
[Fact]
public void KindPropertyReturnsKeyAsSegmentSupportedEnumMember()
{
// Arrange & Act
KeyAsSegmentSupported keyAsSegment = new KeyAsSegmentSupported();
// Assert
Assert.Equal(CapabilitesTermKind.KeyAsSegmentSupported, keyAsSegment.Kind);
}
[Fact]
public void UnknownAnnotatableTargetReturnsDefaultTopSupportedValues()
{
// Arrange
EdmEntityContainer container = new EdmEntityContainer("NS", "Default");
KeyAsSegmentSupported keyAsSegment = new KeyAsSegmentSupported();
EdmEntityType entityType = new EdmEntityType("NS", "Entity");
// Act
KeyAsSegmentSupported keyAsSegment = new KeyAsSegmentSupported(EdmCoreModel.Instance, container);
// Act
bool result = keyAsSegment.Load(EdmCoreModel.Instance, entityType);
// Assert
Assert.Equal(CapabilitiesConstants.KeyAsSegmentSupported, keyAsSegment.QualifiedName);
Assert.False(result);
Assert.True(keyAsSegment.IsSupported);
Assert.Null(keyAsSegment.Supported);
}
@ -40,9 +51,11 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
Assert.NotNull(model); // guard
// Act
KeyAsSegmentSupported KeyAsSegmentSupported = new KeyAsSegmentSupported(model, model.EntityContainer);
KeyAsSegmentSupported KeyAsSegmentSupported = new KeyAsSegmentSupported();
bool result = KeyAsSegmentSupported.Load(model, model.EntityContainer);
// Assert
Assert.True(result);
Assert.NotNull(KeyAsSegmentSupported.Supported);
Assert.Equal(support, KeyAsSegmentSupported.Supported.Value);
}
@ -53,13 +66,7 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
EdmEntityContainer container = new EdmEntityContainer("NS", "Default");
model.AddElement(container);
IEdmTerm term = model.FindTerm(CapabilitiesConstants.KeyAsSegmentSupported);
if (term == null)
{
// NOTE: KeyAsSegmentSupported annotation term is not included in OData Spec 4.0.
// Please remove the codes here once it's supported in the latest OData lib.
term = new EdmTerm(CapabilitiesConstants.Namespace, "KeyAsSegmentSupported", EdmPrimitiveTypeKind.Boolean);
model.AddElement(term);
}
Assert.NotNull(term);
IEdmBooleanConstantExpression boolean = new EdmBooleanConstant(supported);
EdmVocabularyAnnotation annotation = new EdmVocabularyAnnotation(container, term, boolean);

View file

@ -13,17 +13,29 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
{
public class NavigationRestrictionsTests
{
[Fact]
public void KindPropertyReturnsNavigationRestrictionsEnumMember()
{
// Arrange & Act
NavigationRestrictions navigation = new NavigationRestrictions();
// Assert
Assert.Equal(CapabilitesTermKind.NavigationRestrictions, navigation.Kind);
}
[Fact]
public void UnknownAnnotatableTargetReturnsDefaultPropertyValues()
{
// Arrange
NavigationRestrictions navigation = new NavigationRestrictions();
EdmEntityType entityType = new EdmEntityType("NS", "Entity");
// Act
NavigationRestrictions navigation = new NavigationRestrictions(EdmCoreModel.Instance, entityType);
// Act
bool result = navigation.Load(EdmCoreModel.Instance, entityType);
// Assert
Assert.Equal(CapabilitiesConstants.NavigationRestrictions, navigation.QualifiedName);
Assert.False(result);
Assert.True(navigation.IsNavigable);
Assert.Null(navigation.Navigability);
Assert.Null(navigation.RestrictedProperties);
}
@ -69,12 +81,14 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
model = CapabilitiesModelHelper.GetEdmModelTypeInline(navigationAnnotation);
}
IEdmEntityType calendar = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "Calendar");
IEdmEntitySet calendars = model.EntityContainer.FindEntitySet("Calendars");
// Act
NavigationRestrictions navigation = new NavigationRestrictions(model, calendar);
NavigationRestrictions navigation = new NavigationRestrictions();
bool result = navigation.Load(model, calendars);
// Assert
Assert.True(result);
Assert.NotNull(navigation.Navigability);
Assert.Equal(NavigationType.Recursive, navigation.Navigability.Value);
@ -135,121 +149,18 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
IEdmEntitySet calendars = model.EntityContainer.FindEntitySet("Calendars");
// Act
NavigationRestrictions navigation = new NavigationRestrictions(model, calendars);
// Assert
Assert.NotNull(navigation.Navigability);
Assert.Equal(NavigationType.Recursive, navigation.Navigability.Value);
Assert.NotNull(navigation.RestrictedProperties);
Assert.Equal(2, navigation.RestrictedProperties.Count);
NavigationPropertyRestriction navRestriction = navigation.RestrictedProperties.First();
Assert.NotNull(navRestriction.Navigability);
Assert.Equal(NavigationType.Single, navRestriction.Navigability.Value);
Assert.Equal("abc", navRestriction.NavigationProperty);
navRestriction = navigation.RestrictedProperties.Last();
Assert.NotNull(navRestriction.Navigability);
Assert.Equal(NavigationType.None, navRestriction.Navigability.Value);
Assert.Equal("xyz", navRestriction.NavigationProperty);
}
[Theory]
[InlineData(EdmVocabularyAnnotationSerializationLocation.Inline)]
[InlineData(EdmVocabularyAnnotationSerializationLocation.OutOfLine)]
public void TargetOnNavigationPropertyReturnsCorrectNavigationRestrictionsValue(EdmVocabularyAnnotationSerializationLocation location)
{
// Arrange
const string outOfLineTemplate = @"
<Annotations Target=""NS.Calendar/RelatedEvents"">
{0}
</Annotations>";
string navigationAnnotation = @"
<Annotation Term=""Org.OData.Capabilities.V1.NavigationRestrictions"" >
<Record>
<PropertyValue Property=""Navigability"" >
<EnumMember>Org.OData.Capabilities.V1.NavigationType/Recursive</EnumMember>
</PropertyValue>
</Record>
</Annotation>";
IEdmModel model;
if (location == EdmVocabularyAnnotationSerializationLocation.OutOfLine)
{
navigationAnnotation = string.Format(outOfLineTemplate, navigationAnnotation);
model = CapabilitiesModelHelper.GetEdmModelOutline(navigationAnnotation);
}
else
{
model = CapabilitiesModelHelper.GetEdmModelNavInline(navigationAnnotation);
}
IEdmEntityType calendar = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "Calendar");
IEdmNavigationProperty navigationProperty = calendar.DeclaredNavigationProperties().First(c => c.Name == "RelatedEvents");
// Act
NavigationRestrictions navigation = new NavigationRestrictions(model, navigationProperty);
// Assert
Assert.NotNull(navigation.Navigability);
Assert.Equal(NavigationType.Recursive, navigation.Navigability.Value);
Assert.Null(navigation.RestrictedProperties);
}
[Theory]
[InlineData(EdmVocabularyAnnotationSerializationLocation.Inline)]
[InlineData(EdmVocabularyAnnotationSerializationLocation.OutOfLine)]
public void IsRestrictedPropertyReturnsCorrectForNavigationProperty(EdmVocabularyAnnotationSerializationLocation location)
{
// Arrange
const string outOfLineTemplate = @"
<Annotations Target=""NS.Calendar"">
{0}
</Annotations>";
string navigationAnnotation = @"
<Annotation Term=""Org.OData.Capabilities.V1.NavigationRestrictions"" >
<Record>
<PropertyValue Property=""Navigability"" >
<EnumMember>Org.OData.Capabilities.V1.NavigationType/Recursive</EnumMember>
</PropertyValue>
<PropertyValue Property=""RestrictedProperties"" >
<Collection>
<Record>
<PropertyValue Property=""Navigability"" >
<EnumMember>Org.OData.Capabilities.V1.NavigationType/None</EnumMember>
</PropertyValue>
<PropertyValue Property=""NavigationProperty"" NavigationPropertyPath=""RelatedEvents"" />
</Record>
</Collection>
</PropertyValue>
</Record>
</Annotation>";
IEdmModel model;
if (location == EdmVocabularyAnnotationSerializationLocation.OutOfLine)
{
navigationAnnotation = string.Format(outOfLineTemplate, navigationAnnotation);
model = CapabilitiesModelHelper.GetEdmModelOutline(navigationAnnotation);
}
else
{
model = CapabilitiesModelHelper.GetEdmModelTypeInline(navigationAnnotation);
}
IEdmEntityType calendar = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "Calendar");
IEdmNavigationProperty navigationProperty = calendar.DeclaredNavigationProperties().First(c => c.Name == "RelatedEvents");
// Act
NavigationRestrictions navigation = new NavigationRestrictions(model, calendar);
Assert.NotNull(navigation.Navigability); // Guard
bool result = navigation.IsRestrictedProperty(navigationProperty);
NavigationRestrictions navigation = new NavigationRestrictions();
bool result = navigation.Load(model, calendars);
// Assert
Assert.True(result);
VerifyNavigationRestrictions(navigation);
NavigationPropertyRestriction navRestriction = navigation.RestrictedProperties.Last();
Assert.NotNull(navRestriction.Navigability);
Assert.Equal(NavigationType.None, navRestriction.Navigability.Value);
Assert.Equal("xyz", navRestriction.NavigationProperty);
Assert.True(navigation.IsRestrictedProperty("xyz"));
}
[Fact]
@ -271,11 +182,32 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
IEdmEntityType calendar = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "Calendar");
// Act
NavigationRestrictions navigation = new NavigationRestrictions(model, calendar);
NavigationRestrictions navigation = new NavigationRestrictions();
bool result = navigation.Load(model, calendar);
// Assert
Assert.True(result);
Assert.Null(navigation.Navigability);
Assert.Null(navigation.RestrictedProperties);
}
private static void VerifyNavigationRestrictions(NavigationRestrictions navigation)
{
Assert.NotNull(navigation);
Assert.True(navigation.IsNavigable);
Assert.NotNull(navigation.Navigability);
Assert.Equal(NavigationType.Recursive, navigation.Navigability.Value);
Assert.NotNull(navigation.RestrictedProperties);
Assert.Equal(2, navigation.RestrictedProperties.Count);
NavigationPropertyRestriction navRestriction = navigation.RestrictedProperties.First();
Assert.NotNull(navRestriction.Navigability);
Assert.Equal(NavigationType.Single, navRestriction.Navigability.Value);
Assert.Equal("abc", navRestriction.NavigationProperty);
Assert.False(navigation.IsRestrictedProperty("abc"));
}
}
}

View file

@ -12,17 +12,29 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
{
public class SearchRestrictionsTests
{
[Fact]
public void KindPropertyReturnsSearchRestrictionsEnumMember()
{
// Arrange & Act
SearchRestrictions search = new SearchRestrictions();
// Assert
Assert.Equal(CapabilitesTermKind.SearchRestrictions, search.Kind);
}
[Fact]
public void UnknownAnnotatableTargetReturnsDefaultPropertyValues()
{
// Arrange
SearchRestrictions search = new SearchRestrictions();
EdmEntityType entityType = new EdmEntityType("NS", "Entity");
// Act
SearchRestrictions search = new SearchRestrictions(EdmCoreModel.Instance, entityType);
// Act
bool result = search.Load(EdmCoreModel.Instance, entityType);
// Assert
Assert.Equal(CapabilitiesConstants.SearchRestrictions, search.QualifiedName);
Assert.False(result);
Assert.True(search.IsSearchable);
Assert.Null(search.Searchable);
Assert.Null(search.UnsupportedExpressions);
}
@ -47,12 +59,17 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
IEdmEntityType calendar = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "Calendar");
// Act
SearchRestrictions search = new SearchRestrictions(model, calendar);
SearchRestrictions search = new SearchRestrictions();
bool result = search.Load(model, calendar);
// Assert
Assert.True(result);
Assert.False(search.Searchable);
Assert.NotNull(search.UnsupportedExpressions);
Assert.Equal(SearchExpressions.phrase, search.UnsupportedExpressions.Value);
Assert.False(search.IsUnsupportedExpressions(SearchExpressions.AND));
Assert.True(search.IsUnsupportedExpressions(SearchExpressions.phrase));
}
[Fact]
@ -75,41 +92,17 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
IEdmEntitySet calendars = model.EntityContainer.FindEntitySet("Calendars");
// Act
SearchRestrictions search = new SearchRestrictions(model, calendars);
SearchRestrictions search = new SearchRestrictions();
bool result = search.Load(model, calendars);
// Assert
Assert.True(result);
Assert.False(search.Searchable);
Assert.NotNull(search.UnsupportedExpressions);
Assert.Equal(SearchExpressions.group, search.UnsupportedExpressions.Value);
}
[Fact]
public void AnnotatableTargetOnNavigationPropertyReturnsCorrectPropertyValue()
{
// Arrange
const string searchAnnotation = @"
<Annotations Target=""NS.Calendar/RelatedEvents"" >
<Annotation Term=""Org.OData.Capabilities.V1.SearchRestrictions"">
<Record>
<PropertyValue Property=""Searchable"" Bool=""false"" />
<PropertyValue Property=""UnsupportedExpressions"">
<EnumMember>Org.OData.Capabilities.V1.SearchExpressions/AND</EnumMember>
</PropertyValue >
</Record>
</Annotation>
</Annotations>";
IEdmModel model = CapabilitiesModelHelper.GetModelOutline(searchAnnotation);
IEdmEntityType calendar = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "Calendar");
IEdmNavigationProperty property = calendar.DeclaredNavigationProperties().First(d => d.Name == "RelatedEvents");
// Act
SearchRestrictions search = new SearchRestrictions(model, property);
// Assert
Assert.False(search.Searchable);
Assert.NotNull(search.UnsupportedExpressions);
Assert.Equal(SearchExpressions.AND, search.UnsupportedExpressions.Value);
Assert.False(search.IsUnsupportedExpressions(SearchExpressions.AND));
Assert.True(search.IsUnsupportedExpressions(SearchExpressions.group));
}
[Fact]
@ -132,9 +125,11 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
IEdmEntityType calendar = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "Calendar");
// Act
SearchRestrictions search = new SearchRestrictions(model, calendar);
SearchRestrictions search = new SearchRestrictions();
bool result = search.Load(model, calendar);
// Assert
Assert.True(result);
Assert.False(search.Searchable);
Assert.Null(search.UnsupportedExpressions);
}
@ -159,36 +154,11 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
IEdmEntitySet calendars = model.EntityContainer.FindEntitySet("Calendars");
// Act
SearchRestrictions search = new SearchRestrictions(model, calendars);
// Assert
Assert.False(search.Searchable);
Assert.Null(search.UnsupportedExpressions);
}
[Fact]
public void AnnotatableTargetOnNavigationPropertyWithUnknownEnumMemberDoesnotReturnsUnsupportedExpressions()
{
// Arrange
const string searchAnnotation = @"
<Annotations Target=""NS.Calendar/RelatedEvents"" >
<Annotation Term=""Org.OData.Capabilities.V1.SearchRestrictions"">
<Record>
<PropertyValue Property=""Searchable"" Bool=""false"" />
<PropertyValue Property=""UnsupportedExpressions"">
<EnumMember>Org.OData.Capabilities.V1.SearchExpressions/Unknown</EnumMember>
</PropertyValue >
</Record>
</Annotation>
</Annotations>";
IEdmModel model = CapabilitiesModelHelper.GetModelOutline(searchAnnotation);
IEdmEntityType calendar = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "Calendar");
IEdmNavigationProperty property = calendar.DeclaredNavigationProperties().First(d => d.Name == "RelatedEvents");
// Act
SearchRestrictions search = new SearchRestrictions(model, property);
SearchRestrictions search = new SearchRestrictions();
bool result = search.Load(model, calendars);
// Assert
Assert.True(result);
Assert.False(search.Searchable);
Assert.Null(search.UnsupportedExpressions);
}
@ -213,9 +183,11 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
IEdmEntityType calendar = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "Calendar");
// Act
SearchRestrictions search = new SearchRestrictions(model, calendar);
SearchRestrictions search = new SearchRestrictions();
bool result = search.Load(model, calendar);
// Assert
Assert.True(result);
Assert.False(search.Searchable);
Assert.NotNull(search.UnsupportedExpressions);
Assert.Equal(SearchExpressions.AND | SearchExpressions.OR, search.UnsupportedExpressions.Value);
@ -241,41 +213,18 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
IEdmEntitySet calendars = model.EntityContainer.FindEntitySet("Calendars");
// Act
SearchRestrictions search = new SearchRestrictions(model, calendars);
SearchRestrictions search = new SearchRestrictions();
bool result = search.Load(model, calendars);
// Assert
Assert.True(result);
Assert.False(search.Searchable);
Assert.NotNull(search.UnsupportedExpressions);
Assert.Equal(SearchExpressions.AND | SearchExpressions.OR, search.UnsupportedExpressions.Value);
}
[Fact]
public void AnnotatableTargetOnNavigationPropertyWithMultipleEnumMemberReturnsCorrectPropertyValue()
{
// Arrange
const string searchAnnotation = @"
<Annotations Target=""NS.Calendar/RelatedEvents"" >
<Annotation Term=""Org.OData.Capabilities.V1.SearchRestrictions"">
<Record>
<PropertyValue Property=""Searchable"" Bool=""false"" />
<PropertyValue Property=""UnsupportedExpressions"">
<EnumMember>Org.OData.Capabilities.V1.SearchExpressions/AND Org.OData.Capabilities.V1.SearchExpressions/OR</EnumMember>
</PropertyValue >
</Record>
</Annotation>
</Annotations>";
IEdmModel model = CapabilitiesModelHelper.GetModelOutline(searchAnnotation);
IEdmEntityType calendar = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "Calendar");
IEdmNavigationProperty property = calendar.DeclaredNavigationProperties().First(d => d.Name == "RelatedEvents");
// Act
SearchRestrictions search = new SearchRestrictions(model, property);
// Assert
Assert.False(search.Searchable);
Assert.NotNull(search.UnsupportedExpressions);
Assert.Equal(SearchExpressions.AND | SearchExpressions.OR, search.UnsupportedExpressions.Value);
Assert.True(search.IsUnsupportedExpressions(SearchExpressions.AND));
Assert.True(search.IsUnsupportedExpressions(SearchExpressions.OR));
Assert.False(search.IsUnsupportedExpressions(SearchExpressions.group));
}
}
}

View file

@ -3,7 +3,6 @@
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System.Linq;
using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Csdl;
@ -14,17 +13,29 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
{
public class SkipSupportedTests
{
[Fact]
public void KindPropertyReturnsSkipSupportedEnumMember()
{
// Arrange & Act
SkipSupported skip = new SkipSupported();
// Assert
Assert.Equal(CapabilitesTermKind.SkipSupported, skip.Kind);
}
[Fact]
public void UnknownAnnotatableTargetReturnsDefaultSkipSupportedValues()
{
// Arrange
SkipSupported skip = new SkipSupported();
EdmEntityType entityType = new EdmEntityType("NS", "Entity");
// Act
SkipSupported skip = new SkipSupported(EdmCoreModel.Instance, entityType);
// Act
bool result = skip.Load(EdmCoreModel.Instance, entityType);
// Assert
Assert.Equal(CapabilitiesConstants.SkipSupported, skip.QualifiedName);
Assert.False(result);
Assert.True(skip.IsSupported);
Assert.Null(skip.Supported);
}
@ -46,9 +57,12 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
Assert.NotNull(calendar); // guard
// Act
SkipSupported skip = new SkipSupported(model, calendar);
SkipSupported skip = new SkipSupported();
bool result = skip.Load(model, calendar);
// Assert
Assert.True(result);
Assert.False(skip.IsSupported);
Assert.NotNull(skip.Supported);
Assert.False(skip.Supported.Value);
}
@ -71,42 +85,16 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
Assert.NotNull(calendars); // guard
// Act
SkipSupported skip = new SkipSupported(model, calendars);
SkipSupported skip = new SkipSupported();
bool result = skip.Load(model, calendars);
// Assert
Assert.True(result);
Assert.NotNull(skip.Supported);
Assert.False(skip.Supported.Value);
}
[Theory]
[InlineData(EdmVocabularyAnnotationSerializationLocation.Inline)]
[InlineData(EdmVocabularyAnnotationSerializationLocation.OutOfLine)]
public void TargetOnNavigationPropertyReturnsCorrectSkipSupportedValue(EdmVocabularyAnnotationSerializationLocation location)
{
// Arrange
const string template = @"
<Annotations Target=""NS.Calendar/RelatedEvents"">
{0}
</Annotations>";
IEdmModel model = GetEdmModel(template, location, true);
Assert.NotNull(model); // guard
IEdmEntityType calendar = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "Calendar");
Assert.NotNull(calendar); // guard
IEdmNavigationProperty navigationProperty = calendar.DeclaredNavigationProperties().First(c => c.Name == "RelatedEvents");
Assert.NotNull(navigationProperty); // guard
// Act
SkipSupported skip = new SkipSupported(model, navigationProperty);
// Assert
Assert.NotNull(skip.Supported);
Assert.False(skip.Supported.Value);
}
private static IEdmModel GetEdmModel(string template, EdmVocabularyAnnotationSerializationLocation location, bool navInLine = false)
private static IEdmModel GetEdmModel(string template, EdmVocabularyAnnotationSerializationLocation location)
{
string countAnnotation = @"<Annotation Term=""Org.OData.Capabilities.V1.SkipSupported"" Bool=""false"" />";
@ -117,14 +105,7 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
}
else
{
if (navInLine)
{
return CapabilitiesModelHelper.GetEdmModelNavInline(countAnnotation);
}
else
{
return CapabilitiesModelHelper.GetEdmModelTypeInline(countAnnotation);
}
return CapabilitiesModelHelper.GetEdmModelTypeInline(countAnnotation);
}
}
}

View file

@ -14,16 +14,28 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
public class SortRestrictionsTests
{
[Fact]
public void UnknownAnnotatableTargetReturnsDefaultSortRestrictionsValues()
public void KindPropertyReturnsSortRestrictionsEnumMember()
{
// Arrange
EdmEntityType entityType = new EdmEntityType("NS", "Entity");
// Act
SortRestrictions sort = new SortRestrictions(EdmCoreModel.Instance, entityType);
// Arrange & Act
SortRestrictions sort = new SortRestrictions();
// Assert
Assert.Equal(CapabilitiesConstants.SortRestrictions, sort.QualifiedName);
Assert.Equal(CapabilitesTermKind.SortRestrictions, sort.Kind);
}
[Fact]
public void UnknownAnnotatableTargetReturnsDefaultSortRestrictionsValues()
{
// Arrange & Act
SortRestrictions sort = new SortRestrictions();
EdmEntityType entityType = new EdmEntityType("NS", "Entity");
// Act
bool result = sort.Load(EdmCoreModel.Instance, entityType);
// Assert
Assert.False(result);
Assert.True(sort.IsSortable);
Assert.Null(sort.Sortable);
Assert.Null(sort.AscendingOnlyProperties);
Assert.Null(sort.DescendingOnlyProperties);
@ -48,9 +60,11 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
Assert.NotNull(calendar); // guard
// Act
SortRestrictions sort = new SortRestrictions(model, calendar);
SortRestrictions sort = new SortRestrictions();
bool result = sort.Load(model, calendar);
// Assert
Assert.True(result);
VerifySortRestrictions(sort);
}
@ -72,68 +86,14 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
Assert.NotNull(calendars); // guard
// Act
SortRestrictions sort = new SortRestrictions(model, calendars);
SortRestrictions sort = new SortRestrictions();
bool result = sort.Load(model, calendars);
// Assert
Assert.True(result);
VerifySortRestrictions(sort);
}
[Theory]
[InlineData(EdmVocabularyAnnotationSerializationLocation.Inline)]
[InlineData(EdmVocabularyAnnotationSerializationLocation.OutOfLine)]
public void TargetOnNavigationPropertyReturnsCorrectSortRestrictionsValue(EdmVocabularyAnnotationSerializationLocation location)
{
// Arrange
const string template = @"
<Annotations Target=""NS.Calendar/RelatedEvents"">
{0}
</Annotations>";
IEdmModel model = GetEdmModel(template, location, true);
Assert.NotNull(model); // guard
IEdmEntityType calendar = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "Calendar");
Assert.NotNull(calendar); // guard
IEdmNavigationProperty navigationProperty = calendar.DeclaredNavigationProperties().First(c => c.Name == "RelatedEvents");
Assert.NotNull(navigationProperty); // guard
// Act
SortRestrictions sort = new SortRestrictions(model, navigationProperty);
// Assert
VerifySortRestrictions(sort);
}
[Theory]
[InlineData(EdmVocabularyAnnotationSerializationLocation.Inline)]
[InlineData(EdmVocabularyAnnotationSerializationLocation.OutOfLine)]
public void IsNonSortablePropertiesReturnsCorrectForProperty(EdmVocabularyAnnotationSerializationLocation location)
{
// Arrange
const string template = @"
<Annotations Target=""NS.Calendar"">
{0}
</Annotations>";
IEdmModel model = GetEdmModel(template, location);
Assert.NotNull(model); // guard
IEdmEntityType calendar = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "Calendar");
Assert.NotNull(calendar); // Guard
IEdmProperty emails = calendar.DeclaredStructuralProperties().First(c => c.Name == "Emails");
Assert.NotNull(emails); // Guard
// Act
SortRestrictions sort = new SortRestrictions(model, calendar);
// Assert
Assert.NotNull(sort.Sortable);
Assert.False(sort.Sortable.Value);
Assert.True(sort.IsNonSortableProperty(emails));
}
private static IEdmModel GetEdmModel(string template, EdmVocabularyAnnotationSerializationLocation location, bool navInLine = false)
{
string countAnnotation = @"
@ -165,14 +125,7 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
}
else
{
if (navInLine)
{
return CapabilitiesModelHelper.GetEdmModelNavInline(countAnnotation);
}
else
{
return CapabilitiesModelHelper.GetEdmModelTypeInline(countAnnotation);
}
return CapabilitiesModelHelper.GetEdmModelTypeInline(countAnnotation);
}
}
@ -194,6 +147,15 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
Assert.NotNull(sort.NonSortableProperties);
Assert.Single(sort.NonSortableProperties);
Assert.Equal("Emails", sort.NonSortableProperties.First());
Assert.True(sort.IsAscendingOnlyProperty("abc"));
Assert.False(sort.IsAscendingOnlyProperty("rst"));
Assert.False(sort.IsDescendingOnlyProperty("abc"));
Assert.True(sort.IsDescendingOnlyProperty("rst"));
Assert.False(sort.IsNonSortableProperty("abc"));
Assert.True(sort.IsNonSortableProperty("Emails"));
}
}
}

View file

@ -13,17 +13,29 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
{
public class TopSupportedTests
{
[Fact]
public void KindPropertyReturnsTopSupportedEnumMember()
{
// Arrange & Act
TopSupported top = new TopSupported();
// Assert
Assert.Equal(CapabilitesTermKind.TopSupported, top.Kind);
}
[Fact]
public void UnknownAnnotatableTargetReturnsDefaultTopSupportedValues()
{
// Arrange
TopSupported top = new TopSupported();
EdmEntityType entityType = new EdmEntityType("NS", "Entity");
// Act
TopSupported top = new TopSupported(EdmCoreModel.Instance, entityType);
// Act
bool result = top.Load(EdmCoreModel.Instance, entityType);
// Assert
Assert.Equal(CapabilitiesConstants.TopSupported, top.QualifiedName);
Assert.False(result);
Assert.True(top.IsSupported);
Assert.Null(top.Supported);
}
@ -45,9 +57,12 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
Assert.NotNull(calendar); // guard
// Act
TopSupported top = new TopSupported(model, calendar);
TopSupported top = new TopSupported();
bool result = top.Load(model, calendar);
// Assert
Assert.True(result);
Assert.False(top.IsSupported);
Assert.NotNull(top.Supported);
Assert.False(top.Supported.Value);
}
@ -70,42 +85,17 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
Assert.NotNull(calendars); // guard
// Act
TopSupported top = new TopSupported(model, calendars);
TopSupported top = new TopSupported();
bool result = top.Load(model, calendars);
// Assert
Assert.True(result);
Assert.False(top.IsSupported);
Assert.NotNull(top.Supported);
Assert.False(top.Supported.Value);
}
[Theory]
[InlineData(EdmVocabularyAnnotationSerializationLocation.Inline)]
[InlineData(EdmVocabularyAnnotationSerializationLocation.OutOfLine)]
public void TargetOnNavigationPropertyReturnsCorrectTopSupportedValue(EdmVocabularyAnnotationSerializationLocation location)
{
// Arrange
const string template = @"
<Annotations Target=""NS.Calendar/RelatedEvents"">
{0}
</Annotations>";
IEdmModel model = GetEdmModel(template, location, true);
Assert.NotNull(model); // guard
IEdmEntityType calendar = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "Calendar");
Assert.NotNull(calendar); // guard
IEdmNavigationProperty navigationProperty = calendar.DeclaredNavigationProperties().First(c => c.Name == "RelatedEvents");
Assert.NotNull(navigationProperty); // guard
// Act
TopSupported top = new TopSupported(model, navigationProperty);
// Assert
Assert.NotNull(top.Supported);
Assert.False(top.Supported.Value);
}
private static IEdmModel GetEdmModel(string template, EdmVocabularyAnnotationSerializationLocation location, bool navInLine = false)
private static IEdmModel GetEdmModel(string template, EdmVocabularyAnnotationSerializationLocation location)
{
string countAnnotation = @"<Annotation Term=""Org.OData.Capabilities.V1.TopSupported"" Bool=""false"" />";
@ -116,14 +106,7 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
}
else
{
if (navInLine)
{
return CapabilitiesModelHelper.GetEdmModelNavInline(countAnnotation);
}
else
{
return CapabilitiesModelHelper.GetEdmModelTypeInline(countAnnotation);
}
return CapabilitiesModelHelper.GetEdmModelTypeInline(countAnnotation);
}
}
}

View file

@ -14,17 +14,29 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
{
public class UpdateRestrictionsTests
{
[Fact]
public void KindPropertyReturnsUpdateRestrictionsEnumMember()
{
// Arrange & Act
UpdateRestrictions update = new UpdateRestrictions();
// Assert
Assert.Equal(CapabilitesTermKind.UpdateRestrictions, update.Kind);
}
[Fact]
public void UnknownAnnotatableTargetReturnsDefaultUpdateRestrictionsValues()
{
// Arrange
UpdateRestrictions update = new UpdateRestrictions();
EdmEntityType entityType = new EdmEntityType("NS", "Entity");
// Act
UpdateRestrictions update = new UpdateRestrictions(EdmCoreModel.Instance, entityType);
// Act
bool result = update.Load(EdmCoreModel.Instance, entityType);
// Assert
Assert.Equal(CapabilitiesConstants.UpdateRestrictions, update.QualifiedName);
Assert.False(result);
Assert.True(update.IsUpdatable);
Assert.Null(update.Updatable);
Assert.Null(update.NonUpdatableNavigationProperties);
}
@ -47,9 +59,11 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
Assert.NotNull(calendar); // guard
// Act
UpdateRestrictions update = new UpdateRestrictions(model, calendar);
UpdateRestrictions update = new UpdateRestrictions();
bool result = update.Load(model, calendar);
// Assert
Assert.True(result);
VerifyUpdateRestrictions(update);
}
@ -71,69 +85,15 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
Assert.NotNull(calendars); // guard
// Act
UpdateRestrictions update = new UpdateRestrictions(model, calendars);
UpdateRestrictions update = new UpdateRestrictions();
bool result = update.Load(model, calendars);
// Assert
Assert.True(result);
VerifyUpdateRestrictions(update);
}
[Theory]
[InlineData(EdmVocabularyAnnotationSerializationLocation.Inline)]
[InlineData(EdmVocabularyAnnotationSerializationLocation.OutOfLine)]
public void TargetOnNavigationPropertyReturnsCorrectUpdateRestrictionsValue(EdmVocabularyAnnotationSerializationLocation location)
{
// Arrange
const string template = @"
<Annotations Target=""NS.Calendar/RelatedEvents"">
{0}
</Annotations>";
IEdmModel model = GetEdmModel(template, location, true);
Assert.NotNull(model); // guard
IEdmEntityType calendar = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "Calendar");
Assert.NotNull(calendar); // guard
IEdmNavigationProperty navigationProperty = calendar.DeclaredNavigationProperties().First(c => c.Name == "RelatedEvents");
Assert.NotNull(navigationProperty); // guard
// Act
UpdateRestrictions update = new UpdateRestrictions(model, navigationProperty);
// Assert
VerifyUpdateRestrictions(update);
}
[Theory]
[InlineData(EdmVocabularyAnnotationSerializationLocation.Inline)]
[InlineData(EdmVocabularyAnnotationSerializationLocation.OutOfLine)]
public void IsNonUpdatableNavigationPropertyReturnsCorrectForProperty(EdmVocabularyAnnotationSerializationLocation location)
{
// Arrange
const string template = @"
<Annotations Target=""NS.Calendar"">
{0}
</Annotations>";
IEdmModel model = GetEdmModel(template, location);
Assert.NotNull(model); // guard
IEdmEntityType calendar = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "Calendar");
Assert.NotNull(calendar); // Guard
IEdmNavigationProperty navigationProperty = calendar.DeclaredNavigationProperties().First(c => c.Name == "RelatedEvents");
Assert.NotNull(navigationProperty); // Guard
// Act
UpdateRestrictions update = new UpdateRestrictions(model, calendar);
// Assert
Assert.NotNull(update.Updatable);
Assert.False(update.Updatable.Value);
Assert.True(update.IsNonUpdatableNavigationProperty(navigationProperty));
}
private static IEdmModel GetEdmModel(string template, EdmVocabularyAnnotationSerializationLocation location, bool navInLine = false)
private static IEdmModel GetEdmModel(string template, EdmVocabularyAnnotationSerializationLocation location)
{
string countAnnotation = @"
<Annotation Term=""Org.OData.Capabilities.V1.UpdateRestrictions"" >
@ -155,14 +115,7 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
}
else
{
if (navInLine)
{
return CapabilitiesModelHelper.GetEdmModelNavInline(countAnnotation);
}
else
{
return CapabilitiesModelHelper.GetEdmModelTypeInline(countAnnotation);
}
return CapabilitiesModelHelper.GetEdmModelTypeInline(countAnnotation);
}
}
@ -176,6 +129,10 @@ namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests
Assert.NotNull(update.NonUpdatableNavigationProperties);
Assert.Equal(2, update.NonUpdatableNavigationProperties.Count);
Assert.Equal("abc|RelatedEvents", String.Join("|", update.NonUpdatableNavigationProperties));
Assert.True(update.IsNonUpdatableNavigationProperty("abc"));
Assert.True(update.IsNonUpdatableNavigationProperty("RelatedEvents"));
Assert.False(update.IsNonUpdatableNavigationProperty("Others"));
}
}
}

View file

@ -3,26 +3,62 @@
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System;
using System.Linq;
using Microsoft.OData.Edm;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Edm;
using Microsoft.OpenApi.OData.Tests;
using Microsoft.OpenApi.OData.Properties;
using Xunit;
namespace Microsoft.OpenApi.OData.PathItem.Tests
{
public class EntityPathItemGeneratorTests
public class EntityPathItemHandlerTests
{
private EntityPathItemHandler _pathItemHandler = new EntityPathItemHandler();
[Fact]
public void CreatePathItemThrowsForNullContext()
{
// Arrange & Act & Assert
Assert.Throws<ArgumentNullException>("context",
() => _pathItemHandler.CreatePathItem(context: null, path: new ODataPath()));
}
[Fact]
public void CreatePathItemThrowsForNullPath()
{
// Arrange & Act & Assert
Assert.Throws<ArgumentNullException>("path",
() => _pathItemHandler.CreatePathItem(new ODataContext(EdmCoreModel.Instance), path: null));
}
[Fact]
public void CreatePathItemThrowsForNonEntityPath()
{
// Arrange
IEdmModel model = EntitySetPathItemHandlerTests.GetEdmModel(annotation: "");
ODataContext context = new ODataContext(model);
IEdmEntitySet entitySet = model.EntityContainer.FindEntitySet("Customers");
Assert.NotNull(entitySet); // guard
var path = new ODataPath(new ODataNavigationSourceSegment(entitySet));
Assert.Equal(ODataPathKind.EntitySet, path.Kind); // guard
// Act
Action test = () => _pathItemHandler.CreatePathItem(context, path);
// Assert
var exception = Assert.Throws<InvalidOperationException>(test);
Assert.Equal(String.Format(SRResource.InvalidPathKindForPathItemHandler, "EntityPathItemHandler", path.Kind), exception.Message);
}
[Fact]
public void CreateEntityPathItemReturnsCorrectPathItem()
{
// Arrange
IEdmModel model = EdmModelHelper.BasicEdmModel;
IEdmModel model = EntitySetPathItemHandlerTests.GetEdmModel(annotation: "");
ODataContext context = new ODataContext(model);
IEdmEntitySet entitySet = model.EntityContainer.FindEntitySet("People");
IEdmEntitySet entitySet = model.EntityContainer.FindEntitySet("Customers");
Assert.NotNull(entitySet); // guard
ODataPath path = new ODataPath(new ODataNavigationSourceSegment(entitySet), new ODataKeySegment(entitySet.EntityType()));
@ -38,5 +74,91 @@ namespace Microsoft.OpenApi.OData.PathItem.Tests
Assert.Equal(new OperationType[] { OperationType.Get, OperationType.Patch, OperationType.Delete },
pathItem.Operations.Select(o => o.Key));
}
[Theory]
[InlineData(true, new OperationType[] { OperationType.Get, OperationType.Patch, OperationType.Delete })]
[InlineData(false, new OperationType[] { OperationType.Patch, OperationType.Delete })]
public void CreateEntityPathItemWorksForIndexableByKeyRestrictionsCapablities(bool indexableByKey, OperationType[] expected)
{
// Arrange
string annotation = String.Format(@"
<Annotation Term=""Org.OData.Capabilities.V1.IndexableByKey"" Bool=""{0}"" />", indexableByKey);
IEdmModel model = EntitySetPathItemHandlerTests.GetEdmModel(annotation);
ODataContext context = new ODataContext(model);
IEdmEntitySet entitySet = model.EntityContainer.FindEntitySet("Customers");
Assert.NotNull(entitySet); // guard
ODataPath path = new ODataPath(new ODataNavigationSourceSegment(entitySet), new ODataKeySegment(entitySet.EntityType()));
// Act
var pathItem = _pathItemHandler.CreatePathItem(context, path);
// Assert
Assert.NotNull(pathItem);
Assert.NotNull(pathItem.Operations);
Assert.NotEmpty(pathItem.Operations);
Assert.Equal(expected, pathItem.Operations.Select(e => e.Key));
}
[Theory]
[InlineData(true, new OperationType[] { OperationType.Get, OperationType.Patch, OperationType.Delete })]
[InlineData(false, new OperationType[] { OperationType.Get, OperationType.Delete })]
public void CreateEntityPathItemWorksForUpdateRestrictionsCapablities(bool updatable, OperationType[] expected)
{
// Arrange
string annotation = String.Format(@"
<Annotation Term=""Org.OData.Capabilities.V1.UpdateRestrictions"">
<Record>
<PropertyValue Property=""Updatable"" Bool=""{0}"" />
</Record>
</Annotation>", updatable);
IEdmModel model = EntitySetPathItemHandlerTests.GetEdmModel(annotation);
ODataContext context = new ODataContext(model);
IEdmEntitySet entitySet = model.EntityContainer.FindEntitySet("Customers");
Assert.NotNull(entitySet); // guard
ODataPath path = new ODataPath(new ODataNavigationSourceSegment(entitySet), new ODataKeySegment(entitySet.EntityType()));
// Act
var pathItem = _pathItemHandler.CreatePathItem(context, path);
// Assert
Assert.NotNull(pathItem);
Assert.NotNull(pathItem.Operations);
Assert.NotEmpty(pathItem.Operations);
Assert.Equal(expected, pathItem.Operations.Select(e => e.Key));
}
[Theory]
[InlineData(true, new OperationType[] { OperationType.Get, OperationType.Patch, OperationType.Delete })]
[InlineData(false, new OperationType[] { OperationType.Get, OperationType.Patch })]
public void CreateEntityPathItemWorksForDeleteRestrictionsCapablities(bool deletable, OperationType[] expected)
{
// Arrange
string annotation = String.Format(@"
<Annotation Term=""Org.OData.Capabilities.V1.DeleteRestrictions"">
<Record>
<PropertyValue Property=""Deletable"" Bool=""{0}"" />
</Record>
</Annotation>", deletable);
IEdmModel model = EntitySetPathItemHandlerTests.GetEdmModel(annotation);
ODataContext context = new ODataContext(model);
IEdmEntitySet entitySet = model.EntityContainer.FindEntitySet("Customers");
Assert.NotNull(entitySet); // guard
ODataPath path = new ODataPath(new ODataNavigationSourceSegment(entitySet), new ODataKeySegment(entitySet.EntityType()));
// Act
var pathItem = _pathItemHandler.CreatePathItem(context, path);
// Assert
Assert.NotNull(pathItem);
Assert.NotNull(pathItem.Operations);
Assert.NotEmpty(pathItem.Operations);
Assert.Equal(expected, pathItem.Operations.Select(e => e.Key));
}
}
}

View file

@ -3,11 +3,16 @@
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Csdl;
using Microsoft.OData.Edm.Validation;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Edm;
using Microsoft.OpenApi.OData.Tests;
using Microsoft.OpenApi.OData.Properties;
using Xunit;
namespace Microsoft.OpenApi.OData.PathItem.Tests
@ -16,13 +21,48 @@ namespace Microsoft.OpenApi.OData.PathItem.Tests
{
private EntitySetPathItemHandler _pathItemHandler = new EntitySetPathItemHandler();
[Fact]
public void CreatePathItemThrowsForNullContext()
{
// Arrange & Act & Assert
Assert.Throws<ArgumentNullException>("context",
() => _pathItemHandler.CreatePathItem(context: null, path: new ODataPath()));
}
[Fact]
public void CreatePathItemThrowsForNullPath()
{
// Arrange & Act & Assert
Assert.Throws<ArgumentNullException>("path",
() => _pathItemHandler.CreatePathItem(new ODataContext(EdmCoreModel.Instance), path: null));
}
[Fact]
public void CreatePathItemThrowsForNonEntitySetPath()
{
// Arrange
IEdmModel model = GetEdmModel(annotation: "");
ODataContext context = new ODataContext(model);
var entitySet = model.EntityContainer.FindEntitySet("Customers");
Assert.NotNull(entitySet); // guard
var path = new ODataPath(new ODataNavigationSourceSegment(entitySet), new ODataKeySegment(entitySet.EntityType()));
Assert.Equal(ODataPathKind.Entity, path.Kind); // guard
// Act
Action test = () => _pathItemHandler.CreatePathItem(context, path);
// Assert
var exception = Assert.Throws<InvalidOperationException>(test);
Assert.Equal(String.Format(SRResource.InvalidPathKindForPathItemHandler, "EntitySetPathItemHandler", path.Kind), exception.Message);
}
[Fact]
public void CreateEntitySetPathItemReturnsCorrectPathItem()
{
// Arrange
IEdmModel model = EdmModelHelper.BasicEdmModel;
IEdmModel model = GetEdmModel(annotation: "");
ODataContext context = new ODataContext(model);
IEdmEntitySet entitySet = model.EntityContainer.FindEntitySet("People");
IEdmEntitySet entitySet = model.EntityContainer.FindEntitySet("Customers");
Assert.NotNull(entitySet); // guard
ODataPath path = new ODataPath(new ODataNavigationSourceSegment(entitySet));
@ -38,5 +78,107 @@ namespace Microsoft.OpenApi.OData.PathItem.Tests
Assert.Equal(new OperationType[] { OperationType.Get, OperationType.Post },
pathItem.Operations.Select(o => o.Key));
}
[Theory]
[InlineData("None")]
[InlineData("Single")]
[InlineData("Recursive")]
public void CreateEntitySetPathItemWorksForNavigationRestrictionsCapablities(string navigationType)
{
// Arrange
string annotation = String.Format(@"
<Annotation Term=""Org.OData.Capabilities.V1.NavigationRestrictions"">
<Record>
<PropertyValue Property=""Navigability"">
<EnumMember>Org.OData.Capabilities.V1.NavigationType/{0}</EnumMember>
</PropertyValue>
</Record>
</Annotation>", navigationType);
IEdmModel model = GetEdmModel(annotation);
ODataContext context = new ODataContext(model);
IEdmEntitySet entitySet = model.EntityContainer.FindEntitySet("Customers");
Assert.NotNull(entitySet); // guard
ODataPath path = new ODataPath(new ODataNavigationSourceSegment(entitySet));
// Act
var pathItem = _pathItemHandler.CreatePathItem(context, path);
// Assert
Assert.NotNull(pathItem);
Assert.NotNull(pathItem.Operations);
Assert.NotEmpty(pathItem.Operations);
Assert.Contains(OperationType.Post, pathItem.Operations.Select(e => e.Key));
if (navigationType == "None")
{
Assert.DoesNotContain(OperationType.Get, pathItem.Operations.Select(e => e.Key));
}
else
{
Assert.Contains(OperationType.Get, pathItem.Operations.Select(e => e.Key));
}
}
[Theory]
[InlineData(true, new OperationType[] { OperationType.Get, OperationType.Post })]
[InlineData(false, new OperationType[] { OperationType.Get })]
public void CreateEntitySetPathItemWorksForInsertRestrictionsCapablities(bool insertable, OperationType[] expected)
{
// Arrange
string annotation = String.Format(@"
<Annotation Term=""Org.OData.Capabilities.V1.InsertRestrictions"">
<Record>
<PropertyValue Property=""Insertable"" Bool=""{0}"" />
</Record>
</Annotation>", insertable);
IEdmModel model = GetEdmModel(annotation);
ODataContext context = new ODataContext(model);
IEdmEntitySet entitySet = model.EntityContainer.FindEntitySet("Customers");
Assert.NotNull(entitySet); // guard
ODataPath path = new ODataPath(new ODataNavigationSourceSegment(entitySet));
// Act
var pathItem = _pathItemHandler.CreatePathItem(context, path);
// Assert
Assert.NotNull(pathItem);
Assert.NotNull(pathItem.Operations);
Assert.NotEmpty(pathItem.Operations);
Assert.Equal(expected, pathItem.Operations.Select(e => e.Key));
}
public static IEdmModel GetEdmModel(string annotation)
{
const string template = @"<edmx:Edmx Version=""4.0"" xmlns:edmx=""http://docs.oasis-open.org/odata/ns/edmx"">
<edmx:DataServices>
<Schema Namespace=""NS"" xmlns=""http://docs.oasis-open.org/odata/ns/edm"">
<EntityType Name=""Customer"">
<Key>
<PropertyRef Name=""ID"" />
</Key>
<Property Name=""ID"" Type=""Edm.Int32"" Nullable=""false"" />
</EntityType>
<EntityContainer Name =""Default"">
<EntitySet Name=""Customers"" EntityType=""NS.Customer"" />
</EntityContainer>
<Annotations Target=""NS.Default/Customers"">
{0}
</Annotations>
</Schema>
</edmx:DataServices>
</edmx:Edmx>";
string modelText = string.Format(template, annotation);
IEdmModel model;
IEnumerable<EdmError> errors;
bool result = CsdlReader.TryParse(XElement.Parse(modelText).CreateReader(), out model, out errors);
Assert.True(result);
return model;
}
}
}

View file

@ -3,8 +3,13 @@
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Csdl;
using Microsoft.OData.Edm.Validation;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Edm;
using Microsoft.OpenApi.OData.Tests;
@ -12,10 +17,45 @@ using Xunit;
namespace Microsoft.OpenApi.OData.PathItem.Tests
{
public class NavigationPropertyPathItemGeneratorTest
public class NavigationPropertyPathItemHandlerTest
{
private NavigationPropertyPathItemHandler _pathItemHandler = new NavigationPropertyPathItemHandler();
[Fact]
public void CreatePathItemThrowsForNullContext()
{
// Arrange & Act & Assert
Assert.Throws<ArgumentNullException>("context",
() => _pathItemHandler.CreatePathItem(context: null, path: new ODataPath()));
}
[Fact]
public void CreatePathItemThrowsForNullPath()
{
// Arrange & Act & Assert
Assert.Throws<ArgumentNullException>("path",
() => _pathItemHandler.CreatePathItem(new ODataContext(EdmCoreModel.Instance), path: null));
}
/*
[Fact]
public void CreatePathItemThrowsForNonNavigationPropertyPath()
{
// Arrange
IEdmModel model = GetEdmModel(annotation: "");
ODataContext context = new ODataContext(model);
var entitySet = model.EntityContainer.FindEntitySet("Customers");
Assert.NotNull(entitySet); // guard
var path = new ODataPath(new ODataNavigationSourceSegment(entitySet), new ODataKeySegment(entitySet.EntityType()));
Assert.Equal(ODataPathKind.Entity, path.Kind); // guard
// Act
Action test = () => _pathItemHandler.CreatePathItem(context, path);
// Assert
var exception = Assert.Throws<InvalidOperationException>(test);
Assert.Equal(String.Format(SRResource.InvalidPathKindForPathItemHandler, "EntitySetPathItemHandler", path.Kind), exception.Message);
}*/
[Theory]
[InlineData(true, true, new OperationType[] { OperationType.Get, OperationType.Patch })]
[InlineData(true, false, new OperationType[] { OperationType.Get, OperationType.Post })]
@ -84,5 +124,43 @@ namespace Microsoft.OpenApi.OData.PathItem.Tests
Assert.NotEmpty(pathItem.Operations);
Assert.Equal(expected, pathItem.Operations.Select(o => o.Key));
}
public static IEdmModel GetEdmModel(string annotation)
{
const string template = @"<edmx:Edmx Version=""4.0"" xmlns:edmx=""http://docs.oasis-open.org/odata/ns/edmx"">
<edmx:DataServices>
<Schema Namespace=""NS"" xmlns=""http://docs.oasis-open.org/odata/ns/edm"">
<EntityType Name=""Customer"">
<Key>
<PropertyRef Name=""ID"" />
</Key>
<Property Name=""ID"" Type=""Edm.Int32"" Nullable=""false"" />
<NavigationProperty Name=""DirectOrders"" Type=""Collection(NS.Order)"" />
</EntityType>
<EntityType Name=""Order"">
<Key>
<PropertyRef Name=""ID"" />
</Key>
<Property Name=""ID"" Type=""Edm.Int32"" Nullable=""false"" />
</EntityType>
<EntityContainer Name =""Default"">
<EntitySet Name=""Customers"" EntityType=""NS.Customer"" />
<EntitySet Name=""Orders"" EntityType=""NS.Order"" />
</EntityContainer>
<Annotations Target=""NS.Default/Customers"">
{0}
</Annotations>
</Schema>
</edmx:DataServices>
</edmx:Edmx>";
string modelText = string.Format(template, annotation);
IEdmModel model;
IEnumerable<EdmError> errors;
bool result = CsdlReader.TryParse(XElement.Parse(modelText).CreateReader(), out model, out errors);
Assert.True(result);
return model;
}
}
}

View file

@ -3,6 +3,7 @@
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System;
using System.Linq;
using Microsoft.OData.Edm;
using Microsoft.OpenApi.Models;
@ -12,10 +13,26 @@ using Xunit;
namespace Microsoft.OpenApi.OData.PathItem.Tests
{
public class OperationImportPathItemGeneratorTest
public class OperationImportPathItemHandlerTest
{
private OperationImportPathItemHandler _pathItemHandler = new OperationImportPathItemHandler();
[Fact]
public void CreatePathItemThrowsForNullContext()
{
// Arrange & Act & Assert
Assert.Throws<ArgumentNullException>("context",
() => _pathItemHandler.CreatePathItem(context: null, path: new ODataPath()));
}
[Fact]
public void CreatePathItemThrowsForNullPath()
{
// Arrange & Act & Assert
Assert.Throws<ArgumentNullException>("path",
() => _pathItemHandler.CreatePathItem(new ODataContext(EdmCoreModel.Instance), path: null));
}
[Theory]
[InlineData("GetNearestAirport", OperationType.Get)]
[InlineData("ResetDataSource", OperationType.Post)]

View file

@ -3,6 +3,7 @@
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System;
using System.Linq;
using Microsoft.OData.Edm;
using Microsoft.OpenApi.Models;
@ -12,10 +13,26 @@ using Xunit;
namespace Microsoft.OpenApi.OData.PathItem.Tests
{
public class OperationPathItemGeneratorTest
public class OperationPathItemHandlerTest
{
private OperationPathItemHandler _pathItemHandler = new OperationPathItemHandler();
[Fact]
public void CreatePathItemThrowsForNullContext()
{
// Arrange & Act & Assert
Assert.Throws<ArgumentNullException>("context",
() => _pathItemHandler.CreatePathItem(context: null, path: new ODataPath()));
}
[Fact]
public void CreatePathItemThrowsForNullPath()
{
// Arrange & Act & Assert
Assert.Throws<ArgumentNullException>("path",
() => _pathItemHandler.CreatePathItem(new ODataContext(EdmCoreModel.Instance), path: null));
}
[Theory]
[InlineData("GetFriendsTrips", "People", OperationType.Get)]
[InlineData("ShareTrip", "People", OperationType.Post)]

View file

@ -18,7 +18,7 @@ using Xunit;
namespace Microsoft.OpenApi.OData.PathItem.Tests
{
public class SingletonPathItemGeneratorTest
public class SingletonPathItemHandlerTest
{
private SingletonPathItemHandler _pathItemHandler = new SingletonPathItemHandler();

View file

@ -89,7 +89,10 @@
"AddressInfo",
"HomeAddress",
"FavoriteFeature",
"Features"
"Features",
"Friends",
"BestFriend",
"Trips"
],
"type": "string"
}
@ -212,7 +215,10 @@
"AddressInfo",
"HomeAddress",
"FavoriteFeature",
"Features"
"Features",
"Friends",
"BestFriend",
"Trips"
],
"type": "string"
}
@ -1183,7 +1189,10 @@
"AddressInfo",
"HomeAddress",
"FavoriteFeature",
"Features"
"Features",
"Friends",
"BestFriend",
"Trips"
],
"type": "string"
}
@ -1306,7 +1315,10 @@
"AddressInfo",
"HomeAddress",
"FavoriteFeature",
"Features"
"Features",
"Friends",
"BestFriend",
"Trips"
],
"type": "string"
}
@ -1664,7 +1676,10 @@
"AddressInfo",
"HomeAddress",
"FavoriteFeature",
"Features"
"Features",
"Friends",
"BestFriend",
"Trips"
],
"type": "string"
}

View file

@ -68,6 +68,9 @@ paths:
- HomeAddress
- FavoriteFeature
- Features
- Friends
- BestFriend
- Trips
type: string
- name: $expand
in: query
@ -153,6 +156,9 @@ paths:
- HomeAddress
- FavoriteFeature
- Features
- Friends
- BestFriend
- Trips
type: string
- name: $expand
in: query
@ -792,6 +798,9 @@ paths:
- HomeAddress
- FavoriteFeature
- Features
- Friends
- BestFriend
- Trips
type: string
- name: $expand
in: query
@ -877,6 +886,9 @@ paths:
- HomeAddress
- FavoriteFeature
- Features
- Friends
- BestFriend
- Trips
type: string
- name: $expand
in: query
@ -1114,6 +1126,9 @@ paths:
- HomeAddress
- FavoriteFeature
- Features
- Friends
- BestFriend
- Trips
type: string
- name: $expand
in: query