< Summary

Information
Class: AsiBackbone.Core.Results.OperationResult
Assembly: AsiBackbone.Core
File(s): /home/runner/work/AsiBackbone/AsiBackbone/src/AsiBackbone.Core/Results/OperationResult.cs
Line coverage
100%
Covered lines: 85
Uncovered lines: 0
Coverable lines: 85
Total lines: 362
Line coverage: 100%
Branch coverage
100%
Covered branches: 40
Total branches: 40
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%11100%
.ctor(...)100%11100%
get_Succeeded()100%11100%
get_Failed()100%11100%
get_Reasons()100%11100%
get_ReasonCodes()100%11100%
get_Warnings()100%11100%
get_HasWarnings()100%11100%
Success()100%11100%
Success(...)100%11100%
Success(...)100%11100%
Success(...)100%11100%
Failure(...)100%11100%
Failure(...)100%11100%
Failure(...)100%11100%
Failure(...)100%11100%
Failure(...)100%11100%
Failure(...)100%11100%
Failure(...)100%11100%
Failure(...)100%11100%
Failure()100%11100%
Failure()100%11100%
ToFailure()100%22100%
NormalizeReasons(...)100%11100%
NormalizeReasons(...)100%2424100%
TryGetReasonCount(...)100%44100%
CreateFallbackReason(...)100%11100%
NormalizeWarnings(...)100%66100%
CreateReasonCodes(...)100%44100%

File(s)

/home/runner/work/AsiBackbone/AsiBackbone/src/AsiBackbone.Core/Results/OperationResult.cs

