Skip to content

Commit

Permalink
Improve exceptions details for GetUnsafe methods on monads (#372)
Browse files Browse the repository at this point in the history
* Add NoneStateException for Maybe<T>

* Use explicit exceptions for GetUnsafe methods on Result

* Fix typos in Xml Docs

* Comply to ISerializable implementation

* Add missing Serializable attribute
  • Loading branch information
Tr00d authored Mar 16, 2023
1 parent a7fff14 commit b9e8b38
Show file tree
Hide file tree
Showing 8 changed files with 81 additions and 27 deletions.
3 changes: 2 additions & 1 deletion Vonage.Common.Test/Monads/MaybeTest.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using FluentAssertions;
using Vonage.Common.Monads;
using Vonage.Common.Monads.Exceptions;
using Vonage.Common.Test.Extensions;

namespace Vonage.Common.Test.Monads
Expand Down Expand Up @@ -69,7 +70,7 @@ public void GetUnsafe_ShouldReturnValue_GivenSome<T>(T value) =>
public void GetUnsafe_ShouldThrowException_GivenNone()
{
Action act = () => Maybe<string>.None.GetUnsafe();
act.Should().Throw<UnsafeValueException>().WithMessage("State is None.");
act.Should().Throw<NoneStateException>();
}

[Fact]
Expand Down
8 changes: 6 additions & 2 deletions Vonage.Common.Test/Monads/ResultTest.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using FluentAssertions;
using Vonage.Common.Failures;
using Vonage.Common.Monads;
using Vonage.Common.Monads.Exceptions;
using Vonage.Common.Test.Extensions;

namespace Vonage.Common.Test.Monads
Expand Down Expand Up @@ -112,7 +113,8 @@ public void GetFailureUnsafe_ShouldReturnFailure_GivenFailure() =>
public void GetFailureUnsafe_ShouldThrowException_GivenSuccess()
{
Action act = () => CreateSuccess(5).GetFailureUnsafe();
act.Should().Throw<UnsafeValueException>().WithMessage("State is Success.");
act.Should().Throw<SuccessStateException<int>>().WithMessage("State is Success.")
.Which.Success.Should().Be(5);
}

[Fact]
Expand All @@ -137,7 +139,9 @@ public void GetSuccessUnsafe_ShouldReturn_GivenSuccess() =>
public void GetSuccessUnsafe_ShouldThrowException_GivenFailure()
{
Action act = () => CreateFailure().GetSuccessUnsafe();
act.Should().Throw<UnsafeValueException>().WithMessage("State is Failure.");
act.Should().Throw<FailureStateException>()
.WithMessage("State is Failure.")
.Which.Failure.Should().Be(CreateResultFailure());
}

[Fact]
Expand Down
24 changes: 24 additions & 0 deletions Vonage.Common/Monads/Exceptions/FailureStateException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System;
using Vonage.Common.Failures;

namespace Vonage.Common.Monads.Exceptions;

/// <summary>
/// Represents errors that occurs when a Result is in a Failure state.
/// </summary>
[Serializable]
public class FailureStateException : Exception
{
/// <summary>
/// Gets the failure value of the Result.
/// </summary>
public IResultFailure Failure { get; }

/// <summary>
/// Creates a FailureStateException.
/// </summary>
/// <param name="failure">The failure value of the Result.</param>
public FailureStateException(IResultFailure failure)
: base("State is Failure.") =>
this.Failure = failure;
}
18 changes: 18 additions & 0 deletions Vonage.Common/Monads/Exceptions/NoneStateException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System;

namespace Vonage.Common.Monads.Exceptions;

/// <summary>
/// Represents errors that occurs when a Maybe is in a None state.
/// </summary>
[Serializable]
public class NoneStateException : Exception
{
/// <summary>
/// Creates a NoneStateException.
/// </summary>
public NoneStateException()
: base("State is None.")
{
}
}
23 changes: 23 additions & 0 deletions Vonage.Common/Monads/Exceptions/SuccessStateException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System;

namespace Vonage.Common.Monads.Exceptions;

/// <summary>
/// Represents errors that occurs when a Result is in a Success state.
/// </summary>
[Serializable]
public class SuccessStateException<T> : Exception
{
/// <summary>
/// Gets the success value of the Result.
/// </summary>
public T Success { get; }

/// <summary>
/// Creates a SuccessStateException.
/// </summary>
/// <param name="success">The success value of the Result.</param>
public SuccessStateException(T success)
: base("State is Success.") =>
this.Success = success;
}
5 changes: 3 additions & 2 deletions Vonage.Common/Monads/Maybe.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using Vonage.Common.Monads.Exceptions;

namespace Vonage.Common.Monads;

Expand Down Expand Up @@ -58,8 +59,8 @@ private Maybe(TA value)
/// Retrieves the Maybe's value. This method is unsafe and will throw an exception if in None state.
/// </summary>
/// <returns>The value if in Some state.</returns>
/// <exception cref="UnsafeValueException">When in None state.</exception>
public TA GetUnsafe() => this.IfNone(() => throw new UnsafeValueException("State is none."));
/// <exception cref="NoneStateException">When in None state.</exception>
public TA GetUnsafe() => this.IfNone(() => throw new NoneStateException());

/// <summary>
/// Returns the result of the operation if Maybe is in the None state, the Some value otherwise.
Expand Down
9 changes: 5 additions & 4 deletions Vonage.Common/Monads/Result.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Threading.Tasks;
using Vonage.Common.Failures;
using Vonage.Common.Monads.Exceptions;

namespace Vonage.Common.Monads;

Expand Down Expand Up @@ -85,9 +86,9 @@ public async Task<Result<TB>> BindAsync<TB>(Func<T, Task<Result<TB>>> bind) =>
/// Retrieves the Failure value. This method is unsafe and will throw an exception if in Success state.
/// </summary>
/// <returns>The Failure value when in Failure state.</returns>
/// <exception cref="UnsafeValueException">When in Success state.</exception>
/// <exception cref="FailureStateException">When in Success state.</exception>
public IResultFailure GetFailureUnsafe() =>
this.Match(_ => throw new UnsafeValueException("State is Success."), _ => _);
this.Match(value => throw new SuccessStateException<T>(value), _ => _);

/// <inheritdoc />
public override int GetHashCode() => this.IsSuccess ? this.success.GetHashCode() : this.failure.GetHashCode();
Expand All @@ -96,8 +97,8 @@ public IResultFailure GetFailureUnsafe() =>
/// Retrieves the Success value. This method is unsafe and will throw an exception if in Failure state.
/// </summary>
/// <returns>The Success value if in Success state.</returns>
/// <exception cref="UnsafeValueException">When in Failure state.</exception>
public T GetSuccessUnsafe() => this.Match(_ => _, _ => throw new UnsafeValueException("State is Failure."));
/// <exception cref="FailureStateException">When in Failure state.</exception>
public T GetSuccessUnsafe() => this.IfFailure(value => throw new FailureStateException(value));

/// <summary>
/// Invokes the action if Result is in the Failure state, otherwise nothing happens.
Expand Down
18 changes: 0 additions & 18 deletions Vonage.Common/Monads/UnsafeValueException.cs

This file was deleted.

0 comments on commit b9e8b38

Please sign in to comment.