Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions src/Ramstack.HtmxToolkit/Argument.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// ReSharper disable ParameterOnlyUsedForPreconditionCheck.Local

using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;

namespace Ramstack.HtmxToolkit;

/// <summary>
/// Provides helper methods to validate arguments and throw exceptions if the arguments do not meet specified conditions.
/// </summary>
internal static class Argument
{
/// <summary>
/// Throws an <see cref="ArgumentNullException"/> if the specified object is <see langword="null"/>.
/// </summary>
/// <param name="value">The object to check.</param>
/// <param name="paramName">The name of the parameter being checked. Automatically supplied by the compiler.</param>
public static void ThrowIfNull([NotNull] object? value, [CallerArgumentExpression(nameof(value))] string? paramName = null)
{
if (value is null)
Error_ArgumentNull(paramName);
}

/// <summary>
/// Throws an <see cref="ArgumentNullException"/> if the specified string is <see langword="null"/>,
/// or an <see cref="ArgumentException"/> if it is empty.
/// </summary>
/// <param name="value">The string to check.</param>
/// <param name="paramName">The name of the parameter being checked. Automatically supplied by the compiler.</param>
public static void ThrowIfNullOrEmpty([NotNull] string? value, [CallerArgumentExpression(nameof(value))] string? paramName = null)
{
if (string.IsNullOrEmpty(value))
Error_ArgumentNullOrEmpty(value, paramName);
}

/// <summary>
/// Throws an <see cref="ArgumentNullException"/> if the specified string is <see langword="null"/>,
/// or an <see cref="ArgumentException"/> if it is empty or consists only of white-space characters.
/// </summary>
/// <param name="value">The string to check.</param>
/// <param name="paramName">The name of the parameter being checked. Automatically supplied by the compiler.</param>
public static void ThrowIfNullOrWhiteSpace([NotNull] string? value, [CallerArgumentExpression(nameof(value))] string? paramName = null)
{
if (string.IsNullOrWhiteSpace(value))
Error_ArgumentNullOrWhiteSpace(value, paramName);
}

[DoesNotReturn]
private static void Error_ArgumentNull(string? paramName) =>
throw new ArgumentNullException(paramName);

[DoesNotReturn]
private static void Error_ArgumentNullOrEmpty(string? value, string? paramName)
{
if (value is null)
throw new ArgumentNullException(paramName);

throw new ArgumentException(
"Argument should not be empty.",
paramName);
}

[DoesNotReturn]
private static void Error_ArgumentNullOrWhiteSpace(string? value, string? paramName)
{
if (value is null)
throw new ArgumentNullException(paramName);

throw new ArgumentException(
"Argument should not be empty or whitespace.",
paramName);
}
}
4 changes: 2 additions & 2 deletions src/Ramstack.HtmxToolkit/Collections/SmallDictionary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public TValue this[TKey key]
/// <param name="comparer">The comparer to use when comparing keys.</param>
public SmallDictionary(IComparer<TKey> comparer)
{
ArgumentNullException.ThrowIfNull(comparer);
Argument.ThrowIfNull(comparer);
_comparer = comparer;
}

