Skip to content

Commit

Permalink
Define pre and post conditions
Browse files Browse the repository at this point in the history
  • Loading branch information
Richard Beauchamp committed Dec 19, 2015
1 parent 08daf8e commit 55c945d
Show file tree
Hide file tree
Showing 23 changed files with 210 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,15 @@ public IQueryable<Order> GetOrders()
}

/// <summary>
/// Create a new order for the customer with the given <paramref name="customerId"/>
/// Create a new order for the customer with the given id
/// </summary>
/// <param name="customerId">The customer id</param>
/// <param name="order">Order details</param>
[ResponseType(typeof(Order))]
public async Task<IHttpActionResult> Post([FromODataUri] int customerId, Order order)
{
order.OrderId = SequentialGuidGenerator.Generate(SequentialGuidType.SequentialAtEnd);
order.CustomerId = customerId;

if (!ModelState.IsValid)
{
Expand Down
36 changes: 26 additions & 10 deletions Swashbuckle.OData/Descriptions/EdmLibHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,8 @@ public static IEdmType GetEdmType(this IEdmModel edmModel, Type clrType)

private static IEdmType GetEdmType(IEdmModel edmModel, Type clrType, bool testCollections)
{
Contract.Assert(edmModel != null);
Contract.Assert(clrType != null);
Contract.Requires(edmModel != null);
Contract.Requires(clrType != null);

var primitiveType = GetEdmPrimitiveTypeOrNull(clrType);
if (primitiveType != null)
Expand Down Expand Up @@ -160,6 +160,8 @@ private static IEdmType GetEdmType(IEdmModel edmModel, Type clrType, bool testCo

public static IEdmTypeReference GetEdmTypeReference(this IEdmModel edmModel, Type clrType)
{
Contract.Requires(clrType != null);

var edmType = edmModel.GetEdmType(clrType);
if (edmType != null)
{
Expand All @@ -172,7 +174,7 @@ public static IEdmTypeReference GetEdmTypeReference(this IEdmModel edmModel, Typ

public static IEdmTypeReference ToEdmTypeReference(this IEdmType edmType, bool isNullable)
{
Contract.Assert(edmType != null);
Contract.Requires(edmType != null);

switch (edmType.TypeKind)
{
Expand Down Expand Up @@ -229,9 +231,9 @@ public static Type GetClrType(IEdmType edmType, IEdmModel edmModel)

public static Type GetClrType(IEdmType edmType, IEdmModel edmModel, IAssembliesResolver assembliesResolver)
{
var edmSchemaType = edmType as IEdmSchemaType;
Contract.Requires(edmType is IEdmSchemaType);

Contract.Assert(edmSchemaType != null);
var edmSchemaType = (IEdmSchemaType) edmType;

var annotation = edmModel.GetAnnotationValue<ClrTypeAnnotation>(edmSchemaType);
if (annotation != null)
Expand Down Expand Up @@ -291,8 +293,8 @@ public static bool IsAutoExpand(IEdmProperty edmProperty, IEdmModel edmModel)

private static QueryableRestrictionsAnnotation GetPropertyRestrictions(IEdmProperty edmProperty, IEdmModel edmModel)
{
Contract.Assert(edmProperty != null);
Contract.Assert(edmModel != null);
Contract.Requires(edmProperty != null);
Contract.Requires(edmModel != null);

return edmModel.GetAnnotationValue<QueryableRestrictionsAnnotation>(edmProperty);
}
Expand Down Expand Up @@ -332,12 +334,16 @@ public static PropertyInfo GetDynamicPropertyDictionary(IEdmStructuredType edmTy

public static IEdmPrimitiveType GetEdmPrimitiveTypeOrNull(Type clrType)
{
Contract.Requires(clrType != null);

IEdmPrimitiveType primitiveType;
return BuiltInTypesMapping.TryGetValue(clrType, out primitiveType) ? primitiveType : null;
}

public static IEdmPrimitiveTypeReference GetEdmPrimitiveTypeReferenceOrNull(Type clrType)
{
Contract.Requires(clrType != null);

var primitiveType = GetEdmPrimitiveTypeOrNull(clrType);
return primitiveType != null ? CoreModel.GetPrimitive(primitiveType.PrimitiveKind, IsNullable(clrType)) : null;
}
Expand All @@ -346,6 +352,8 @@ public static IEdmPrimitiveTypeReference GetEdmPrimitiveTypeReferenceOrNull(Type
// and returns the corresponding clr type to which we map like uint => long.
public static Type IsNonstandardEdmPrimitive(Type type, out bool isNonstandardEdmPrimitive)
{
Contract.Requires(type != null);

var edmType = GetEdmPrimitiveTypeReferenceOrNull(type);
if (edmType == null)
{
Expand All @@ -363,19 +371,23 @@ public static Type IsNonstandardEdmPrimitive(Type type, out bool isNonstandardEd
// to a valid EDM literal (the C# type name IEnumerable<int>).
public static string EdmName(this Type clrType)
{
Contract.Requires(clrType != null);

// We cannot use just Type.Name here as it doesn't work for generic types.
return MangleClrTypeName(clrType);
}

public static string EdmFullName(this Type clrType)
{
Contract.Requires(clrType != null);

return string.Format(CultureInfo.InvariantCulture, "{0}.{1}", clrType.Namespace, clrType.EdmName());
}

public static IEnumerable<IEdmStructuralProperty> GetConcurrencyProperties(this IEdmModel model, IEdmEntitySet entitySet)
{
Contract.Assert(model != null);
Contract.Assert(entitySet != null);
Contract.Requires(model != null);
Contract.Requires(entitySet != null);

IEnumerable<IEdmStructuralProperty> cachedProperties;
if (_concurrencyProperties != null && _concurrencyProperties.TryGetValue(entitySet, out cachedProperties))
Expand Down Expand Up @@ -427,6 +439,8 @@ private static IEdmPrimitiveType GetPrimitiveType(EdmPrimitiveTypeKind primitive

public static bool IsNullable(Type type)
{
Contract.Requires(type != null);

return !type.IsValueType || Nullable.GetUnderlyingType(type) != null;
}

Expand All @@ -438,13 +452,15 @@ private static Type ExtractGenericInterface(Type queryType, Type interfaceType)

private static IEnumerable<Type> GetMatchingTypes(string edmFullName, IAssembliesResolver assembliesResolver)
{
Contract.Requires(assembliesResolver != null);

return TypeHelper.GetLoadedTypes(assembliesResolver).Where(t => t.IsPublic && t.EdmFullName() == edmFullName);
}

// TODO (workitem 336): Support nested types and anonymous types.
private static string MangleClrTypeName(Type type)
{
Contract.Assert(type != null);
Contract.Requires(type != null);

return !type.IsGenericType
? type.Name
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Linq;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Web.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Description;
Expand All @@ -9,6 +10,8 @@ internal static class HttpActionDescriptorExtensions
{
public static ResponseDescription CreateResponseDescription(this HttpActionDescriptor actionDescriptor)
{
Contract.Requires(actionDescriptor != null);

var responseTypeAttribute = actionDescriptor.GetCustomAttributes<ResponseTypeAttribute>();
var responseType = responseTypeAttribute.Select(attribute => attribute.ResponseType).FirstOrDefault();

Expand All @@ -22,6 +25,8 @@ public static ResponseDescription CreateResponseDescription(this HttpActionDescr

private static string GetApiResponseDocumentation(this HttpActionDescriptor actionDescriptor)
{
Contract.Requires(actionDescriptor != null);

var documentationProvider = actionDescriptor.Configuration.Services.GetDocumentationProvider();
return documentationProvider?.GetResponseDocumentation(actionDescriptor);
}
Expand Down
2 changes: 1 addition & 1 deletion Swashbuckle.OData/Descriptions/IODataRouteGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public interface IODataRouteGenerator
}

[ContractClassFor(typeof(IODataRouteGenerator))]
public sealed class ODataRouteGeneratorContract : IODataRouteGenerator
public abstract class ODataRouteGeneratorContract : IODataRouteGenerator
{
public List<SwaggerRoute> Generate(string routePrefix, IEdmModel model)
{
Expand Down
2 changes: 1 addition & 1 deletion Swashbuckle.OData/Descriptions/IParameterMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public interface IParameterMapper
}

[ContractClassFor(typeof(IParameterMapper))]
public sealed class ParameterMapperContract : IParameterMapper
public abstract class ParameterMapperContract : IParameterMapper
{
public HttpParameterDescriptor Map(Parameter swaggerParameter, int parameterIndex, HttpActionDescriptor actionDescriptor)
{
Expand Down
21 changes: 21 additions & 0 deletions Swashbuckle.OData/Descriptions/ODataApiExplorer.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Formatting;
Expand Down Expand Up @@ -63,6 +64,8 @@ private Collection<ApiDescription> GetApiDescriptions()
/// <returns></returns>
private List<ApiDescription> GetApiDescriptions(ODataRoute oDataRoute)
{
Contract.Requires(oDataRoute != null);

var apiDescriptions = new List<ApiDescription>();

var standardRoutes = _routeGenerator.Generate(oDataRoute.RoutePrefix, oDataRoute.GetEdmModel());
Expand All @@ -79,6 +82,8 @@ private List<ApiDescription> GetApiDescriptions(ODataRoute oDataRoute)

private List<ApiDescription> GetApiDescriptions(ODataRoute oDataRoute, SwaggerRoute potentialSwaggerRoute)
{
Contract.Requires(potentialSwaggerRoute != null);

var apiDescriptions = new List<ApiDescription>();

apiDescriptions.AddIfNotNull(GetApiDescription(new HttpMethod("DELETE"), potentialSwaggerRoute.PathItem.delete, potentialSwaggerRoute.Template, oDataRoute));
Expand Down Expand Up @@ -134,6 +139,8 @@ private HttpRequestMessage CreateHttpRequestMessage(HttpMethod httpMethod, Opera

private ApiDescription GetApiDescription(HttpActionDescriptor actionDescriptor, HttpMethod httpMethod, Operation operation, string potentialPathTemplate, ODataRoute oDataRoute)
{
Contract.Requires(actionDescriptor == null || operation != null);

if (actionDescriptor == null)
{
return null;
Expand Down Expand Up @@ -212,11 +219,15 @@ private static HttpActionDescriptor MapForRestierIfNecessary(HttpActionDescripto

private static IEnumerable<MediaTypeFormatter> GetInnerFormatters(IEnumerable<MediaTypeFormatter> mediaTypeFormatters)
{
Contract.Requires(mediaTypeFormatters != null);

return mediaTypeFormatters.Select(Decorator.GetInner);
}

private List<SwaggerApiParameterDescription> CreateParameterDescriptions(Operation operation, HttpActionDescriptor actionDescriptor)
{
Contract.Requires(operation != null);

return operation.parameters.Select((parameter, index) => GetParameterDescription(parameter, index, actionDescriptor)).ToList();
}

Expand All @@ -242,6 +253,8 @@ private HttpParameterDescriptor GetHttpParameterDescriptor(Parameter parameter,

private static string GetApiParameterDocumentation(Parameter parameter, HttpParameterDescriptor parameterDescriptor)
{
Contract.Requires(parameterDescriptor != null);

var documentationProvider = parameterDescriptor.Configuration.Services.GetDocumentationProvider();

return documentationProvider != null
Expand All @@ -251,6 +264,8 @@ private static string GetApiParameterDocumentation(Parameter parameter, HttpPara

private static string GetApiDocumentation(HttpActionDescriptor actionDescriptor, Operation operation)
{
Contract.Requires(actionDescriptor != null);

var documentationProvider = actionDescriptor.Configuration.Services.GetDocumentationProvider();
return documentationProvider != null
? documentationProvider.GetDocumentation(actionDescriptor)
Expand Down Expand Up @@ -284,5 +299,11 @@ private static IEnumerable<IHttpRoute> FlattenRoutes(IEnumerable<IHttpRoute> rou
}
}
}

[ContractInvariantMethod]
private void ObjectInvariant()
{
Contract.Invariant(_apiDescriptions != null);
}
}
}
7 changes: 6 additions & 1 deletion Swashbuckle.OData/Descriptions/ODataRouteExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Linq;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Web.OData.Routing;
using Microsoft.OData.Edm;

Expand All @@ -8,11 +9,15 @@ public static class ODataRouteExtensions
{
public static IEdmModel GetEdmModel(this ODataRoute oDataRoute)
{
Contract.Requires(oDataRoute != null);

return oDataRoute.GetODataPathRouteConstraint().EdmModel;
}

public static ODataPathRouteConstraint GetODataPathRouteConstraint(this ODataRoute oDataRoute)
{
Contract.Requires(oDataRoute != null);

return oDataRoute.Constraints.Values.SingleOrDefault(value => value is ODataPathRouteConstraint) as ODataPathRouteConstraint;
}
}
Expand Down
Loading

0 comments on commit 55c945d

Please sign in to comment.