#LineLine coverage
 1using System.Collections.ObjectModel;
 2
 3namespace AsiBackbone.Core.Results;
 4
 5/// <summary>
 6/// Represents the framework-neutral outcome of an operation.
 7/// </summary>
 8public class OperationResult
 9{
 10    private const string DefaultFailureCode = "operation.failed";
 11    private const string DefaultFailureMessage = "Operation failed.";
 12
 513    private static readonly OperationReason[] EmptyReasons = [];
 14
 515    private static readonly string[] EmptyWarnings = [];
 16
 517    private static readonly ReadOnlyCollection<string> EmptyReasonCodes =
 518        Array.AsReadOnly(Array.Empty<string>());
 19
 20    /// <summary>
 21    /// Initializes a new instance of the <see cref="OperationResult"/> class.
 22    /// </summary>
 23    /// <param name="succeeded">A value indicating whether the operation succeeded.</param>
 24    /// <param name="reasons">The reasons associated with the operation result.</param>
 25    /// <param name="warnings">The warnings associated with the operation result.</param>
 11626    protected OperationResult(
 11627        bool succeeded,
 11628        IReadOnlyList<OperationReason> reasons,
 11629        IReadOnlyList<string> warnings)
 30    {
 11631        Succeeded = succeeded;
 11632        Reasons = reasons;
 11633        Warnings = warnings;
 11634        ReasonCodes = CreateReasonCodes(reasons);
 11635    }
 36
 37    /// <summary>
 38    /// Gets a value indicating whether the operation succeeded.
 39    /// </summary>
 10940    public bool Succeeded { get; }
 41
 42    /// <summary>
 43    /// Gets a value indicating whether the operation failed.
 44    /// </summary>
 1845    public bool Failed => !Succeeded;
 46
 47    /// <summary>
 48    /// Gets the reasons associated with the operation result.
 49    /// </summary>
 3450    public IReadOnlyList<OperationReason> Reasons { get; }
 51
 52    /// <summary>
 53    /// Gets machine-readable reason codes associated with the operation result.
 54    /// </summary>
 3655    public IReadOnlyList<string> ReasonCodes { get; }
 56
 57    /// <summary>
 58    /// Gets human-readable warning messages associated with the operation result.
 59    /// </summary>
 4160    public IReadOnlyList<string> Warnings { get; }
 61
 62    /// <summary>
 63    /// Gets a value indicating whether the operation result has warning messages.
 64    /// </summary>
 1865    public bool HasWarnings => Warnings.Count > 0;
 66
 67    /// <summary>
 68    /// Creates a successful operation result.
 69    /// </summary>
 70    /// <returns>A successful operation result.</returns>
 71    public static OperationResult Success()
 72    {
 973        return new OperationResult(true, EmptyReasons, EmptyWarnings);
 74    }
 75
 76    /// <summary>
 77    /// Creates a successful operation result with warnings.
 78    /// </summary>
 79    /// <param name="warnings">The warnings associated with the successful result.</param>
 80    /// <returns>A successful operation result.</returns>
 81    public static OperationResult Success(IEnumerable<string> warnings)
 82    {
 783        return new OperationResult(true, EmptyReasons, NormalizeWarnings(warnings));
 84    }
 85
 86    /// <summary>
 87    /// Creates a successful operation result with a value.
 88    /// </summary>
 89    /// <typeparam name="TValue">The result value type.</typeparam>
 90    /// <param name="value">The operation value.</param>
 91    /// <returns>A successful operation result.</returns>
 92    public static OperationResult<TValue> Success<TValue>(TValue value)
 93    {
 4294        return new OperationResult<TValue>(value, EmptyReasons, EmptyWarnings);
 95    }
 96
 97    /// <summary>
 98    /// Creates a successful operation result with a value and warnings.
 99    /// </summary>
 100    /// <typeparam name="TValue">The result value type.</typeparam>
 101    /// <param name="value">The operation value.</param>
 102    /// <param name="warnings">The warnings associated with the successful result.</param>
 103    /// <returns>A successful operation result.</returns>
 104    public static OperationResult<TValue> Success<TValue>(TValue value, IEnumerable<string> warnings)
 105    {
 2106        return new OperationResult<TValue>(value, EmptyReasons, NormalizeWarnings(warnings));
 107    }
 108
 109    /// <summary>
 110    /// Creates a failed operation result.
 111    /// </summary>
 112    /// <param name="code">The machine-readable reason code.</param>
 113    /// <param name="message">The human-readable reason message.</param>
 114    /// <returns>A failed operation result.</returns>
 115    public static OperationResult Failure(string code, string message)
 116    {
 18117        return Failure(OperationReason.Create(code, message));
 118    }
 119
 120    /// <summary>
 121    /// Creates a failed operation result.
 122    /// </summary>
 123    /// <typeparam name="TValue">The result value type.</typeparam>
 124    /// <param name="code">The machine-readable reason code.</param>
 125    /// <param name="message">The human-readable reason message.</param>
 126    /// <returns>A failed operation result.</returns>
 127    public static OperationResult<TValue> Failure<TValue>(string code, string message)
 128    {
 8129        return Failure<TValue>(OperationReason.Create(code, message));
 130    }
 131
 132    /// <summary>
 133    /// Creates a failed operation result.
 134    /// </summary>
 135    /// <param name="reason">The reason associated with the failed result.</param>
 136    /// <returns>A failed operation result.</returns>
 137    public static OperationResult Failure(OperationReason reason)
 138    {
 20139        ArgumentNullException.ThrowIfNull(reason);
 140
 18141        return new OperationResult(false, Array.AsReadOnly([reason]), EmptyWarnings);
 142    }
 143
 144    /// <summary>
 145    /// Creates a failed operation result.
 146    /// </summary>
 147    /// <typeparam name="TValue">The result value type.</typeparam>
 148    /// <param name="reason">The reason associated with the failed result.</param>
 149    /// <returns>A failed operation result.</returns>
 150    public static OperationResult<TValue> Failure<TValue>(OperationReason reason)
 151    {
 10152        ArgumentNullException.ThrowIfNull(reason);
 153
 8154        return new OperationResult<TValue>(Array.AsReadOnly([reason]), EmptyWarnings);
 155    }
 156
 157    /// <summary>
 158    /// Creates a failed operation result.
 159    /// </summary>
 160    /// <param name="reasons">The reasons associated with the failed result.</param>
 161    /// <returns>A failed operation result.</returns>
 162    public static OperationResult Failure(IEnumerable<OperationReason> reasons)
 163    {
 18164        return new OperationResult(false, NormalizeReasons(reasons), EmptyWarnings);
 165    }
 166
 167    /// <summary>
 168    /// Creates a failed operation result.
 169    /// </summary>
 170    /// <typeparam name="TValue">The result value type.</typeparam>
 171    /// <param name="reasons">The reasons associated with the failed result.</param>
 172    /// <returns>A failed operation result.</returns>
 173    public static OperationResult<TValue> Failure<TValue>(IEnumerable<OperationReason> reasons)
 174    {
 4175        return new OperationResult<TValue>(NormalizeReasons(reasons), EmptyWarnings);
 176    }
 177
 178    /// <summary>
 179    /// Creates a failed operation result with warnings.
 180    /// </summary>
 181    /// <param name="reasons">The reasons associated with the failed result.</param>
 182    /// <param name="warnings">The warnings associated with the failed result.</param>
 183    /// <returns>A failed operation result.</returns>
 184    public static OperationResult Failure(
 185        IEnumerable<OperationReason> reasons,
 186        IEnumerable<string> warnings)
 187    {
 2188        return new OperationResult(false, NormalizeReasons(reasons), NormalizeWarnings(warnings));
 189    }
 190
 191    /// <summary>
 192    /// Creates a failed operation result with warnings.
 193    /// </summary>
 194    /// <typeparam name="TValue">The result value type.</typeparam>
 195    /// <param name="reasons">The reasons associated with the failed result.</param>
 196    /// <param name="warnings">The warnings associated with the failed result.</param>
 197    /// <returns>A failed operation result.</returns>
 198    public static OperationResult<TValue> Failure<TValue>(
 199        IEnumerable<OperationReason> reasons,
 200        IEnumerable<string> warnings)
 201    {
 2202        return new OperationResult<TValue>(NormalizeReasons(reasons), NormalizeWarnings(warnings));
 203    }
 204
 205    /// <summary>
 206    /// Creates a failed operation result using the default failure reason.
 207    /// </summary>
 208    /// <returns>A failed operation result.</returns>
 209    public static OperationResult Failure()
 210    {
 2211        return Failure(DefaultFailureCode, DefaultFailureMessage);
 212    }
 213
 214    /// <summary>
 215    /// Creates a failed operation result using the default failure reason.
 216    /// </summary>
 217    /// <typeparam name="TValue">The result value type.</typeparam>
 218    /// <returns>A failed operation result.</returns>
 219    public static OperationResult<TValue> Failure<TValue>()
 220    {
 4221        return new OperationResult<TValue>(NormalizeReasons(null), EmptyWarnings);
 222    }
 223
 224    /// <summary>
 225    /// Creates a failed operation result from this result's reasons and warnings.
 226    /// </summary>
 227    /// <returns>A failed operation result.</returns>
 228    public OperationResult ToFailure()
 229    {
 4230        return Failed
 4231            ? this
 4232            : Failure();
 233    }
 234
 235    /// <summary>
 236    /// Normalizes operation reasons and provides a default failure reason when none are supplied.
 237    /// </summary>
 238    /// <param name="reasons">The reasons to normalize.</param>
 239    /// <returns>A normalized reason collection.</returns>
 240    protected static IReadOnlyList<OperationReason> NormalizeReasons(IEnumerable<OperationReason>? reasons)
 241    {
 30242        return NormalizeReasons(reasons, DefaultFailureCode, DefaultFailureMessage);
 243    }
 244
 245    private static ReadOnlyCollection<OperationReason> NormalizeReasons(
 246        IEnumerable<OperationReason>? reasons,
 247        string fallbackCode,
 248        string fallbackMessage)
 249    {
 30250        if (reasons is null)
 251        {
 6252            return CreateFallbackReason(fallbackCode, fallbackMessage);
 253        }
 254
 24255        if (TryGetReasonCount(reasons, out int count))
 256        {
 20257            if (count == 0)
 258            {
 6259                return CreateFallbackReason(fallbackCode, fallbackMessage);
 260            }
 261
 14262            var normalizedReasons = new OperationReason[count];
 14263            int normalizedCount = 0;
 264
 72265            foreach (OperationReason? reason in reasons)
 266            {
 22267                if (reason is not null)
 268                {
 18269                    normalizedReasons[normalizedCount] = reason;
 18270                    normalizedCount++;
 271                }
 272            }
 273
 14274            if (normalizedCount == 0)
 275            {
 2276                return CreateFallbackReason(fallbackCode, fallbackMessage);
 277            }
 278
 12279            if (normalizedCount == normalizedReasons.Length)
 280            {
 10281                return Array.AsReadOnly(normalizedReasons);
 282            }
 283
 2284            var filteredReasons = new OperationReason[normalizedCount];
 2285            Array.Copy(normalizedReasons, filteredReasons, normalizedCount);
 286
 2287            return Array.AsReadOnly(filteredReasons);
 288        }
 289
 4290        List<OperationReason>? normalizedList = null;
 291
 16292        foreach (OperationReason? reason in reasons)
 293        {
 4294            if (reason is not null)
 295            {
 4296                normalizedList ??= [];
 4297                normalizedList.Add(reason);
 298            }
 299        }
 300
 4301        return normalizedList is null || normalizedList.Count == 0
 4302            ? CreateFallbackReason(fallbackCode, fallbackMessage)
 4303            : Array.AsReadOnly([.. normalizedList]);
 304    }
 305
 306    private static bool TryGetReasonCount(IEnumerable<OperationReason> reasons, out int count)
 307    {
 24308        if (reasons.TryGetNonEnumeratedCount(out count))
 309        {
 16310            return true;
 311        }
 312
 8313        if (reasons is IReadOnlyCollection<OperationReason> readOnlyCollection)
 314        {
 4315            count = readOnlyCollection.Count;
 4316            return true;
 317        }
 318
 4319        return false;
 320    }
 321
 322    private static ReadOnlyCollection<OperationReason> CreateFallbackReason(
 323        string fallbackCode,
 324        string fallbackMessage)
 325    {
 16326        return Array.AsReadOnly([OperationReason.Create(fallbackCode, fallbackMessage)]);
 327    }
 328
 329    /// <summary>
 330    /// Normalizes warning messages.
 331    /// </summary>
 332    /// <param name="warnings">The warnings to normalize.</param>
 333    /// <returns>A normalized warning collection.</returns>
 334    protected static IReadOnlyList<string> NormalizeWarnings(IEnumerable<string>? warnings)
 335    {
 13336        string[] normalizedWarnings = warnings?
 21337            .Where(warning => !string.IsNullOrWhiteSpace(warning))
 15338            .Select(warning => warning.Trim())
 13339            .ToArray() ?? [];
 340
 13341        return normalizedWarnings.Length == 0
 13342            ? EmptyWarnings
 13343            : Array.AsReadOnly(normalizedWarnings);
 344    }
 345
 346    private static ReadOnlyCollection<string> CreateReasonCodes(IReadOnlyList<OperationReason> reasons)
 347    {
 116348        if (reasons.Count == 0)
 349        {
 60350            return EmptyReasonCodes;
 351        }
 352
 56353        string[] reasonCodes = new string[reasons.Count];
 354
 240355        for (int index = 0; index < reasons.Count; index++)
 356        {
 64357            reasonCodes[index] = reasons[index].Code;
 358        }
 359
 56360        return Array.AsReadOnly(reasonCodes);
 361    }
 362}

