< 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: 71_21978539030
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);
 10236        foreach (var (queryParameter, parameters) in httpQueryParameterGroup)
 37        {
 2838            var openApiParameter = new OpenApiParameter
 2839            {
 2840                Name = queryParameter,
 2841                Description = "Pages the result by the given page number.",
 2842                Schema = new OpenApiSchema
 2843                {
 2844                    Type = JsonSchemaType.Integer,
 2845                    Format = "int32"
 2846                },
 2847                In = ParameterLocation.Query,
 2848                Extensions = new Dictionary<string, IOpenApiExtension>(StringComparer.Ordinal)
 2849                {
 2850                    [ENTITY_PAGE_EXTENSION] = new JsonNodeExtension(JsonValue.Create(true))
 2851                }
 2852            };
 53
 2854            operation.Parameters ??= new List<IOpenApiParameter>();
 2855            var insertionIndex = operation.Parameters.IndexOf(parameters[0].OpenApiParameter);
 2856            operation.Parameters.Insert(insertionIndex, openApiParameter);
 57        }
 2358    }
 59
 60    private static void ReplacePageSizeParameters(OpenApiOperation operation, IList<PageParameterReplacement> parameters
 61    {
 2362        var httpQueryParameterGroup = GroupByPageSizeHttpQueryParameterName(parametersToReplace);
 10063        foreach (var (queryParameter, parameters) in httpQueryParameterGroup)
 64        {
 2765            var openApiParameter = new OpenApiParameter
 2766            {
 2767                Name = queryParameter,
 2768                Description = "Pages the result by the given page size.",
 2769                Schema = new OpenApiSchema
 2770                {
 2771                    Type = JsonSchemaType.Integer,
 2772                    Format = "int32"
 2773                },
 2774                In = ParameterLocation.Query,
 2775                Extensions = new Dictionary<string, IOpenApiExtension>(StringComparer.Ordinal)
 2776                {
 2777                    [ENTITY_PAGE_EXTENSION] = new JsonNodeExtension(JsonValue.Create(true))
 2778                }
 2779            };
 80
 2781            operation.Parameters ??= new List<IOpenApiParameter>();
 2782            var insertionIndex = operation.Parameters.IndexOf(parameters[0].OpenApiParameter);
 2783            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    {
 114107        foreach (var parameter in parameters)
 108        {
 34109            if (parameter.OpenApiParameter is not IOpenApiExtensible extensibleParameter)
 0110                throw new InvalidOperationException("The OpenApiParameter must implement IOpenApiExtensible to be replac
 111
 34112            extensibleParameter.Extensions ??= new Dictionary<string, IOpenApiExtension>(StringComparer.OrdinalIgnoreCas
 34113            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
 114131        foreach (var parameter in parametersToRemove)
 34132            operation.Parameters.Remove(parameter);
 23133    }
 134
 135    private static string GetPageNumberParameterName(ParameterDescriptor parameterDescriptor)
 136    {
 34137        var actionParameterName = parameterDescriptor.Name;
 34138        var bindingParameterName = parameterDescriptor.BindingInfo?.BinderModelName;
 34139        var (pageNumberName, _) = ParameterExtensions.GetPageParameterNames(actionParameterName, bindingParameterName);
 34140        return pageNumberName;
 141    }
 142
 143    private static string GetPageSizeParameterName(ParameterDescriptor parameterDescriptor)
 144    {
 34145        var actionParameterName = parameterDescriptor.Name;
 34146        var bindingParameterName = parameterDescriptor.BindingInfo?.BinderModelName;
 34147        var (_, pageSizeName) = ParameterExtensions.GetPageParameterNames(actionParameterName, bindingParameterName);
 34148        return pageSizeName;
 149    }
 150}