Skip to content

Commit 7ba91aa

Browse files
authored
Command-processing (#14)
* ICommandResult, UnsuccessfulCommandResult * v1 action
1 parent 7fa76bd commit 7ba91aa

11 files changed

+303
-1
lines changed

.github/workflows/push.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ on: [push]
55
jobs:
66
push:
77
permissions:
8+
checks: write
89
contents: read
910
packages: write
10-
uses: NetChris/workflows/.github/workflows/push-dotnet-build-test-pack-push-default.yml@v0.0
11+
uses: NetChris/workflows/.github/workflows/push-dotnet-build-test-pack-push-default.yml@v1
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using FluentAssertions;
2+
using NetChris.Core.CommandResult;
3+
using Xunit;
4+
5+
namespace NetChris.Core.UnitTests.CommandResult;
6+
7+
public abstract class SuccessfulCommandResultTests
8+
{
9+
protected abstract ICommandResult CommandResult { get; }
10+
11+
[Fact]
12+
public void IsSuccessful()
13+
{
14+
CommandResult.Successful.Should().BeTrue();
15+
}
16+
17+
[Fact]
18+
public void HasEmptyFailureDetail()
19+
{
20+
CommandResult.FailureDetail.Should().BeEmpty();
21+
}
22+
23+
[Fact]
24+
public void HasNoPrimaryFailure()
25+
{
26+
CommandResult.PrimaryFailure.Should().BeNull();
27+
}
28+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using FluentAssertions;
2+
using NetChris.Core.CommandResult;
3+
using Xunit;
4+
5+
namespace NetChris.Core.UnitTests.CommandResult;
6+
7+
public class TypedSuccessfulCommandResultTests : SuccessfulCommandResultTests
8+
{
9+
private readonly ICommandResult<TypedSuccessfulCommandResultTests> _typedResult;
10+
11+
public TypedSuccessfulCommandResultTests()
12+
{
13+
_typedResult =
14+
new SuccessfulCommandResult<TypedSuccessfulCommandResultTests>(this);
15+
}
16+
17+
protected override ICommandResult CommandResult => _typedResult;
18+
19+
[Fact]
20+
public void ThereIsAResult()
21+
{
22+
_typedResult.Result.Should().Be(this);
23+
}
24+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using FluentAssertions;
2+
using NetChris.Core.CommandResult;
3+
using Xunit;
4+
5+
namespace NetChris.Core.UnitTests.CommandResult;
6+
7+
public class TypedUnsuccessfulCommandResultTests : UnsuccessfulCommandResultTests
8+
{
9+
private readonly ICommandResult<TypedUnsuccessfulCommandResultTests> _typedResult =
10+
UnsuccessfulCommandResult.FromSingleFailure<TypedUnsuccessfulCommandResultTests>(
11+
"TypedResourceNotFound", "Resource not found: TYPED");
12+
13+
[Fact]
14+
public void ThereIsNoResult()
15+
{
16+
_typedResult.Result.Should().BeNull();
17+
}
18+
19+
protected override ICommandResult CommandResult => _typedResult;
20+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using FluentAssertions;
2+
using NetChris.Core.CommandResult;
3+
using Xunit;
4+
5+
namespace NetChris.Core.UnitTests.CommandResult;
6+
7+
public abstract class UnsuccessfulCommandResultTests
8+
{
9+
protected abstract ICommandResult CommandResult { get; }
10+
11+
[Fact]
12+
public void IsNotSuccessful()
13+
{
14+
CommandResult.Successful.Should().BeFalse();
15+
}
16+
17+
[Fact]
18+
public void HasNonEmptyFailureDetail()
19+
{
20+
CommandResult.FailureDetail.Should().NotBeEmpty();
21+
}
22+
23+
[Fact]
24+
public void HasPrimaryFailure()
25+
{
26+
CommandResult.PrimaryFailure.Should().NotBeNull();
27+
}
28+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
using NetChris.Core.CommandResult;
2+
3+
namespace NetChris.Core.UnitTests.CommandResult;
4+
5+
public class UntypedSuccessfulCommandResultTests : SuccessfulCommandResultTests
6+
{
7+
protected override ICommandResult CommandResult => new SuccessfulCommandResult();
8+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using NetChris.Core.CommandResult;
2+
3+
namespace NetChris.Core.UnitTests.CommandResult;
4+
5+
public class UntypedUnsuccessfulCommandResultTests : UnsuccessfulCommandResultTests
6+
{
7+
protected override ICommandResult CommandResult => UnsuccessfulCommandResult.FromSingleFailure(
8+
"UntypedResourceNotFound", "Resource not found: UNTYPED");
9+
10+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using NetChris.Core.Values;
4+
5+
namespace NetChris.Core.CommandResult;
6+
7+
/// <summary>
8+
/// Result of executing a command, with a typed result object
9+
/// </summary>
10+
public interface ICommandResult<TResult> : ICommandResult
11+
{
12+
/// <summary>
13+
/// The result of the command
14+
/// </summary>
15+
TResult? Result { get; }
16+
}
17+
18+
/// <summary>
19+
/// Result of executing a command
20+
/// </summary>
21+
public interface ICommandResult
22+
{
23+
/// <summary>
24+
/// Gets a value indicating whether the command was successful.
25+
/// </summary>
26+
bool Successful { get; }
27+
28+
/// <summary>
29+
/// Gets the command result failure detail.
30+
/// </summary>
31+
IEnumerable<SimpleResult> FailureDetail { get; }
32+
33+
/// <summary>
34+
/// Gets the <see cref="Exception"/> causing the command failure, if any.
35+
/// </summary>
36+
Exception? Exception { get; }
37+
38+
/// <summary>
39+
/// The primary failure, if any
40+
/// </summary>
41+
SimpleResult? PrimaryFailure { get; }
42+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
using NetChris.Core.Values;
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Collections.ObjectModel;
5+
6+
namespace NetChris.Core.CommandResult;
7+
8+
/// <summary>
9+
/// Simple implementation of a successful command result.
10+
/// </summary>
11+
public class SuccessfulCommandResult : ICommandResult
12+
{
13+
/// <inheritdoc />
14+
public bool Successful => true;
15+
16+
/// <inheritdoc />
17+
public IEnumerable<SimpleResult> FailureDetail => new ReadOnlyCollection<SimpleResult>(new List<SimpleResult>());
18+
19+
/// <inheritdoc />
20+
public virtual Exception? Exception => null;
21+
22+
/// <inheritdoc />
23+
public SimpleResult? PrimaryFailure => null;
24+
}
25+
26+
/// <summary>
27+
/// Simple implementation of a successful command result, with the typed result object.
28+
/// </summary>
29+
public class SuccessfulCommandResult<TResult> : SuccessfulCommandResult, ICommandResult<TResult>
30+
{
31+
/// <summary>
32+
/// Initializes a new instance of the <see cref="SuccessfulCommandResult{T}" /> class.
33+
/// </summary>
34+
public SuccessfulCommandResult(TResult result)
35+
{
36+
Result = result;
37+
}
38+
39+
/// <inheritdoc />
40+
public TResult Result { get; }
41+
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
using NetChris.Core.Values;
2+
using System;
3+
using System.Collections.Generic;
4+
5+
namespace NetChris.Core.CommandResult;
6+
7+
/// <summary>
8+
/// Simple implementation of an unsuccessful command result.
9+
/// </summary>
10+
public class UnsuccessfulCommandResult : ICommandResult
11+
{
12+
/// <summary>
13+
/// Get a new instance of <see cref="UnsuccessfulCommandResult"/> with a single failure.
14+
/// </summary>
15+
public static UnsuccessfulCommandResult FromSingleFailure(SimpleResult primaryFailure)
16+
{
17+
return new UnsuccessfulCommandResult(new[] { primaryFailure }, primaryFailure);
18+
}
19+
20+
/// <summary>
21+
/// Get a new instance of <see cref="UnsuccessfulCommandResult"/> with a single failure.
22+
/// </summary>
23+
public static UnsuccessfulCommandResult FromSingleFailure(string resultCode, string message)
24+
{
25+
return FromSingleFailure(new SimpleResult(resultCode, message));
26+
}
27+
/// <summary>
28+
/// Get a new instance of <see cref="UnsuccessfulCommandResult"/> with a single failure.
29+
/// </summary>
30+
public static UnsuccessfulCommandResult<TSingleFailureResult> FromSingleFailure<TSingleFailureResult>(SimpleResult primaryFailure)
31+
{
32+
return new UnsuccessfulCommandResult<TSingleFailureResult>(new[] { primaryFailure }, primaryFailure);
33+
}
34+
35+
/// <summary>
36+
/// Get a new instance of <see cref="UnsuccessfulCommandResult"/> with a single failure.
37+
/// </summary>
38+
public static UnsuccessfulCommandResult<TSingleFailureResult> FromSingleFailure<TSingleFailureResult>(string resultCode, string message)
39+
{
40+
return FromSingleFailure<TSingleFailureResult>(new SimpleResult(resultCode, message));
41+
}
42+
43+
/// <summary>
44+
/// Initializes a new instance of the <see cref="UnsuccessfulCommandResult" /> class.
45+
/// </summary>
46+
/// <param name="failureDetail">The command result failure reasons.</param>
47+
/// <param name="primaryFailure">The primary command result failure reason.</param>
48+
public UnsuccessfulCommandResult(IEnumerable<SimpleResult> failureDetail, SimpleResult primaryFailure)
49+
{
50+
FailureDetail = failureDetail;
51+
PrimaryFailure = primaryFailure;
52+
}
53+
54+
/// <inheritdoc />
55+
public bool Successful => false;
56+
57+
/// <inheritdoc />
58+
public IEnumerable<SimpleResult> FailureDetail { get; }
59+
60+
/// <inheritdoc />
61+
public virtual Exception? Exception => null;
62+
63+
/// <inheritdoc />
64+
public SimpleResult PrimaryFailure { get; }
65+
}
66+
67+
/// <summary>
68+
/// Simple implementation of an unsuccessful command result.
69+
/// </summary>
70+
public class UnsuccessfulCommandResult<TResult> : UnsuccessfulCommandResult, ICommandResult<TResult>
71+
{
72+
73+
/// <summary>
74+
/// Initializes a new instance of the <see cref="UnsuccessfulCommandResult" /> class.
75+
/// </summary>
76+
/// <param name="failureDetail">The command result failure reasons.</param>
77+
/// <param name="primaryFailure">The primary command result failure reason.</param>
78+
public UnsuccessfulCommandResult(IEnumerable<SimpleResult> failureDetail, SimpleResult primaryFailure) : base(
79+
failureDetail, primaryFailure)
80+
{
81+
}
82+
83+
/// <inheritdoc />
84+
public TResult? Result => default;
85+
}

0 commit comments

Comments
 (0)