< Summary

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

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
get_Errors()100%11100%

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{
 16    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>
 22    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>
 27    public string[] FailedConditions => [.. _failedConditions];
 28
 29    /// <summary>
 30    /// Indicates whether all evaluated conditions have succeeded (i.e. there are no failures).
 31    /// </summary>
 32    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    {
 41        _expression = expression;
 42
 43        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    {
 53        _expression = !expression;
 54
 55        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    {
 70        ArgumentNullException.ThrowIfNull(error);
 71
 72        if (_expression is null)
 73        {
 74            throw new InvalidOperationException(
 75                $"{nameof(FailsWith)} must follow a call to {nameof(True)} or {nameof(False)}.");
 76        }
 77
 78        if (!_expression.Value)
 79        {
 80            _failedConditions.Add(error);
 81        }
 82
 83        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    {
 92        if (IsSatisfied)
 93        {
 94            return;
 95        }
 96
 97        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    {
 106        var output = new ProcessOutput();
 107
 108        if (!IsSatisfied)
 109        {
 110            output.AddErrors(_failedConditions.ToList());
 111        }
 112
 113        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)
 1122    : 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>
 2127    public string[] Errors { get; } = errors;
 128}