< Summary

Information
Class: ArturRios.Util.FlowControl.Condition
Assembly: ArturRios.Util
File(s): /home/runner/work/dotnet-util/dotnet-util/src/FlowControl/Condition.cs
Line coverage
100%
Covered lines: 22
Uncovered lines: 0
Coverable lines: 22
Total lines: 128
Line coverage: 100%
Branch coverage
100%
Covered branches: 8
Total branches: 8
Branch coverage: 100%
Method coverage
100%
Covered methods: 9
Fully covered methods: 9
Total methods: 9
Method coverage: 100%
Full method coverage: 100%

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor()100%11100%
get_Create()100%11100%
get_FailedConditions()100%11100%
get_IsSatisfied()100%11100%
True(...)100%11100%
False(...)100%11100%
FailsWith(...)100%44100%
ThrowIfNotSatisfied()100%22100%
ToProcessOutput()100%22100%

File(s)

/home/runner/work/dotnet-util/dotnet-util/src/FlowControl/Condition.cs

#LineLine coverage
 1using ArturRios.Output;
 2
 3namespace ArturRios.Util.FlowControl;
 4
 5/// <summary>
 6/// A fluent helper to evaluate multiple boolean conditions and aggregate failures.
 7/// </summary>
 8/// <remarks>
 9/// Use <see cref="True"/> or <see cref="False"/> to set the result of an expression and chain <see cref="FailsWith"/> t
 10/// After building all conditions call <see cref="ThrowIfNotSatisfied"/> or inspect <see cref="IsSatisfied"/> / <see cre
 11/// Failures are reported in the order they were recorded, and two conditions that fail with the same
 12/// message are reported twice: the count reflects conditions, not distinct wordings.
 13/// </remarks>
 14public class Condition
 15{
 1416    private readonly List<string> _failedConditions = [];
 17    private bool? _expression;
 18
 19    /// <summary>
 20    /// Creates a new <see cref="Condition"/> instance. Syntactic sugar for <c>new Condition()</c>.
 21    /// </summary>
 1422    public static Condition Create => new();
 23
 24    /// <summary>
 25    /// Gets an array of all failure messages collected by <see cref="FailsWith"/>, in the order they failed.
 26    /// </summary>
 827    public string[] FailedConditions => [.. _failedConditions];
 28
 29    /// <summary>
 30    /// Indicates whether all evaluated conditions have succeeded (i.e. there are no failures).
 31    /// </summary>
 932    public bool IsSatisfied => _failedConditions.Count == 0;
 33
 34    /// <summary>
 35    /// Sets the current expression result to <paramref name="expression"/>.
 36    /// </summary>
 37    /// <param name="expression">The boolean value representing the success of the condition.</param>
 38    /// <returns>The current <see cref="Condition"/> for fluent chaining.</returns>
 39    public Condition True(bool expression)
 40    {
 1541        _expression = expression;
 42
 1543        return this;
 44    }
 45
 46    /// <summary>
 47    /// Sets the current expression result to the negated value of <paramref name="expression"/>.
 48    /// </summary>
 49    /// <param name="expression">The boolean to negate.</param>
 50    /// <returns>The current <see cref="Condition"/> for fluent chaining.</returns>
 51    public Condition False(bool expression)
 52    {
 553        _expression = !expression;
 54
 555        return this;
 56    }
 57
 58    /// <summary>
 59    /// Adds an error message if the most recently set expression evaluated to <c>false</c>.
 60    /// </summary>
 61    /// <param name="error">The error message describing the failure.</param>
 62    /// <returns>The current <see cref="Condition"/> for fluent chaining.</returns>
 63    /// <exception cref="ArgumentNullException"><paramref name="error"/> is <c>null</c>.</exception>
 64    /// <exception cref="InvalidOperationException">
 65    /// No <see cref="True"/> or <see cref="False"/> call precedes this one. Recording a failure for an
 66    /// expression that was never evaluated would silently invent one.
 67    /// </exception>
 68    public Condition FailsWith(string error)
 69    {
 2270        ArgumentNullException.ThrowIfNull(error);
 71
 2172        if (_expression is null)
 73        {
 174            throw new InvalidOperationException(
 175                $"{nameof(FailsWith)} must follow a call to {nameof(True)} or {nameof(False)}.");
 76        }
 77
 2078        if (!_expression.Value)
 79        {
 1380            _failedConditions.Add(error);
 81        }
 82
 2083        return this;
 84    }
 85
 86    /// <summary>
 87    /// Throws a <see cref="ConditionFailedException"/> if any condition failed.
 88    /// </summary>
 89    /// <exception cref="ConditionFailedException">Thrown when <see cref="IsSatisfied"/> is false.</exception>
 90    public void ThrowIfNotSatisfied()
 91    {
 292        if (IsSatisfied)
 93        {
 194            return;
 95        }
 96
 197        throw new ConditionFailedException(FailedConditions);
 98    }
 99
 100    /// <summary>
 101    /// Converts the condition failures into a <see cref="ProcessOutput"/> instance.
 102    /// </summary>
 103    /// <returns>A <see cref="ProcessOutput"/> with errors populated when the condition is not satisfied.</returns>
 104    public ProcessOutput ToProcessOutput()
 105    {
 4106        var output = new ProcessOutput();
 107
 4108        if (!IsSatisfied)
 109        {
 2110            output.AddErrors(_failedConditions.ToList());
 111        }
 112
 4113        return output;
 114    }
 115}
 116
 117/// <summary>
 118/// Exception raised when one or more conditions fail in a <see cref="Condition"/> chain.
 119/// </summary>
 120/// <param name="errors">The set of failure messages collected.</param>
 121public class ConditionFailedException(string[] errors)
 122    : Exception($"A total of {errors.Length} conditions failed: {string.Join("; ", errors)}")
 123{
 124    /// <summary>
 125    /// The failure messages that caused this exception, in the order they failed.
 126    /// </summary>
 127    public string[] Errors { get; } = errors;
 128}