< Summary

Information
Class: IceRpc.Slice.IncomingResponseExtensions
Assembly: IceRpc.Slice
File(s): /home/runner/work/icerpc-csharp/icerpc-csharp/src/IceRpc.Slice/IncomingResponseExtensions.cs
Tag: 275_13775359185
Line coverage
92%
Covered lines: 59
Uncovered lines: 5
Coverable lines: 64
Total lines: 169
Line coverage: 92.1%
Branch coverage
88%
Covered branches: 23
Total branches: 26
Branch coverage: 88.4%
Method coverage
85%
Covered methods: 6
Total methods: 7
Method coverage: 85.7%

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
DecodeReturnValueAsync(...)83.33%12.021295.23%
DecodeAndThrowExceptionAsync()100%210%
DecodeVoidReturnValueAsync(...)100%1010100%
DecodeAndThrowExceptionAsync()100%11100%
DecodeVoidReturnValueAsync(...)100%11100%
DecodeSliceExceptionAsync()50%2.01284.61%
DecodeBuffer()100%22100%

File(s)

/home/runner/work/icerpc-csharp/icerpc-csharp/src/IceRpc.Slice/IncomingResponseExtensions.cs

#LineLine coverage
 1// Copyright (c) ZeroC, Inc.
 2
 3using IceRpc.Internal;
 4using IceRpc.Slice.Internal;
 5using System.Buffers;
 6using System.Diagnostics;
 7using System.IO.Pipelines;
 8using ZeroC.Slice;
 9
 10namespace IceRpc.Slice;
 11
 12/// <summary>Provides extension methods for <see cref="IncomingResponse" /> to decode its Slice-encoded payload.
 13/// </summary>
 14public static class IncomingResponseExtensions
 15{
 16    /// <summary>Decodes a response payload.</summary>
 17    /// <typeparam name="T">The type of the return value.</typeparam>
 18    /// <param name="response">The incoming response.</param>
 19    /// <param name="request">The outgoing request.</param>
 20    /// <param name="encoding">The encoding of the response payload.</param>
 21    /// <param name="sender">The proxy that sent the request.</param>
 22    /// <param name="decodeReturnValue">A function that decodes the return value.</param>
 23    /// <param name="defaultActivator">The activator to use when the activator provided by the request's <see
 24    /// cref="ISliceFeature" /> is <see langword="null" />. Used only when <paramref name="encoding" /> is <see
 25    /// cref="SliceEncoding.Slice1" />.</param>
 26    /// <param name="cancellationToken">A cancellation token that receives the cancellation requests.</param>
 27    /// <returns>A value task that holds the operation's return value. This value task is faulted and holds a <see
 28    /// cref="SliceException" /> when encoding is Slice1 and the status code is
 29    /// <see cref="StatusCode.ApplicationError"/>.</returns>
 30    /// <exception cref="DispatchException">Thrown when the encoding is Slice1 and the status code of the response is
 31    /// greater than <see cref="StatusCode.ApplicationError"/>, or when the encoding is Slice2 and the status code is
 32    /// greater than <see cref="StatusCode.Ok"/>.</exception>
 33    public static ValueTask<T> DecodeReturnValueAsync<T>(
 34        this IncomingResponse response,
 35        OutgoingRequest request,
 36        SliceEncoding encoding,
 37        IProxy sender,
 38        DecodeFunc<T> decodeReturnValue,
 39        IActivator? defaultActivator = null,
 40        CancellationToken cancellationToken = default)
 9541    {
 9542        ISliceFeature feature = request.Features.Get<ISliceFeature>() ?? SliceFeature.Default;
 9543        IActivator? activator = feature.Activator ?? defaultActivator;
 44
 9545        return response.StatusCode switch
 9546        {
 9447            StatusCode.Ok => response.DecodeValueAsync(
 9448                encoding,
 9449                feature,
 9450                feature.BaseProxy ?? sender,
 9451                decodeReturnValue,
 9452                activator,
 9453                cancellationToken),
 9554
 055            StatusCode.ApplicationError when encoding == SliceEncoding.Slice1 => DecodeAndThrowExceptionAsync(),
 9556
 157            _ => throw new DispatchException(response.StatusCode, response.ErrorMessage)
 158            {
 159                ConvertToInternalError = true
 160            }
 9561        };
 62
 63        async ValueTask<T> DecodeAndThrowExceptionAsync() =>
 064            throw await response.DecodeSliceExceptionAsync(feature, sender, activator, cancellationToken)
 065                .ConfigureAwait(false);
 9466    }
 67
 68    /// <summary>Verifies that a Slice-encoded response payload carries no return value or only tagged return values.
 69    /// </summary>
 70    /// <param name="response">The incoming response.</param>
 71    /// <param name="request">The outgoing request.</param>
 72    /// <param name="encoding">The encoding of the response payload.</param>
 73    /// <param name="sender">The proxy that sent the request.</param>
 74    /// <param name="defaultActivator">The activator to use when the activator provided by the request's <see
 75    /// cref="ISliceFeature" /> is <see langword="null" />. Used only when <paramref name="encoding" /> is <see
 76    /// cref="SliceEncoding.Slice1" />.</param>
 77    /// <param name="cancellationToken">A cancellation token that receives the cancellation requests.</param>
 78    /// <returns>A value task representing the asynchronous completion of the operation. This value task is faulted and
 79    /// holds a <see cref="SliceException" /> when encoding is Slice1 and the status code is
 80    /// <see cref="StatusCode.ApplicationError" />.</returns>
 81    /// <exception cref="DispatchException">Thrown when the encoding is Slice1 and the status code of the response is
 82    /// greater than <see cref="StatusCode.ApplicationError"/>, or when the encoding is Slice2 and the status code is
 83    /// greater than <see cref="StatusCode.Ok"/>.</exception>
 84    public static ValueTask DecodeVoidReturnValueAsync(
 85        this IncomingResponse response,
 86        OutgoingRequest request,
 87        SliceEncoding encoding,
 88        IProxy sender,
 89        IActivator? defaultActivator = null,
 90        CancellationToken cancellationToken = default)
 7991    {
 7992        ISliceFeature feature = request.Features.Get<ISliceFeature>() ?? SliceFeature.Default;
 7993        IActivator? activator = defaultActivator ?? feature.Activator;
 94
 7995        return response.StatusCode switch
 7996        {
 4997            StatusCode.Ok => response.DecodeVoidAsync(encoding, feature, cancellationToken),
 3298            StatusCode.ApplicationError when encoding == SliceEncoding.Slice1 => DecodeAndThrowExceptionAsync(),
 1499            _ => throw new DispatchException(response.StatusCode, response.ErrorMessage)
 14100            {
 14101                ConvertToInternalError = true
 14102            }
 79103        };
 104
 105        async ValueTask DecodeAndThrowExceptionAsync() =>
 16106            throw await response.DecodeSliceExceptionAsync(feature, sender, activator, cancellationToken)
 16107                .ConfigureAwait(false);
 65108    }
 109
 110    /// <summary>Verifies that a Slice2-encoded response payload carries no return value or only tagged return values.
 111    /// </summary>
 112    /// <param name="response">The incoming response.</param>
 113    /// <param name="request">The outgoing request.</param>
 114    /// <param name="sender">The proxy that sent the request (not used by this method).</param>
 115    /// <param name="cancellationToken">A cancellation token that receives the cancellation requests.</param>
 116    /// <returns>A value task representing the asynchronous completion of the operation.</returns>
 117    /// <exception cref="DispatchException">Thrown if the status code of the response is greater than <see
 118    /// cref="StatusCode.Ok" />.</exception>
 119    /// <remarks>This method is a <see cref="ResponseDecodeFunc" />.</remarks>
 120    public static ValueTask DecodeVoidReturnValueAsync(
 121        this IncomingResponse response,
 122        OutgoingRequest request,
 123        IProxy sender,
 124        CancellationToken cancellationToken = default) =>
 15125        response.DecodeVoidReturnValueAsync(request, SliceEncoding.Slice2, sender, null, cancellationToken);
 126
 127    // Slice1-only
 128    private static async ValueTask<SliceException> DecodeSliceExceptionAsync(
 129        this IncomingResponse response,
 130        ISliceFeature feature,
 131        IProxy sender,
 132        IActivator? activator,
 133        CancellationToken cancellationToken)
 16134    {
 16135        Debug.Assert(response.StatusCode == StatusCode.ApplicationError);
 136
 16137        ReadResult readResult = await response.Payload.ReadSegmentAsync(
 16138            SliceEncoding.Slice1,
 16139            feature.MaxSegmentSize,
 16140            cancellationToken).ConfigureAwait(false);
 141
 142        // We never call CancelPendingRead on response.Payload; an interceptor can but it's not correct.
 16143        if (readResult.IsCanceled)
 0144        {
 0145            throw new InvalidOperationException("Unexpected call to CancelPendingRead.");
 146        }
 147
 16148        SliceException exception = DecodeBuffer(readResult.Buffer);
 16149        response.Payload.AdvanceTo(readResult.Buffer.End);
 16150        return exception;
 151
 152        SliceException DecodeBuffer(ReadOnlySequence<byte> buffer)
 16153        {
 154            // A Slice exception never sets Message, even when received over icerpc.
 155
 16156            var decoder = new SliceDecoder(
 16157                buffer,
 16158                SliceEncoding.Slice1,
 16159                feature.BaseProxy ?? sender,
 16160                maxCollectionAllocation: feature.MaxCollectionAllocation,
 16161                activator,
 16162                maxDepth: feature.MaxDepth);
 163
 16164            SliceException exception = decoder.DecodeException(response.ErrorMessage);
 16165            decoder.CheckEndOfBuffer();
 16166            return exception;
 16167        }
 16168    }
 169}