< Summary - Code Coverage

Information
Class: Plainquire.Page.Swashbuckle.OpenApiOperationExtensions
Assembly: Plainquire.Page.Swashbuckle
File(s): /home/runner/work/plainquire/plainquire/Plainquire.Page/Plainquire.Page.Swashbuckle/Extensions/OpenApiOperationExtensions.cs
Tag: 70_19770578580
Line coverage
98%
Covered lines: 88
Uncovered lines: 1
Coverable lines: 89
Total lines: 150
Line coverage: 98.8%
Branch coverage
72%
Covered branches: 16
Total branches: 22
Branch coverage: 72.7%
Method coverage
100%
Covered methods: 9
Total methods: 9
Method coverage: 100%

Metrics

File(s)

/home/runner/work/plainquire/plainquire/Plainquire.Page/Plainquire.Page.Swashbuckle/Extensions/OpenApiOperationExtensions.cs

#LineLine coverage
 1using Microsoft.AspNetCore.Mvc.Abstractions;
 2using Microsoft.OpenApi;
 3using Plainquire.Page.Swashbuckle.Models;
 4using System;
 5using System.Collections.Generic;
 6using System.Linq;
 7using System.Text.Json.Nodes;
 8
 9namespace Plainquire.Page.Swashbuckle;
 10
 11/// <summary>
 12/// Extension methods for <see cref="OpenApiOperation"/>.
 13/// </summary>
 14public static class OpenApiOperationExtensions
 15{
 16    private const string ENTITY_PAGE_EXTENSION = "x-entity-page";
 17    private const string ENTITY_DELETE_EXTENSION = "x-entity-page-delete";
 18
 19
 20    /// <summary>
 21    /// Replaces <see cref="EntityPage{TEntity}"/> and with the sort parameters.
 22    /// </summary>
 23    /// <param name="operation">The <see cref="OpenApiOperation"/> to operate on.</param>
 24    /// <param name="parametersToReplace">The parameters to replace.</param>
 25    public static void ReplacePageParameters(this OpenApiOperation operation, IList<PageParameterReplacement> parameters
 26    {
 2327        MarkExistingParametersForDeletion(parametersToReplace);
 2328        ReplacePageNumberParameters(operation, parametersToReplace);
 2329        ReplacePageSizeParameters(operation, parametersToReplace);
 2330        RemoveParametersMarkedForDeletion(operation);
 2331    }
 32
 33    private static void ReplacePageNumberParameters(OpenApiOperation operation, IList<PageParameterReplacement> paramete
 34    {
 2335        var httpQueryParameterGroup = GroupByPageNumberHttpQueryParameterName(parametersToReplace);
 10636        foreach (var (queryParameter, parameters) in httpQueryParameterGroup)
 37        {
 3038            var openApiParameter = new OpenApiParameter
 3039            {
 3040                Name = queryParameter,
 3041                Description = "Pages the result by the given page number.",
 3042                Schema = new OpenApiSchema
 3043                {
 3044                    Type = JsonSchemaType.Integer,
 3045                    Format = "int32"
 3046                },
 3047                In = ParameterLocation.Query,
 3048                Extensions = new Dictionary<string, IOpenApiExtension>(StringComparer.Ordinal)
 3049                {
 3050                    [ENTITY_PAGE_EXTENSION] = new JsonNodeExtension(JsonValue.Create(true))
 3051                }
 3052            };
 53
 3054            operation.Parameters ??= new List<IOpenApiParameter>();
 3055            var insertionIndex = operation.Parameters.IndexOf(parameters[0].OpenApiParameter);
 3056            operation.Parameters.Insert(insertionIndex, openApiParameter);
 57        }
 2358    }
 59
 60    private static void ReplacePageSizeParameters(OpenApiOperation operation, IList<PageParameterReplacement> parameters
 61    {
 2362        var httpQueryParameterGroup = GroupByPageSizeHttpQueryParameterName(parametersToReplace);
 10463        foreach (var (queryParameter, parameters) in httpQueryParameterGroup)
 64        {
 2965            var openApiParameter = new OpenApiParameter
 2966            {
 2967                Name = queryParameter,
 2968                Description = "Pages the result by the given page size.",
 2969                Schema = new OpenApiSchema
 2970                {
 2971                    Type = JsonSchemaType.Integer,
 2972                    Format = "int32"
 2973                },
 2974                In = ParameterLocation.Query,
 2975                Extensions = new Dictionary<string, IOpenApiExtension>(StringComparer.Ordinal)
 2976                {
 2977                    [ENTITY_PAGE_EXTENSION] = new JsonNodeExtension(JsonValue.Create(true))
 2978                }
 2979            };
 80
 2981            operation.Parameters ??= new List<IOpenApiParameter>();
 2982            var insertionIndex = operation.Parameters.IndexOf(parameters[0].OpenApiParameter);
 2983            operation.Parameters.Insert(insertionIndex, openApiParameter);
 84        }
 2385    }
 86
 87    private static Dictionary<string, List<PageParameterReplacement>> GroupByPageNumberHttpQueryParameterName(IList<Page
 2388        => parametersToReplace
 2389            .GroupBy(parameter => GetPageNumberParameterName(parameter.OpenApiDescription.ParameterDescriptor), StringCo
 2390            .ToDictionary(
 2391                group => group.Key,
 2392                group => group.ToList(),
 2393                StringComparer.Ordinal
 2394            );
 95
 96    private static Dictionary<string, List<PageParameterReplacement>> GroupByPageSizeHttpQueryParameterName(IList<PagePa
 2397        => parametersToReplace
 2398            .GroupBy(parameter => GetPageSizeParameterName(parameter.OpenApiDescription.ParameterDescriptor), StringComp
 2399            .ToDictionary(
 23100                group => group.Key,
 23101                group => group.ToList(),
 23102                StringComparer.Ordinal
 23103            );
 104
 105    private static void MarkExistingParametersForDeletion(IList<PageParameterReplacement> parameters)
 106    {
 132107        foreach (var parameter in parameters)
 108        {
 43109            if (parameter.OpenApiParameter is not IOpenApiExtensible extensibleParameter)
 0110                throw new InvalidOperationException("The OpenApiParameter must implement IOpenApiExtensible to be replac
 111
 43112            extensibleParameter.Extensions ??= new Dictionary<string, IOpenApiExtension>(StringComparer.OrdinalIgnoreCas
 43113            extensibleParameter.Extensions.TryAdd(ENTITY_DELETE_EXTENSION, new JsonNodeExtension(JsonValue.Create(true))
 114        }
 23115    }
 116
 117    private static void RemoveParametersMarkedForDeletion(OpenApiOperation operation)
 118    {
 23119        operation.Parameters ??= new List<IOpenApiParameter>();
 23120        var parametersToRemove = operation.Parameters
 23121            .Where(parameter =>
 23122            {
 23123                if (parameter is not IOpenApiExtensible extensibleParameter)
 23124                    throw new InvalidOperationException("The OpenApiParameter must implement IOpenApiExtensible to be re
 23125
 23126                extensibleParameter.Extensions ??= new Dictionary<string, IOpenApiExtension>(StringComparer.OrdinalIgnor
 23127                return extensibleParameter.Extensions.ContainsKey(ENTITY_DELETE_EXTENSION);
 23128            })
 23129            .ToList();
 130
 132131        foreach (var parameter in parametersToRemove)
 43132            operation.Parameters.Remove(parameter);
 23133    }
 134
 135    private static string GetPageNumberParameterName(ParameterDescriptor parameterDescriptor)
 136    {
 43137        var actionParameterName = parameterDescriptor.Name;
 43138        var bindingParameterName = parameterDescriptor.BindingInfo?.BinderModelName;
 43139        var (pageNumberName, _) = ParameterExtensions.GetPageParameterNames(actionParameterName, bindingParameterName);
 43140        return pageNumberName;
 141    }
 142
 143    private static string GetPageSizeParameterName(ParameterDescriptor parameterDescriptor)
 144    {
 43145        var actionParameterName = parameterDescriptor.Name;
 43146        var bindingParameterName = parameterDescriptor.BindingInfo?.BinderModelName;
 43147        var (_, pageSizeName) = ParameterExtensions.GetPageParameterNames(actionParameterName, bindingParameterName);
 43148        return pageSizeName;
 149    }
 150}