Methods/Properties

.cctor()
.ctor(System.Boolean,System.Collections.Generic.IReadOnlyList`1<AsiBackbone.Core.Results.OperationReason>,System.Collections.Generic.IReadOnlyList`1<System.String>)
get_Succeeded()
get_Failed()
get_Reasons()
get_ReasonCodes()
get_Warnings()
get_HasWarnings()
Success()
Success(System.Collections.Generic.IEnumerable`1<System.String>)
Success(TValue)
Success(TValue,System.Collections.Generic.IEnumerable`1<System.String>)
Failure(System.String,System.String)
Failure(System.String,System.String)
Failure(AsiBackbone.Core.Results.OperationReason)
Failure(AsiBackbone.Core.Results.OperationReason)
Failure(System.Collections.Generic.IEnumerable`1<AsiBackbone.Core.Results.OperationReason>)
Failure(System.Collections.Generic.IEnumerable`1<AsiBackbone.Core.Results.OperationReason>)
Failure(System.Collections.Generic.IEnumerable`1<AsiBackbone.Core.Results.OperationReason>,System.Collections.Generic.IEnumerable`1<System.String>)
Failure(System.Collections.Generic.IEnumerable`1<AsiBackbone.Core.Results.OperationReason>,System.Collections.Generic.IEnumerable`1<System.String>)
Failure()
Failure()
ToFailure()
NormalizeReasons(System.Collections.Generic.IEnumerable`1<AsiBackbone.Core.Results.OperationReason>)
NormalizeReasons(System.Collections.Generic.IEnumerable`1<AsiBackbone.Core.Results.OperationReason>,System.String,System.String)
TryGetReasonCount(System.Collections.Generic.IEnumerable`1<AsiBackbone.Core.Results.OperationReason>,System.Int32&)
CreateFallbackReason(System.String,System.String)
NormalizeWarnings(System.Collections.Generic.IEnumerable`1<System.String>)
CreateReasonCodes(System.Collections.Generic.IReadOnlyList`1<AsiBackbone.Core.Results.OperationReason>)