< Summary

Information
Class: AsiBackbone.Core.Constraints.ConstraintEvaluationResult
Assembly: AsiBackbone.Core
File(s): /home/runner/work/AsiBackbone/AsiBackbone/src/AsiBackbone.Core/Constraints/ConstraintEvaluationResult.cs
Line coverage
100%
Covered lines: 70
Uncovered lines: 0
Coverable lines: 70
Total lines: 252
Line coverage: 100%
Branch coverage
100%
Covered branches: 28
Total branches: 28
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_CanProceed()100%11100%
get_IsDenied()100%11100%
get_IsWarning()100%11100%
get_IsNotApplicable()100%11100%
get_HasReasons()100%11100%
Allow()100%11100%
NotApplicable()100%11100%
Deny(...)100%11100%
Deny(...)100%11100%
Deny(...)100%11100%
Warning(...)100%11100%
Warning(...)100%11100%
Warning(...)100%11100%
NormalizeReasons(...)100%2424100%
CreateFallbackReason(...)100%11100%
CreateReasonCodes(...)100%44100%

File(s)

/home/runner/work/AsiBackbone/AsiBackbone/src/AsiBackbone.Core/Constraints/ConstraintEvaluationResult.cs

#LineLine coverage
 1using System.Collections.ObjectModel;
 2using AsiBackbone.Core.Results;
 3
 4namespace AsiBackbone.Core.Constraints;
 5
 6/// <summary>
 7/// Represents the framework-neutral result of evaluating a constraint.
 8/// </summary>
 9public sealed class ConstraintEvaluationResult
 10{
 11    private const string DefaultDeniedCode = "constraint.denied";
 12    private const string DefaultDeniedMessage = "Constraint denied the operation.";
 13    private const string DefaultWarningCode = "constraint.warning";
 14    private const string DefaultWarningMessage = "Constraint produced a warning.";
 15
 216    private static readonly OperationReason[] EmptyReasons = [];
 17
 218    private static readonly ReadOnlyCollection<string> EmptyReasonCodes =
 219        Array.AsReadOnly(Array.Empty<string>());
 20
 221    private static readonly ConstraintEvaluationResult AllowedResult =
 222        new(ConstraintEvaluationOutcome.Allowed, EmptyReasons);
 23
 224    private static readonly ConstraintEvaluationResult NotApplicableResult =
 225        new(ConstraintEvaluationOutcome.NotApplicable, EmptyReasons);
 26
 11027    private ConstraintEvaluationResult(
 11028        ConstraintEvaluationOutcome outcome,
 11029        IReadOnlyList<OperationReason> reasons)
 30    {
 11031        Outcome = outcome;
 11032        Reasons = reasons;
 11033        ReasonCodes = CreateReasonCodes(reasons);
 11034    }
 35
 36    /// <summary>
 37    /// Gets the constraint evaluation outcome.
 38    /// </summary>
 39    public ConstraintEvaluationOutcome Outcome { get; }
 40
 41    /// <summary>
 42    /// Gets reasons associated with denied or warning outcomes.
 43    /// </summary>
 44    public IReadOnlyList<OperationReason> Reasons { get; }
 45
 46    /// <summary>
 47    /// Gets machine-readable reason codes associated with denied or warning outcomes.
 48    /// </summary>
 49    public IReadOnlyList<string> ReasonCodes { get; }
 50
 51    /// <summary>
 52    /// Gets a value indicating whether the constraint allows the operation to proceed.
 53    /// </summary>
 1054    public bool CanProceed => Outcome is not ConstraintEvaluationOutcome.Denied;
 55
 56    /// <summary>
 57    /// Gets a value indicating whether this result denies the operation.
 58    /// </summary>
 27359    public bool IsDenied => Outcome is ConstraintEvaluationOutcome.Denied;
 60
 61    /// <summary>
 62    /// Gets a value indicating whether this result contains warnings.
 63    /// </summary>
 23064    public bool IsWarning => Outcome is ConstraintEvaluationOutcome.Warning;
 65
 66    /// <summary>
 67    /// Gets a value indicating whether this result is not applicable to the supplied context.
 68    /// </summary>
 669    public bool IsNotApplicable => Outcome is ConstraintEvaluationOutcome.NotApplicable;
 70
 71    /// <summary>
 72    /// Gets a value indicating whether the result contains reason data.
 73    /// </summary>
 474    public bool HasReasons => Reasons.Count > 0;
 75
 76    /// <summary>
 77    /// Creates an allowed constraint result.
 78    /// </summary>
 79    /// <returns>An allowed constraint evaluation result.</returns>
 80    public static ConstraintEvaluationResult Allow()
 81    {
 7982        return AllowedResult;
 83    }
 84
 85    /// <summary>
 86    /// Creates a not-applicable constraint result.
 87    /// </summary>
 88    /// <returns>A not-applicable constraint evaluation result.</returns>
 89    public static ConstraintEvaluationResult NotApplicable()
 90    {
 1891        return NotApplicableResult;
 92    }
 93
 94    /// <summary>
 95    /// Creates a denied constraint result.
 96    /// </summary>
 97    /// <param name="code">The machine-readable reason code.</param>
 98    /// <param name="message">The human-readable reason message.</param>
 99    /// <returns>A denied constraint evaluation result.</returns>
 100    public static ConstraintEvaluationResult Deny(string code, string message)
 101    {
 48102        return Deny(OperationReason.Create(code, message));
 103    }
 104
 105    /// <summary>
 106    /// Creates a denied constraint result.
 107    /// </summary>
 108    /// <param name="reason">The reason associated with the denied result.</param>
 109    /// <returns>A denied constraint evaluation result.</returns>
 110    public static ConstraintEvaluationResult Deny(OperationReason reason)
 111    {
 50112        ArgumentNullException.ThrowIfNull(reason);
 113
 49114        return new ConstraintEvaluationResult(
 49115            ConstraintEvaluationOutcome.Denied,
 49116            Array.AsReadOnly([reason]));
 117    }
 118
 119    /// <summary>
 120    /// Creates a denied constraint result.
 121    /// </summary>
 122    /// <param name="reasons">The reasons associated with the denied result.</param>
 123    /// <returns>A denied constraint evaluation result.</returns>
 124    public static ConstraintEvaluationResult Deny(IEnumerable<OperationReason> reasons)
 125    {
 8126        return new ConstraintEvaluationResult(
 8127            ConstraintEvaluationOutcome.Denied,
 8128            NormalizeReasons(reasons, DefaultDeniedCode, DefaultDeniedMessage));
 129    }
 130
 131    /// <summary>
 132    /// Creates a warning constraint result.
 133    /// </summary>
 134    /// <param name="code">The machine-readable reason code.</param>
 135    /// <param name="message">The human-readable reason message.</param>
 136    /// <returns>A warning constraint evaluation result.</returns>
 137    public static ConstraintEvaluationResult Warning(string code, string message)
 138    {
 38139        return Warning(OperationReason.Create(code, message));
 140    }
 141
 142    /// <summary>
 143    /// Creates a warning constraint result.
 144    /// </summary>
 145    /// <param name="reason">The reason associated with the warning result.</param>
 146    /// <returns>A warning constraint evaluation result.</returns>
 147    public static ConstraintEvaluationResult Warning(OperationReason reason)
 148    {
 40149        ArgumentNullException.ThrowIfNull(reason);
 150
 39151        return new ConstraintEvaluationResult(
 39152            ConstraintEvaluationOutcome.Warning,
 39153            Array.AsReadOnly([reason]));
 154    }
 155
 156    /// <summary>
 157    /// Creates a warning constraint result.
 158    /// </summary>
 159    /// <param name="reasons">The reasons associated with the warning result.</param>
 160    /// <returns>A warning constraint evaluation result.</returns>
 161    public static ConstraintEvaluationResult Warning(IEnumerable<OperationReason> reasons)
 162    {
 5163        return new ConstraintEvaluationResult(
 5164            ConstraintEvaluationOutcome.Warning,
 5165            NormalizeReasons(reasons, DefaultWarningCode, DefaultWarningMessage));
 166    }
 167
 168    private static ReadOnlyCollection<OperationReason> NormalizeReasons(
 169        IEnumerable<OperationReason>? reasons,
 170        string fallbackCode,
 171        string fallbackMessage)
 172    {
 13173        if (reasons is null)
 174        {
 2175            return CreateFallbackReason(fallbackCode, fallbackMessage);
 176        }
 177
 11178        if (reasons is ICollection<OperationReason> collection)
 179        {
 9180            if (collection.Count == 0)
 181            {
 2182                return CreateFallbackReason(fallbackCode, fallbackMessage);
 183            }
 184
 7185            var normalizedReasons = new OperationReason[collection.Count];
 7186            int normalizedCount = 0;
 187
 42188            foreach (OperationReason? reason in collection)
 189            {
 14190                if (reason is not null)
 191                {
 8192                    normalizedReasons[normalizedCount] = reason;
 8193                    normalizedCount++;
 194                }
 195            }
 196
 7197            if (normalizedCount == 0)
 198            {
 2199                return CreateFallbackReason(fallbackCode, fallbackMessage);
 200            }
 201
 5202            if (normalizedCount == normalizedReasons.Length)
 203            {
 1204                return Array.AsReadOnly(normalizedReasons);
 205            }
 206
 4207            var filteredReasons = new OperationReason[normalizedCount];
 4208            Array.Copy(normalizedReasons, filteredReasons, normalizedCount);
 209
 4210            return Array.AsReadOnly(filteredReasons);
 211        }
 212
 2213        List<OperationReason>? normalizedList = null;
 214
 8215        foreach (OperationReason? reason in reasons)
 216        {
 2217            if (reason is not null)
 218            {
 2219                normalizedList ??= [];
 2220                normalizedList.Add(reason);
 221            }
 222        }
 223
 2224        return normalizedList is null || normalizedList.Count == 0
 2225            ? CreateFallbackReason(fallbackCode, fallbackMessage)
 2226            : Array.AsReadOnly([.. normalizedList]);
 227    }
 228
 229    private static ReadOnlyCollection<OperationReason> CreateFallbackReason(
 230        string fallbackCode,
 231        string fallbackMessage)
 232    {
 7233        return Array.AsReadOnly([OperationReason.Create(fallbackCode, fallbackMessage)]);
 234    }
 235
 236    private static ReadOnlyCollection<string> CreateReasonCodes(IReadOnlyList<OperationReason> reasons)
 237    {
 110238        if (reasons.Count == 0)
 239        {
 6240            return EmptyReasonCodes;
 241        }
 242
 104243        string[] reasonCodes = new string[reasons.Count];
 244
 424245        for (int index = 0; index < reasons.Count; index++)
 246        {
 108247            reasonCodes[index] = reasons[index].Code;
 248        }
 249
 104250        return Array.AsReadOnly(reasonCodes);
 251    }
 252}