Skip to content

Commit

Permalink
Improving code coverage and documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
tsutomi committed Jul 6, 2024
1 parent ada0a0d commit aef1770
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 0 deletions.
54 changes: 54 additions & 0 deletions src/Deveel.Results/OperationResultExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,33 @@ public static bool HasValidationErrors(this IOperationResult result)
public static IReadOnlyList<ValidationResult> ValidationResults(this IOperationResult result)
=> result.HasValidationErrors() ? ((IValidationError)result.Error!).ValidationResults : Array.Empty<ValidationResult>();

/// <summary>
/// Attempts to match the operation result to a specific state
/// that can be handled by the caller.
/// </summary>
/// <typeparam name="TResult">
/// The type of the result that is returned by the match.
/// </typeparam>
/// <param name="result">
/// The operation result to match.
/// </param>
/// <param name="ifSuccess">
/// A function that is called when the operation result was a success.
/// </param>
/// <param name="ifError">
/// A function that is called when the operation result was an error.
/// </param>
/// <param name="ifUnchanged">
/// A function that is called when the operation result caused no changed
/// to the object.
/// </param>
/// <returns>
/// Returns the result of the function that was called based on the state
/// of the operation result.
/// </returns>
/// <exception cref="InvalidOperationException">
/// Thrown when the operation result is in an unknown state.
/// </exception>
public static TResult Match<TResult>(this IOperationResult result,
Func<TResult>? ifSuccess = null,
Func<IOperationError?, TResult>? ifError = null,
Expand Down Expand Up @@ -116,6 +143,33 @@ public static TResult Match<TResult>(this IOperationResult result,
throw new InvalidOperationException("The operation result is in an unknown state.");
}

/// <summary>
/// Attempts to match the operation result to a specific state
/// that can be handled by the caller.
/// </summary>
/// <typeparam name="TResult">
/// The type of the result that is returned by the match.
/// </typeparam>
/// <param name="result">
/// The operation result to match.
/// </param>
/// <param name="ifSuccess">
/// A function that is called when the operation result was a success.
/// </param>
/// <param name="ifError">
/// A function that is called when the operation result was an error.
/// </param>
/// <param name="ifUnchanged">
/// A function that is called when the operation result caused no changed
/// to the object.
/// </param>
/// <returns>
/// Returns the result of the function that was called based on the state
/// of the operation result.
/// </returns>
/// <exception cref="InvalidOperationException">
/// Thrown when the operation result is in an unknown state.
/// </exception>
public static Task<TResult> MatchAsync<TResult>(this IOperationResult result,
Func<Task<TResult>>? ifSuccess = null,
Func<IOperationError?, Task<TResult>>? ifError = null,
Expand Down
36 changes: 36 additions & 0 deletions src/Deveel.Results/OperationResult_T.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

namespace Deveel
{
/// <summary>
/// A result of an operation that has a value of a specific type.
/// </summary>
/// <typeparam name="T">
/// The type of the value that represents the result of the operation.
/// </typeparam>
public readonly struct OperationResult<T> : IOperationResult<T>
{
private OperationResult(OperationResultType resultType, T? value, IOperationError? error)
Expand Down Expand Up @@ -111,11 +117,41 @@ public static OperationResult<T> Fail(string code, string domain, string? messag
public static OperationResult<T> ValidationFailed(string code, string domain, IEnumerable<ValidationResult> results)
=> Fail(new OperationValidationError(code, domain, results.ToList()));

/// <summary>
/// Implicitly converts an instance of <see cref="OperationResult{T}"/>
/// to an instance of <see cref="OperationResult"/>.
/// </summary>
/// <remarks>
/// This conversion is useful when you need to convert an operation result
/// to a strongly-typed result, for example, in contexts where the expected
/// result of a method is strongly-typed, but a child operation may return
/// a generic result, that is an error, and you want to propagate the error
/// without losing the type information.
/// </remarks>
/// <param name="result">
/// The operation result to convert.
/// </param>
public static implicit operator OperationResult<T>(OperationResult result)
=> new OperationResult<T>(result.ResultType, default, result.Error);

/// <summary>
/// Implicitly converts an instance of <typeparamref name="T"/> to an
/// operation result that represents a success.
/// </summary>
/// <param name="value">
/// The value to convert to an operation result.
/// </param>
/// <seealso cref="Success"/>
public static implicit operator OperationResult<T>(T value) => Success(value);

/// <summary>
/// Implicitly converts an instance of <see cref="OperationException"/>
/// to an operation result that represents a failure.
/// </summary>
/// <param name="error">
/// The error that caused the operation to fail.
/// </param>
/// <seealso cref="Fail(IOperationError)"/>
public static implicit operator OperationResult<T>(OperationException error) => Fail(error);
}
}
22 changes: 22 additions & 0 deletions test/Deveel.Results.XUnit/OperationErrorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -111,5 +111,27 @@ public static void ValidationError_WithResults()
Assert.Equal("biz", error.Domain);
Assert.Same(results, error.ValidationResults);
}

[Fact]
public static void OperationException_InnerExceptionIsOperationError()
{
var inner = new OperationException("err.2", "biz");
var exception = new OperationException("err.1", "biz", "An error has occurred", inner);

Assert.Equal("err.1", exception.ErrorCode);
Assert.Equal("biz", exception.ErrorDomain);
Assert.Equal("An error has occurred", exception.Message);
Assert.NotNull(exception.InnerException);

var error = Assert.IsAssignableFrom<IOperationError>(exception);
Assert.Equal("err.1", error.Code);
Assert.Equal("biz", error.Domain);
Assert.NotNull(error.InnerError);

Assert.NotNull(exception.InnerException);
var innerError = Assert.IsAssignableFrom<IOperationError>(exception.InnerException);
Assert.Equal("err.2", innerError.Code);
Assert.Equal("biz", innerError.Domain);
}
}
}
18 changes: 18 additions & 0 deletions test/Deveel.Results.XUnit/OperationResultOfTTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,24 @@ public static void OperationResultOfT_Success(Type resultType, object? value)
Assert.Equal(value, GetValue(result));
}

[Fact]
public static void OperationResultOfT_NotChanged()
{
var result = OperationResult<int>.NotChanged;
Assert.Equal(OperationResultType.Unchanged, result.ResultType);
Assert.Null(result.Error);
Assert.Equal(default, result.Value);
}

[Fact]
public static void OperationResultOfT_Cancelled()
{
var result = OperationResult<int>.Cancelled;
Assert.Equal(OperationResultType.Cancelled, result.ResultType);
Assert.Null(result.Error);
Assert.Equal(default, result.Value);
}

[Fact]
public static void OperationResult_FailWithCode()
{
Expand Down
15 changes: 15 additions & 0 deletions test/Deveel.Results.XUnit/OperationResultTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -201,4 +201,19 @@ public static void OperationResult_ValidationErrors()
Assert.True(result.HasValidationErrors());
Assert.Equal(errors, result.ValidationResults());
}

[Fact]
public static void OperationResult_Fail_WithValidationErrors()
{
var errors = new List<ValidationResult> {
new ValidationResult("The value is required", new[] { "value" }),
new ValidationResult("The value must be greater than 0", new[] { "value" })
};

var result = OperationResult.ValidationFailed("err.1", "biz", errors);

Assert.True(result.IsError());
Assert.True(result.HasValidationErrors());
Assert.Equal(errors, result.ValidationResults());
}
}

0 comments on commit aef1770

Please sign in to comment.