| | | 1 | | namespace Allyaria.Abstractions.Validation; |
| | | 2 | | |
| | | 3 | | /// <summary> |
| | | 4 | | /// Provides a set of helper methods for argument validation, returning <see cref="AryArgumentException" /> instances wh |
| | | 5 | | /// conditions fail. |
| | | 6 | | /// </summary> |
| | | 7 | | internal static class AryChecks |
| | | 8 | | { |
| | | 9 | | /// <summary>Validates that a value lies within a specified exclusive range.</summary> |
| | | 10 | | /// <typeparam name="T">The comparable type.</typeparam> |
| | | 11 | | /// <param name="value">The value to validate.</param> |
| | | 12 | | /// <param name="min">The minimum value (exclusive).</param> |
| | | 13 | | /// <param name="max">The maximum value (exclusive).</param> |
| | | 14 | | /// <param name="argName">The argument name.</param> |
| | | 15 | | /// <returns>An exception if out of range; otherwise, <c>null</c>.</returns> |
| | | 16 | | public static AryArgumentException? Between<T>(T value, T min, T max, string argName) |
| | | 17 | | where T : IComparable<T> |
| | 6 | 18 | | => value.CompareTo(other: min) <= 0 || value.CompareTo(other: max) >= 0 |
| | 6 | 19 | | ? new AryArgumentException( |
| | 6 | 20 | | message: $"{argName} must be between {min} and {max} (exclusive).", argName: argName, argValue: value |
| | 6 | 21 | | ) |
| | 6 | 22 | | : null; |
| | | 23 | | |
| | | 24 | | /// <summary>Validates a condition and throws a custom message if it fails.</summary> |
| | | 25 | | /// <param name="condition">The condition to test.</param> |
| | | 26 | | /// <param name="argName">The argument name.</param> |
| | | 27 | | /// <param name="message">The failure message.</param> |
| | | 28 | | /// <returns>An exception if condition is false; otherwise, <c>null</c>.</returns> |
| | | 29 | | public static AryArgumentException? Check(bool condition, string argName, string message) |
| | 21479 | 30 | | => !condition |
| | 21479 | 31 | | ? new AryArgumentException(message: message, argName: argName) |
| | 21479 | 32 | | : null; |
| | | 33 | | |
| | | 34 | | /// <summary>Validates that the specified enumeration value is defined within its type.</summary> |
| | | 35 | | /// <typeparam name="TEnum">The enumeration type.</typeparam> |
| | | 36 | | /// <param name="value">The value to check.</param> |
| | | 37 | | /// <param name="argName">The name of the argument being validated.</param> |
| | | 38 | | /// <returns>An <see cref="AryArgumentException" /> if the value is not defined; otherwise, <c>null</c>.</returns> |
| | | 39 | | public static AryArgumentException? EnumDefined<TEnum>(TEnum value, string argName) |
| | | 40 | | where TEnum : struct, Enum |
| | 6 | 41 | | => !Enum.IsDefined(value: value) |
| | 6 | 42 | | ? new AryArgumentException( |
| | 6 | 43 | | message: $"{argName} is not a valid value for this enum.", argName: argName, argValue: value |
| | 6 | 44 | | ) |
| | 6 | 45 | | : null; |
| | | 46 | | |
| | | 47 | | /// <summary>Validates that two values are equal.</summary> |
| | | 48 | | /// <typeparam name="T">The value type.</typeparam> |
| | | 49 | | /// <param name="value">The value to validate.</param> |
| | | 50 | | /// <param name="compare">The expected value to compare to.</param> |
| | | 51 | | /// <param name="argName">The name of the argument being validated.</param> |
| | | 52 | | /// <returns>An <see cref="AryArgumentException" /> if the values are not equal; otherwise, <c>null</c>.</returns> |
| | | 53 | | public static AryArgumentException? EqualTo<T>(T value, T compare, string argName) |
| | | 54 | | where T : IEquatable<T> |
| | 6 | 55 | | => !value.Equals(other: compare) |
| | 6 | 56 | | ? new AryArgumentException( |
| | 6 | 57 | | message: $"{argName} must be equal to {compare}.", argName: argName, argValue: value |
| | 6 | 58 | | ) |
| | 6 | 59 | | : null; |
| | | 60 | | |
| | | 61 | | /// <summary>Validates that a condition is <c>false</c>.</summary> |
| | | 62 | | /// <param name="condition">The boolean condition to evaluate.</param> |
| | | 63 | | /// <param name="argName">The name of the argument being validated.</param> |
| | | 64 | | /// <returns>An <see cref="AryArgumentException" /> if the condition is <c>true</c>; otherwise, <c>null</c>.</return |
| | | 65 | | public static AryArgumentException? False(bool condition, string argName) |
| | 6 | 66 | | => condition |
| | 6 | 67 | | ? new AryArgumentException(message: $"{argName} must be false.", argName: argName) |
| | 6 | 68 | | : null; |
| | | 69 | | |
| | | 70 | | /// <summary>Validates that a value is greater than a minimum exclusive value.</summary> |
| | | 71 | | /// <typeparam name="T">The comparable type.</typeparam> |
| | | 72 | | /// <param name="value">The value to validate.</param> |
| | | 73 | | /// <param name="minExclusive">The minimum exclusive value.</param> |
| | | 74 | | /// <param name="argName">The name of the argument.</param> |
| | | 75 | | /// <returns>An <see cref="AryArgumentException" /> if validation fails; otherwise, <c>null</c>.</returns> |
| | | 76 | | public static AryArgumentException? GreaterThan<T>(T value, T minExclusive, string argName) |
| | | 77 | | where T : IComparable<T> |
| | 6 | 78 | | => value.CompareTo(other: minExclusive) <= 0 |
| | 6 | 79 | | ? new AryArgumentException( |
| | 6 | 80 | | message: $"{argName} must be greater than {minExclusive}.", argName: argName, argValue: value |
| | 6 | 81 | | ) |
| | 6 | 82 | | : null; |
| | | 83 | | |
| | | 84 | | /// <summary>Validates that a value is greater than or equal to a specified minimum inclusive value.</summary> |
| | | 85 | | /// <typeparam name="T">The comparable type.</typeparam> |
| | | 86 | | /// <param name="value">The value to validate.</param> |
| | | 87 | | /// <param name="minInclusive">The minimum inclusive value.</param> |
| | | 88 | | /// <param name="argName">The argument name.</param> |
| | | 89 | | /// <returns>An exception if validation fails; otherwise, <c>null</c>.</returns> |
| | | 90 | | public static AryArgumentException? GreaterThanOrEqualTo<T>(T value, T minInclusive, string argName) |
| | | 91 | | where T : IComparable<T> |
| | 6 | 92 | | => value.CompareTo(other: minInclusive) < 0 |
| | 6 | 93 | | ? new AryArgumentException( |
| | 6 | 94 | | message: $"{argName} must be greater than or equal to {minInclusive}.", argName: argName, |
| | 6 | 95 | | argValue: value |
| | 6 | 96 | | ) |
| | 6 | 97 | | : null; |
| | | 98 | | |
| | | 99 | | /// <summary>Validates that a value lies within a specified inclusive range.</summary> |
| | | 100 | | /// <typeparam name="T">The comparable type.</typeparam> |
| | | 101 | | /// <param name="value">The value to validate.</param> |
| | | 102 | | /// <param name="min">The minimum value (inclusive).</param> |
| | | 103 | | /// <param name="max">The maximum value (inclusive).</param> |
| | | 104 | | /// <param name="argName">The argument name.</param> |
| | | 105 | | /// <returns>An exception if out of range; otherwise, <c>null</c>.</returns> |
| | | 106 | | public static AryArgumentException? InRange<T>(T value, T min, T max, string argName) |
| | | 107 | | where T : IComparable<T> |
| | 1345951 | 108 | | => value.CompareTo(other: min) < 0 || value.CompareTo(other: max) > 0 |
| | 1345951 | 109 | | ? new AryArgumentException( |
| | 1345951 | 110 | | message: $"{argName} must be between {min} and {max} (inclusive).", argName: argName, argValue: value |
| | 1345951 | 111 | | ) |
| | 1345951 | 112 | | : null; |
| | | 113 | | |
| | | 114 | | /// <summary>Validates that an object is assignable to the specified target type.</summary> |
| | | 115 | | /// <typeparam name="TTarget">The target type.</typeparam> |
| | | 116 | | /// <param name="value">The value to check.</param> |
| | | 117 | | /// <param name="argName">The argument name.</param> |
| | | 118 | | /// <returns>An exception if assignability fails; otherwise, <c>null</c>.</returns> |
| | | 119 | | public static AryArgumentException? IsAssignableTo<TTarget>(object? value, string argName) |
| | 6 | 120 | | => value is null || value is not TTarget |
| | 6 | 121 | | ? new AryArgumentException( |
| | 6 | 122 | | message: $"{argName} must be assignable to {typeof(TTarget).FullName}.", argName: argName, |
| | 6 | 123 | | argValue: value |
| | 6 | 124 | | ) |
| | 6 | 125 | | : null; |
| | | 126 | | |
| | | 127 | | /// <summary>Validates that a value is less than a maximum exclusive value.</summary> |
| | | 128 | | /// <typeparam name="T">The comparable type.</typeparam> |
| | | 129 | | /// <param name="value">The value to validate.</param> |
| | | 130 | | /// <param name="maxExclusive">The maximum exclusive value.</param> |
| | | 131 | | /// <param name="argName">The argument name.</param> |
| | | 132 | | /// <returns>An exception if validation fails; otherwise, <c>null</c>.</returns> |
| | | 133 | | public static AryArgumentException? LessThan<T>(T value, T maxExclusive, string argName) |
| | | 134 | | where T : IComparable<T> |
| | 6 | 135 | | => value.CompareTo(other: maxExclusive) >= 0 |
| | 6 | 136 | | ? new AryArgumentException( |
| | 6 | 137 | | message: $"{argName} must be less than {maxExclusive}.", argName: argName, argValue: value |
| | 6 | 138 | | ) |
| | 6 | 139 | | : null; |
| | | 140 | | |
| | | 141 | | /// <summary>Validates that a value is less than or equal to a maximum inclusive value.</summary> |
| | | 142 | | /// <typeparam name="T">The comparable type.</typeparam> |
| | | 143 | | /// <param name="value">The value to validate.</param> |
| | | 144 | | /// <param name="maxInclusive">The maximum inclusive value.</param> |
| | | 145 | | /// <param name="argName">The argument name.</param> |
| | | 146 | | /// <returns>An exception if validation fails; otherwise, <c>null</c>.</returns> |
| | | 147 | | public static AryArgumentException? LessThanOrEqualTo<T>(T value, T maxInclusive, string argName) |
| | | 148 | | where T : IComparable<T> |
| | 6 | 149 | | => value.CompareTo(other: maxInclusive) > 0 |
| | 6 | 150 | | ? new AryArgumentException( |
| | 6 | 151 | | message: $"{argName} must be less than or equal to {maxInclusive}.", argName: argName, argValue: value |
| | 6 | 152 | | ) |
| | 6 | 153 | | : null; |
| | | 154 | | |
| | | 155 | | /// <summary>Validates that a value is not its type’s default.</summary> |
| | | 156 | | /// <typeparam name="T">The struct type.</typeparam> |
| | | 157 | | /// <param name="value">The value to validate.</param> |
| | | 158 | | /// <param name="argName">The argument name.</param> |
| | | 159 | | /// <returns>An exception if value equals default; otherwise, <c>null</c>.</returns> |
| | | 160 | | public static AryArgumentException? NotDefault<T>(T value, string argName) |
| | | 161 | | where T : struct, IEquatable<T> |
| | 6 | 162 | | => value.Equals(other: default(T)) |
| | 6 | 163 | | ? new AryArgumentException(message: $"{argName} cannot be the default value.", argName: argName) |
| | 6 | 164 | | : null; |
| | | 165 | | |
| | | 166 | | /// <summary>Validates that two values are not equal.</summary> |
| | | 167 | | /// <typeparam name="T">The struct type.</typeparam> |
| | | 168 | | /// <param name="value">The first value.</param> |
| | | 169 | | /// <param name="compare">The second value.</param> |
| | | 170 | | /// <param name="argName">The argument name.</param> |
| | | 171 | | /// <returns>An exception if values are equal; otherwise, <c>null</c>.</returns> |
| | | 172 | | public static AryArgumentException? NotEqualTo<T>(T value, T compare, string argName) |
| | | 173 | | where T : IEquatable<T> |
| | 6 | 174 | | => value.Equals(other: compare) |
| | 6 | 175 | | ? new AryArgumentException( |
| | 6 | 176 | | message: $"{argName} must not be equal to {compare}.", argName: argName, argValue: value |
| | 6 | 177 | | ) |
| | 6 | 178 | | : null; |
| | | 179 | | |
| | | 180 | | /// <summary>Validates that a reference or nullable value is not <c>null</c>.</summary> |
| | | 181 | | /// <typeparam name="T">The type of value.</typeparam> |
| | | 182 | | /// <param name="value">The value to check.</param> |
| | | 183 | | /// <param name="argName">The argument name.</param> |
| | | 184 | | /// <returns>An exception if null; otherwise, <c>null</c>.</returns> |
| | | 185 | | public static AryArgumentException? NotNull<T>(T? value, string argName) |
| | 1482 | 186 | | => value is null |
| | 1482 | 187 | | ? new AryArgumentException(message: $"{argName} cannot be null.", argName: argName) |
| | 1482 | 188 | | : null; |
| | | 189 | | |
| | | 190 | | /// <summary>Validates that a string is not null or empty.</summary> |
| | | 191 | | /// <param name="value">The string to check.</param> |
| | | 192 | | /// <param name="argName">The argument name.</param> |
| | | 193 | | /// <returns>An exception if null or empty; otherwise, <c>null</c>.</returns> |
| | | 194 | | public static AryArgumentException? NotNullOrEmpty(string? value, string argName) |
| | 6 | 195 | | => string.IsNullOrEmpty(value: value) |
| | 6 | 196 | | ? new AryArgumentException(message: $"{argName} cannot be null or empty.", argName: argName) |
| | 6 | 197 | | : null; |
| | | 198 | | |
| | | 199 | | /// <summary>Validates that a collection is not null or empty.</summary> |
| | | 200 | | /// <typeparam name="T">The element type.</typeparam> |
| | | 201 | | /// <param name="collection">The collection to validate.</param> |
| | | 202 | | /// <param name="argName">The argument name.</param> |
| | | 203 | | /// <returns>An exception if null or empty; otherwise, <c>null</c>.</returns> |
| | | 204 | | public static AryArgumentException? NotNullOrEmpty<T>(IReadOnlyCollection<T>? collection, string argName) |
| | 6 | 205 | | => collection is null || collection.Count == 0 |
| | 6 | 206 | | ? new AryArgumentException(message: $"{argName} cannot be null or an empty collection.", argName: argName) |
| | 6 | 207 | | : null; |
| | | 208 | | |
| | | 209 | | /// <summary>Validates that a string is not null, empty, or whitespace.</summary> |
| | | 210 | | /// <param name="value">The string to validate.</param> |
| | | 211 | | /// <param name="argName">The argument name.</param> |
| | | 212 | | /// <returns>An exception if invalid; otherwise, <c>null</c>.</returns> |
| | | 213 | | public static AryArgumentException? NotNullOrWhiteSpace(string? value, string argName) |
| | 13068 | 214 | | => string.IsNullOrWhiteSpace(value: value) |
| | 13068 | 215 | | ? new AryArgumentException(message: $"{argName} cannot be null, empty, or whitespace.", argName: argName) |
| | 13068 | 216 | | : null; |
| | | 217 | | |
| | | 218 | | /// <summary>Validates that two values are of the same type.</summary> |
| | | 219 | | /// <typeparam name="T1">The first value type.</typeparam> |
| | | 220 | | /// <typeparam name="T2">The second value type.</typeparam> |
| | | 221 | | /// <param name="value1">The first value.</param> |
| | | 222 | | /// <param name="value2">The second value.</param> |
| | | 223 | | /// <param name="argName">The argument name.</param> |
| | | 224 | | /// <returns>An exception if type mismatch occurs; otherwise, <c>null</c>.</returns> |
| | | 225 | | public static AryArgumentException? SameType<T1, T2>(T1 value1, T2 value2, string argName) |
| | | 226 | | { |
| | 10 | 227 | | if (value1 is null || value2 is null) |
| | | 228 | | { |
| | 4 | 229 | | return new AryArgumentException( |
| | 4 | 230 | | message: $"{argName} cannot be compared because one or both values are null.", argName: argName, |
| | 4 | 231 | | argValue: value1 ?? (object?)value2 |
| | 4 | 232 | | ); |
| | | 233 | | } |
| | | 234 | | |
| | 6 | 235 | | var type1 = value1.GetType(); |
| | 6 | 236 | | var type2 = value2.GetType(); |
| | | 237 | | |
| | 6 | 238 | | return type1 != type2 |
| | 6 | 239 | | ? new AryArgumentException( |
| | 6 | 240 | | message: $"{argName} type mismatch: {type1.FullName} cannot be compared with {type2.FullName}.", |
| | 6 | 241 | | argName: argName, argValue: value1 |
| | 6 | 242 | | ) |
| | 6 | 243 | | : null; |
| | | 244 | | } |
| | | 245 | | |
| | | 246 | | /// <summary>Validates that a condition is <c>true</c>.</summary> |
| | | 247 | | /// <param name="condition">The boolean condition to evaluate.</param> |
| | | 248 | | /// <param name="argName">The name of the argument being validated.</param> |
| | | 249 | | /// <returns>An <see cref="AryArgumentException" /> if the condition is <c>false</c>; otherwise, <c>null</c>.</retur |
| | | 250 | | public static AryArgumentException? True(bool condition, string argName) |
| | 6 | 251 | | => !condition |
| | 6 | 252 | | ? new AryArgumentException(message: $"{argName} must be true.", argName: argName) |
| | 6 | 253 | | : null; |
| | | 254 | | } |