diff --git a/src/SixLabors.Core/Helpers/DebugGuard.cs b/src/SixLabors.Core/Helpers/DebugGuard.cs
index bfc2a7a8d6..c7fb796b3d 100644
--- a/src/SixLabors.Core/Helpers/DebugGuard.cs
+++ b/src/SixLabors.Core/Helpers/DebugGuard.cs
@@ -3,6 +3,7 @@
using System;
using System.Diagnostics;
+using System.Runtime.CompilerServices;
namespace SixLabors
{
@@ -13,26 +14,47 @@ namespace SixLabors
internal static class DebugGuard
{
///
- /// Verifies, that the method parameter with specified object value is not null
- /// and throws an exception if it is found to be so.
+ /// Ensures that the value is not null.
///
- /// The target object, which cannot be null.
+ /// The target object, which cannot be null.
/// The name of the parameter that is to be checked.
- /// is null.
- /// The type of the object to verify.
+ /// The type of the value.
+ /// is null.
[Conditional("DEBUG")]
- public static void NotNull(T target, string parameterName)
- where T : class
+ [DebuggerStepThrough]
+ public static void NotNull(TValue value, string parameterName)
+ where TValue : class
{
- if (target is null)
+ if (value is null)
{
- throw new ArgumentNullException(parameterName);
+ ThrowArgumentNullException(parameterName);
}
}
///
- /// Verifies that the specified value is less than a maximum value
- /// and throws an exception if it is not.
+ /// Ensures that the target value is not null, empty, or whitespace.
+ ///
+ /// The target string, which should be checked against being null or empty.
+ /// Name of the parameter.
+ /// is null.
+ /// is empty or contains only blanks.
+ [Conditional("DEBUG")]
+ [DebuggerStepThrough]
+ public static void NotNullOrWhiteSpace(string value, string parameterName)
+ {
+ if (value is null)
+ {
+ ThrowArgumentNullException(parameterName);
+ }
+
+ if (string.IsNullOrWhiteSpace(value))
+ {
+ ThrowArgumentException("Must not be empty or whitespace.", parameterName);
+ }
+ }
+
+ ///
+ /// Ensures that the specified value is less than a maximum value.
///
/// The target value, which should be validated.
/// The maximum value.
@@ -42,12 +64,13 @@ namespace SixLabors
/// is greater than the maximum value.
///
[Conditional("DEBUG")]
+ [DebuggerStepThrough]
public static void MustBeLessThan(TValue value, TValue max, string parameterName)
where TValue : IComparable
{
if (value.CompareTo(max) >= 0)
{
- throw new ArgumentOutOfRangeException(parameterName, $"Value must be less than {max}.");
+ ThrowArgumentOutOfRangeException(parameterName, $"Value {value} must be less than {max}.");
}
}
@@ -63,12 +86,13 @@ namespace SixLabors
/// is greater than the maximum value.
///
[Conditional("DEBUG")]
+ [DebuggerStepThrough]
public static void MustBeLessThanOrEqualTo(TValue value, TValue max, string parameterName)
where TValue : IComparable
{
if (value.CompareTo(max) > 0)
{
- throw new ArgumentOutOfRangeException(parameterName, $"Value must be less than or equal to {max}.");
+ ThrowArgumentOutOfRangeException(parameterName, $"Value {value} must be less than or equal to {max}.");
}
}
@@ -84,14 +108,15 @@ namespace SixLabors
/// is less than the minimum value.
///
[Conditional("DEBUG")]
+ [DebuggerStepThrough]
public static void MustBeGreaterThan(TValue value, TValue min, string parameterName)
where TValue : IComparable
{
if (value.CompareTo(min) <= 0)
{
- throw new ArgumentOutOfRangeException(
+ ThrowArgumentOutOfRangeException(
parameterName,
- $"Value must be greater than {min}.");
+ $"Value {value} must be greater than {min}.");
}
}
@@ -107,33 +132,177 @@ namespace SixLabors
/// is less than the minimum value.
///
[Conditional("DEBUG")]
+ [DebuggerStepThrough]
public static void MustBeGreaterThanOrEqualTo(TValue value, TValue min, string parameterName)
where TValue : IComparable
{
if (value.CompareTo(min) < 0)
{
- throw new ArgumentOutOfRangeException(parameterName, $"Value must be greater than or equal to {min}.");
+ ThrowArgumentOutOfRangeException(parameterName, $"Value {value} must be greater than or equal to {min}.");
}
}
///
- /// Verifies, that the `target` array has declared the length or longer.
+ /// Verifies that the specified value is greater than or equal to a minimum value and less than
+ /// or equal to a maximum value and throws an exception if it is not.
///
- /// The element type of the spans.
- /// The target array.
- /// The min length the array must have.
+ /// The target value, which should be validated.
+ /// The minimum value.
+ /// The maximum value.
/// The name of the parameter that is to be checked.
+ /// The type of the value.
+ ///
+ /// is less than the minimum value of greater than the maximum value.
+ ///
+ [Conditional("DEBUG")]
+ [DebuggerStepThrough]
+ public static void MustBeBetweenOrEqualTo(TValue value, TValue min, TValue max, string parameterName)
+ where TValue : IComparable
+ {
+ if (value.CompareTo(min) < 0 || value.CompareTo(max) > 0)
+ {
+ ThrowArgumentOutOfRangeException(parameterName, $"Value {value} must be greater than or equal to {min} and less than or equal to {max}.");
+ }
+ }
+
+ ///
+ /// Verifies, that the method parameter with specified target value is true
+ /// and throws an exception if it is found to be so.
+ ///
+ /// The target value, which cannot be false.
+ /// The name of the parameter that is to be checked.
+ /// The error message, if any to add to the exception.
+ ///
+ /// is false.
+ ///
+ [Conditional("DEBUG")]
+ [DebuggerStepThrough]
+ public static void IsTrue(bool target, string parameterName, string message)
+ {
+ if (!target)
+ {
+ ThrowArgumentException(message, parameterName);
+ }
+ }
+
+ ///
+ /// Verifies, that the method parameter with specified target value is false
+ /// and throws an exception if it is found to be so.
+ ///
+ /// The target value, which cannot be true.
+ /// The name of the parameter that is to be checked.
+ /// The error message, if any to add to the exception.
///
/// is true.
///
[Conditional("DEBUG")]
- public static void MustBeSizedAtLeast(T[] target, int minLength, string parameterName)
- where T : struct
+ [DebuggerStepThrough]
+ public static void IsFalse(bool target, string parameterName, string message)
{
- if (target.Length < minLength)
+ if (target)
{
- throw new ArgumentException($"The size must be at least {minLength}.", parameterName);
+ ThrowArgumentException(message, parameterName);
}
}
+
+ ///
+ /// Verifies, that the `source` span has the length of 'minLength', or longer.
+ ///
+ /// The element type of the spans.
+ /// The source span.
+ /// The minimum length.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// has less than items.
+ ///
+ [Conditional("DEBUG")]
+ [DebuggerStepThrough]
+ public static void MustBeSizedAtLeast(ReadOnlySpan source, int minLength, string parameterName)
+ {
+ if (source.Length < minLength)
+ {
+ ThrowArgumentException($"Span-s must be at least of length {minLength}!", parameterName);
+ }
+ }
+
+ ///
+ /// Verifies that the 'destination' span is not shorter than 'source'.
+ ///
+ /// The source element type.
+ /// The destination element type.
+ /// The source span.
+ /// The destination span.
+ /// The name of the argument for 'destination'.
+ [Conditional("DEBUG")]
+ [DebuggerStepThrough]
+ public static void DestinationShouldNotBeTooShort(
+ ReadOnlySpan source,
+ Span destination,
+ string destinationParamName)
+ {
+ if (destination.Length < source.Length)
+ {
+ ThrowArgumentException($"Destination span is too short!", destinationParamName);
+ }
+ }
+
+ ///
+ /// Verifies that the 'destination' span is not shorter than 'source'.
+ ///
+ /// The source element type.
+ /// The destination element type.
+ /// The source span.
+ /// The destination span.
+ /// The name of the argument for 'destination'.
+ [Conditional("DEBUG")]
+ [DebuggerStepThrough]
+ public static void DestinationShouldNotBeTooShort(
+ Span source,
+ Span destination,
+ string destinationParamName)
+ {
+ if (destination.Length < source.Length)
+ {
+ ThrowArgumentException($"Destination span is too short!", destinationParamName);
+ }
+ }
+
+ ///
+ /// Verifies, that the `source` span has the length of 'minLength', or longer.
+ ///
+ /// The element type of the spans.
+ /// The target span.
+ /// The minimum length.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// has less than items.
+ ///
+ [Conditional("DEBUG")]
+ [DebuggerStepThrough]
+ public static void MustBeSizedAtLeast(Span source, int minLength, string parameterName)
+ {
+ if (source.Length < minLength)
+ {
+ ThrowArgumentException($"Span-s must be at least of length {minLength}!", parameterName);
+ }
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static void ThrowArgumentException(string message, string parameterName)
+ {
+ throw new ArgumentException(message, parameterName);
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static void ThrowArgumentOutOfRangeException(string parameterName, string message)
+ {
+ throw new ArgumentOutOfRangeException(parameterName, message);
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static void ThrowArgumentNullException(string parameterName)
+ {
+ throw new ArgumentNullException(parameterName);
+ }
}
}
\ No newline at end of file
diff --git a/src/SixLabors.Core/Helpers/Guard.cs b/src/SixLabors.Core/Helpers/Guard.cs
index d6616aa78e..09c8675d3a 100644
--- a/src/SixLabors.Core/Helpers/Guard.cs
+++ b/src/SixLabors.Core/Helpers/Guard.cs
@@ -4,7 +4,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
-using System.Linq;
+using System.Runtime.CompilerServices;
namespace SixLabors
{
@@ -15,22 +15,63 @@ namespace SixLabors
internal static class Guard
{
///
- /// Verifies that the specified value is less than a maximum value
- /// and throws an exception if it is not.
+ /// Ensures that the value is not null.
+ ///
+ /// The target object, which cannot be null.
+ /// The name of the parameter that is to be checked.
+ /// The type of the value.
+ /// is null.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [DebuggerStepThrough]
+ public static void NotNull(TValue value, string parameterName)
+ where TValue : class
+ {
+ if (value is null)
+ {
+ ThrowArgumentNullException(parameterName);
+ }
+ }
+
+ ///
+ /// Ensures that the target value is not null, empty, or whitespace.
+ ///
+ /// The target string, which should be checked against being null or empty.
+ /// Name of the parameter.
+ /// is null.
+ /// is empty or contains only blanks.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [DebuggerStepThrough]
+ public static void NotNullOrWhiteSpace(string value, string parameterName)
+ {
+ if (value is null)
+ {
+ ThrowArgumentNullException(parameterName);
+ }
+
+ if (string.IsNullOrWhiteSpace(value))
+ {
+ ThrowArgumentException("Must not be empty or whitespace.", parameterName);
+ }
+ }
+
+ ///
+ /// Ensures that the specified value is less than a maximum value.
///
/// The target value, which should be validated.
/// The maximum value.
/// The name of the parameter that is to be checked.
/// The type of the value.
- ///
+ ///
/// is greater than the maximum value.
///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [DebuggerStepThrough]
public static void MustBeLessThan(TValue value, TValue max, string parameterName)
- where TValue : IComparable
+ where TValue : IComparable
{
if (value.CompareTo(max) >= 0)
{
- throw new ArgumentOutOfRangeException(parameterName, $"Value must be less than {max}.");
+ ThrowArgumentOutOfRangeException(parameterName, $"Value {value} must be less than {max}.");
}
}
@@ -42,15 +83,17 @@ namespace SixLabors
/// The maximum value.
/// The name of the parameter that is to be checked.
/// The type of the value.
- ///
+ ///
/// is greater than the maximum value.
///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [DebuggerStepThrough]
public static void MustBeLessThanOrEqualTo(TValue value, TValue max, string parameterName)
- where TValue : IComparable
+ where TValue : IComparable
{
if (value.CompareTo(max) > 0)
{
- throw new ArgumentOutOfRangeException(parameterName, $"Value must be less than or equal to {max}.");
+ ThrowArgumentOutOfRangeException(parameterName, $"Value {value} must be less than or equal to {max}.");
}
}
@@ -62,15 +105,19 @@ namespace SixLabors
/// The minimum value.
/// The name of the parameter that is to be checked.
/// The type of the value.
- ///
+ ///
/// is less than the minimum value.
///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [DebuggerStepThrough]
public static void MustBeGreaterThan(TValue value, TValue min, string parameterName)
where TValue : IComparable
{
if (value.CompareTo(min) <= 0)
{
- throw new ArgumentOutOfRangeException(parameterName, $"Value must be greater than {min}.");
+ ThrowArgumentOutOfRangeException(
+ parameterName,
+ $"Value {value} must be greater than {min}.");
}
}
@@ -82,15 +129,17 @@ namespace SixLabors
/// The minimum value.
/// The name of the parameter that is to be checked.
/// The type of the value.
- ///
+ ///
/// is less than the minimum value.
///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [DebuggerStepThrough]
public static void MustBeGreaterThanOrEqualTo(TValue value, TValue min, string parameterName)
where TValue : IComparable
{
if (value.CompareTo(min) < 0)
{
- throw new ArgumentOutOfRangeException(parameterName, $"Value must be greater than or equal to {min}.");
+ ThrowArgumentOutOfRangeException(parameterName, $"Value {value} must be greater than or equal to {min}.");
}
}
@@ -103,34 +152,158 @@ namespace SixLabors
/// The maximum value.
/// The name of the parameter that is to be checked.
/// The type of the value.
- ///
+ ///
/// is less than the minimum value of greater than the maximum value.
///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [DebuggerStepThrough]
public static void MustBeBetweenOrEqualTo(TValue value, TValue min, TValue max, string parameterName)
where TValue : IComparable
{
if (value.CompareTo(min) < 0 || value.CompareTo(max) > 0)
{
- throw new ArgumentOutOfRangeException(parameterName, $"Value must be greater than or equal to {min} and less than or equal to {max}.");
+ ThrowArgumentOutOfRangeException(parameterName, $"Value {value} must be greater than or equal to {min} and less than or equal to {max}.");
+ }
+ }
+
+ ///
+ /// Verifies, that the method parameter with specified target value is true
+ /// and throws an exception if it is found to be so.
+ ///
+ /// The target value, which cannot be false.
+ /// The name of the parameter that is to be checked.
+ /// The error message, if any to add to the exception.
+ ///
+ /// is false.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [DebuggerStepThrough]
+ public static void IsTrue(bool target, string parameterName, string message)
+ {
+ if (!target)
+ {
+ ThrowArgumentException(message, parameterName);
+ }
+ }
+
+ ///
+ /// Verifies, that the method parameter with specified target value is false
+ /// and throws an exception if it is found to be so.
+ ///
+ /// The target value, which cannot be true.
+ /// The name of the parameter that is to be checked.
+ /// The error message, if any to add to the exception.
+ ///
+ /// is true.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [DebuggerStepThrough]
+ public static void IsFalse(bool target, string parameterName, string message)
+ {
+ if (target)
+ {
+ ThrowArgumentException(message, parameterName);
}
}
///
- /// Verifies, that the `target` span has the length of 'minLength', or longer.
+ /// Verifies, that the `source` span has the length of 'minLength', or longer.
///
/// The element type of the spans.
- /// The target span.
+ /// The source span.
/// The minimum length.
/// The name of the parameter that is to be checked.
///
- /// The length of is less than .
+ /// has less than items.
///
- public static void MustBeSizedAtLeast(T[] value, int minLength, string parameterName)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [DebuggerStepThrough]
+ public static void MustBeSizedAtLeast(ReadOnlySpan source, int minLength, string parameterName)
{
- if (value.Length < minLength)
+ if (source.Length < minLength)
{
- throw new ArgumentException($"The size must be at least {minLength}.", parameterName);
+ ThrowArgumentException($"Span-s must be at least of length {minLength}!", parameterName);
}
}
+
+ ///
+ /// Verifies, that the `source` span has the length of 'minLength', or longer.
+ ///
+ /// The element type of the spans.
+ /// The target span.
+ /// The minimum length.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// has less than items.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [DebuggerStepThrough]
+ public static void MustBeSizedAtLeast(Span source, int minLength, string parameterName)
+ {
+ if (source.Length < minLength)
+ {
+ ThrowArgumentException($"The size must be at least {minLength}.", parameterName);
+ }
+ }
+
+ ///
+ /// Verifies that the 'destination' span is not shorter than 'source'.
+ ///
+ /// The source element type.
+ /// The destination element type.
+ /// The source span.
+ /// The destination span.
+ /// The name of the argument for 'destination'.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [DebuggerStepThrough]
+ public static void DestinationShouldNotBeTooShort(
+ ReadOnlySpan source,
+ Span destination,
+ string destinationParamName)
+ {
+ if (destination.Length < source.Length)
+ {
+ ThrowArgumentException($"Destination span is too short!", destinationParamName);
+ }
+ }
+
+ ///
+ /// Verifies that the 'destination' span is not shorter than 'source'.
+ ///
+ /// The source element type.
+ /// The destination element type.
+ /// The source span.
+ /// The destination span.
+ /// The name of the argument for 'destination'.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [DebuggerStepThrough]
+ public static void DestinationShouldNotBeTooShort(
+ Span source,
+ Span destination,
+ string destinationParamName)
+ {
+ if (destination.Length < source.Length)
+ {
+ ThrowArgumentException($"Destination span is too short!", destinationParamName);
+ }
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static void ThrowArgumentException(string message, string parameterName)
+ {
+ throw new ArgumentException(message, parameterName);
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static void ThrowArgumentOutOfRangeException(string parameterName, string message)
+ {
+ throw new ArgumentOutOfRangeException(parameterName, message);
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static void ThrowArgumentNullException(string parameterName)
+ {
+ throw new ArgumentNullException(parameterName);
+ }
}
-}
\ No newline at end of file
+}
diff --git a/tests/SixLabors.Core.Tests/Helpers/GuardTests.cs b/tests/SixLabors.Core.Tests/Helpers/GuardTests.cs
index d6ef967b83..bed743767a 100644
--- a/tests/SixLabors.Core.Tests/Helpers/GuardTests.cs
+++ b/tests/SixLabors.Core.Tests/Helpers/GuardTests.cs
@@ -8,6 +8,96 @@ namespace SixLabors.Helpers.Tests
{
public class GuardTests
{
+ private class Foo
+ {
+ }
+
+ [Fact]
+ public void NotNull_WhenNull_Throws()
+ {
+ Foo foo = null;
+ Assert.Throws(() => Guard.NotNull(foo, nameof(foo)));
+ }
+
+ [Fact]
+ public void NotNull_NotNull()
+ {
+ Foo foo = new Foo();
+ Guard.NotNull(foo, nameof(foo));
+ }
+
+ [Theory]
+ [InlineData(null, true)]
+ [InlineData("", true)]
+ [InlineData(" ", true)]
+ [InlineData("$", false)]
+ [InlineData("lol", false)]
+ public void NotNullOrWhiteSpace(string str, bool shouldThrow)
+ {
+ if (shouldThrow)
+ {
+ Assert.ThrowsAny(() => Guard.NotNullOrWhiteSpace(str, nameof(str)));
+ }
+ else
+ {
+ Guard.NotNullOrWhiteSpace(str, nameof(str));
+ }
+ }
+
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void IsTrue(bool value)
+ {
+ if (!value)
+ {
+ Assert.Throws(() => Guard.IsTrue(value, nameof(value), "Boo!"));
+ }
+ else
+ {
+ Guard.IsTrue(value, nameof(value), "Boo.");
+ }
+ }
+
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void IsFalse(bool value)
+ {
+ if (value)
+ {
+ Assert.Throws(() => Guard.IsFalse(value, nameof(value), "Boo!"));
+ }
+ else
+ {
+ Guard.IsFalse(value, nameof(value), "Boo.");
+ }
+ }
+
+ [Theory]
+ [InlineData(0, 0, false)]
+ [InlineData(1, 1, false)]
+ [InlineData(1, 0, false)]
+ [InlineData(13, 13, false)]
+ [InlineData(20, 13, false)]
+ [InlineData(12, 13, true)]
+ [InlineData(0, 1, true)]
+ public void MustBeSizedAtLeast(int length, int minLength, bool shouldThrow)
+ {
+ int[] data = new int[length];
+
+ if (shouldThrow)
+ {
+ Assert.Throws(() => Guard.MustBeSizedAtLeast((Span)data, minLength, nameof(data)));
+ Assert.Throws(() => Guard.MustBeSizedAtLeast((ReadOnlySpan)data, minLength, nameof(data)));
+ }
+ else
+ {
+ Guard.MustBeSizedAtLeast((Span)data, minLength, nameof(data));
+ Guard.MustBeSizedAtLeast((ReadOnlySpan)data, minLength, nameof(data));
+ }
+ }
+
[Fact]
public void MustBeLessThan_IsLess_ThrowsNoException()
{
@@ -25,7 +115,7 @@ namespace SixLabors.Helpers.Tests
});
Assert.Equal("myParamName", exception.ParamName);
- Assert.Contains($"Value must be less than {max}.", exception.Message);
+ Assert.Contains($"Value {value} must be less than {max}.", exception.Message);
}
[Theory]
@@ -45,7 +135,7 @@ namespace SixLabors.Helpers.Tests
});
Assert.Equal("myParamName", exception.ParamName);
- Assert.Contains($"Value must be less than or equal to 1.", exception.Message);
+ Assert.Contains($"Value 2 must be less than or equal to 1.", exception.Message);
}
[Fact]
@@ -65,7 +155,7 @@ namespace SixLabors.Helpers.Tests
});
Assert.Equal("myParamName", exception.ParamName);
- Assert.Contains($"Value must be greater than {min}.", exception.Message);
+ Assert.Contains($"Value {value} must be greater than {min}.", exception.Message);
}
[Theory]
@@ -85,7 +175,7 @@ namespace SixLabors.Helpers.Tests
});
Assert.Equal("myParamName", exception.ParamName);
- Assert.Contains($"Value must be greater than or equal to 2.", exception.Message);
+ Assert.Contains($"Value 1 must be greater than or equal to 2.", exception.Message);
}
[Theory]
@@ -108,7 +198,7 @@ namespace SixLabors.Helpers.Tests
});
Assert.Equal("myParamName", exception.ParamName);
- Assert.Contains($"Value must be greater than or equal to {min} and less than or equal to {max}.", exception.Message);
+ Assert.Contains($"Value {value} must be greater than or equal to {min} and less than or equal to {max}.", exception.Message);
}
[Theory]
@@ -128,7 +218,7 @@ namespace SixLabors.Helpers.Tests
});
Assert.Equal("myParamName", exception.ParamName);
- Assert.Contains("The size must be at least 3.", exception.Message);
+ Assert.Contains("The size must be at least 3", exception.Message);
}
}
}