Expand All @@ -90,7 +90,7 @@ public SmallDictionary(IComparer<TKey> comparer)
/// <param name="comparer">The comparer to use when comparing keys.</param>
public SmallDictionary(IEnumerable<KeyValuePair<TKey, TValue>> collection, IComparer<TKey> comparer) : this(comparer)
{
ArgumentNullException.ThrowIfNull(collection);
Argument.ThrowIfNull(collection);

if (collection is Dictionary<TKey, TValue> dictionary)
{
Expand Down
8 changes: 3 additions & 5 deletions src/Ramstack.HtmxToolkit/HtmxResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,7 @@ static HtmxResponse LocationImpl(HtmxResponse response, string path, HtmxLocatio
/// </remarks>
public HtmxResponse PushUrl(string url)
{
if (string.IsNullOrEmpty(url))
throw new ArgumentException("URL cannot be null or empty.", nameof(url));
Argument.ThrowIfNullOrEmpty(url);

return SetHistoryHeader(this, HtmxResponseHeaderNames.PushUrl, url, HtmxResponseHeaderNames.ReplaceUrl);
}
Expand Down Expand Up @@ -127,8 +126,7 @@ public HtmxResponse PushUrl(string url)
/// </remarks>
public HtmxResponse ReplaceUrl(string url)
{
if (string.IsNullOrEmpty(url))
throw new ArgumentException("URL cannot be null or empty.", nameof(url));
Argument.ThrowIfNullOrEmpty(url);

return SetHistoryHeader(this, HtmxResponseHeaderNames.ReplaceUrl, url, HtmxResponseHeaderNames.PushUrl);
}
Expand Down Expand Up @@ -344,7 +342,7 @@ private static HtmxResponse TriggerEventCore<T>(HtmxResponse response, string ev

private static string SerializeEventDetail<T>(T detail, JsonTypeInfo<T> jsonTypeInfo)
{
ArgumentNullException.ThrowIfNull(jsonTypeInfo);
Argument.ThrowIfNull(jsonTypeInfo);

var buffer = new ArrayBufferWriter<byte>();
using (var writer = new Utf8JsonWriter(buffer, new JsonWriterOptions { Encoder = JsonOptions.Encoder, SkipValidation = true }))
Expand Down
7 changes: 2 additions & 5 deletions src/Ramstack.HtmxToolkit/Internal/PendingEvents.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,8 @@ private PendingEvents(HttpResponse response) =>
/// <param name="detailJson">The event detail as JSON.</param>
public void AddEvent(HtmxTriggerTiming timing, string eventName, string detailJson)
{
if (string.IsNullOrWhiteSpace(eventName))
throw new ArgumentException("Event name cannot be null or whitespace.", nameof(eventName));

if (string.IsNullOrWhiteSpace(detailJson))
throw new ArgumentException("Event detail JSON cannot be null or whitespace.", nameof(detailJson));
Argument.ThrowIfNullOrWhiteSpace(eventName);
Argument.ThrowIfNullOrWhiteSpace(detailJson);

if (eventName == ProxyEventName)
throw new ArgumentException(
Expand Down
2 changes: 1 addition & 1 deletion tests/Ramstack.HtmxToolkit.Tests/HtmxResponseTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ public void ReplaceUrl_NullOrEmpty_ThrowsArgumentException(string? url)
{
var context = TestHelper.CreateHtmxRequestContext();

var exception = Assert.Throws<ArgumentException>(() =>
var exception = Assert.Catch<ArgumentException>(() =>
context.Response.Htmx(r => r.ReplaceUrl(url!)));

Assert.That(exception?.ParamName, Is.EqualTo("url"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ public void AddEvent_NullOrWhitespaceDetail_ThrowsArgumentException(string? deta
var context = TestHelper.CreateHttpContext();
var pending = PendingEvents.GetOrCreate(context.Response);

var exception = Assert.Throws<ArgumentException>(() =>
var exception = Assert.Catch<ArgumentException>(() =>
pending.AddEvent(HtmxTriggerTiming.Receive, "e", detail!));

Assert.That(exception?.ParamName, Is.EqualTo("detailJson"));
Expand All @@ -371,7 +371,7 @@ public void AddEvent_NullOrWhitespaceEventName_ThrowsArgumentException(string? e
var context = TestHelper.CreateHttpContext();
var pending = PendingEvents.GetOrCreate(context.Response);

var exception = Assert.Throws<ArgumentException>(() =>
var exception = Assert.Catch<ArgumentException>(() =>
pending.AddEvent(HtmxTriggerTiming.Receive, eventName!, "1"));

Assert.That(exception?.ParamName, Is.EqualTo("eventName"));
Expand Down
Loading