< Summary

Information
Class: IceRpc.Ice.Operations.IncomingResponseExtensions
Assembly: IceRpc.Ice
File(s): /home/runner/work/icerpc-csharp/icerpc-csharp/src/IceRpc.Ice/Operations/IncomingResponseExtensions.cs
Tag: 1321_24790053727
Line coverage
91%
Covered lines: 55
Uncovered lines: 5
Coverable lines: 60
Total lines: 139
Line coverage: 91.6%
Branch coverage
86%
Covered branches: 19
Total branches: 22
Branch coverage: 86.3%
Method coverage
83%
Covered methods: 5
Fully covered methods: 3
Total methods: 6
Method coverage: 83.3%
Full method coverage: 50%

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
DecodeReturnValueAsync(...)70%121075%
DecodeAndThrowExceptionAsync()100%210%
DecodeVoidReturnValueAsync(...)100%88100%
DecodeAndThrowExceptionAsync()100%11100%
DecodeIceExceptionAsync()50%2283.33%
DecodeBuffer()100%22100%

File(s)

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

#LineLine coverage
 1// Copyright (c) ZeroC, Inc.
 2
 3using IceRpc.Features;
 4using IceRpc.Ice.Codec;
 5using IceRpc.Ice.Operations.Internal;
 6using System.Buffers;
 7using System.Diagnostics;
 8using System.IO.Pipelines;
 9
 10namespace IceRpc.Ice.Operations;
 11
 12/// <summary>Provides extension methods for <see cref="IncomingResponse" /> to decode its Ice-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="sender">The proxy that sent the request.</param>
 21    /// <param name="decodeReturnValue">A function that decodes the return value.</param>
 22    /// <param name="defaultActivator">The activator to use when the activator provided by the request's
 23    /// <see cref="IIceFeature" /> is <see langword="null" />.</param>
 24    /// <param name="cancellationToken">A cancellation token that receives the cancellation requests.</param>
 25    /// <returns>A value task that holds the operation's return value. This value task is faulted and holds a <see
 26    /// cref="IceException" /> when the status code is <see cref="StatusCode.ApplicationError"/>.</returns>
 27    /// <exception cref="DispatchException">Thrown when the status code of the response is greater than
 28    /// <see cref="StatusCode.ApplicationError"/>.</exception>
 29    public static ValueTask<T> DecodeReturnValueAsync<T>(
 30        this IncomingResponse response,
 31        OutgoingRequest request,
 32        IIceProxy sender,
 33        DecodeFunc<T> decodeReturnValue,
 34        IActivator defaultActivator,
 35        CancellationToken cancellationToken = default)
 5936    {
 5937        IIceFeature feature = request.Features.Get<IIceFeature>() ?? IceFeature.Default;
 5938        IActivator activator = feature.Activator ?? defaultActivator;
 39
 5940        return response.StatusCode switch
 5941        {
 5842            StatusCode.Ok => response.DecodeValueAsync(
 5843                feature,
 5844                feature.BaseProxy ?? sender,
 5845                decodeReturnValue,
 5846                activator,
 5847                cancellationToken),
 5948
 049            StatusCode.ApplicationError => DecodeAndThrowExceptionAsync(),
 5950
 151            _ => throw new DispatchException(response.StatusCode, response.ErrorMessage)
 152            {
 153                ConvertToInternalError = true
 154            }
 5955        };
 56
 57        async ValueTask<T> DecodeAndThrowExceptionAsync() =>
 058            throw await response.DecodeIceExceptionAsync(feature, sender, activator, cancellationToken)
 059                .ConfigureAwait(false);
 5860    }
 61
 62    /// <summary>Verifies that an Ice-encoded response payload carries no return value or only tagged return values.
 63    /// </summary>
 64    /// <param name="response">The incoming response.</param>
 65    /// <param name="request">The outgoing request.</param>
 66    /// <param name="sender">The proxy that sent the request.</param>
 67    /// <param name="defaultActivator">The activator to use when the activator provided by the request's
 68    /// <see cref="IIceFeature" /> is <see langword="null" />.</param>
 69    /// <param name="cancellationToken">A cancellation token that receives the cancellation requests.</param>
 70    /// <returns>A value task representing the asynchronous completion of the operation. This value task is faulted and
 71    /// holds a <see cref="IceException" /> when the status code is <see cref="StatusCode.ApplicationError" />.
 72    /// </returns>
 73    /// <exception cref="DispatchException">Thrown when the status code of the response is greater than
 74    /// <see cref="StatusCode.ApplicationError"/>.</exception>
 75    public static ValueTask DecodeVoidReturnValueAsync(
 76        this IncomingResponse response,
 77        OutgoingRequest request,
 78        IIceProxy sender,
 79        IActivator defaultActivator,
 80        CancellationToken cancellationToken = default)
 7381    {
 7382        IIceFeature feature = request.Features.Get<IIceFeature>() ?? IceFeature.Default;
 7383        IActivator activator = feature.Activator ?? defaultActivator;
 84
 7385        return response.StatusCode switch
 7386        {
 4387            StatusCode.Ok => response.DecodeVoidAsync(feature, cancellationToken),
 1688            StatusCode.ApplicationError => DecodeAndThrowExceptionAsync(),
 1489            _ => throw new DispatchException(response.StatusCode, response.ErrorMessage)
 1490            {
 1491                ConvertToInternalError = true
 1492            }
 7393        };
 94
 95        async ValueTask DecodeAndThrowExceptionAsync() =>
 1696            throw await response.DecodeIceExceptionAsync(feature, sender, activator, cancellationToken)
 1697                .ConfigureAwait(false);
 5998    }
 99
 100    private static async ValueTask<IceException> DecodeIceExceptionAsync(
 101        this IncomingResponse response,
 102        IIceFeature feature,
 103        IIceProxy sender,
 104        IActivator activator,
 105        CancellationToken cancellationToken)
 16106    {
 16107        Debug.Assert(response.StatusCode == StatusCode.ApplicationError);
 108
 16109        ReadResult readResult = await response.Payload.ReadFullPayloadAsync(
 16110            feature.MaxPayloadSize,
 16111            cancellationToken).ConfigureAwait(false);
 112
 113        // We never call CancelPendingRead on response.Payload; an interceptor can but it's not correct.
 16114        if (readResult.IsCanceled)
 0115        {
 0116            throw new InvalidOperationException("Unexpected call to CancelPendingRead.");
 117        }
 118
 16119        IceException exception = DecodeBuffer(readResult.Buffer);
 16120        response.Payload.AdvanceTo(readResult.Buffer.End);
 16121        return exception;
 122
 123        IceException DecodeBuffer(ReadOnlySequence<byte> buffer)
 16124        {
 125            // An Ice exception never sets Message, even when received over icerpc.
 126
 16127            var decoder = new IceDecoder(
 16128                buffer,
 16129                feature.BaseProxy ?? sender,
 16130                maxCollectionAllocation: feature.MaxCollectionAllocation,
 16131                activator,
 16132                maxDepth: feature.MaxDepth);
 133
 16134            IceException exception = decoder.DecodeException(response.ErrorMessage);
 16135            decoder.CheckEndOfBuffer();
 16136            return exception;
 16137        }
 16138    }
 139}